aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--AUTHORS54
-rw-r--r--COPYRIGHT276
-rw-r--r--Makefile.common3
-rw-r--r--NEWS192
-rw-r--r--README1426
-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/midiparser_smf.cpp2
-rw-r--r--audio/midiparser_xmidi.cpp2
-rw-r--r--audio/miles_adlib.cpp1
-rw-r--r--audio/mods/maxtrax.cpp4
-rw-r--r--audio/mods/protracker.cpp2
-rw-r--r--audio/rate.cpp32
-rw-r--r--audio/rate_arm.cpp21
-rw-r--r--audio/rate_arm_asm.s34
-rw-r--r--audio/softsynth/fluidsynth.cpp14
-rw-r--r--audio/softsynth/fmtowns_pc98/towns_audio.cpp43
-rw-r--r--audio/softsynth/fmtowns_pc98/towns_audio.h4
-rw-r--r--audio/softsynth/fmtowns_pc98/towns_euphony.cpp1192
-rw-r--r--audio/softsynth/fmtowns_pc98/towns_euphony.h239
-rw-r--r--audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp4
-rw-r--r--audio/softsynth/mt32.cpp22
-rw-r--r--audio/softsynth/mt32/ROMInfo.cpp11
-rw-r--r--audio/softsynth/opl/mame.cpp4
-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.cpp67
-rw-r--r--backends/audiocd/sdl/sdl-audiocd.h15
-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/dinguxsdl/dinguxsdl-events.cpp5
-rw-r--r--backends/events/ps3sdl/ps3sdl-events.cpp8
-rw-r--r--backends/events/sdl/sdl-events.cpp106
-rw-r--r--backends/events/sdl/sdl-events.h5
-rw-r--r--backends/fs/abstract-fs.h14
-rw-r--r--backends/fs/chroot/chroot-fs-factory.cpp59
-rw-r--r--backends/fs/chroot/chroot-fs-factory.h46
-rw-r--r--backends/fs/chroot/chroot-fs.cpp124
-rw-r--r--backends/fs/chroot/chroot-fs.h57
-rw-r--r--backends/fs/posix/posix-fs.cpp64
-rw-r--r--backends/fs/posix/posix-fs.h14
-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.cpp353
-rw-r--r--backends/graphics/opengl/opengl-graphics.h88
-rw-r--r--backends/graphics/opengl/opengl-sys.h158
-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.cpp149
-rw-r--r--backends/graphics/openglsdl/openglsdl-graphics.h5
-rw-r--r--backends/graphics/surfacesdl/surfacesdl-graphics.cpp116
-rw-r--r--backends/graphics/surfacesdl/surfacesdl-graphics.h31
-rw-r--r--backends/midi/timidity.cpp1
-rw-r--r--backends/midi/windows.cpp3
-rw-r--r--backends/mixer/sdl/sdl-mixer.cpp59
-rw-r--r--backends/mixer/sdl13/sdl13-mixer.cpp108
-rw-r--r--backends/module.mk34
-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/gfx.cpp2
-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/dc/vmsave.cpp29
-rw-r--r--backends/platform/dingux/README.GCW035
-rwxr-xr-xbackends/platform/dingux/build.gcw0.sh6
-rw-r--r--backends/platform/dingux/dingux.mk21
-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/ios7/README.md150
-rw-r--r--backends/platform/ios7/ios7_app_delegate.h (renamed from backends/graphics/opengl/extensions.h)23
-rw-r--r--backends/platform/ios7/ios7_app_delegate.mm113
-rw-r--r--backends/platform/ios7/ios7_common.h131
-rw-r--r--backends/platform/ios7/ios7_keyboard.h44
-rw-r--r--backends/platform/ios7/ios7_keyboard.mm98
-rw-r--r--backends/platform/ios7/ios7_main.mm47
-rw-r--r--backends/platform/ios7/ios7_osys_events.cpp576
-rw-r--r--backends/platform/ios7/ios7_osys_main.cpp395
-rw-r--r--backends/platform/ios7/ios7_osys_main.h237
-rw-r--r--backends/platform/ios7/ios7_osys_sound.cpp105
-rw-r--r--backends/platform/ios7/ios7_osys_video.mm545
-rw-r--r--backends/platform/ios7/ios7_scummvm_view_controller.h33
-rw-r--r--backends/platform/ios7/ios7_scummvm_view_controller.mm32
-rw-r--r--backends/platform/ios7/ios7_video.h131
-rw-r--r--backends/platform/ios7/ios7_video.mm1002
-rw-r--r--backends/platform/ios7/module.mk17
-rw-r--r--backends/platform/iphone/iphone_keyboard.mm2
-rw-r--r--backends/platform/iphone/iphone_main.mm2
-rw-r--r--backends/platform/iphone/iphone_video.h4
-rw-r--r--backends/platform/iphone/iphone_video.mm2
-rw-r--r--backends/platform/iphone/osys_events.cpp2
-rw-r--r--backends/platform/iphone/osys_main.cpp8
-rw-r--r--backends/platform/iphone/osys_main.h2
-rw-r--r--backends/platform/iphone/osys_sound.cpp2
-rw-r--r--backends/platform/iphone/osys_video.mm4
-rw-r--r--backends/platform/maemo/debian/changelog18
-rwxr-xr-xbackends/platform/maemo/debian/rules18
-rw-r--r--backends/platform/maemo/maemo.cpp26
-rw-r--r--backends/platform/psp/README.PSP2
-rw-r--r--backends/platform/sdl/amigaos/amigaos-main.cpp35
-rw-r--r--backends/platform/sdl/amigaos/amigaos.mk11
-rw-r--r--backends/platform/sdl/macosx/appmenu_osx.mm25
-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.cpp132
-rw-r--r--backends/platform/sdl/posix/posix.h4
-rw-r--r--backends/platform/sdl/ps3/ps3.cpp9
-rw-r--r--backends/platform/sdl/raspberrypi/README.RASPBERRYPI77
-rw-r--r--backends/platform/sdl/sdl-sys.h32
-rw-r--r--backends/platform/sdl/sdl.cpp23
-rw-r--r--backends/platform/sdl/sdl.h5
-rw-r--r--backends/platform/sdl/win32/win32-main.cpp10
-rw-r--r--backends/platform/sdl/win32/win32.cpp11
-rw-r--r--backends/platform/sdl/win32/win32.h4
-rw-r--r--backends/platform/symbian/AdaptAllMMPs.pl2
-rw-r--r--backends/platform/symbian/BuildPackageUpload_LocalSettings.pl42
-rw-r--r--backends/platform/symbian/README2
-rw-r--r--backends/platform/symbian/S60/ScummVM_S60.mmp.in2
-rw-r--r--backends/platform/symbian/S60/ScummVM_S60_App.mmp2
-rw-r--r--backends/platform/symbian/S60v3/ScummVM_A0000658_S60v3.mmp.in5
-rw-r--r--backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in5
-rw-r--r--backends/platform/symbian/S80/ScummVM_S80.mmp.in2
-rw-r--r--backends/platform/symbian/S80/ScummVM_S80_App.mmp2
-rw-r--r--backends/platform/symbian/S90/Scummvm_S90.mmp.in2
-rw-r--r--backends/platform/symbian/S90/Scummvm_S90_App.mmp2
-rw-r--r--backends/platform/symbian/UIQ2/ScummVM.rss2
-rw-r--r--backends/platform/symbian/UIQ3/ScummVM.rss2
-rw-r--r--backends/platform/symbian/UIQ3/ScummVM_A0000658.rss2
-rw-r--r--backends/platform/symbian/UIQ3/ScummVM_A0000658_UIQ3.mmp.in2
-rw-r--r--backends/platform/symbian/UIQ3/ScummVM_UIQ3.mmp.in2
-rw-r--r--backends/platform/symbian/UIQ3/scummvm_A0000658_loc.rss2
-rw-r--r--backends/platform/symbian/help/ScummVM.rtf104
-rw-r--r--backends/platform/symbian/help/build_help.mk5
-rw-r--r--backends/platform/symbian/mmp/config.mmh2
-rw-r--r--backends/platform/symbian/mmp/scummvm_access.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_agi.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_agos.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_avalanche.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_base.mmp.in4
-rw-r--r--backends/platform/symbian/mmp/scummvm_bbvs.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_cge.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_cge2.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_cine.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_composer.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_cruise.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_draci.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_drascula.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_dreamweb.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_fullpipe.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_gob.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_groovie.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_hopkins.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_hugo.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_kyra.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_lastexpress.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_lure.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_m4.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_made.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_mads.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_mohawk.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_mortevielle.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_neverhood.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_parallaction.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_pegasus.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_prince.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_queen.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_saga.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_sci.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_scumm.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_sherlock.mmp.in53
-rw-r--r--backends/platform/symbian/mmp/scummvm_sky.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_sword1.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_sword2.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_sword25.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_teenagent.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_testbed.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_tinsel.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_toltecs.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_tony.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_toon.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_touche.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_tsage.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_tucker.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_voyeur.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_wintermute.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_zvision.mmp.in2
-rw-r--r--backends/platform/symbian/res/ScummVmAif.rss2
-rw-r--r--backends/platform/symbian/res/scummvm.rss2
-rw-r--r--backends/platform/symbian/res/scummvm_A0000658.rss2
-rw-r--r--backends/platform/symbian/src/ScummVm.hrh2
-rw-r--r--backends/platform/symbian/src/portdefs.h3
-rw-r--r--backends/platform/tizen/graphics.cpp10
-rw-r--r--backends/platform/tizen/graphics.h4
-rw-r--r--backends/platform/tizen/system.cpp49
-rw-r--r--backends/platform/wince/portdefs.h3
-rw-r--r--backends/platform/wince/wince-sdl.cpp4
-rw-r--r--backends/plugins/win32/win32-provider.cpp2
-rw-r--r--backends/saves/default/default-saves.cpp155
-rw-r--r--backends/saves/default/default-saves.h25
-rw-r--r--backends/saves/posix/posix-saves.cpp71
-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.cpp44
-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.cpp18
-rw-r--r--base/internal_version.h2
-rw-r--r--base/main.cpp35
-rw-r--r--base/version.cpp2
-rw-r--r--common/algorithm.h27
-rw-r--r--common/archive.cpp29
-rw-r--r--common/array.h95
-rw-r--r--common/dcl.cpp4
-rw-r--r--common/dcl.h1
-rw-r--r--common/fs.h7
-rw-r--r--common/gui_options.cpp23
-rw-r--r--common/gui_options.h75
-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/rational.h2
-rw-r--r--common/recorderfile.cpp4
-rw-r--r--common/rect.h3
-rw-r--r--common/rendermode.cpp30
-rw-r--r--common/rendermode.h5
-rw-r--r--common/savefile.h45
-rw-r--r--common/scummsys.h19
-rw-r--r--common/str.cpp94
-rw-r--r--common/str.h59
-rw-r--r--common/taskbar.h2
-rw-r--r--common/updates.cpp68
-rw-r--r--common/updates.h42
-rw-r--r--common/xmlparser.cpp48
-rwxr-xr-xconfig.guess143
-rwxr-xr-xconfig.sub38
-rwxr-xr-xconfigure733
-rw-r--r--devtools/convbdf.cpp4
-rw-r--r--devtools/create_access/amazon_resources.cpp757
-rw-r--r--devtools/create_access/amazon_resources.h62
-rw-r--r--devtools/create_access/create_access_dat.cpp430
-rw-r--r--devtools/create_access/create_access_dat.h184
-rw-r--r--devtools/create_access/martian_resources.cpp182
-rw-r--r--devtools/create_access/martian_resources.h52
-rw-r--r--devtools/create_access/module.mk13
-rwxr-xr-xdevtools/create_classicmacfonts.sh119
-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_kyradat/resources/lok_pc98_japanese.h5
-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/codeblocks.cpp5
-rw-r--r--devtools/create_project/codeblocks.h2
-rw-r--r--devtools/create_project/create_project.cpp188
-rw-r--r--devtools/create_project/create_project.h26
-rw-r--r--devtools/create_project/module.mk1
-rw-r--r--devtools/create_project/msbuild.cpp39
-rw-r--r--devtools/create_project/msvc.cpp5
-rw-r--r--devtools/create_project/msvc.h2
-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/scripts/postbuild.cmd2
-rw-r--r--devtools/create_project/scripts/prebuild.cmd2
-rw-r--r--devtools/create_project/xcode.cpp933
-rw-r--r--devtools/create_project/xcode.h184
-rw-r--r--devtools/create_project/xcode/create_project.xcodeproj/project.pbxproj22
-rw-r--r--devtools/create_translations/create_translations.h6
-rwxr-xr-xdevtools/credits.pl73
-rwxr-xr-xdevtools/dist-scummvm.sh70
-rwxr-xr-xdevtools/encode-macbinary.sh11
-rw-r--r--devtools/scumm-md5.txt150
-rw-r--r--devtools/skycpt/COMPACT.TXT2
-rw-r--r--devtools/skycpt/README4
-rwxr-xr-xdevtools/update-version.pl3
-rw-r--r--dists/amiga/RM2AG.rx170
-rw-r--r--dists/amiga/convertRM.sed17
-rw-r--r--dists/android/AndroidManifest.xml27
-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/debian/copyright2
-rw-r--r--dists/engine-data/README3
-rw-r--r--dists/engine-data/access.datbin0 -> 322768 bytes
-rw-r--r--dists/engine-data/kyra.datbin496648 -> 496555 bytes
-rw-r--r--dists/engine-data/sky.cptbin419427 -> 419427 bytes
-rw-r--r--dists/engine-data/testbed-audiocd-files/TESTBED0
-rw-r--r--dists/gcw0/default.gcw0.desktop5
-rwxr-xr-xdists/gcw0/scummvm.sh2
-rw-r--r--dists/gph/README-GPH2
-rw-r--r--dists/gph/scummvm.ini2
-rw-r--r--dists/ios7/Images.xcassets/AppIcon.appiconset/Contents.json86
-rw-r--r--dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29.pngbin0 -> 3084 bytes
-rw-r--r--dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29@2x.pngbin0 -> 6829 bytes
-rw-r--r--dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29@3x.pngbin0 -> 12228 bytes
-rw-r--r--dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40.pngbin0 -> 4356 bytes
-rw-r--r--dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40@2x.pngbin0 -> 10744 bytes
-rw-r--r--dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40@3x.pngbin0 -> 18115 bytes
-rw-r--r--dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-60@2x.pngbin0 -> 18115 bytes
-rw-r--r--dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-60@3x.pngbin0 -> 33953 bytes
-rw-r--r--dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-76.pngbin0 -> 10147 bytes
-rw-r--r--dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-76@2x.pngbin0 -> 26351 bytes
-rw-r--r--dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-83.5@2x.pngbin0 -> 24888 bytes
-rw-r--r--dists/ios7/Images.xcassets/Contents.json6
-rw-r--r--dists/ios7/Images.xcassets/LaunchImage.launchimage/Contents.json150
-rw-r--r--dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-1024x768.pngbin0 -> 94736 bytes
-rw-r--r--dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-1242x2208.pngbin0 -> 189477 bytes
-rw-r--r--dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-1536x2048.pngbin0 -> 233209 bytes
-rw-r--r--dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-2048x1536.pngbin0 -> 238722 bytes
-rw-r--r--dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-2208x1242.pngbin0 -> 251185 bytes
-rw-r--r--dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-640x1136-1.pngbin0 -> 80122 bytes
-rw-r--r--dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-750x1334.pngbin0 -> 98133 bytes
-rw-r--r--dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-768x1024.pngbin0 -> 95204 bytes
-rw-r--r--dists/ios7/Info.plist57
-rw-r--r--dists/ios7/Info.plist.in57
-rw-r--r--dists/iphone/Info.plist4
-rw-r--r--dists/irix/scummvm.spec2
-rw-r--r--dists/macosx/DS_Storebin12292 -> 15364 bytes
-rw-r--r--dists/macosx/Info.plist41
-rw-r--r--dists/macosx/Info.plist.in37
-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
-rw-r--r--dists/msvc14/create_msvc14.bat4
-rw-r--r--dists/openpandora/PXML.xml8
-rw-r--r--dists/openpandora/README-OPENPANDORA2
-rw-r--r--dists/openpandora/README-PND.txt2
-rw-r--r--dists/openpandora/index.html4
-rwxr-xr-xdists/openpandora/pnd_make.sh13
-rw-r--r--dists/ps3/readme-ps3.md4
-rw-r--r--dists/redhat/scummvm-tools.spec2
-rw-r--r--dists/redhat/scummvm.spec6
-rw-r--r--dists/redhat/scummvm.spec.in4
-rw-r--r--dists/samsungtv/README-SamsungTV2
-rw-r--r--dists/scummvm.rc14
-rw-r--r--dists/scummvm.rc.in6
-rw-r--r--dists/scummvm_logo.bmpbin0 -> 16052 bytes
-rwxr-xr-xdists/slackware/scummvm.SlackBuild2
-rw-r--r--dists/wii/meta.xml2
-rw-r--r--dists/win32/ScummVM.iss4
-rw-r--r--dists/win32/migration.bat2
-rw-r--r--dists/win32/scummvm.nsi6
-rw-r--r--dists/win32/scummvm.nsi.in2
-rw-r--r--doc/cz/PrectiMe1033
-rw-r--r--doc/de/Liesmich1502
-rw-r--r--doc/de/Neues190
-rw-r--r--engines/access/access.cpp34
-rw-r--r--engines/access/access.h12
-rw-r--r--engines/access/amazon/amazon_game.cpp79
-rw-r--r--engines/access/amazon/amazon_logic.cpp49
-rw-r--r--engines/access/amazon/amazon_resources.cpp2022
-rw-r--r--engines/access/amazon/amazon_resources.h63
-rw-r--r--engines/access/amazon/amazon_room.cpp5
-rw-r--r--engines/access/amazon/amazon_scripts.cpp21
-rw-r--r--engines/access/animation.cpp12
-rw-r--r--engines/access/asurface.cpp250
-rw-r--r--engines/access/asurface.h48
-rw-r--r--engines/access/bubble_box.cpp36
-rw-r--r--engines/access/char.cpp34
-rw-r--r--engines/access/configure.engine2
-rw-r--r--engines/access/debugger.cpp54
-rw-r--r--engines/access/debugger.h5
-rw-r--r--engines/access/detection.cpp7
-rw-r--r--engines/access/detection_tables.h16
-rw-r--r--engines/access/events.cpp7
-rw-r--r--engines/access/events.h2
-rw-r--r--engines/access/files.cpp39
-rw-r--r--engines/access/files.h7
-rw-r--r--engines/access/font.cpp9
-rw-r--r--engines/access/font.h4
-rw-r--r--engines/access/inventory.cpp35
-rw-r--r--engines/access/martian/martian_game.cpp24
-rw-r--r--engines/access/martian/martian_resources.cpp714
-rw-r--r--engines/access/martian/martian_resources.h30
-rw-r--r--engines/access/martian/martian_room.cpp2
-rw-r--r--engines/access/module.mk1
-rw-r--r--engines/access/resources.cpp135
-rw-r--r--engines/access/resources.h65
-rw-r--r--engines/access/room.cpp34
-rw-r--r--engines/access/screen.cpp102
-rw-r--r--engines/access/screen.h33
-rw-r--r--engines/access/scripts.cpp24
-rw-r--r--engines/access/scripts.h2
-rw-r--r--engines/access/sound.cpp57
-rw-r--r--engines/access/sound.h23
-rw-r--r--engines/access/video.cpp8
-rw-r--r--engines/access/video.h8
-rw-r--r--engines/access/video/movie_decoder.cpp741
-rw-r--r--engines/access/video/movie_decoder.h152
-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 engines/sci/graphics/paint.h)28
-rw-r--r--engines/advancedDetector.cpp79
-rw-r--r--engines/advancedDetector.h15
-rw-r--r--engines/agi/agi.cpp784
-rw-r--r--engines/agi/agi.h835
-rw-r--r--engines/agi/appleIIgs_timedelay_overwrite.h91
-rw-r--r--engines/agi/checks.cpp343
-rw-r--r--engines/agi/console.cpp423
-rw-r--r--engines/agi/console.h8
-rw-r--r--engines/agi/cycle.cpp544
-rw-r--r--engines/agi/detection.cpp183
-rw-r--r--engines/agi/detection_tables.h52
-rw-r--r--engines/agi/font.cpp1296
-rw-r--r--engines/agi/font.h1064
-rw-r--r--engines/agi/global.cpp308
-rw-r--r--engines/agi/graphics.cpp2313
-rw-r--r--engines/agi/graphics.h218
-rw-r--r--engines/agi/id.cpp2
-rw-r--r--engines/agi/inv.cpp322
-rw-r--r--engines/agi/inv.h61
-rw-r--r--engines/agi/keyboard.cpp792
-rw-r--r--engines/agi/keyboard.h101
-rw-r--r--engines/agi/loader_v1.cpp136
-rw-r--r--engines/agi/loader_v2.cpp101
-rw-r--r--engines/agi/loader_v3.cpp103
-rw-r--r--engines/agi/logic.cpp52
-rw-r--r--engines/agi/logic.h12
-rw-r--r--engines/agi/lzw.cpp17
-rw-r--r--engines/agi/menu.cpp947
-rw-r--r--engines/agi/menu.h119
-rw-r--r--engines/agi/module.mk2
-rw-r--r--engines/agi/motion.cpp222
-rw-r--r--engines/agi/mouse_cursor.h206
-rw-r--r--engines/agi/objects.cpp24
-rw-r--r--engines/agi/op_cmd.cpp2422
-rw-r--r--engines/agi/op_dbg.cpp58
-rw-r--r--engines/agi/op_test.cpp251
-rw-r--r--engines/agi/opcodes.cpp642
-rw-r--r--engines/agi/opcodes.h452
-rw-r--r--engines/agi/palette.h406
-rw-r--r--engines/agi/picture.cpp1143
-rw-r--r--engines/agi/picture.h78
-rw-r--r--engines/agi/preagi.cpp57
-rw-r--r--engines/agi/preagi.h23
-rw-r--r--engines/agi/preagi_mickey.cpp304
-rw-r--r--engines/agi/preagi_mickey.h722
-rw-r--r--engines/agi/preagi_troll.cpp65
-rw-r--r--engines/agi/preagi_troll.h144
-rw-r--r--engines/agi/preagi_winnie.cpp136
-rw-r--r--engines/agi/preagi_winnie.h336
-rw-r--r--engines/agi/saveload.cpp1105
-rw-r--r--engines/agi/sound.cpp17
-rw-r--r--engines/agi/sound.h30
-rw-r--r--engines/agi/sound_2gs.cpp333
-rw-r--r--engines/agi/sound_2gs.h154
-rw-r--r--engines/agi/sound_midi.cpp15
-rw-r--r--engines/agi/sound_pcjr.cpp58
-rw-r--r--engines/agi/sound_pcjr.h6
-rw-r--r--engines/agi/sound_sarien.cpp22
-rw-r--r--engines/agi/sound_sarien.h28
-rw-r--r--engines/agi/sprite.cpp996
-rw-r--r--engines/agi/sprite.h91
-rw-r--r--engines/agi/systemui.cpp1172
-rw-r--r--engines/agi/systemui.h167
-rw-r--r--engines/agi/text.cpp1502
-rw-r--r--engines/agi/text.h217
-rw-r--r--engines/agi/view.cpp748
-rw-r--r--engines/agi/view.h117
-rw-r--r--engines/agi/wagparser.cpp18
-rw-r--r--engines/agi/words.cpp369
-rw-r--r--engines/agi/words.h69
-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.cpp11
-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/sound.cpp2
-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/POTFILES1
-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.cpp7
-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.cpp4
-rw-r--r--engines/avalanche/parser.cpp6
-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.cpp48
-rw-r--r--engines/bbvs/bbvs.h13
-rw-r--r--engines/bbvs/configure.engine2
-rw-r--r--engines/bbvs/detection.cpp22
-rw-r--r--engines/bbvs/dialogs.cpp43
-rw-r--r--engines/bbvs/dialogs.h6
-rw-r--r--engines/bbvs/graphics.cpp4
-rw-r--r--engines/bbvs/minigames/bbairguitar.cpp26
-rw-r--r--engines/bbvs/minigames/bbtennis.cpp2
-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.cpp13
-rw-r--r--engines/bbvs/walk.cpp4
-rw-r--r--engines/cge/POTFILES1
-rw-r--r--engines/cge/cge.h4
-rw-r--r--engines/cge/detection.cpp9
-rw-r--r--engines/cge/events.cpp7
-rw-r--r--engines/cge/sound.cpp4
-rw-r--r--engines/cge/sound.h9
-rw-r--r--engines/cge2/POTFILES1
-rw-r--r--engines/cge2/cge2.h6
-rw-r--r--engines/cge2/detection.cpp9
-rw-r--r--engines/cge2/events.cpp7
-rw-r--r--engines/cge2/saveload.cpp4
-rw-r--r--engines/cge2/sound.cpp5
-rw-r--r--engines/cge2/sound.h16
-rw-r--r--engines/cge2/vga13h.cpp13
-rw-r--r--engines/cine/POTFILES1
-rw-r--r--engines/cine/anim.cpp2
-rw-r--r--engines/cine/cine.cpp49
-rw-r--r--engines/cine/cine.h8
-rw-r--r--engines/cine/detection.cpp35
-rw-r--r--engines/cine/detection_tables.h2
-rw-r--r--engines/cine/main_loop.cpp2
-rw-r--r--engines/cine/saveload.cpp7
-rw-r--r--engines/cine/script_fw.cpp4
-rw-r--r--engines/cine/sound.cpp4
-rw-r--r--engines/cine/various.cpp68
-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.cpp55
-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.cpp11
-rw-r--r--engines/cruise/sound.cpp7
-rw-r--r--engines/dialogs.cpp10
-rw-r--r--engines/draci/detection.cpp7
-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.cpp9
-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.cpp10
-rw-r--r--engines/dreamweb/detection_tables.h20
-rw-r--r--engines/dreamweb/dreamweb.cpp2
-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.cpp68
-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.cpp9
-rw-r--r--engines/fullpipe/fullpipe.cpp4
-rw-r--r--engines/fullpipe/fullpipe.h8
-rw-r--r--engines/fullpipe/gameloader.cpp14
-rw-r--r--engines/fullpipe/interaction.cpp2
-rw-r--r--engines/fullpipe/lift.cpp2
-rw-r--r--engines/fullpipe/messagehandlers.cpp9
-rw-r--r--engines/fullpipe/mgm.cpp92
-rw-r--r--engines/fullpipe/motion.cpp339
-rw-r--r--engines/fullpipe/motion.h107
-rw-r--r--engines/fullpipe/scenes.cpp4
-rw-r--r--engines/fullpipe/scenes.h8
-rw-r--r--engines/fullpipe/scenes/scene04.cpp16
-rw-r--r--engines/fullpipe/scenes/scene06.cpp12
-rw-r--r--engines/fullpipe/scenes/scene07.cpp4
-rw-r--r--engines/fullpipe/scenes/scene08.cpp4
-rw-r--r--engines/fullpipe/scenes/scene09.cpp6
-rw-r--r--engines/fullpipe/scenes/scene10.cpp2
-rw-r--r--engines/fullpipe/scenes/scene11.cpp8
-rw-r--r--engines/fullpipe/scenes/scene13.cpp16
-rw-r--r--engines/fullpipe/scenes/scene14.cpp18
-rw-r--r--engines/fullpipe/scenes/scene16.cpp2
-rw-r--r--engines/fullpipe/scenes/scene18and19.cpp2
-rw-r--r--engines/fullpipe/scenes/scene22.cpp8
-rw-r--r--engines/fullpipe/scenes/scene23.cpp6
-rw-r--r--engines/fullpipe/scenes/scene25.cpp2
-rw-r--r--engines/fullpipe/scenes/scene26.cpp2
-rw-r--r--engines/fullpipe/scenes/scene27.cpp8
-rw-r--r--engines/fullpipe/scenes/scene28.cpp2
-rw-r--r--engines/fullpipe/scenes/scene29.cpp14
-rw-r--r--engines/fullpipe/scenes/scene32.cpp8
-rw-r--r--engines/fullpipe/scenes/scene34.cpp12
-rw-r--r--engines/fullpipe/scenes/sceneFinal.cpp2
-rw-r--r--engines/fullpipe/sound.cpp22
-rw-r--r--engines/fullpipe/sound.h8
-rw-r--r--engines/fullpipe/statics.cpp12
-rw-r--r--engines/fullpipe/utils.cpp8
-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/gob.h6
-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/script.cpp2
-rw-r--r--engines/gob/sound/adlib.cpp7
-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.cpp11
-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.cpp7
-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/POTFILES1
-rw-r--r--engines/hugo/detection.cpp7
-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.cpp5
-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.cpp6
-rw-r--r--engines/kyra/detection.cpp9
-rw-r--r--engines/kyra/detection_tables.h16
-rw-r--r--engines/kyra/eobcommon.cpp6
-rw-r--r--engines/kyra/gui.cpp17
-rw-r--r--engines/kyra/gui_lol.cpp2
-rw-r--r--engines/kyra/gui_v1.cpp2
-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.cpp18
-rw-r--r--engines/kyra/sound_adlib.cpp6
-rw-r--r--engines/kyra/sound_intern.h2
-rw-r--r--engines/kyra/sound_lol.cpp10
-rw-r--r--engines/kyra/sound_towns.cpp127
-rw-r--r--engines/kyra/staticres.cpp14
-rw-r--r--engines/kyra/staticres_lol.cpp2
-rw-r--r--engines/lab/anim.cpp355
-rw-r--r--engines/lab/anim.h103
-rw-r--r--engines/lab/configure.engine3
-rw-r--r--engines/lab/console.cpp138
-rw-r--r--engines/lab/console.h46
-rw-r--r--engines/lab/detection.cpp231
-rw-r--r--engines/lab/dispman.cpp961
-rw-r--r--engines/lab/dispman.h274
-rw-r--r--engines/lab/engine.cpp1124
-rw-r--r--engines/lab/eventman.cpp196
-rw-r--r--engines/lab/eventman.h95
-rw-r--r--engines/lab/image.cpp136
-rw-r--r--engines/lab/image.h83
-rw-r--r--engines/lab/interface.cpp242
-rw-r--r--engines/lab/interface.h91
-rw-r--r--engines/lab/intro.cpp417
-rw-r--r--engines/lab/intro.h67
-rw-r--r--engines/lab/lab.cpp234
-rw-r--r--engines/lab/lab.h509
-rw-r--r--engines/lab/labsets.cpp77
-rw-r--r--engines/lab/labsets.h61
-rw-r--r--engines/lab/map.cpp559
-rw-r--r--engines/lab/module.mk30
-rw-r--r--engines/lab/music.cpp171
-rw-r--r--engines/lab/music.h96
-rw-r--r--engines/lab/processroom.cpp629
-rw-r--r--engines/lab/processroom.h190
-rw-r--r--engines/lab/resource.cpp343
-rw-r--r--engines/lab/resource.h124
-rw-r--r--engines/lab/savegame.cpp260
-rw-r--r--engines/lab/special.cpp477
-rw-r--r--engines/lab/speciallocks.cpp395
-rw-r--r--engines/lab/speciallocks.h94
-rw-r--r--engines/lab/utils.cpp272
-rw-r--r--engines/lab/utils.h105
-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/game/savegame.cpp3
-rw-r--r--engines/lastexpress/lastexpress.h6
-rw-r--r--engines/lastexpress/sound/entry.cpp2
-rw-r--r--engines/logo_data.h1099
-rw-r--r--engines/lure/detection.cpp25
-rw-r--r--engines/lure/game.cpp24
-rw-r--r--engines/lure/hotspots.cpp20
-rw-r--r--engines/lure/lure.h6
-rw-r--r--engines/lure/menu.cpp9
-rw-r--r--engines/lure/res.cpp4
-rw-r--r--engines/lure/res_struct.cpp21
-rw-r--r--engines/lure/res_struct.h14
-rw-r--r--engines/lure/scripts.cpp6
-rw-r--r--engines/lure/surface.cpp1
-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/action.h1
-rw-r--r--engines/mads/animation.cpp44
-rw-r--r--engines/mads/animation.h17
-rw-r--r--engines/mads/assets.h5
-rw-r--r--engines/mads/camera.cpp192
-rw-r--r--engines/mads/camera.h63
-rw-r--r--engines/mads/configure.engine2
-rw-r--r--engines/mads/conversations.cpp1018
-rw-r--r--engines/mads/conversations.h505
-rw-r--r--engines/mads/debugger.cpp16
-rw-r--r--engines/mads/debugger.h1
-rw-r--r--engines/mads/detection.cpp7
-rw-r--r--engines/mads/detection_tables.h4
-rw-r--r--engines/mads/dialogs.cpp92
-rw-r--r--engines/mads/dialogs.h35
-rw-r--r--engines/mads/dragonsphere/dragonsphere_scenes.cpp25
-rw-r--r--engines/mads/dragonsphere/dragonsphere_scenes.h89
-rw-r--r--engines/mads/dragonsphere/dragonsphere_scenes1.cpp3684
-rw-r--r--engines/mads/dragonsphere/dragonsphere_scenes1.h188
-rw-r--r--engines/mads/dragonsphere/game_dragonsphere.cpp2
-rw-r--r--engines/mads/dragonsphere/game_dragonsphere.h13
-rw-r--r--engines/mads/dragonsphere/globals_dragonsphere.cpp51
-rw-r--r--engines/mads/dragonsphere/globals_dragonsphere.h184
-rw-r--r--engines/mads/events.cpp11
-rw-r--r--engines/mads/events.h8
-rw-r--r--engines/mads/font.cpp23
-rw-r--r--engines/mads/font.h2
-rw-r--r--engines/mads/game.cpp93
-rw-r--r--engines/mads/game.h14
-rw-r--r--engines/mads/hotspots.cpp21
-rw-r--r--engines/mads/hotspots.h20
-rw-r--r--engines/mads/mads.cpp9
-rw-r--r--engines/mads/mads.h5
-rw-r--r--engines/mads/menu_views.cpp107
-rw-r--r--engines/mads/menu_views.h9
-rw-r--r--engines/mads/messages.cpp16
-rw-r--r--engines/mads/messages.h7
-rw-r--r--engines/mads/module.mk8
-rw-r--r--engines/mads/msurface.cpp343
-rw-r--r--engines/mads/msurface.h166
-rw-r--r--engines/mads/nebular/dialogs_nebular.cpp56
-rw-r--r--engines/mads/nebular/game_nebular.cpp28
-rw-r--r--engines/mads/nebular/menu_nebular.cpp30
-rw-r--r--engines/mads/nebular/menu_nebular.h15
-rw-r--r--engines/mads/nebular/nebular_scenes.cpp16
-rw-r--r--engines/mads/nebular/nebular_scenes.h4
-rw-r--r--engines/mads/nebular/nebular_scenes1.cpp30
-rw-r--r--engines/mads/nebular/nebular_scenes2.cpp94
-rw-r--r--engines/mads/nebular/nebular_scenes3.cpp166
-rw-r--r--engines/mads/nebular/nebular_scenes3.h2
-rw-r--r--engines/mads/nebular/nebular_scenes4.cpp124
-rw-r--r--engines/mads/nebular/nebular_scenes5.cpp54
-rw-r--r--engines/mads/nebular/nebular_scenes6.cpp254
-rw-r--r--engines/mads/nebular/nebular_scenes7.cpp94
-rw-r--r--engines/mads/nebular/nebular_scenes8.cpp36
-rw-r--r--engines/mads/nebular/sound_nebular.cpp15
-rw-r--r--engines/mads/nebular/sound_nebular.h12
-rw-r--r--engines/mads/palette.h2
-rw-r--r--engines/mads/phantom/game_phantom.cpp779
-rw-r--r--engines/mads/phantom/game_phantom.h51
-rw-r--r--engines/mads/phantom/globals_phantom.cpp5
-rw-r--r--engines/mads/phantom/globals_phantom.h16
-rw-r--r--engines/mads/phantom/phantom_scenes.cpp117
-rw-r--r--engines/mads/phantom/phantom_scenes.h49
-rw-r--r--engines/mads/phantom/phantom_scenes1.cpp9423
-rw-r--r--engines/mads/phantom/phantom_scenes1.h338
-rw-r--r--engines/mads/phantom/phantom_scenes2.cpp7001
-rw-r--r--engines/mads/phantom/phantom_scenes2.h307
-rw-r--r--engines/mads/phantom/phantom_scenes3.cpp2767
-rw-r--r--engines/mads/phantom/phantom_scenes3.h248
-rw-r--r--engines/mads/phantom/phantom_scenes4.cpp4975
-rw-r--r--engines/mads/phantom/phantom_scenes4.h265
-rw-r--r--engines/mads/phantom/phantom_scenes5.cpp4308
-rw-r--r--engines/mads/phantom/phantom_scenes5.h219
-rw-r--r--engines/mads/player.cpp132
-rw-r--r--engines/mads/player.h37
-rw-r--r--engines/mads/rails.cpp16
-rw-r--r--engines/mads/rails.h4
-rw-r--r--engines/mads/resources.cpp6
-rw-r--r--engines/mads/scene.cpp224
-rw-r--r--engines/mads/scene.h24
-rw-r--r--engines/mads/scene_data.cpp108
-rw-r--r--engines/mads/scene_data.h12
-rw-r--r--engines/mads/screen.cpp121
-rw-r--r--engines/mads/screen.h38
-rw-r--r--engines/mads/sequence.cpp28
-rw-r--r--engines/mads/sequence.h5
-rw-r--r--engines/mads/sound.cpp8
-rw-r--r--engines/mads/sound.h18
-rw-r--r--engines/mads/sprites.cpp28
-rw-r--r--engines/mads/user_interface.cpp52
-rw-r--r--engines/mads/user_interface.h8
-rw-r--r--engines/metaengine.h3
-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/console.cpp42
-rw-r--r--engines/mohawk/console.h1
-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.cpp115
-rw-r--r--engines/mohawk/detection_tables.h191
-rw-r--r--engines/mohawk/dialogs.cpp152
-rw-r--r--engines/mohawk/dialogs.h58
-rw-r--r--engines/mohawk/graphics.h8
-rw-r--r--engines/mohawk/mohawk.h4
-rw-r--r--engines/mohawk/myst.cpp587
-rw-r--r--engines/mohawk/myst.h124
-rw-r--r--engines/mohawk/myst_areas.cpp411
-rw-r--r--engines/mohawk/myst_areas.h162
-rw-r--r--engines/mohawk/myst_graphics.cpp105
-rw-r--r--engines/mohawk/myst_graphics.h8
-rw-r--r--engines/mohawk/myst_scripts.cpp135
-rw-r--r--engines/mohawk/myst_scripts.h28
-rw-r--r--engines/mohawk/myst_stacks/channelwood.cpp64
-rw-r--r--engines/mohawk/myst_stacks/channelwood.h14
-rw-r--r--engines/mohawk/myst_stacks/credits.cpp6
-rw-r--r--engines/mohawk/myst_stacks/credits.h6
-rw-r--r--engines/mohawk/myst_stacks/demo.h4
-rw-r--r--engines/mohawk/myst_stacks/dni.h6
-rw-r--r--engines/mohawk/myst_stacks/intro.cpp4
-rw-r--r--engines/mohawk/myst_stacks/intro.h10
-rw-r--r--engines/mohawk/myst_stacks/makingof.cpp2
-rw-r--r--engines/mohawk/myst_stacks/makingof.h4
-rw-r--r--engines/mohawk/myst_stacks/mechanical.cpp94
-rw-r--r--engines/mohawk/myst_stacks/mechanical.h26
-rw-r--r--engines/mohawk/myst_stacks/myst.cpp203
-rw-r--r--engines/mohawk/myst_stacks/myst.h56
-rw-r--r--engines/mohawk/myst_stacks/preview.cpp6
-rw-r--r--engines/mohawk/myst_stacks/preview.h8
-rw-r--r--engines/mohawk/myst_stacks/selenitic.cpp99
-rw-r--r--engines/mohawk/myst_stacks/selenitic.h61
-rw-r--r--engines/mohawk/myst_stacks/slides.cpp1
-rw-r--r--engines/mohawk/myst_stacks/slides.h4
-rw-r--r--engines/mohawk/myst_stacks/stoneship.cpp38
-rw-r--r--engines/mohawk/myst_stacks/stoneship.h20
-rw-r--r--engines/mohawk/myst_state.cpp227
-rw-r--r--engines/mohawk/myst_state.h37
-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.cpp37
-rw-r--r--engines/mohawk/sound.h8
-rw-r--r--engines/mohawk/video.cpp135
-rw-r--r--engines/mohawk/video.h4
-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/mortevielle/utils.cpp4
-rw-r--r--engines/neverhood/configure.engine2
-rw-r--r--engines/neverhood/detection.cpp28
-rw-r--r--engines/neverhood/diskplayerscene.cpp1
-rw-r--r--engines/neverhood/diskplayerscene.h2
-rw-r--r--engines/neverhood/menumodule.cpp46
-rw-r--r--engines/neverhood/menumodule.h1
-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/module2700.cpp12
-rw-r--r--engines/neverhood/modules/module2700.h4
-rw-r--r--engines/neverhood/modules/module2800.cpp1
-rw-r--r--engines/neverhood/navigationscene.h1
-rw-r--r--engines/neverhood/neverhood.cpp6
-rw-r--r--engines/neverhood/neverhood.h7
-rw-r--r--engines/neverhood/resourceman.cpp23
-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.cpp7
-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.cpp9
-rw-r--r--engines/parallaction/sound_br.cpp7
-rw-r--r--engines/parallaction/sound_ns.cpp7
-rw-r--r--engines/parallaction/staticres.cpp1
-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.cpp22
-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.cpp91
-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.cpp11
-rw-r--r--engines/saga/detection_tables.h67
-rw-r--r--engines/saga/displayinfo.h18
-rw-r--r--engines/saga/font.cpp2
-rw-r--r--engines/saga/interface.cpp38
-rw-r--r--engines/saga/isomap.cpp17
-rw-r--r--engines/saga/itedata.cpp24
-rw-r--r--engines/saga/music.cpp6
-rw-r--r--engines/saga/music.h5
-rw-r--r--engines/saga/puzzle.cpp8
-rw-r--r--engines/saga/render.cpp3
-rw-r--r--engines/saga/saga.cpp11
-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/savestate.h9
-rw-r--r--engines/sci/configure.engine2
-rw-r--r--engines/sci/console.cpp194
-rw-r--r--engines/sci/console.h3
-rw-r--r--engines/sci/decompressor.cpp2
-rw-r--r--engines/sci/detection.cpp117
-rw-r--r--engines/sci/detection_tables.h723
-rw-r--r--engines/sci/engine/features.cpp70
-rw-r--r--engines/sci/engine/features.h15
-rw-r--r--engines/sci/engine/file.cpp293
-rw-r--r--engines/sci/engine/file.h51
-rw-r--r--engines/sci/engine/gc.cpp10
-rw-r--r--engines/sci/engine/kernel.cpp37
-rw-r--r--engines/sci/engine/kernel.h141
-rw-r--r--engines/sci/engine/kernel_tables.h483
-rw-r--r--engines/sci/engine/kevent.cpp73
-rw-r--r--engines/sci/engine/kfile.cpp220
-rw-r--r--engines/sci/engine/kgraphics.cpp87
-rw-r--r--engines/sci/engine/kgraphics32.cpp1359
-rw-r--r--engines/sci/engine/klists.cpp24
-rw-r--r--engines/sci/engine/kmisc.cpp70
-rw-r--r--engines/sci/engine/kpathing.cpp26
-rw-r--r--engines/sci/engine/kscripts.cpp5
-rw-r--r--engines/sci/engine/ksound.cpp280
-rw-r--r--engines/sci/engine/kstring.cpp354
-rw-r--r--engines/sci/engine/kvideo.cpp157
-rw-r--r--engines/sci/engine/message.cpp2
-rw-r--r--engines/sci/engine/object.cpp17
-rw-r--r--engines/sci/engine/object.h61
-rw-r--r--engines/sci/engine/savegame.cpp475
-rw-r--r--engines/sci/engine/savegame.h7
-rw-r--r--engines/sci/engine/script.cpp18
-rw-r--r--engines/sci/engine/script_patches.cpp1316
-rw-r--r--engines/sci/engine/script_patches.h21
-rw-r--r--engines/sci/engine/scriptdebug.cpp10
-rw-r--r--engines/sci/engine/seg_manager.cpp120
-rw-r--r--engines/sci/engine/seg_manager.h12
-rw-r--r--engines/sci/engine/segment.cpp20
-rw-r--r--engines/sci/engine/segment.h23
-rw-r--r--engines/sci/engine/selector.cpp29
-rw-r--r--engines/sci/engine/selector.h18
-rw-r--r--engines/sci/engine/state.cpp9
-rw-r--r--engines/sci/engine/state.h13
-rw-r--r--engines/sci/engine/static_selectors.cpp18
-rw-r--r--engines/sci/engine/vm.cpp68
-rw-r--r--engines/sci/engine/vm.h18
-rw-r--r--engines/sci/engine/vm_types.cpp46
-rw-r--r--engines/sci/engine/vm_types.h17
-rw-r--r--engines/sci/engine/workarounds.cpp29
-rw-r--r--engines/sci/engine/workarounds.h3
-rw-r--r--engines/sci/event.cpp174
-rw-r--r--engines/sci/event.h120
-rw-r--r--engines/sci/graphics/animate.cpp92
-rw-r--r--engines/sci/graphics/animate.h10
-rw-r--r--engines/sci/graphics/cache.cpp4
-rw-r--r--engines/sci/graphics/cache.h2
-rw-r--r--engines/sci/graphics/celobj32.cpp1151
-rw-r--r--engines/sci/graphics/celobj32.h607
-rw-r--r--engines/sci/graphics/compare.cpp82
-rw-r--r--engines/sci/graphics/compare.h3
-rw-r--r--engines/sci/graphics/controls16.cpp2
-rw-r--r--engines/sci/graphics/controls32.cpp912
-rw-r--r--engines/sci/graphics/controls32.h469
-rw-r--r--engines/sci/graphics/cursor.cpp12
-rw-r--r--engines/sci/graphics/cursor.h14
-rw-r--r--engines/sci/graphics/frameout.cpp2193
-rw-r--r--engines/sci/graphics/frameout.h571
-rw-r--r--engines/sci/graphics/helpers.h134
-rw-r--r--engines/sci/graphics/lists32.h192
-rw-r--r--engines/sci/graphics/maciconbar.cpp2
-rw-r--r--engines/sci/graphics/menu.cpp12
-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.cpp160
-rw-r--r--engines/sci/graphics/palette.h37
-rw-r--r--engines/sci/graphics/palette32.cpp841
-rw-r--r--engines/sci/graphics/palette32.h411
-rw-r--r--engines/sci/graphics/picture.cpp6
-rw-r--r--engines/sci/graphics/picture.h3
-rw-r--r--engines/sci/graphics/plane32.cpp951
-rw-r--r--engines/sci/graphics/plane32.h531
-rw-r--r--engines/sci/graphics/portrait.cpp4
-rw-r--r--engines/sci/graphics/ports.cpp6
-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.cpp282
-rw-r--r--engines/sci/graphics/screen.h315
-rw-r--r--engines/sci/graphics/screen_item32.cpp743
-rw-r--r--engines/sci/graphics/screen_item32.h326
-rw-r--r--engines/sci/graphics/text16.cpp65
-rw-r--r--engines/sci/graphics/text32.cpp880
-rw-r--r--engines/sci/graphics/text32.h464
-rw-r--r--engines/sci/graphics/video32.cpp415
-rw-r--r--engines/sci/graphics/video32.h312
-rw-r--r--engines/sci/graphics/view.cpp47
-rw-r--r--engines/sci/graphics/view.h3
-rw-r--r--engines/sci/module.mk11
-rw-r--r--engines/sci/parser/vocabulary.cpp14
-rw-r--r--engines/sci/parser/vocabulary.h2
-rw-r--r--engines/sci/resource.cpp248
-rw-r--r--engines/sci/resource.h24
-rw-r--r--engines/sci/resource_audio.cpp14
-rw-r--r--engines/sci/sci.cpp298
-rw-r--r--engines/sci/sci.h40
-rw-r--r--engines/sci/sound/audio.cpp111
-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.cpp4
-rw-r--r--engines/sci/sound/midiparser_sci.cpp6
-rw-r--r--engines/sci/sound/music.cpp85
-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/sci/util.cpp11
-rw-r--r--engines/sci/util.h3
-rw-r--r--engines/scumm/POTFILES2
-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.cpp99
-rw-r--r--engines/scumm/configure.engine2
-rw-r--r--engines/scumm/debugger.cpp22
-rw-r--r--engines/scumm/detection.cpp27
-rw-r--r--engines/scumm/detection_tables.h2
-rw-r--r--engines/scumm/dialogs.cpp14
-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/puttrace.cpp2
-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.cpp44
-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.cpp4
-rw-r--r--engines/scumm/imuse_digi/dimuse_track.h5
-rw-r--r--engines/scumm/input.cpp21
-rw-r--r--engines/scumm/insane/insane.cpp2
-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_towns.cpp69
-rw-r--r--engines/scumm/players/player_towns.h4
-rw-r--r--engines/scumm/players/player_v2.cpp2
-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_v4a.cpp4
-rw-r--r--engines/scumm/players/player_v5m.h4
-rw-r--r--engines/scumm/resource.cpp2
-rw-r--r--engines/scumm/saveload.cpp8
-rw-r--r--engines/scumm/saveload.h2
-rw-r--r--engines/scumm/script_v2.cpp4
-rw-r--r--engines/scumm/scumm-md5.h52
-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_v4.h2
-rw-r--r--engines/scumm/scumm_v6.h3
-rw-r--r--engines/scumm/smush/imuse_channel.cpp2
-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.cpp42
-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/POTFILES3
-rw-r--r--engines/sherlock/animation.cpp6
-rw-r--r--engines/sherlock/configure.engine2
-rw-r--r--engines/sherlock/debugger.cpp3
-rw-r--r--engines/sherlock/decompress.cpp128
-rw-r--r--engines/sherlock/detection_tables.h24
-rw-r--r--engines/sherlock/events.cpp15
-rw-r--r--engines/sherlock/events.h5
-rw-r--r--engines/sherlock/fixed_text.cpp184
-rw-r--r--engines/sherlock/fixed_text.h47
-rw-r--r--engines/sherlock/fonts.cpp83
-rw-r--r--engines/sherlock/fonts.h6
-rw-r--r--engines/sherlock/image_file.cpp114
-rw-r--r--engines/sherlock/image_file.h8
-rw-r--r--engines/sherlock/journal.cpp188
-rw-r--r--engines/sherlock/journal.h5
-rw-r--r--engines/sherlock/module.mk2
-rw-r--r--engines/sherlock/music.cpp14
-rw-r--r--engines/sherlock/music.h6
-rw-r--r--engines/sherlock/objects.cpp34
-rw-r--r--engines/sherlock/people.cpp5
-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.cpp250
-rw-r--r--engines/sherlock/scalpel/scalpel_darts.cpp36
-rw-r--r--engines/sherlock/scalpel/scalpel_debugger.cpp5
-rw-r--r--engines/sherlock/scalpel/scalpel_fixed_text.cpp449
-rw-r--r--engines/sherlock/scalpel/scalpel_fixed_text.h110
-rw-r--r--engines/sherlock/scalpel/scalpel_inventory.cpp94
-rw-r--r--engines/sherlock/scalpel/scalpel_inventory.h17
-rw-r--r--engines/sherlock/scalpel/scalpel_journal.cpp198
-rw-r--r--engines/sherlock/scalpel/scalpel_journal.h31
-rw-r--r--engines/sherlock/scalpel/scalpel_map.cpp58
-rw-r--r--engines/sherlock/scalpel/scalpel_saveload.cpp92
-rw-r--r--engines/sherlock/scalpel/scalpel_saveload.h29
-rw-r--r--engines/sherlock/scalpel/scalpel_scene.cpp182
-rw-r--r--engines/sherlock/scalpel/scalpel_scene.h2
-rw-r--r--engines/sherlock/scalpel/scalpel_screen.cpp345
-rw-r--r--engines/sherlock/scalpel/scalpel_screen.h44
-rw-r--r--engines/sherlock/scalpel/scalpel_talk.cpp87
-rw-r--r--engines/sherlock/scalpel/scalpel_talk.h15
-rw-r--r--engines/sherlock/scalpel/scalpel_user_interface.cpp508
-rw-r--r--engines/sherlock/scalpel/scalpel_user_interface.h46
-rw-r--r--engines/sherlock/scalpel/settings.cpp238
-rw-r--r--engines/sherlock/scalpel/settings.h28
-rw-r--r--engines/sherlock/scalpel/tsage/logo.cpp9
-rw-r--r--engines/sherlock/scene.cpp82
-rw-r--r--engines/sherlock/scene.h4
-rw-r--r--engines/sherlock/screen.cpp134
-rw-r--r--engines/sherlock/screen.h46
-rw-r--r--engines/sherlock/sherlock.cpp3
-rw-r--r--engines/sherlock/sherlock.h10
-rw-r--r--engines/sherlock/sound.cpp104
-rw-r--r--engines/sherlock/sound.h16
-rw-r--r--engines/sherlock/surface.cpp261
-rw-r--r--engines/sherlock/surface.h157
-rw-r--r--engines/sherlock/talk.cpp43
-rw-r--r--engines/sherlock/talk.h4
-rw-r--r--engines/sherlock/tattoo/tattoo.cpp9
-rw-r--r--engines/sherlock/tattoo/tattoo_darts.cpp253
-rw-r--r--engines/sherlock/tattoo/tattoo_fixed_text.cpp732
-rw-r--r--engines/sherlock/tattoo/tattoo_fixed_text.h162
-rw-r--r--engines/sherlock/tattoo/tattoo_journal.cpp268
-rw-r--r--engines/sherlock/tattoo/tattoo_journal.h12
-rw-r--r--engines/sherlock/tattoo/tattoo_map.cpp45
-rw-r--r--engines/sherlock/tattoo/tattoo_people.cpp18
-rw-r--r--engines/sherlock/tattoo/tattoo_people.h5
-rw-r--r--engines/sherlock/tattoo/tattoo_resources.cpp394
-rw-r--r--engines/sherlock/tattoo/tattoo_resources.h9
-rw-r--r--engines/sherlock/tattoo/tattoo_scene.cpp53
-rw-r--r--engines/sherlock/tattoo/tattoo_screen.cpp38
-rw-r--r--engines/sherlock/tattoo/tattoo_screen.h44
-rw-r--r--engines/sherlock/tattoo/tattoo_talk.cpp9
-rw-r--r--engines/sherlock/tattoo/tattoo_user_interface.cpp24
-rw-r--r--engines/sherlock/tattoo/tattoo_user_interface.h3
-rw-r--r--engines/sherlock/tattoo/widget_base.cpp41
-rw-r--r--engines/sherlock/tattoo/widget_credits.cpp17
-rw-r--r--engines/sherlock/tattoo/widget_files.cpp48
-rw-r--r--engines/sherlock/tattoo/widget_files.h1
-rw-r--r--engines/sherlock/tattoo/widget_foolscap.cpp7
-rw-r--r--engines/sherlock/tattoo/widget_inventory.cpp32
-rw-r--r--engines/sherlock/tattoo/widget_options.cpp43
-rw-r--r--engines/sherlock/tattoo/widget_password.cpp8
-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.cpp5
-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.cpp21
-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.cpp17
-rw-r--r--engines/sword1/logic.h5
-rw-r--r--engines/sword1/objectman.cpp6
-rw-r--r--engines/sword1/objectman.h2
-rw-r--r--engines/sword1/resman.cpp13
-rw-r--r--engines/sword1/router.cpp2
-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/interpreter.cpp4
-rw-r--r--engines/sword2/memory.cpp2
-rw-r--r--engines/sword2/music.cpp3
-rw-r--r--engines/sword2/router.cpp2
-rw-r--r--engines/sword2/screen.cpp4
-rw-r--r--engines/sword2/sword2.cpp5
-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.h38
-rw-r--r--engines/sword25/fmv/movieplayer.cpp2
-rw-r--r--engines/sword25/fmv/movieplayer.h2
-rw-r--r--engines/sword25/gfx/animation.cpp4
-rw-r--r--engines/sword25/gfx/animationresource.cpp5
-rw-r--r--engines/sword25/gfx/fontresource.cpp5
-rw-r--r--engines/sword25/gfx/graphicengine.cpp36
-rw-r--r--engines/sword25/gfx/graphicengine.h2
-rw-r--r--engines/sword25/gfx/image/imgloader.cpp29
-rw-r--r--engines/sword25/gfx/image/imgloader.h19
-rw-r--r--engines/sword25/gfx/image/renderedimage.cpp16
-rw-r--r--engines/sword25/gfx/image/renderedimage.h3
-rw-r--r--engines/sword25/gfx/image/swimage.cpp19
-rw-r--r--engines/sword25/gfx/image/swimage.h9
-rw-r--r--engines/sword25/gfx/image/vectorimage.cpp15
-rw-r--r--engines/sword25/gfx/image/vectorimage.h1
-rw-r--r--engines/sword25/gfx/image/vectorimagerenderer.cpp3
-rw-r--r--engines/sword25/gfx/panel.cpp2
-rw-r--r--engines/sword25/gfx/renderobject.cpp29
-rw-r--r--engines/sword25/gfx/screenshot.cpp34
-rw-r--r--engines/sword25/gfx/staticbitmap.cpp4
-rw-r--r--engines/sword25/gfx/text.cpp39
-rw-r--r--engines/sword25/kernel/kernel_script.cpp1
-rw-r--r--engines/sword25/math/polygon.cpp2
-rw-r--r--engines/sword25/package/packagemanager.cpp45
-rw-r--r--engines/sword25/package/packagemanager.h3
-rw-r--r--engines/sword25/script/luacallback.cpp2
-rw-r--r--engines/sword25/script/luascript.cpp2
-rw-r--r--engines/sword25/sfx/soundengine.cpp1
-rw-r--r--engines/sword25/sfx/soundengine.h1
-rw-r--r--engines/sword25/sword25.cpp4
-rw-r--r--engines/sword25/sword25.h4
-rw-r--r--engines/sword25/util/lua/lbaselib.cpp2
-rw-r--r--engines/sword25/util/lua/ldo.cpp7
-rw-r--r--engines/sword25/util/lua/luaconf.h2
-rw-r--r--engines/sword25/util/lua/scummvm_file.cpp4
-rw-r--r--engines/sword25/util/lua_persistence_util.cpp9
-rw-r--r--engines/sword25/util/lua_persistence_util.h1
-rw-r--r--engines/sword25/util/lua_unpersist.cpp2
-rw-r--r--engines/teenagent/detection.cpp7
-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.cpp3
-rw-r--r--engines/testbed/testbed.h6
-rw-r--r--engines/testbed/testsuite.cpp3
-rw-r--r--engines/tinsel/anim.cpp4
-rw-r--r--engines/tinsel/bmv.cpp5
-rw-r--r--engines/tinsel/bmv.h5
-rw-r--r--engines/tinsel/detection.cpp19
-rw-r--r--engines/tinsel/detection_tables.h21
-rw-r--r--engines/tinsel/dialogs.cpp30
-rw-r--r--engines/tinsel/graphics.cpp2
-rw-r--r--engines/tinsel/handle.cpp2
-rw-r--r--engines/tinsel/music.cpp36
-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.cpp13
-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.cpp9
-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.cpp3
-rw-r--r--engines/toltecs/toltecs.h6
-rw-r--r--engines/tony/configure.engine2
-rw-r--r--engines/tony/detection.cpp5
-rw-r--r--engines/tony/detection_tables.h22
-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/loc.cpp27
-rw-r--r--engines/tony/loc.h2
-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.cpp209
-rw-r--r--engines/tony/sound.h13
-rw-r--r--engines/tony/tony.cpp43
-rw-r--r--engines/tony/tony.h7
-rw-r--r--engines/toon/POTFILES1
-rw-r--r--engines/toon/configure.engine2
-rw-r--r--engines/toon/detection.cpp7
-rw-r--r--engines/toon/toon.cpp19
-rw-r--r--engines/touche/configure.engine2
-rw-r--r--engines/touche/detection.cpp2
-rw-r--r--engines/touche/opcodes.cpp18
-rw-r--r--engines/touche/touche.cpp1
-rw-r--r--engines/touche/touche.h7
-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.cpp11
-rw-r--r--engines/tsage/detection_tables.h4
-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.h (renamed from backends/mixer/sdl13/sdl13-mixer.h)57
-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.cpp4
-rw-r--r--engines/tucker/resource.cpp8
-rw-r--r--engines/tucker/sequences.cpp23
-rw-r--r--engines/tucker/staticres.cpp8
-rw-r--r--engines/tucker/tucker.cpp4
-rw-r--r--engines/tucker/tucker.h14
-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.cpp7
-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.cpp78
-rw-r--r--engines/voyeur/module.mk2
-rw-r--r--engines/voyeur/screen.cpp (renamed from engines/voyeur/graphics.cpp)142
-rw-r--r--engines/voyeur/screen.h (renamed from engines/voyeur/graphics.h)22
-rw-r--r--engines/voyeur/sound.cpp5
-rw-r--r--engines/voyeur/sound.h2
-rw-r--r--engines/voyeur/voyeur.cpp167
-rw-r--r--engines/voyeur/voyeur.h4
-rw-r--r--engines/voyeur/voyeur_game.cpp311
-rw-r--r--engines/wage/combat.cpp916
-rw-r--r--engines/wage/configure.engine3
-rw-r--r--engines/wage/debugger.cpp97
-rw-r--r--engines/wage/debugger.h47
-rw-r--r--engines/wage/design.cpp543
-rw-r--r--engines/wage/design.h105
-rw-r--r--engines/wage/detection.cpp152
-rw-r--r--engines/wage/detection_tables.h180
-rw-r--r--engines/wage/dialog.cpp244
-rw-r--r--engines/wage/dialog.h101
-rw-r--r--engines/wage/entities.cpp531
-rw-r--r--engines/wage/entities.h338
-rw-r--r--engines/wage/gui-console.cpp563
-rw-r--r--engines/wage/gui.cpp359
-rw-r--r--engines/wage/gui.h158
-rw-r--r--engines/wage/macmenu.cpp563
-rw-r--r--engines/wage/macmenu.h161
-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.mk31
-rw-r--r--engines/wage/randomhat.cpp83
-rw-r--r--engines/wage/randomhat.h77
-rw-r--r--engines/wage/script.cpp1175
-rw-r--r--engines/wage/script.h161
-rw-r--r--engines/wage/sound.cpp86
-rw-r--r--engines/wage/sound.h64
-rw-r--r--engines/wage/util.cpp138
-rw-r--r--engines/wage/wage.cpp502
-rw-r--r--engines/wage/wage.h232
-rw-r--r--engines/wage/world.cpp541
-rw-r--r--engines/wage/world.h138
-rw-r--r--engines/wintermute/ad/ad_actor.cpp4
-rw-r--r--engines/wintermute/ad/ad_entity.cpp3
-rw-r--r--engines/wintermute/ad/ad_entity.h1
-rw-r--r--engines/wintermute/ad/ad_game.cpp5
-rw-r--r--engines/wintermute/ad/ad_game.h1
-rw-r--r--engines/wintermute/ad/ad_scene.cpp5
-rw-r--r--engines/wintermute/ad/ad_scene.h2
-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_frame.cpp3
-rw-r--r--engines/wintermute/base/base_frame.h2
-rw-r--r--engines/wintermute/base/base_game.cpp8
-rw-r--r--engines/wintermute/base/base_game.h8
-rw-r--r--engines/wintermute/base/base_keyboard_state.cpp46
-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/base_region.cpp3
-rw-r--r--engines/wintermute/base/base_region.h2
-rw-r--r--engines/wintermute/base/base_script_holder.cpp15
-rw-r--r--engines/wintermute/base/base_scriptable.cpp5
-rw-r--r--engines/wintermute/base/base_scriptable.h1
-rw-r--r--engines/wintermute/base/base_sprite.cpp3
-rw-r--r--engines/wintermute/base/base_sprite.h1
-rw-r--r--engines/wintermute/base/base_sub_frame.cpp6
-rw-r--r--engines/wintermute/base/base_sub_frame.h1
-rw-r--r--engines/wintermute/base/base_viewport.cpp3
-rw-r--r--engines/wintermute/base/base_viewport.h1
-rw-r--r--engines/wintermute/base/file/base_disk_file.cpp27
-rw-r--r--engines/wintermute/base/file/base_file.cpp2
-rw-r--r--engines/wintermute/base/file/base_save_thumb_file.cpp3
-rw-r--r--engines/wintermute/base/font/base_font_truetype.cpp4
-rw-r--r--engines/wintermute/base/gfx/base_surface.cpp5
-rw-r--r--engines/wintermute/base/scriptables/debuggable/debuggable_script.cpp148
-rw-r--r--engines/wintermute/base/scriptables/debuggable/debuggable_script.h67
-rw-r--r--engines/wintermute/base/scriptables/debuggable/debuggable_script_engine.cpp35
-rw-r--r--engines/wintermute/base/scriptables/debuggable/debuggable_script_engine.h110
-rw-r--r--engines/wintermute/base/scriptables/script.cpp33
-rw-r--r--engines/wintermute/base/scriptables/script.h14
-rw-r--r--engines/wintermute/base/scriptables/script_engine.cpp8
-rw-r--r--engines/wintermute/base/scriptables/script_engine.h14
-rw-r--r--engines/wintermute/base/sound/base_sound_manager.cpp15
-rw-r--r--engines/wintermute/configure.engine2
-rw-r--r--engines/wintermute/debugger.cpp346
-rw-r--r--engines/wintermute/debugger.h120
-rw-r--r--engines/wintermute/debugger/breakpoint.cpp68
-rw-r--r--engines/wintermute/debugger/breakpoint.h58
-rw-r--r--engines/wintermute/debugger/debugger_controller.cpp325
-rw-r--r--engines/wintermute/debugger/debugger_controller.h119
-rw-r--r--engines/wintermute/debugger/error.cpp137
-rw-r--r--engines/wintermute/debugger/error.h73
-rw-r--r--engines/wintermute/debugger/listing.cpp46
-rw-r--r--engines/wintermute/debugger/listing.h64
-rw-r--r--engines/wintermute/debugger/listing_provider.h42
-rw-r--r--engines/wintermute/debugger/listing_providers/basic_source_listing_provider.cpp92
-rw-r--r--engines/wintermute/debugger/listing_providers/basic_source_listing_provider.h44
-rw-r--r--engines/wintermute/debugger/listing_providers/blank_listing.cpp38
-rw-r--r--engines/wintermute/debugger/listing_providers/blank_listing.h39
-rw-r--r--engines/wintermute/debugger/listing_providers/blank_listing_provider.cpp35
-rw-r--r--engines/wintermute/debugger/listing_providers/blank_listing_provider.h38
-rw-r--r--engines/wintermute/debugger/listing_providers/cached_source_listing_provider.cpp80
-rw-r--r--engines/wintermute/debugger/listing_providers/cached_source_listing_provider.h52
-rw-r--r--engines/wintermute/debugger/listing_providers/source_listing.cpp57
-rw-r--r--engines/wintermute/debugger/listing_providers/source_listing.h37
-rw-r--r--engines/wintermute/debugger/listing_providers/source_listing_provider.h49
-rw-r--r--engines/wintermute/debugger/script_monitor.cpp26
-rw-r--r--engines/wintermute/debugger/script_monitor.h43
-rw-r--r--engines/wintermute/debugger/watch.cpp42
-rw-r--r--engines/wintermute/debugger/watch.h51
-rw-r--r--engines/wintermute/debugger/watch_instance.cpp53
-rw-r--r--engines/wintermute/debugger/watch_instance.h44
-rw-r--r--engines/wintermute/detection.cpp12
-rw-r--r--engines/wintermute/detection_tables.h34
-rw-r--r--engines/wintermute/module.mk14
-rw-r--r--engines/wintermute/ui/ui_window.cpp11
-rw-r--r--engines/wintermute/utils/convert_utf.cpp6
-rw-r--r--engines/wintermute/utils/convert_utf.h3
-rw-r--r--engines/wintermute/wintermute.cpp9
-rw-r--r--engines/wintermute/wintermute.h12
-rw-r--r--engines/zvision/configure.engine2
-rw-r--r--engines/zvision/core/events.cpp1
-rw-r--r--engines/zvision/detection.cpp112
-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/text/truetype_font.cpp2
-rw-r--r--engines/zvision/zvision.cpp5
-rw-r--r--graphics/VectorRenderer.cpp29
-rw-r--r--graphics/VectorRenderer.h60
-rw-r--r--graphics/VectorRendererSpec.cpp1787
-rw-r--r--graphics/VectorRendererSpec.h77
-rw-r--r--graphics/font.cpp23
-rw-r--r--graphics/font.h4
-rw-r--r--graphics/fonts/ttf.cpp144
-rw-r--r--graphics/fonts/ttf.h24
-rw-r--r--graphics/managed_surface.cpp260
-rw-r--r--graphics/managed_surface.h376
-rw-r--r--graphics/module.mk4
-rw-r--r--graphics/nine_patch.cpp279
-rw-r--r--graphics/nine_patch.h98
-rw-r--r--graphics/pixelformat.cpp64
-rw-r--r--graphics/pixelformat.h3
-rw-r--r--graphics/primitives.cpp349
-rw-r--r--graphics/primitives.h11
-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/thumbnail.cpp2
-rw-r--r--graphics/transparent_surface.cpp139
-rw-r--r--graphics/transparent_surface.h46
-rw-r--r--gui/EventRecorder.cpp3
-rw-r--r--gui/ThemeEngine.cpp527
-rw-r--r--gui/ThemeEngine.h51
-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/about.cpp2
-rw-r--r--gui/credits.h46
-rw-r--r--gui/debugger.cpp11
-rw-r--r--gui/dialog.cpp10
-rw-r--r--gui/dialog.h2
-rw-r--r--gui/filebrowser-dialog.cpp160
-rw-r--r--gui/filebrowser-dialog.h64
-rw-r--r--gui/gui-manager.cpp54
-rw-r--r--gui/gui-manager.h11
-rw-r--r--gui/launcher.cpp4
-rw-r--r--gui/module.mk20
-rw-r--r--gui/object.cpp13
-rw-r--r--gui/onscreendialog.cpp34
-rw-r--r--gui/options.cpp71
-rw-r--r--gui/options.h9
-rw-r--r--gui/predictivedialog.cpp436
-rw-r--r--gui/predictivedialog.h87
-rw-r--r--gui/recorderdialog.cpp3
-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.inc97
-rw-r--r--gui/themes/scummclassic.zipbin110106 -> 115643 bytes
-rw-r--r--gui/themes/scummclassic/THEMERC2
-rw-r--r--gui/themes/scummclassic/classic_layout.stx59
-rw-r--r--gui/themes/scummclassic/classic_layout_lowres.stx57
-rw-r--r--gui/themes/scummmodern.zipbin1485886 -> 1491681 bytes
-rw-r--r--gui/themes/scummmodern/THEMERC2
-rw-r--r--gui/themes/scummmodern/scummmodern_layout.stx61
-rw-r--r--gui/themes/scummmodern/scummmodern_layout_lowres.stx59
-rwxr-xr-xgui/themes/scummtheme.py30
-rw-r--r--gui/themes/translations.datbin468051 -> 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.cpp9
-rw-r--r--gui/widgets/edittext.cpp11
-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/indeo3.cpp95
-rw-r--r--image/codecs/msrle4.cpp140
-rw-r--r--image/codecs/msrle4.h53
-rw-r--r--image/codecs/msvideo1.cpp100
-rw-r--r--image/codecs/msvideo1.h4
-rw-r--r--image/codecs/rpza.cpp1
-rw-r--r--image/module.mk1
-rw-r--r--image/pict.cpp2
-rw-r--r--po/POTFILES43
-rw-r--r--po/be_BY.po1808
-rw-r--r--po/ca_ES.po1571
-rw-r--r--po/cs_CZ.po1621
-rw-r--r--po/da_DK.po (renamed from po/da_DA.po)1724
-rw-r--r--po/de_DE.po1620
-rw-r--r--po/es_ES.po1716
-rw-r--r--po/eu.po1872
-rw-r--r--po/fi_FI.po1567
-rw-r--r--po/fr_FR.po1904
-rw-r--r--po/gl_ES.po1762
-rwxr-xr-x[-rw-r--r--]po/hu_HU.po1739
-rw-r--r--po/it_IT.po1591
-rw-r--r--po/module.mk2
-rw-r--r--po/nb_NO.po1699
-rw-r--r--po/nl_NL.po1690
-rw-r--r--po/nn_NO.po1910
-rw-r--r--po/pl_PL.po1732
-rw-r--r--po/pt_BR.po1585
-rw-r--r--po/ru_RU.po1866
-rw-r--r--po/scummvm.pot1508
-rw-r--r--po/sv_SE.po (renamed from po/se_SE.po)1726
-rw-r--r--po/uk_UA.po1797
-rw-r--r--po/zh-Latn_CN.po3856
-rw-r--r--ports.mk228
-rw-r--r--test/common/algorithm.h74
-rw-r--r--test/common/array.h82
-rw-r--r--test/common/rational.h11
-rw-r--r--test/common/str.h77
-rw-r--r--test/module.mk1
-rw-r--r--video/avi_decoder.cpp16
-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
-rw-r--r--video/qt_decoder.cpp4
1945 files changed, 214369 insertions, 47408 deletions
diff --git a/.gitignore b/.gitignore
index 17012f3bb7..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
@@ -152,6 +154,7 @@ Thumbs.db
*.sbr
*.sdf
*.opensdf
+*.opendb
obj/
_ReSharper*/
ipch/
@@ -163,6 +166,7 @@ ipch/
*.vcxproj*
*.bat
*.tss
+*.VC.db
#Ignore default Visual Studio build folders
[Dd]ebug/
diff --git a/AUTHORS b/AUTHORS
index e2cad187fe..59e0d70fcf 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -47,10 +47,11 @@ ScummVM Team
AGI:
Stuart George
- Matthew Hoops
+ Matthew Hoops - (retired)
Filippos Karapetis
+ Martin Kiewitz
Pawel Kolodziejski
- Walter van Niftrik - (retired)
+ Walter van Niftrik
Kari Salminen
Eugene Sandulenko
David Symonds - (retired)
@@ -62,10 +63,17 @@ ScummVM Team
Oliver Kiehl - (retired)
Ludvig Strigeus - (retired)
+ Access:
+ Arnaud Boutonne
+ Paul Gilbert
+
Avalanche:
Peter Bozso
Arnaud Boutonne
+ BBVS:
+ Benjamin Haisch
+
CGE:
Arnaud Boutonne
Paul Gilbert
@@ -96,6 +104,7 @@ ScummVM Team
Drascula:
Filippos Karapetis
Pawel Kolodziejski
+ Thierry Crozat
DreamWeb:
Torbjorn Andersson
@@ -104,6 +113,10 @@ ScummVM Team
Vladimir Menshakov - (retired)
Willem Jan Palenstijn
+ Gnap:
+ Arnaud Boutonne
+ Benjamin Haisch
+
Gob:
Torbjorn Andersson
Arnaud Boutonne
@@ -132,7 +145,7 @@ ScummVM Team
Johannes Schickel
Lastexpress:
- Matthew Hoops
+ Matthew Hoops - (retired)
Jordi Vilalta Prat
Julien Templier
@@ -150,7 +163,7 @@ ScummVM Team
Mohawk:
Bastien Bouclet
- Matthew Hoops
+ Matthew Hoops - (retired)
Filippos Karapetis
Alyssa Milburn
Eugene Sandulenko
@@ -168,7 +181,7 @@ ScummVM Team
peres
Pegasus:
- Matthew Hoops
+ Matthew Hoops - (retired)
Queen:
David Eriksson - (retired)
@@ -189,11 +202,15 @@ ScummVM Team
Max Horn - (retired)
Filippos Karapetis
Martin Kiewitz
- Walter van Niftrik - (retired)
+ Walter van Niftrik
Willem Jan Palenstijn
Jordi Vilalta Prat
Lars Skovlund
+ Sherlock:
+ Paul Gilbert
+ Martin Kiewitz
+
Sky:
Robert Goeffringmann - (retired)
Oliver Kiehl - (retired)
@@ -269,15 +286,20 @@ ScummVM Team
Android:
Andre Heider
Angus Lees
+ Lubomyr Lisen
Dreamcast:
Marcus Comstedt
+ GCW0:
+ Eugene Sandulenko
+
GPH Devices (GP2X, GP2XWiz & Caanoo):
John Willis
- iPhone:
+ iPhone / iPad:
Oystein Eftevaag
+ Vincent Benony
LinuxMoto:
Lubomyr Lisen
@@ -286,6 +308,9 @@ ScummVM Team
Frantisek Dufka - (retired)
Tarek Soliman
+ Nintendo 3DS:
+ Thomas Edvalson
+
Nintendo 64:
Fabio Battaglia
@@ -327,6 +352,9 @@ ScummVM Team
Wii:
Andre Heider
+ Raspberry Pi:
+ Manuel Alfayate
+
Other subsystems
----------------
Infrastructure:
@@ -382,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
--------------------
@@ -425,6 +454,7 @@ Other contributions
Mac OS X:
Max Horn - (retired)
Oystein Eftevaag
+ Thierry Crozat
Mandriva:
Dominik Scherer - (retired)
@@ -719,3 +749,11 @@ Special thanks to
Bob Bell, Michel Kripalani, Tommy Yune, from Presto Studios for providing
the source code of The Journeyman Project: Pegasus Prime.
+ Electronic Arts IP Preservation Team, particularly Stefan Serbicki, and
+ Vasyl Tsvirkunov of Electronic Arts for providing the source code of the
+ two Lost Files of Sherlock Holmes games. James M. Ferguson and Barry
+ Duncan for their tenacious efforts to recover the sources.
+
+ The mindFactory team for writing Broken Sword 2.5, a splendid fan-made
+ sequel, and for sharing the source code with us.
+
diff --git a/COPYRIGHT b/COPYRIGHT
index 8e6b12cd04..5ac5822799 100644
--- a/COPYRIGHT
+++ b/COPYRIGHT
@@ -1,217 +1,407 @@
ScummVM
-Copyright (C) 2001-2015 by the following:
+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/Makefile.common b/Makefile.common
index 993b833f4e..df24d397de 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -246,6 +246,9 @@ DIST_FILES_THEMES:=$(addprefix $(srcdir)/gui/themes/,$(DIST_FILES_THEMES))
# Engine data files
DIST_FILES_ENGINEDATA=
+ifdef ENABLE_ACCESS
+DIST_FILES_ENGINEDATA+=access.dat
+endif
ifdef ENABLE_DRASCULA
DIST_FILES_ENGINEDATA+=drascula.dat
endif
diff --git a/NEWS b/NEWS
index bee4a0409a..193141d8b7 100644
--- a/NEWS
+++ b/NEWS
@@ -1,23 +1,191 @@
For a more comprehensive changelog of the latest experimental code, see:
https://github.com/scummvm/scummvm/commits/
-1.8.0 (????-??-??)
+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:
- Added support for Rex Nebular and the Cosmic Gender Bender.
- Added support for Sfinx.
- Added support for Zork Nemesis: The Forbidden Lands.
- Added support for Zork: Grand Inquisitor.
+ - Added support for The Lost Files of Sherlock Holmes: The Case of the
+ Serrated Scalpel.
+ - Added support for The Lost Files of Sherlock Holmes: The Case of the Rose
+ Tattoo.
+ - Added support for Beavis and Butthead in Virtual Stupidity.
+ - Added support for Amazon: Guardians of Eden.
+ - Added support for Broken Sword 2.5: The Return of the Templars.
+ - Added support for The Labyrinth of Time.
+
+ New Ports:
+ - Added Raspberry Pi port.
+ - Added GCW0 port.
General:
- Updated Munt MT-32 emulation code to version 1.5.0.
+ SDL:
+ - Alt-x no longer quits ScummVM. Use Cmd-q/Ctrl-q/Ctrl-z instead; see README.
+ - On POSIX systems we now follow the XDG Base Directory Specification for
+ placement of files for users. This effectively results in new locations
+ for our configuration file, our log file, and our default savegame path.
+ We still support our previous locations. As long as they are present, we
+ continue to use them. Please refer to the README for the new locations.
+ File locations on Mac OS X are not affected by this change.
+
3 Skulls of the Toltecs:
- Improved AdLib music support.
AGI:
- It is now possible to disable mouse support (except for Amiga versions
and fanmade games, that require a mouse).
- - Fix incorrect volume attenuation in PCjr sound code (bug #6858).
+ - Fixed PCjr sound volumes.
+ - Major rewrite of graphics subsystem.
+ - Support for Apple IIgs, Amiga + Atari ST transitions, fonts and mouse
+ cursors. The Atari ST 8x8 system font is not included with ScummVM.
+ - Added ability to make for example a PC version look like an Apple IIgs
+ version. This includes palette, cursor, transition and even font. Just
+ set corresponding render mode.
+ - Fixed Apple IIgs game versions running too fast.
+ - Added support for automatic saving/restoring used by Mixed Up Mother Goose.
+ - Removed forced two second delay on room changes; replaced with heuristic.
+ - Fixed certain key bindings breaking after saving/reloading.
AGOS:
- Fixed arpeggio effect used in music of Amiga version of Elvira 1.
@@ -29,11 +197,8 @@ For a more comprehensive changelog of the latest experimental code, see:
output and makes it closer to the original.
Broken Sword 1:
- - Fix speech endianness detection on big endian systems for the Macintosh
- version (bug #6720).
- - Fix crash when reloading a game from the Main Menu while in the bull's
- head scene (bug #6728). It may have been happening in other scenes as
- well.
+ - Fixed Macintosh version speech when running on big endian systems.
+ - Fixed loading from Main Menu in bull's head scene, and maybe other scenes.
CinE:
- Added support for music in CD version of Future Wars.
@@ -47,14 +212,20 @@ For a more comprehensive changelog of the latest experimental code, see:
SCI:
- Handling of music priority has been greatly improved.
- A lot of fixes for original game script bugs that also occurred when
- using the original interpreter.
- KQ6 (Dual Mode), LSL5, QfG1 (EGA), QfG1 (VGA), QfG2, QfG3, SQ1, SQ4 (CD)
+ using the original interpreter. This affects the following games:
+ KQ6 (Dual Mode), LSL5, PQ1, QfG1 (EGA), QfG1 (VGA), QfG2, QfG3, SQ1,
+ SQ4 (CD).
- Restoring from the ScummVM in-game menu should now work all the time.
- - Improve support for Japanese PC-9801 games.
+ - Improved support for Japanese PC-9801 games.
+ - Default to hi res version of KQ6, changeable using engine option.
SCUMM:
+ - Major improvements to Korean versions text rendering.
+ - Implemented original Maniac Mansion v0-v1 walking code.
- It is now possible to play Maniac Mansion from within Day of the
Tentacle, with a few caveats. See README for details.
+ - Alt-x can now be used to quit SCUMM games on all platforms.
+ - Improved lip sync animation in later HE games.
Tinsel:
- Improved AdLib music support in Discworld 1.
@@ -1758,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 2a1d7c390e..353d25d9d0 100644
--- a/README
+++ b/README
@@ -3,7 +3,7 @@ ScummVM README
For more information, compatibility lists, details on donating, the latest
release, progress reports and more, please visit the ScummVM home page
-at: http://www.scummvm.org/
+at: <http://www.scummvm.org/>
Table of Contents:
@@ -11,38 +11,47 @@ Table of Contents:
1.0) Introduction
* 1.1 About ScummVM
* 1.2 Quick start
+ * 1.3 F.A.Q.
2.0) Contact
* 2.1 Reporting Bugs
3.0) Supported Games
* 3.1 Copy Protection
- * 3.2 Day of the Tentacle notes
- * 3.3 Commodore64 games notes
- * 3.4 Maniac Mansion NES notes
- * 3.5 Macintosh games notes
- * 3.6 Multi-CD games notes
- * 3.7 The Curse of Monkey Island notes
- * 3.8 Broken Sword games notes
- * 3.9 Beneath a Steel Sky notes
+ * 3.2 Datafiles
+ * 3.3 Multi-CD games notes
+ * 3.4 Known Problems
+ * 3.5 Beneath a Steel Sky notes
+ * 3.6 Broken Sword games notes
+ * * 3.6.1 Broken Sword
+ * * 3.6.2 Broken Sword II
+ * * 3.6.3 Broken Sword games cutscenes
+ * * 3.6.4 Broken Sword games cutscenes, in retrospect
+ * 3.7 Day of the Tentacle notes
+ * 3.8 Discworld II notes
+ * 3.9 Dragon History notes
* 3.10 Flight of the Amazon Queen notes
* 3.11 Gobliiins notes
- * 3.12 Inherit the Earth: Quest for the Orb notes
- * 3.13 Simon the Sorcerer notes
- * 3.14 The Feeble Files notes
- * 3.15 The Legend of Kyrandia notes
- * 3.16 Sierra AGI games Predictive Input Dialog notes
- * 3.17 Mickey's Space Adventure notes
- * 3.18 Winnie the Pooh notes
- * 3.19 Troll's Tale notes
- * 3.20 Dragon History notes
- * 3.21 Simultaneous speech and subtitles in Sierra SCI games
- * 3.22 Known Problems
+ * 3.12 Inherit the Earth: Quest for the Orb notes
+ * 3.13 Maniac Mansion Apple II/NES notes
+ * 3.14 Mickey's Space Adventure notes
+ * 3.15 Nippon Safes Inc. Amiga notes
+ * 3.16 Simon the Sorcerer notes
+ * 3.17 The Curse of Monkey Island notes
+ * 3.18 The Feeble Files notes
+ * 3.19 The Legend of Kyrandia notes
+ * 3.20 Troll's Tale notes
+ * 3.21 Winnie the Pooh notes
+ * 3.22 Sierra AGI games: Predictive Input Dialog notes
+ * 3.23 Sierra SCI games: Simultaneous speech and subtitles
+ * 3.24 Zork games notes
+ * 3.25 Commodore64 games notes
+ * 3.26 Macintosh games notes
4.0) Supported Platforms
5.0) Running ScummVM
* 5.1 Command Line Options
- * 5.2 Language Options
+ * 5.2 Global Menu
* 5.3 Graphics Filters
- * 5.4 Global Menu
- * 5.5 Hotkeys
+ * 5.4 Hotkeys
+ * 5.5 Language Options
6.0) Saved Games
* 6.1 Autosaves
* 6.2 Converting saved games
@@ -53,14 +62,27 @@ Table of Contents:
* 7.3 MT-32 emulation
* 7.4 MIDI emulation
* 7.5 Native MIDI support
+ * 7.5.1 Using MIDI options to customize Native MIDI output
* 7.6 UNIX native, ALSA and dmedia sequencer support
+ * * 7.6.1 ALSA sequencer [UNIX ONLY]
+ * * 7.6.2 IRIX dmedia sequencer [UNIX ONLY]
* 7.7 TiMidity++ MIDI server support
* 7.8 Using compressed audio files (MP3, Ogg Vorbis, Flac)
+ * * 7.8.1 Using MP3 files for CD audio
+ * * 7.8.2 Using Ogg Vorbis files for CD audio
+ * * 7.8.3 Using Flac files for CD audio
+ * * 7.8.4 Compressing MONSTER.SOU with MP3
+ * * 7.8.5 Compressing MONSTER.SOU with Ogg Vorbis
+ * * 7.8.6 Compressing MONSTER.SOU with Flac
+ * * 7.8.7 Compressing music/sfx/speech in AGOS games
+ * * 7.8.8 Compressing speech/music in Broken Sword
+ * * 7.8.9 Compressing speech/music in Broken Sword II
* 7.9 Output sample rate
8.0) Configuration file
* 8.1 Recognized configuration keywords
* 8.2 Custom game options that can be toggled via the GUI
9.0) Compiling
+10.0) Credits
1.0) Introduction:
@@ -127,7 +149,7 @@ you want to play.
datafiles (do not try to select the datafiles themselves!) and press
'Choose'.
-4. A dialog should popup allowing you to configure various settings if
+4. A dialog should pop up allowing you to configure various settings if
you wish to (it should be just fine to leave everything at its default,
though). Confirm the dialog.
@@ -137,16 +159,23 @@ In the future, you should be able to directly skip to step 5, unless you
want to add more games.
Hint: If you want to add multiple games in one go, try pressing and
-holding the shift key before clicking 'Add game' -- its label will
+holding the shift key before clicking 'Add game' -- it's label will
change to 'Mass Add' and if you press it, you are again asked to select
a directory, only this time ScummVM will search through all
subdirectories for supported games.
+1.3) F.A.Q.
+---- ------
+We've compiled a list of F.A.Q. at:
+
+ <http://www.scummvm.org/faq/>
+
+
2.0) Contact:
---- --------
The easiest way to contact the ScummVM team is by submitting bug reports
-(see section 2.1) or by using our forums at http://forums.scummvm.org .
+(see section 2.1) or by using our forums at <http://forums.scummvm.org>.
You can also join and e-mail the scummvm-devel mailing list, or chat
with us on IRC (#scummvm on irc.freenode.net) Please do not ask us to
support an unsupported game -- read the FAQ on our web site first.
@@ -160,7 +189,7 @@ reproducible, and still occurs in the latest git/Daily build version.
Also check the known problems list (below) and the compatibility list
on our website for that game, to ensure the issue is not already known:
- http://www.scummvm.org/compatibility_stable.php
+ <http://scummvm.org/compatibility/>
Please do not report bugs on games that are not listed as being
completeable in the 'Supported Games' section, or compatibility list. We
@@ -186,12 +215,16 @@ each individual bug).
---- ----------------
At the moment the following games have been reported to work, and should
be playable to the end:
+A more detailed compatibility list of the supported games can be found here:
+
+ <http://www.scummvm.org/compatibility/>)
-SCUMM Games by LucasArts:
+LucasArts (SCUMM) Games:
Maniac Mansion [maniac]
Zak McKracken and the Alien Mindbenders [zak]
Indiana Jones and the Last Crusade [indy3]
Loom [loom]
+ Passport to Adventure [pass]
The Secret of Monkey Island [monkey]
Monkey Island 2: LeChuck's Revenge [monkey2]
Indiana Jones and the Fate of Atlantis [atlantis]
@@ -201,32 +234,16 @@ SCUMM Games by LucasArts:
The Dig [dig]
The Curse of Monkey Island [comi]
-AGI and preAGI Games by Sierra:
- The Black Cauldron [bc]
- Gold Rush! [goldrush]
- King's Quest I [kq1]
- King's Quest II [kq2]
- King's Quest III [kq3]
- King's Quest IV [kq4]
- Leisure Suit Larry in the Land of the
- Lounge Lizards [lsl1]
- Mixed-Up Mother Goose [mixedup]
- Manhunter 1: New York [mh1]
- Manhunter 2: San Francisco [mh2]
- Police Quest I: In Pursuit of the Death
- Angel [pq1]
- Space Quest I: The Sarien Encounter [sq1]
- Space Quest II: Vohaul's Revenge [sq2]
- Fanmade Games [agi-fanmade]
- Mickey's Space Adventure [mickey]
- Troll's Tale [troll]
- Winnie the Pooh in the Hundred Acre Wood [winnie]
+Activision (MADE) Games:
+ Leather Goddesses of Phobos 2 [lgop2]
+ The Manhole [manhole]
+ Return to Zork [rtz]
+ Rodney's Funscreen [rodney]
-AGOS Games by Adventuresoft/Horrorsoft:
+Adventuresoft/Horrorsoft (AGOS) Games:
Elvira - Mistress of the Dark [elvira1]
Elvira II - The Jaws of Cerberus [elvira2]
Personal Nightmare [pn]
- Waxworks [waxworks]
Simon the Sorcerer 1 [simon1]
Simon the Sorcerer 2 [simon2]
Simon the Sorcerer's Puzzle Pack
@@ -238,16 +255,9 @@ AGOS Games by Adventuresoft/Horrorsoft:
Simon the Sorcerer's Puzzle Pack
- Swampy Adventures [swampy]
The Feeble Files [feeble]
+ Waxworks [waxworks]
-Composer Games by Animation Magic:
- Darby the Dragon [darby]
- Gregory and the Hot Air Balloon [gregory]
- Magic Tales: Liam Finds a Story [liam]
- The Princess and the Crab [princess]
- Sleeping Cub's Test of Courage [sleepingcub]
-
-GOB Games by Coktel Vision:
- Bambou le sauveur de la jungle [bambou]
+Coktel Vision (GOB) Games:
Bargon Attack [bargon]
Fascination [fascination]
Geisha [geisha]
@@ -256,80 +266,40 @@ GOB Games by Coktel Vision:
Goblins 3 [gob3]
Lost in Time [lostintime]
Once Upon A Time: Little Red Riding Hood [littlered]
+ Playtoons: Bambou le sauveur de la jungle [bambou]
The Bizarre Adventures of Woodruff
and the Schnibble [woodruff]
Urban Runner [urban]
Ween: The Prophecy [ween]
-Living Books Games:
- Aesop's Fables: The Tortoise and the Hare [tortoise]
- Arthur's Birthday [arthurbday]
- Arthur's Teacher Trouble [arthur]
- Dr. Seuss's ABC [seussabc]
- Green Eggs and Ham [greeneggs]
- Harry and the Haunted House [harryhh]
- Just Grandma and Me [grandma]
- Little Monster at School [lilmonster]
- Ruff's Bone [ruff]
- Sheila Rae, the Brave [sheila]
- Stellaluna [stellaluna]
- The Berenstain Bears Get in a Fight [bearfight]
- The Berenstain Bears in the Dark [beardark]
- The New Kid on the Block [newkid]
-
-MADE Games by Activision:
- Leather Goddesses of Phobos 2 [lgop2]
- Return to Zork [rtz]
- Rodney's Funscreen [rodney]
- The Manhole [manhole]
-
-Other Games:
- 3 Skulls of the Toltecs [toltecs]
- Blue Force [blueforce]
+Revolution Software (Various) Games:
Beneath a Steel Sky [sky]
Broken Sword: The Shadow of the Templars [sword1]
Broken Sword II: The Smoking Mirror [sword2]
- Bud Tucker in Double Trouble [tucker]
- Cruise for a Corpse [cruise]
- Discworld [dw]
- Discworld 2: Missing Presumed ...!? [dw2]
- Dragon History [draci]
- Drascula: The Vampire Strikes Back [drascula]
- DreamWeb [dreamweb]
- Eye of the Beholder [eob]
- Eye of the Beholder II: The Legend of
- Darkmoon [eob2]
- Flight of the Amazon Queen [queen]
- Future Wars [fw]
- Hopkins FBI [hopkins]
- Hugo's House of Horrors [hugo1]
- Hugo 2: Whodunit? [hugo2]
- Hugo 3: Jungle of Doom [hugo3]
- I Have No Mouth, and I Must Scream [ihnm]
- Inherit the Earth: Quest for the Orb [ite]
- Nippon Safes Inc. [nippon]
- Lands of Lore: The Throne of Chaos [lol]
Lure of the Temptress [lure]
- Mortville Manor [mortevielle]
- Nippon Safes Inc. [nippon]
- Ringworld: Revenge Of The Patriarch [ringworld]
- Return to Ringworld [ringworld2]
- Sfinx [sfinx]
- Soltys [soltys]
- TeenAgent [teenagent]
- The Journeyman Project: Pegasus Prime [pegasus]
- The Legend of Kyrandia [kyra1]
- The Legend of Kyrandia: The Hand of Fate [kyra2]
- The Legend of Kyrandia: Malcolm's Revenge [kyra3]
- The 7th Guest [t7g]
- The Neverhood [neverhood]
- Tony Tough and the Night of Roasted Moths [tony]
- Toonstruck [toon]
- Touche: The Adventures of the Fifth
- Musketeer [touche]
- Voyeur [voyeur]
-SCI Games by Sierra Entertainment:
+Sierra (AGI/preAGI) Games:
+ The Black Cauldron [bc]
+ Gold Rush! [goldrush]
+ King's Quest I [kq1]
+ King's Quest II [kq2]
+ King's Quest III [kq3]
+ King's Quest IV [kq4]
+ Leisure Suit Larry in the Land of the
+ Lounge Lizards [lsl1]
+ Mixed-Up Mother Goose [mixedup]
+ Manhunter 1: New York [mh1]
+ Manhunter 2: San Francisco [mh2]
+ Police Quest I: In Pursuit of the Death
+ Angel [pq1]
+ Space Quest I: The Sarien Encounter [sq1]
+ Space Quest II: Vohaul's Revenge [sq2]
+ Fanmade Games [agi-fanmade]
+ Mickey's Space Adventure [mickey]
+ Troll's Tale [troll]
+ Winnie the Pooh in the Hundred Acre Wood [winnie]
+
+Sierra (SCI) Games:
Castle of Dr. Brain [castlebrain]
Codename: ICEMAN [iceman]
Conquests of Camelot [camelot]
@@ -370,14 +340,59 @@ SCI Games by Sierra Entertainment:
Space Quest V [sq5]
The Island of Dr. Brain [islandbrain]
-Wintermute Games:
+Other Games:
+ 3 Skulls of the Toltecs [toltecs]
+ Amazon: Guardians of Eden [access]
+ Beavis and Butt-head in Virtual Stupidity [bbvs]
+ Blue Force [blueforce]
+ Broken Sword: The Return of the Templars [sword25]
+ Bud Tucker in Double Trouble [tucker]
Chivalry is Not Dead [chivalry]
-
-Z-Vision Games by Activision:
- Zork Nemesis: The Forbidden Lands [znemesis]
+ Cruise for a Corpse [cruise]
+ DreamWeb [dreamweb]
+ Discworld [dw]
+ Discworld 2: Missing Presumed ...!? [dw2]
+ Dragon History [draci]
+ Drascula: The Vampire Strikes Back [drascula]
+ Eye of the Beholder [eob]
+ Eye of the Beholder II: The Legend of
+ Darkmoon [eob2]
+ Flight of the Amazon Queen [queen]
+ Future Wars [fw]
+ Hopkins FBI [hopkins]
+ Hugo's House of Horrors [hugo1]
+ Hugo 2: Whodunit? [hugo2]
+ Hugo 3: Jungle of Doom [hugo3]
+ I Have No Mouth, and I Must Scream [ihnm]
+ Inherit the Earth: Quest for the Orb [ite]
+ Lands of Lore: The Throne of Chaos [lol]
+ Mortville Manor [mortevielle]
+ Nippon Safes Inc. [nippon]
+ Rex Nebular and the Cosmic Gender Bender [nebular]
+ Ringworld: Revenge Of The Patriarch [ringworld]
+ Return to Ringworld [ringworld2]
+ Sfinx [sfinx]
+ Soltys [soltys]
+ The Journeyman Project: Pegasus Prime [pegasus]
+ The Legend of Kyrandia [kyra1]
+ The Legend of Kyrandia: The Hand of Fate [kyra2]
+ The Legend of Kyrandia: Malcolm's Revenge [kyra3]
+ The Lost Files of Sherlock Holmes: The Case
+ of the Serrated Scalpel [scalpel]
+ The Lost Files of Sherlock Holmes: The Case
+ of the Rose Tattoo [rosetattoo]
+ The Neverhood [neverhood]
+ The 7th Guest [t7g]
+ TeenAgent [teenagent]
+ Toonstruck [toon]
+ Tony Tough and the Night of Roasted Moths [tony]
+ Touche: The Adventures of the Fifth
+ Musketeer [touche]
+ Voyeur [voyeur]
Zork: Grand Inquisitor [zgi]
+ Zork Nemesis: The Forbidden Lands [znemesis]
-SCUMM Games by Humongous Entertainment:
+Humongous Entertainment (SCUMM) Games:
Backyard Baseball [baseball]
Backyard Baseball 2001 [baseball2001]
Backyard Baseball 2003 [baseball2003]
@@ -417,12 +432,12 @@ SCUMM Games by Humongous Entertainment:
From Your Head to Your Feet [pajama3]
Pajama Sam's Lost & Found [lost]
Pajama Sam's Sock Works [socks]
- Putt-Putt Joins the Parade [puttputt]
+ Putt-Putt Enters the Race [puttrace]
Putt-Putt Goes to the Moon [puttmoon]
+ Putt-Putt Joins the Circus [puttcircus]
+ Putt-Putt Joins the Parade [puttputt]
Putt-Putt Saves the Zoo [puttzoo]
Putt-Putt Travels Through Time [putttime]
- Putt-Putt Enters the Race [puttrace]
- Putt-Putt Joins the Circus [puttcircus]
Putt-Putt and Pep's Balloon-O-Rama [balloon]
Putt-Putt and Pep's Dog on a Stick [dog]
Putt-Putt & Fatty Bear's Activity Pack [activity]
@@ -443,6 +458,29 @@ and view the compatibility chart.
Backyard Soccer 2004 [soccer2004]
Blue's Treasure Hunt [BluesTreasureHunt]
+Animation Magic (Composer) Games:
+ Darby the Dragon [darby]
+ Gregory and the Hot Air Balloon [gregory]
+ Magic Tales: Liam Finds a Story [liam]
+ The Princess and the Crab [princess]
+ Sleeping Cub's Test of Courage [sleepingcub]
+
+Living Books Games:
+ Aesop's Fables: The Tortoise and the Hare [tortoise]
+ Arthur's Birthday [arthurbday]
+ Arthur's Teacher Trouble [arthur]
+ Dr. Seuss's ABC [seussabc]
+ Green Eggs and Ham [greeneggs]
+ Harry and the Haunted House [harryhh]
+ Just Grandma and Me [grandma]
+ Little Monster at School [lilmonster]
+ Ruff's Bone [ruff]
+ Sheila Rae, the Brave [sheila]
+ Stellaluna [stellaluna]
+ The Berenstain Bears Get in a Fight [bearfight]
+ The Berenstain Bears in the Dark [beardark]
+ The New Kid on the Block [newkid]
+
The following games are based on the SCUMM engine, but NOT supported
by ScummVM (yet):
@@ -492,127 +530,118 @@ ScummVM will skip copy protection in the following games:
* Zak McKracken and the Alien Mindbenders
-3.2) Day of the Tentacle notes:
----- --------------------------
-
-At one point in the game, you come across a computer that allows you
-to play the original Maniac Mansion as an easter egg. ScummVM supports
-this, with a few caveats:
-
-ScummVM will scan your configuration file for a game that's in a
-'Maniac' sub-folder of your Day of the Tentacle folder. If you've
-copied the data files from the CD version, this should already be the
-case but you have to add the game to ScummVM as well.
+3.2) Datafiles:
+---- ----------
+For a comprehensive list of required Datafiles for supported games
+visit:
-To return to Day of the Tentacle, press F5 and select "Return to
-Launcher".
+ <http://wiki.scummvm.org/index.php/Datafiles>
-This means that you could in theory use any game as the easter egg.
-Indeed, there is a "secret" configuration setting, "easter_egg", to
-override the ID of the game to run. Be aware, though, that not all
-games support returning to the launcher, and setting it up to use Day
-of the Tentacle itself as the easter egg game is not recommended.
+3.3) Multi-CD games notes:
+---- ---------------------
+In general, ScummVM does not deal very well with Multi-CD games. This is
+because ScummVM assumes everything about a game can be found in one
+directory. Even if ScummVM does make some provisions for asking the user
+to change CD, the original game executables usually installed a small
+number of files to the hard disk. Unless these files can be found on all
+the CDs, ScummVM will be in trouble.
-3.3) Commodore64 games notes:
----- ------------------------
-Both Maniac Mansion and Zak McKracken run but Maniac Mansion is not yet
-playable. Simply name the D64 disks "maniac1.d64" and "maniac2.d64"
-respectively "zak1.d64" and "zak2.d64", then ScummVM should be able to
-automatically detect the game if you point it at the right directory.
+Fortunately, ScummVM has no problems running the games entirely from
+hard disk, if you create a directory with the correct combination of
+files. Usually, when a file appears on more than one CD you can pick
+either of them.
-Alternatively, you can use 'extract_mm_c64' from the tools package to
-extract the data files. But then the game will not be properly
-autodetected by ScummVM, and you must make sure that the platform is set
-to Commodore64. We recommend using the much simpler approach described
-in the previous paragraph.
+3.4) Known Problems:
+---- ---------------
+This release has the following known problems. There is no need to
+report them, although patches to fix them are welcome. If you discover a
+bug that is not listed here, nor in the compatibility list on the web
+site, please see the section on reporting bugs.
-3.4) Maniac Mansion NES notes:
----- -------------------------
-Supported versions are English GB (E), French (F), German (G), Italian (I),
-Swedish (SW) and English US (U). ScummVM requires just the PRG section
-to run and not the whole ROM.
+ CD Audio Games:
+ - When playing games that use CD Audio (FM-TOWNS games, Loom CD, etc)
+ users of Microsoft Windows 2000/XP may experience random crashes.
+ This is due to a long-standing Windows bug, resulting in corrupt
+ game files being read from the CD. Please copy the game data to
+ your hard disk to avoid this.
-In order to get the game working, you will have to strip out the first
-16 bytes from the ROM you are trying to work with. Any hex editor will
-work as long as you are able to copy/paste. After you open the ROM with
-the hex editor, copy everything from the second row (17th byte) to the
-end. After you do this, paste it to a new hex file. Name the new file
-"Maniac Mansion (XX).prg" while XX stands for the version you are
-working with (E, F, G, I, SW, or U). The final size should be exactly
-262144 bytes.
+ FM-TOWNS versions:
+ - The Kanji versions require the FM-TOWNS Font ROM.
-If you add the game manually make sure that the platform is set to NES.
+ Loom:
+ - Turning off the subtitles via the config file does not work reliably
+ as the Loom scripts automatically turn them on again.
+ - MIDI support in the EGA version requires the Roland update from
+ LucasArts.
+ - The PC-Engine Kanji version requires the system card rom.
-Most common mistakes which prevents the game from running:
+ The Secret of Monkey Island:
+ - MIDI support in the EGA version requires the Roland update from
+ LucasArts.
- * Bad file
- * ROM extracted with the 0.7.0 tools
- * You try to feed ScummVM with the FULL ROM and not just the PRG
- section.
+ Beneath a Steel Sky:
+ - Amiga versions aren't supported.
+ - Floppy demos aren't supported.
+ - Not a bug: CD version is missing speech for some dialogs, this is
+ normal.
-It is also possible to extract the separate LFL files from the PRG
-section. To do so use the 'extract_mm_nes' utility from the tools
-package.
+ Elvira - Mistress of the Dark:
+ - No music in the Atari ST version.
+ Elvira II - The Jaws of Cerberus
+ - No music in the Atari ST version.
+ - No sound effects in the PC version.
+ - Palette issues in the Atari ST version.
-3.5) Macintosh games notes:
----- ----------------------
-All LucasArts SCUMM based adventures, except COMI, also exist in versions
-for the Macintosh. ScummVM can use most (all?) of them, however, in some
-cases some additional work is required. First off, if you are not using
-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
-operating systems.
+ Inherit the Earth: Quest for the Orb:
+ - Amiga versions aren't supported.
-Most of the newer games on the Macintosh shipped with only a single data
-file (note that in some cases this data file was made invisible, so you
-may need extra tools in order to copy it). ScummVM is able to directly
-use such a data file; simply point ScummVM at the directory containing
-it, and it should work (just like with every other supported game).
+ Lure of the Temptress:
+ - No Roland MT-32 support.
+ - Sound support is incomplete and doesn't sound like original.
-We also provide a tool called 'extract_scumm_mac' in the tools package
-to extract the data from these data files, but this is neither required
-nor recommended.
+ Simon the Sorcerer 1:
+ - Subtitles aren't available in the English and German CD versions
+ as they are missing the majority of subtitles.
-For further information on copying Macintosh game files to your hard
-disk see:
+ Simon the Sorcerer 2:
+ - Combined speech and subtitles will often cause speech to be
+ cut off early, this is a limitation of the original game.
+ - Only default language (English) of data files is supported
+ in Amiga and Macintosh versions.
- http://wiki.scummvm.org/index.php/HOWTO-Mac_Games
+ Simon the Sorcerer's Puzzle Pack:
+ - No support for displaying, entering, loading or saving high scores.
+ - No support for displaying names of items, when hovering over them
+ in Swampy Adventures.
+ The Feeble Files:
+ - Subtitles are often incomplete, they were always disabled in the
+ original game.
-3.6) Multi-CD games notes:
----- ---------------------
-In general, ScummVM does not deal very well with Multi-CD games. This is
-because ScummVM assumes everything about a game can be found in one
-directory. Even if ScummVM does make some provisions for asking the user
-to change CD, the original game executables usually installed a small
-number of files to the hard disk. Unless these files can be found on all
-the CDs, ScummVM will be in trouble.
+ The Legend of Kyrandia:
+ - No music or sound effects in the Macintosh floppy versions.
+ - Macintosh CD is using included DOS music and sound effects.
-Fortunately, ScummVM has no problems running the games entirely from
-hard disk, if you create a directory with the correct combination of
-files. Usually, when a file appears on more than one CD you can pick
-either of them.
+ Humongous Entertainment games:
+ - Only the original load and save interface can be used.
+ - No support for multiplayer or printing images.
-3.7) The Curse of Monkey Island notes:
----- ---------------------------------
-For this game, you will need the comi.la0, comi.la1 and comi.la2 files.
-The comi.la0 file can be found on either CD, but since they are
-identical it doesn't matter which one of them you use.
+3.5) Beneath a Steel Sky notes:
+---- --------------------------
+Starting with ScummVM 0.8.0 you need the additional 'SKY.CPT' file to
+run Beneath a Steel Sky.
-In addition, you will need to create a "resource" subdirectory
-containing all of the files from -both- "resource" subdirectories on the
-two CDs. Some of the files appear on both CDs, but again they're
-identical.
+This file is available on the 'Downloads' page of the ScummVM website.
+You can place it in either the directory containing the other game data
+files (SKY.DNR, SKY.DSK), in your extrapath, or in the directory where
+your ScummVM executable resides.
-3.8) Broken Sword games notes:
+3.6) Broken Sword games notes:
---- -------------------------
The instructions for the Broken Sword games are for the Sold-Out
Software versions, with each game on two CDs, since these were the
@@ -621,7 +650,39 @@ them. Hopefully they are general enough to be useful to other releases
as well.
-3.8.1) Broken Sword games cutscenes:
+3.6.1) Broken Sword:
+------ -------------
+For this game, you will need all of the files from the clusters
+directories on both CDs. For the Windows and Macintosh versions, you
+will also need the speech.clu files from the speech directories, but
+since they are not identical you will need to rename them speech1.clu
+and speech2.clu for CD 1 and 2 respectively. The PlayStation version
+requires the speech.tab, speech.dat, speech.lis, and speech.inf.
+
+In addition, the Windows and Macintosh versions require a music
+subdirectory with all of the files from the music subdirectories on
+both CDs. Some of these files appear on both CDs, but in these cases
+they are either identical or, in one case, so nearly identical that it
+makes little difference. The PlayStation version requires tunes.dat and
+tunes.tab.
+
+
+3.6.2) Broken Sword II:
+------ ----------------
+For this game, you will need all of the files from the clusters
+directories on both CDs. (Actually, a few of them may not be strictly
+necessary, but the ones that I'm uncertain about are all fairly small.)
+You will need to rename the speech.clu and music.clu files speech1.clu,
+speech2.clu, music1.clu and music2.clu so that ScummVM can tell which
+ones are from CD 1 and which ones are from CD 2. Any other files that
+appear in both cluster directories are identical. Use whichever you
+like.
+
+In addition, you will need the cd.inf and, optionally, the startup.inf
+files from the sword2 directory on CD 1.
+
+
+3.6.3) Broken Sword games cutscenes:
------ -----------------------------
The cutscenes for the Broken Sword games have a bit of a history (see
the next section, if you are interested), but in general all you need to
@@ -638,13 +699,13 @@ may also use the re-encoded cutscenes mentioned below instead, but this
will not work for all videos in Broken Sword II. For more information,
see:
- http://wiki.scummvm.org/index.php/HOWTO-PlayStation_Videos
+ <http://wiki.scummvm.org/index.php/HOWTO-PlayStation_Videos>
Some re-releases of the games, as well as the PlayStation version, do
not have Smacker videos. Revolution Software has kindly allowed us to
provide re-encoded cutscenes for download on our website:
- http://www.scummvm.org/downloads.php
+ <http://www.scummvm.org/downloads.php>
These cutscenes are provided in DXA format with FLAC audio. Their
quality is equal to the original games due to the use of lossless
@@ -662,7 +723,7 @@ currently does not work when running PlayStation videos. (Broken Sword
II already has subtitles; no extra work is needed for them.)
-3.8.2) Broken Sword games cutscenes, in retrospect:
+3.6.4) Broken Sword games cutscenes, in retrospect:
------ --------------------------------------------
The original releases of the Broken Sword games used RAD Game Tools's
Smacker(tm) format. As RAD was unwilling to open the older legacy
@@ -687,51 +748,61 @@ decoding MPEG movies added a lot of complexity, and they didn't look as
good as the Smacker and DXA versions anyway.
-3.8.3) Broken Sword:
------- -------------
-For this game, you will need all of the files from the clusters
-directories on both CDs. For the Windows and Macintosh versions, you
-will also need the speech.clu files from the speech directories, but
-since they are not identical you will need to rename them speech1.clu
-and speech2.clu for CD 1 and 2 respectively. The PlayStation version
-requires the speech.tab, speech.dat, speech.lis, and speech.inf.
+3.7) Day of the Tentacle notes:
+---- --------------------------
-In addition, the Windows and Macintosh versions require a music
-subdirectory with all of the files from the music subdirectories on
-both CDs. Some of these files appear on both CDs, but in these cases
-they are either identical or, in one case, so nearly identical that it
-makes little difference. The PlayStation version requires tunes.dat and
-tunes.tab.
+At one point in the game, you come across a computer that allows you
+to play the original Maniac Mansion as an easter egg. ScummVM supports
+this, with a few caveats:
+ScummVM will scan your configuration file for a game that's in a
+'Maniac' sub-folder of your Day of the Tentacle folder. If you've
+copied the data files from the CD version, this should already be the
+case but you have to add the game to ScummVM as well.
-3.8.4) Broken Sword II:
------- ----------------
-For this game, you will need all of the files from the clusters
-directories on both CDs. (Actually, a few of them may not be strictly
-necessary, but the ones that I'm uncertain about are all fairly small.)
-You will need to rename the speech.clu and music.clu files speech1.clu,
-speech2.clu, music1.clu and music2.clu so that ScummVM can tell which
-ones are from CD 1 and which ones are from CD 2. Any other files that
-appear in both cluster directories are identical. Use whichever you
-like.
+To return to Day of the Tentacle, press F5 and select "Return to
+Launcher".
-In addition, you will need the cd.inf and, optionally, the startup.inf
-files from the sword2 directory on CD 1.
+This means that you could in theory use any game as the easter egg.
+Indeed, there is a "secret" configuration setting, "easter_egg", to
+override the ID of the game to run. Be aware, though, that not all
+games support returning to the launcher, and setting it up to use Day
+of the Tentacle itself as the easter egg game is not recommended.
-3.9) Beneath a Steel Sky notes:
----- --------------------------
-Starting with ScummVM 0.8.0 you need the additional 'SKY.CPT' file to
-run Beneath a Steel Sky.
+3.8) Discworld II notes:
+---- -------------------
+For this game, you will need all of the files in the DW2 subdirectory
+on both CDs.
+In addition, you will need the SAMPLE.BNK file.
-This file is available on the 'Downloads' page of the ScummVM website.
-You can place it in either the directory containing the other game data
-files (SKY.DNR, SKY.DSK), in your extrapath, or in the directory where
-your ScummVM executable resides.
+You will need to rename ENGLISH.SMP, ENGLISH.IDX and ENGLISH.TXT
+on CD1 to ENGLISH1.SMP, ENGLISH1.IDX and ENGLISH1.txt.
+The same files on CD2 need to be renamed to ENGLISH2.SMP, ENGLISH2.IDX
+and ENGLISH2.TXT.
+
+
+3.9) Dragon History notes:
+---- ---------------------
+There are 4 language variants of the game: Czech, English, Polish and
+German. Each of them is distributed in a separate archive. The only
+official version is the Czech one, and the English, Polish and German
+ports have always been work in progress and never officially released.
+Although all texts are fully translated, it is known that some of them
+contain typos.
+
+There exists an optional Czech dubbing for the game. For bandwidth
+reasons, you can download it separately and then unpack it to the
+directory of the game. You can listen to the Czech dubbing with all
+language variants of the game, while reading the subtitles.
+
+All game files and the walkthrough can be downloaded from:
+
+ <http://www.ucw.cz/draci-historie/index-en.html>
3.10) Flight of the Amazon Queen notes:
----- ---------------------------------
+----- ---------------------------------
In order to use a non-freeware version of Flight of the Amazon Queen
(from original CD), you will need to place the 'queen.tbl' file
(available from the 'Downloads' page on our website) in either the
@@ -761,10 +832,10 @@ In order to run the Mac OS X Wyrmkeep re-release of the game you will
need to copy over data from the CD to your hard disk. If you're on a PC
then consult:
- http://wiki.scummvm.org/index.php/HOWTO-Mac_Games
+ <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:
@@ -775,15 +846,94 @@ format, as they should include both resource and data forks. Copy all
'ITE *' files.
-3.13) Simon the Sorcerer 1 and 2 notes:
------ ---------------------------------
+3.13) Maniac Mansion Apple II/NES notes:
+----- ----------------------------------
+Apple II:
+You need to rename disk image 1 to maniac1.dsk
+You need to rename disk image 1 to maniac2.dsk
+
+NES:
+Supported versions are English GB (E), French (F), German (G), Italian (I),
+Swedish (SW) and English US (U). ScummVM requires just the PRG section
+to run and not the whole ROM.
+
+In order to get the game working, you will have to strip out the first
+16 bytes from the ROM you are trying to work with. Any hex editor will
+work as long as you are able to copy/paste. After you open the ROM with
+the hex editor, copy everything from the second row (17th byte) to the
+end. After you do this, paste it to a new hex file. Name the new file
+"Maniac Mansion (XX).prg" while XX stands for the version you are
+working with (E, F, G, I, SW, or U). The final size should be exactly
+262144 bytes.
+
+If you add the game manually make sure that the platform is set to NES.
+
+Most common mistakes which prevents the game from running:
+
+ * Bad file
+ * ROM extracted with the 0.7.0 tools
+ * You try to feed ScummVM with the FULL ROM and not just the PRG
+ section.
+
+It is also possible to extract the separate LFL files from the PRG
+section. To do so use the 'extract_mm_nes' utility from the tools
+package.
+
+
+3.14) Mickey's Space Adventure notes:
+----- -------------------------------
+To run Mickey's Space Adventure under ScummVM, the original executable
+of the game (mickey.exe) is needed together with the game's data files.
+
+There is extensive mouse support for the game under ScummVM, even though
+there wasn't any mouse support in the original game. Menu items can be
+selected using the mouse, and it is possible to move to other locations
+using the mouse as well. When the mouse cursor is hovered on the edges
+of the screen, it changes color to red if it is possible to walk towards
+that direction. The player can then simply click on the edges of the
+game's screen to change location, similar to many adventure games, which
+is simpler and more straightforward than moving around using the menu.
+
+
+3.15) Nippon Safes Inc. Amiga notes:
+----- ------------------------------
+For this game, you will need disk0, , global.table, pointer and
+it (en, fr, ge for the international version).
+
+In addition, you will need to rename disk image 2 to disk1,
+disk image 3 to disk2, disk image 4 to disk3 and disk image 5 to disk4.
+
+
+3.16) Simon the Sorcerer games notes:
+----- -------------------------------
If you have the dual version of Simon the Sorcerer 1 or 2 on CD, you
will find the Windows version in the main directory of the CD and the
DOS version in the DOS directory of the CD.
-3.14) The Feeble Files notes:
+3.17) The Curse of Monkey Island notes:
+----- ---------------------------------
+For this game, you will need the comi.la0, comi.la1 and comi.la2 files.
+The comi.la0 file can be found on either CD, but since they are
+identical it doesn't matter which one of them you use.
+
+In addition, you will need to create a "resource" subdirectory
+containing all of the files from -both- "resource" subdirectories on the
+two CDs. Some of the files appear on both CDs, but again they're
+identical.
+
+
+3.18) The Feeble Files notes:
----- -----------------------
+Amiga/Macintosh:
+You need to install a small pack of cutscenes that are missing in both
+of these versions of The Feeble Files.
+It's called "The Feeble Files - Omni TV and epilogue cutscenes for the
+Amiga and Macintosh versions" and you can get it here:
+
+ <http://www.scummvm.org/games/#feeble>
+
+Windows:
If you have the Windows version of The Feeble Files, there are several
things to note.
@@ -800,7 +950,7 @@ Rename voices.wav on CD3 to voices3.wav
Rename voices.wav on CD4 to voices4.wav
-3.15) The Legend of Kyrandia notes:
+3.19) The Legend of Kyrandia notes:
----- -----------------------------
To run The Legend of Kyrandia under ScummVM you need the 'kyra.dat'
file. The file should always be included in official ScummVM packages.
@@ -811,8 +961,30 @@ thus you only need to grab it in case ScummVM complains about the file
being missing.
-3.16) Sierra AGI games Predictive Input Dialog notes:
------ -----------------------------------------------
+3.20) Troll's Tale notes:
+----- -------------------
+The original game came in a PC booter disk, therefore it is necessary to
+dump the contents of that disk in an image file and name it "troll.img"
+to be able to play the game under ScummVM.
+
+
+3.21) Winnie the Pooh notes:
+----- ----------------------
+It is possible to import saved games from the original interpreter of the
+game into ScummVM.
+
+There is extensive mouse support for the game under ScummVM, even though
+there wasn't any mouse support in the original game. Menu items can be
+selected using the mouse, and it is possible to move to other locations
+using the mouse as well. When the mouse cursor is hovered on the edges
+of the screen, it changes color to red if it is possible to walk towards
+that direction. The player can then simply click on the edges of the
+game's screen to change location, similar to many adventure games, which
+is simpler and more straightforward than moving around using the menu.
+
+
+3.22) Sierra AGI games: Predictive Input Dialog:
+----- ------------------------------------------
The Predictive Input Dialog is a ScummVM aid for running AGI engine
games (which notoriously require command line input) on devices with
limited keyboard support. In these situations, since typing with emulated
@@ -865,63 +1037,8 @@ naturally mapping the functionality to the numeric keypad. Also, the
dialog's buttons can be navigated with the arrow and the enter keys.
-3.17) Mickey's Space Adventure notes:
------ -------------------------------
-To run Mickey's Space Adventure under ScummVM, the original executable
-of the game (mickey.exe) is needed together with the game's data files.
-
-There is extensive mouse support for the game under ScummVM, even though
-there wasn't any mouse support in the original game. Menu items can be
-selected using the mouse, and it is possible to move to other locations
-using the mouse as well. When the mouse cursor is hovered on the edges
-of the screen, it changes color to red if it is possible to walk towards
-that direction. The player can then simply click on the edges of the
-game's screen to change location, similar to many adventure games, which
-is simpler and more straightforward than moving around using the menu.
-
-
-3.18) Winnie the Pooh notes:
------ ----------------------
-It is possible to import saved games from the original interpreter of the
-game into ScummVM.
-
-There is extensive mouse support for the game under ScummVM, even though
-there wasn't any mouse support in the original game. Menu items can be
-selected using the mouse, and it is possible to move to other locations
-using the mouse as well. When the mouse cursor is hovered on the edges
-of the screen, it changes color to red if it is possible to walk towards
-that direction. The player can then simply click on the edges of the
-game's screen to change location, similar to many adventure games, which
-is simpler and more straightforward than moving around using the menu.
-
-
-3.19) Troll's Tale notes:
------ -------------------
-The original game came in a PC booter disk, therefore it is necessary to
-dump the contents of that disk in an image file and name it "troll.img"
-to be able to play the game under ScummVM.
-
-
-3.20) Dragon History notes:
------ ---------------------
-There are 4 language variants of the game: Czech, English, Polish and
-German. Each of them is distributed in a separate archive. The only
-official version is the Czech one, and the English, Polish and German
-ports have always been work in progress and never officially released.
-Although all texts are fully translated, it is known that some of them
-contain typos.
-
-There exists an optional Czech dubbing for the game. For bandwidth
-reasons, you can download it separately and then unpack it to the
-directory of the game. You can listen to the Czech dubbing with all
-language variants of the game, while reading the subtitles.
-
-All game files and the walkthrough can be downloaded from
-http://www.ucw.cz/draci-historie/index-en.html
-
-
-3.21) Simultaneous speech and subtitles in Sierra SCI games:
------ ------------------------------------------------------
+3.23) Sierra SCI games: Simultaneous speech and subtitles:
+----- ----------------------------------------------------
Certain CD versions of Sierra SCI games had both speech and text
resources. Some have an option to toggle between the two, but there are
some cases where there wasn't any option to enable both simultaneously.
@@ -968,81 +1085,143 @@ Space Quest 4 CD:
options dialog, or via ScummVM's audio options.
-3.22) Known Problems:
------ ---------------
-This release has the following known problems. There is no need to
-report them, although patches to fix them are welcome. If you discover a
-bug that is not listed here, nor in the compatibility list on the web
-site, please see the section on reporting bugs.
-
- CD Audio Games:
- - When playing games that use CD Audio (FM-TOWNS games, Loom CD, etc)
- users of Microsoft Windows 2000/XP may experience random crashes.
- This is due to a long-standing Windows bug, resulting in corrupt
- game files being read from the CD. Please copy the game data to
- your hard disk to avoid this.
-
- FM-TOWNS versions:
- - The Kanji versions require the FM-TOWNS Font ROM
-
- Loom:
- - Turning off the subtitles via the config file does not work reliably
- as the Loom scripts automatically turn them on again
- - MIDI support in the EGA version requires the Roland update from
- LucasArts
- - The PC-Engine Kanji version requires the system card rom
-
- The Secret of Monkey Island:
- - MIDI support in the EGA version requires the Roland update from
- LucasArts
-
- Beneath a Steel Sky:
- - Amiga versions aren't supported
- - Floppy demos aren't supported
- - Not a bug: CD version is missing speech for some dialogs, this is
- normal.
-
- Elvira - Mistress of the Dark
- - No music in the Atari ST version
-
- Elvira II - The Jaws of Cerberus
- - No music in the Atari ST version
- - No sound effects in the PC version
- - Palette issues in the Atari ST version
-
- Inherit the Earth: Quest for the Orb
- - Amiga versions aren't supported
+3.24) Zork games notes:
+----- -----------------
+To run the supported Zork games (Zork Nemesis: The Forbidden Lands
+and Zork: Grand Inquisitor) you need to copy some (extra) data to it's
+corresponding destination.
+
+Zork Nemesis: The Forbidden Lands
+
+All versions
+
+Download the Liberation(tm) fonts package
+<https://fedorahosted.org/releases/l/i/liberation-fonts/liberation-fonts-ttf-2.00.1.tar.gz>
+and unpack all the ttf files into your ScummVM extras directory.
+Alternatively, download the GNU FreeFont TTF package
+<https://ftp.gnu.org/gnu/freefont/freefont-ttf.zip> and unzip all the
+ttf files from the sfd directory into your ScummVM extras directory,
+though at the time of writing these fonts cause some text rendering issues.
+Download the subtitles patch
+<http://www.thezorklibrary.com/installguides/znpatch.zip> and unzip
+the addon directory into the game root directory
+
+GoG version
+
+Use the GoG installer, no further file copying is needed
+
+CD version
+
+Copy the following from the nemesis directory of CD1 into the game root directory:
+The znemmx directory
+The znemscr directory
+nemesis.str
+From CD1, copy the zassets directory into the game root directory
+From CD2, copy the zassets directory into the game root directory, overwriting any duplicate files
+From CD3, copy the zassets directory into the game root directory, overwriting any duplicate files
+
+DVD version
+
+Copy the following from the nemesis directory into the game root directory:
+The znemmx directory
+The znemscr directory
+nemesis.str
+Note: You'll also need to move cursor.zfs from the zassets/global directory into the znemscr directory
+Copy the disc2 directory into the game root directory
+Copy the disc3 directory into the game root directory
+Copy the zassets directory into the game root directory
+
+
+Zork: Grand Inquisitor
+
+All versions
+
+Download the Liberation(tm) fonts package
+<https://fedorahosted.org/releases/l/i/liberation-fonts/liberation-fonts-ttf-2.00.1.tar.gz>
+and unpack all the ttf files into your ScummVM extras directory.
+Alternatively, download the GNU FreeFont TTF package
+<https://ftp.gnu.org/gnu/freefont/freefont-ttf.zip> and unzip all the
+ttf files from the sfd directory into your ScummVM extras directory,
+though at the time of writing these fonts cause some text rendering issues.
+
+GoG version
+
+Use the GoG installer, no further file copying is needed
+
+CD version
+
+Copy the following from the zgi directory of CD1 into the game root directory:
+The zgi_mx directory
+cursor.zfs
+death.zfs
+inquis.str
+inquis.zix
+r.svr
+scripts.zfs
+subtitle.zfs
+From CD1, copy the zassets1 directory into the game root directory
+From CD2, copy the zassets2 directory into the game root directory
+It's recommended to apply patch 1.2
+<http://www.thezorklibrary.com/installguides/Zpatch.exe>, but you may
+have to install the game normally for that, as the patch has its own installer.
+
+DVD version
+
+Copy the following from the zgi_e directory into the game root directory:
+The addon directory (game patch 1.2)
+The zgi_mx directory
+cursor.zfs
+death.zfs
+inquis.str
+inquis.zix
+r.svr
+scripts.zfs
+subtitle.zfs
+Copy the eng_mpeg directory (hires MPEG2 video files) into the game root directory
+Copy the zassetsc directory into the game root directory
+Copy the zassetse directory into the game root directory
+
+
+3.25) Commodore64 games notes:
+----- ------------------------
+Both Maniac Mansion and Zak McKracken run but Maniac Mansion is not yet
+playable. Simply name the D64 disks "maniac1.d64" and "maniac2.d64"
+respectively "zak1.d64" and "zak2.d64", then ScummVM should be able to
+automatically detect the game if you point it at the right directory.
- Lure of the Temptress
- - No Roland MT-32 support
- - Sound support is incomplete and doesn't sound like original
+Alternatively, you can use 'extract_mm_c64' from the tools package to
+extract the data files. But then the game will not be properly
+autodetected by ScummVM, and you must make sure that the platform is set
+to Commodore64. We recommend using the much simpler approach described
+in the previous paragraph.
- Simon the Sorcerer 1:
- - Subtitles aren't available in the English and German CD versions
- as they are missing the majority of subtitles.
- Simon the Sorcerer 2:
- - Combined speech and subtitles will often cause speech to be
- cut off early, this is a limitation of the original game.
- - Only default language (English) of data files is supported
- in Amiga and Macintosh versions.
+3.26) Macintosh games notes:
+----- ----------------------
+All LucasArts SCUMM based adventures, except COMI, also exist in versions
+for the Macintosh. ScummVM can use most (all?) of them, however, in some
+cases some additional work is required. First off, if you are not using
+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
+"HFSExplorer" for Windows and "hfsutils" for Linux and other Unix-like
+operating systems.
- Simon the Sorcerer's Puzzle Pack:
- - No support for displaying, entering, loading or saving high scores.
- - No support for displaying names of items, when hovering over them
- in Swampy Adventures.
+Most of the newer games on the Macintosh shipped with only a single data
+file (note that in some cases this data file was made invisible, so you
+may need extra tools in order to copy it). ScummVM is able to directly
+use such a data file; simply point ScummVM at the directory containing
+it, and it should work (just like with every other supported game).
- The Feeble Files:
- - Subtitles are often incomplete, they were always disabled in the
- original game.
+We also provide a tool called 'extract_scumm_mac' in the tools package
+to extract the data from these data files, but this is neither required
+nor recommended.
- The Legend of Kyrandia:
- - No music or sound effects in the Macintosh floppy versions.
- - Macintosh CD is using included DOS music and sound effects.
+For further information on copying Macintosh game files to your hard
+disk see:
- Humongous Entertainment games:
- - Only the original load and save interface can be used.
- - No support for multiplayer or printing images
+ <http://wiki.scummvm.org/index.php/HOWTO-Mac_Games>
4.0) Supported Platforms:
@@ -1057,7 +1236,8 @@ Supported platforms include (but are not limited to):
UNIX (Linux, Solaris, IRIX, *BSD, ...)
Windows
- Windows CE and Windows Mobile (including Smartphones and PocketPCs)
+ Windows CE
+ Windows Mobile (including Smartphones and PocketPCs)
Mac OS X
AmigaOS
Android
@@ -1080,7 +1260,8 @@ The Dreamcast port does not support The Curse of Monkey Island, nor The
Dig. The Nintendo DS port does not support Full Throttle, The Dig, or
The Curse of Monkey Island.
For more platform specific limitations, please refer to our Wiki:
- http://wiki.scummvm.org/index.php/Platforms
+
+ <http://wiki.scummvm.org/index.php/Platforms>
In the Macintosh port, the right mouse button is emulated via Cmd-Click
(that is, you click the mouse button while holding the
@@ -1138,7 +1319,7 @@ arguments -- see the next section.
--list-themes Display list of all usable GUI themes
-e, --music-driver=MODE Select music driver (see also section 7.0)
--list-audio-devices List all available audio devices
- -q, --language=LANG Select game's language (see also section 5.2)
+ -q, --language=LANG Select game's language (see also section 5.5)
-m, --music-volume=NUM Set the music volume, 0-255 (default: 192)
-s, --sfx-volume=NUM Set the sfx volume, 0-255 (default: 192)
-r, --speech-volume=NUM Set the voice volume, 0-255 (default: 192)
@@ -1168,8 +1349,9 @@ arguments -- see the next section.
--output-rate=RATE Select output sample rate in Hz (e.g. 22050)
--opl-driver=DRIVER Select AdLib (OPL) emulator (db, mame)
--aspect-ratio Enable aspect ratio correction
- --render-mode=MODE Enable additional render modes (cga, ega, hercGreen,
- hercAmber, amiga)
+ --render-mode=MODE Enable additional render modes (hercGreen, hercAmber,
+ cga, ega, vga, amiga, fmtowns, pc9821, pc9801, 2gs,
+ atari, macintosh)
--alt-intro Use alternative intro for CD versions of Beneath a
Steel Sky and Flight of the Amazon Queen
@@ -1206,63 +1388,49 @@ Examples:
/path/to/scummvm -f -n -p/cdrom/resource/ ft
-5.2) Language options:
----- -----------------
-ScummVM includes a language option for Maniac Mansion, Zak McKracken,
-The Dig, The Curse of Monkey Island, Beneath a Steel Sky and
-Broken Sword.
-
-Note that with the exception of Beneath a Steel Sky, Broken Sword,
-multilanguage versions of Goblins games and Nippon Safes Inc., using
-this option does *not* change the language of the game (which usually is
-hardcoded), but rather is only used to select the appropriate font (e.g.
-for a German version of a game, one containing umlauts).
-
-An exception are The Dig and The Curse of Monkey Island -- non-English
-versions can be set to 'English.' This however only affects subtitles;
-game speech will remain the same.
-
-Maniac Mansion and Zak McKracken
- en - English (default)
- de - German
- fr - French
- it - Italian
- es - Spanish
-
-The Dig
- jp - Japanese
- zh - Chinese
- kr - Korean
+5.2) Global Menu:
+---- ------------
+The Global Menu is a general menu which is available to all of the game
+engines by pressing Ctrl-F5. From this menu there are the following
+buttons: Resume, Options, About, Return to Launcher, and Quit. Selecting
+'Options' will display a dialog where basic audio settings, such as
+volume levels, can be adjusted. Selecting 'Return to Launcher' will
+close the current game and return the user back to the ScummVM Launcher,
+where another game may be selected to play.
-The Curse of Monkey Island
- en - English (default)
- de - German
- fr - French
- it - Italian
- pt - Portuguese
- es - Spanish
- jp - Japanese
- zh - Chinese
- kr - Korean
+Note: Returning to the Launcher is not supported by all of the engines,
+and the button will be disabled in the Global Menu if it is not
+supported.
-Beneath a Steel Sky
- gb - English (Great Britain) (default)
- en - English (USA)
- de - German
- fr - French
- it - Italian
- pt - Portuguese
- es - Spanish
- se - Swedish
+Engines which currently support returning to the Launcher are:
-Broken Sword
- en - English (default)
- de - German
- fr - French
- it - Italian
- es - Spanish
- pt - Portuguese
- cz - Czech
+ AGI
+ AGOS
+ CINE
+ COMPOSER
+ CRUISE
+ DRACI
+ DRASCULA
+ GOB
+ GROOVIE
+ HUGO
+ KYRA
+ LURE
+ MADE
+ MOHAWK
+ PARALLACTION
+ QUEEN
+ SAGA
+ SCI
+ SCUMM
+ SKY
+ SWORD1
+ SWORD2
+ TEENAGENT
+ TOUCHE
+ TSAGE
+ TUCKER
+ ZVISION
5.3) Graphics filters:
@@ -1310,52 +1478,7 @@ Curse of Monkey Island or Broken Sword) will be scaled to 1280x960 and
1920x1440.
-5.4) Global Menu:
----- ------------
-The Global Menu is a general menu which is available to all of the game
-engines by pressing Ctrl-F5. From this menu there are the following
-buttons: Resume, Options, About, Return to Launcher, and Quit. Selecting
-'Options' will display a dialog where basic audio settings, such as
-volume levels, can be adjusted. Selecting 'Return to Launcher' will
-close the current game and return the user back to the ScummVM Launcher,
-where another game may be selected to play.
-
-Note: Returning to the Launcher is not supported by all of the engines,
-and the button will be disabled in the Global Menu if it is not
-supported.
-
-Engines which currently support returning to the Launcher are:
-
- AGI
- AGOS
- CINE
- COMPOSER
- CRUISE
- DRACI
- DRASCULA
- GOB
- GROOVIE
- HUGO
- KYRA
- LURE
- MADE
- MOHAWK
- PARALLACTION
- QUEEN
- SAGA
- SCI
- SCUMM
- SKY
- SWORD1
- SWORD2
- TEENAGENT
- TOUCHE
- TSAGE
- TUCKER
- ZVISION
-
-
-5.5) Hotkeys:
+5.4) Hotkeys:
---- --------
ScummVM supports various in-game hotkeys. They differ between SCUMM games and
other games.
@@ -1364,7 +1487,8 @@ other games.
Ctrl-F5 - Displays the Global Menu
Cmd-q - Quit (Mac OS X)
Ctrl-q - Quit (other unices including Linux)
- Ctrl-z OR Alt-x - Quit (other platforms)
+ Alt-F4 - Quit (Windows)
+ Ctrl-z - Quit (other platforms)
Ctrl-u - Mute all sounds
Ctrl-m - Toggle mouse capture
Ctrl-Alt 1-8 - Switch between graphics filters
@@ -1382,6 +1506,7 @@ other games.
of the middle mouse button or wheel.
SCUMM:
+ Alt-x - Quit
Ctrl 0-9 and Alt 0-9 - Load and save game state
Ctrl-d - Starts the debugger
Ctrl-f - Toggle fast mode
@@ -1440,7 +1565,7 @@ other games.
Escape - Skips cutscenes
Space - Skips current line of text
- Future Wars
+ Future Wars:
F1 - Examine
F2 - Take
F3 - Inventory
@@ -1451,7 +1576,7 @@ other games.
F10 - "Use" menu
Escape - Bring on command menu
- Nippon Safes
+ Nippon Safes:
Ctrl-d - Starts the debugger
l - Load game
s - Save game
@@ -1479,7 +1604,7 @@ other games.
combined speech and subtitles
[Simon the Sorcerer 2 CD only]
- Simon the Sorcerer's Puzzle Pack
+ Simon the Sorcerer's Puzzle Pack:
Ctrl-d - Starts the debugger
Ctrl-f - Toggle fast mode
F12 - High speed mode on/off in Swampy Adventures
@@ -1488,7 +1613,7 @@ other games.
s - Sound effects on/off
Pause - Pauses
- The Feeble Files
+ The Feeble Files:
Ctrl-d - Starts the debugger
Ctrl-f - Toggle fast mode
F7 - Switch characters
@@ -1517,7 +1642,7 @@ other games.
t - Switch between 'Voice only',
'Voice and Text' and 'Text only'
- Zork: Grand Inquisitor
+ Zork: Grand Inquisitor:
Ctrl-s - Save
Ctrl-r - Restore
Ctrl-q - Quit
@@ -1530,7 +1655,7 @@ other games.
F9 - Extract coin (must have the coin bag)
Space - Skips movies
- Zork Nemesis: The Forbidden Lands
+ Zork Nemesis: The Forbidden Lands:
Ctrl-s - Save
Ctrl-r - Restore
Ctrl-q - Quit
@@ -1546,6 +1671,65 @@ a small subset of these hot keys are supported via key remapping and/or
panel actions. Please consult the README-WinCE.txt file.
+5.5) Language options:
+---- -----------------
+ScummVM includes a language option for Maniac Mansion, Zak McKracken,
+The Dig, The Curse of Monkey Island, Beneath a Steel Sky and
+Broken Sword.
+
+Note that with the exception of Beneath a Steel Sky, Broken Sword,
+multilanguage versions of Goblins games and Nippon Safes Inc., using
+this option does *not* change the language of the game (which usually is
+hardcoded), but rather is only used to select the appropriate font (e.g.
+for a German version of a game, one containing umlauts).
+
+An exception are The Dig and The Curse of Monkey Island -- non-English
+versions can be set to 'English.' This however only affects subtitles;
+game speech will remain the same.
+
+Maniac Mansion and Zak McKracken
+ en - English (default)
+ de - German
+ fr - French
+ it - Italian
+ es - Spanish
+
+The Dig
+ jp - Japanese
+ zh - Chinese
+ kr - Korean
+
+The Curse of Monkey Island
+ en - English (default)
+ de - German
+ fr - French
+ it - Italian
+ pt - Portuguese
+ es - Spanish
+ jp - Japanese
+ zh - Chinese
+ kr - Korean
+
+Beneath a Steel Sky
+ gb - English (Great Britain) (default)
+ en - English (USA)
+ de - German
+ fr - French
+ it - Italian
+ pt - Portuguese
+ es - Spanish
+ se - Swedish
+
+Broken Sword
+ en - English (default)
+ de - German
+ fr - French
+ it - Italian
+ es - Spanish
+ pt - Portuguese
+ cz - Czech
+
+
6.0) Saved Games:
---- ----------
Saved games are by default put in the current directory on some platforms
@@ -1558,7 +1742,16 @@ The platforms that currently have a different default directory are:
$HOME/Documents/ScummVM Savegames/
Other unices:
- $HOME/.scummvm/
+ 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
+ as value of XDG_DATA_HOME in accordance with the specification.
+
+ If an earlier version of ScummVM was installed on your system, the
+ previous default location of '~/.scummvm' will be kept. This is detected
+ based on the presence of the path '~/.scummvm'.
Windows Vista/7:
\Users\username\AppData\Roaming\ScummVM\Saved games\
@@ -1732,7 +1925,7 @@ offers the best compatibility between machines and games.
7.2) Playing sound with FluidSynth MIDI emulation:
----- ----------------------------------------------
+---- ---------------------------------------------
If ScummVM was build with libfluidsynth support it will be able to play
MIDI music through the FluidSynth driver. You will have to specify a
SoundFont to use, however.
@@ -1924,7 +2117,7 @@ SCUMMVM_PORT=Software Synth in your environment.
---- -----------------------------
If your system lacks any MIDI sequencer, but you still want better MIDI
quality than default AdLib emulation can offer, you can try the
-TiMidity++ MIDI server. See http://timidity.sourceforge.net/ for
+TiMidity++ MIDI server. See <http://timidity.sourceforge.net/> for
download and install instructions.
First, you need to start a daemon:
@@ -1940,7 +2133,7 @@ a "device number" using the "SCUMMVM_MIDIPORT" environment variable.
7.8) Using compressed audio files
---- ----------------------------
-7.8.0) Using MP3 files for CD audio:
+7.8.1) Using MP3 files for CD audio:
------ -----------------------------
Use LAME or some other MP3 encoder to rip the cd audio tracks to files.
Name the files track1.mp3 track2.mp3 etc. ScummVM must be compiled with
@@ -1951,7 +2144,7 @@ can be done with the following LAME command line:
lame -t -q 0 -b 96 track1.wav track1.mp3
-7.8.1) Using Ogg Vorbis files for CD audio:
+7.8.2) Using Ogg Vorbis files for CD audio:
------ ------------------------------------
Use oggenc or some other vorbis encoder to encode the audio tracks to
files. Name the files track1.ogg track2.ogg etc. ScummVM must be
@@ -1963,7 +2156,7 @@ q specifying the desired quality from 0 to 10:
oggenc -q 5 track1.wav
-7.8.2) Using Flac files for CD audio:
+7.8.3) Using Flac files for CD audio:
------ ------------------------------
Use flac or some other flac encoder to encode the audio tracks to files.
Name the files track1.flac track2.flac etc. If your filesystem only
@@ -1978,7 +2171,7 @@ Remember that the quality is always the same, varying encoder options
will only affect the encoding time and resulting filesize.
-7.8.3) Compressing MONSTER.SOU with MP3:
+7.8.4) Compressing MONSTER.SOU with MP3:
------ ---------------------------------
You need LAME, and our 'compress_scumm_sou' utility from the
scummvm-tools package to perform this task, and ScummVM must be compiled
@@ -1990,7 +2183,7 @@ Eventually you will have a much smaller monster.so3 file, copy this file
to your game directory. You can safely remove the monster.sou file.
-7.8.4) Compressing MONSTER.SOU with Ogg Vorbis:
+7.8.5) Compressing MONSTER.SOU with Ogg Vorbis:
------ ----------------------------------------
As above, but ScummVM must be compiled with OGG support. Run:
@@ -2001,7 +2194,7 @@ your game directory. Ogg encoding may take a considerable longer amount
of time than MP3, so have a good book handy.
-7.8.5) Compressing MONSTER.SOU with Flac:
+7.8.6) Compressing MONSTER.SOU with Flac:
------ ----------------------------------
As above, but ScummVM must be compiled with Flac support. Run:
@@ -2016,7 +2209,7 @@ those kind of soundfiles. Be sure to read the encoder documentation
before you use other values.
-7.8.6) Compressing music/sfx/speech in AGOS games:
+7.8.7) Compressing music/sfx/speech in AGOS games:
------ -------------------------------------------
Use our 'compress_agos' utility from the scummvm-tools package to
perform this task. You can choose between multiple target formats, but
@@ -2051,7 +2244,7 @@ Eventually you will have a much smaller *.mp3, *.ogg or *.fla file, copy
this file to your game directory. You can safely remove the old file.
-7.8.7) Compressing speech/music in Broken Sword:
+7.8.8) Compressing speech/music in Broken Sword:
------ -----------------------------------------
The 'compress_sword1' tool from the scummvm-tools package can encode
music and speech to MP3, Ogg Vorbis as well as Flac. The easiest way
@@ -2069,7 +2262,7 @@ instead of MP3.
Use "compress_sword1 --help" to get a full list of the options.
-7.8.8) Compressing speech/music in Broken Sword II:
+7.8.9) Compressing speech/music in Broken Sword II:
------ --------------------------------------------
Use our 'compress_sword2' utility from the scummvm-tools package to
perform this task. You can choose between multiple target formats, but
@@ -2146,7 +2339,15 @@ By default, the configuration file is saved in, and loaded from:
previous default location of '<windir>\scummvm.ini' will be kept.
Unix:
- ~/.scummvmrc
+ We follow the XDG Base Directory Specification. This means our
+ configuration can be found in:
+ $XDG_CONFIG_HOME/scummvm/scummvm.ini
+
+ If XDG_CONFIG_HOME is not defined or empty, '~/.config' will be used
+ as value for XDG_CONFIG_HOME in accordance with the specification.
+
+ If an earlier version of ScummVM was installed on your system, the
+ previous default location of '~/.scummvmrc' will be kept.
Mac OS X:
~/Library/Preferences/ScummVM Preferences
@@ -2222,7 +2423,8 @@ The following keywords are recognized:
aspect_ratio bool Enable aspect ratio correction
gfx_mode string Graphics mode (normal, 2x, 3x, 2xsai,
super2xsai, supereagle, advmame2x, advmame3x,
- hq2x, hq3x, tv2x, dotmatrix)
+ hq2x, hq3x, tv2x, dotmatrix, opengl_linear,
+ opengl_nearest)
confirm_exit bool Ask for confirmation by the user before
quitting (SDL backend only).
@@ -2417,7 +2619,8 @@ configuration of each entry, allowing the custom options to be shown.
---- ----------
For an up-to-date overview on how to compile ScummVM for various
platforms, please consult our Wiki, in particular this page:
- http://wiki.scummvm.org/index.php/Compiling_ScummVM
+
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM>
If you are compiling for Windows, Linux or Mac OS X, you need SDL-1.2.2
or newer (older versions may work, but are unsupported), and a supported
@@ -2429,78 +2632,117 @@ compressed sound. For compressed save states, zlib is required.
Some parts of ScummVM, particularly scalers, have highly optimized
versions written in assembler. If you wish to use this option, you will
-need to install nasm assembler (see http://nasm.sf.net). Note that
-currently we have only x86 MMX optimized versions, and they will not
+need to install nasm assembler (see <http://www.nasm.us/>). Note that
+we currently only have x86 MMX optimized versions, and they will not
compile on other processors.
On Win9x/NT/XP, you can define USE_WINDBG and attach WinDbg to browse
-debug messages (see http://www.sysinternals.com/ntw2k/freeware/debugview.shtml).
-
-
- GCC and MinGW32:
- * Type "./configure"
- * Type "make" (or "gmake", or "gnumake", depending on what GNU make is
- called on your system) and hopefully ScummVM will compile for you.
- * For more information refer to:
- http://wiki.scummvm.org/index.php/Compiling_ScummVM/GCC
- respectively
- http://wiki.scummvm.org/index.php/Compiling_ScummVM/MinGW
-
- Microsoft Visual C++ 9+:
- * Read up on how to create the project files in the appropriate
- "dists\msvc*" directory.
- * Open the resulting solution file.
- * Enter the path to the needed libraries and includes in
- Tools|Options|Projects and Solutions|VC++ Directories".
- * Now it should compile successfully.
- * For more information refer to:
- http://wiki.scummvm.org/index.php/Compiling_ScummVM/Visual_Studio
-
- Windows Mobile:
- * Please refer to:
- http://wiki.scummvm.org/index.php/Compiling_ScummVM/Windows_CE
-
- Mac OS X:
- * Make sure you have the developer tools installed.
- * The SDL developer package for OS X available on the SDL web site is
- _not_ suitable. Rather, you require a unix-style build of SDL. One
- way to get that is to install SDL via Fink (http://fink.sf.net).
- Alternatively you could compile SDL manually from source using its
- unix build system (configure && make).
- * Type "./configure" in the ScummVM directory.
- * You can now type 'make' to create a command line binary.
- * To get a version you can run from Finder, type 'make bundle' which
- will create ScummVM.app (this tries to detect where the static libraries
- are installed, which should work in most cases, but if it doesn't you
- will need to specify this path with --with-staticlib-prefix= when calling
- configure - for example "./configure --with-staticlib-prefix=/Users/foo"
- if the libraries are in /Users/foo/lib).
- * For more information refer to:
- http://wiki.scummvm.org/index.php/Compiling_ScummVM/MacOS_X_Crosscompiling
-
- AmigaOS 4 (Cross-compiling with Cygwin):
- * Make sure that you have SDL installed, you may also need
- libogg, libvorbis, libvorbisfile, zlib, libmad.
- * Type ./configure --host=ppc-amigaos
- * If you got an error about sdl-config, use --with-sdl-prefix
- parameter to set the path.
- * Check 'config.mk' file and if everything seems to be fine:
- * Run 'make'.
- * Cross-compiling with Linux may be as easy.
-
- iPhone:
- * Please refer to:
- http://wiki.scummvm.org/index.php/Compiling_ScummVM/iPhone
-
- Maemo:
- * Install Maemo SDK with 4.1.2 rootstrap
- * Install libmad, Tremor, FLAC from source
- * run 'ln -s backends/platform/maemo/debian'
- * update debian/changelog
- * run 'sb2 dpkg-buildpackage -b'
+debug messages (see <https://technet.microsoft.com/en-us/sysinternals/debugview.aspx>).
+
+
+ Windows:
+ * Dev-C++
+ Please refer to:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/DevCPP>
+ * MinGW
+ Please refer to:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/MinGW>
+ * Visual Studio (MSVC)
+ Please refer to:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Visual_Studio>
+ * Windows CE/Mobile
+ Please refer to:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Windows_CE>
+
+ Linux:
+ * GCC
+ Please refer to:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/GCC>
+
+ AmigaOS4:
+ Please refer to:
+ <http://wiki.scummvm.org/index.php/AmigaOS>
+
+ Apple iPhone:
+ Please refer to:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/iPhone>
+
+ Atari/FreeMiNT:
+ Please refer to:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Atari/FreeMiNT>
+
+ Bada/Tizen:
+ Please refer to:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Bada/Tizen>
+
+ BeOS/ZETA/Haiku:
+ Please refer to:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/BeOS/ZETA/Haiku>
+
+ Google Android:
+ Please refer to:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Android>
+
+ HP webOS:
+ Please refer to:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/WebOS>
+
+ Mac OS:
+ * Mac OS X
+ Please refer to:
+ <http://wiki.scummvm.org/index.php/Mac_OS_X>
+ * Mac OS X 10.2.8
+ Please refer to:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Mac_OS_X_10.2.8>
+ * Mac OS X Crosscompiling
+ Please refer to:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Mac_OS_X_Crosscompiling>
+
+ Maemo:
+ Please refer to:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Maemo>
+
+ Nintendo DS:
+ Please refer to:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Nintendo_DS>
+
+ Nintendo Wii and Gamecube:
+ Please refer to:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Wii>
+
+ RaspberryPi:
+ Please refer to:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/RPI>
+
+ Sega Dreamcast:
+ Please refer to:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Dreamcast>
+
+ Sony Playstation:
+ * Sony PlayStation 2
+ Please refer to:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/PlayStation_2>
+ * Sony PlayStation 3
+ Please refer to:
+ <http://wiki.scummvm.org/index.php/PlayStation_3#Building_from_source>
+ * Sony PlayStation Portable
+ Please refer to:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/PlayStation_Portable>
+
+ Symbian:
+ Please refer to:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Symbian>
+
+
+10.0) Credits
+----- -------
+Please refer to our extensive Credits list at:
+
+ <http://www.scummvm.org/credits/>
+
------------------------------------------------------------------------
Good Luck and Happy Adventuring!
The ScummVM team.
-http://www.scummvm.org/
+<http://www.scummvm.org/>
------------------------------------------------------------------------
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/midiparser_smf.cpp b/audio/midiparser_smf.cpp
index a614e5bd63..d1d86b918f 100644
--- a/audio/midiparser_smf.cpp
+++ b/audio/midiparser_smf.cpp
@@ -204,7 +204,7 @@ bool MidiParser_SMF::loadMusic(byte *data, uint32 size) {
int tracksRead = 0;
while (tracksRead < _numTracks) {
if (memcmp(pos, "MTrk", 4) && !isGMF) {
- warning("Position: %p ('%c')", pos, *pos);
+ warning("Position: %p ('%c')", (void *)pos, *pos);
warning("Hit invalid block '%c%c%c%c' while scanning for track locations", pos[0], pos[1], pos[2], pos[3]);
return false;
}
diff --git a/audio/midiparser_xmidi.cpp b/audio/midiparser_xmidi.cpp
index 8742d7aad1..042e663a13 100644
--- a/audio/midiparser_xmidi.cpp
+++ b/audio/midiparser_xmidi.cpp
@@ -146,7 +146,7 @@ void MidiParser_XMIDI::parseNextEvent(EventInfo &info) {
break;
}
- case 0x75: // XMIDI_CONTORLLER_NEXT_BREAK
+ case 0x75: // XMIDI_CONTROLLER_NEXT_BREAK
if (_loopCount >= 0) {
if (info.basic.param2 < 64) {
// End the current loop.
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 c18812ee54..b0cdaef95a 100644
--- a/audio/mods/maxtrax.cpp
+++ b/audio/mods/maxtrax.cpp
@@ -54,7 +54,7 @@ void nullFunc(int) {}
// Function to calculate 2^x, where x is a fixedpoint number with 16 fraction bits
// using exp would be more accurate and needs less space if mathlibrary is already linked
-// but this function should be faster and doesnt use floats
+// but this function should be faster and doesn't use floats
#if 1
inline uint32 pow2Fixed(int32 val) {
static const uint16 tablePow2[] = {
@@ -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/rate.cpp b/audio/rate.cpp
index 19d9c8c61e..6264465e19 100644
--- a/audio/rate.cpp
+++ b/audio/rate.cpp
@@ -46,6 +46,16 @@ namespace Audio {
*/
#define INTERMEDIATE_BUFFER_SIZE 512
+/**
+ * The default fractional type in frac.h (with 16 fractional bits) limits
+ * the rate conversion code to 65536Hz audio: we need to able to handle
+ * 96kHz audio, so we use fewer fractional bits in this code.
+ */
+enum {
+ FRAC_BITS_LOW = 15,
+ FRAC_ONE_LOW = (1L << FRAC_BITS_LOW),
+ FRAC_HALF_LOW = (1L << (FRAC_BITS_LOW-1))
+};
/**
* Audio rate converter based on simple resampling. Used when no
@@ -187,18 +197,18 @@ public:
*/
template<bool stereo, bool reverseStereo>
LinearRateConverter<stereo, reverseStereo>::LinearRateConverter(st_rate_t inrate, st_rate_t outrate) {
- if (inrate >= 65536 || outrate >= 65536) {
- error("rate effect can only handle rates < 65536");
+ if (inrate >= 131072 || outrate >= 131072) {
+ error("rate effect can only handle rates < 131072");
}
- opos = FRAC_ONE;
+ opos = FRAC_ONE_LOW;
// Compute the linear interpolation increment.
- // This will overflow if inrate >= 2^16, and underflow if outrate >= 2^16.
+ // This will overflow if inrate >= 2^17, and underflow if outrate >= 2^17.
// Also, if the quotient of the two rate becomes too small / too big, that
// would cause problems, but since we rarely scale from 1 to 65536 Hz or vice
// versa, I think we can live with that limitation ;-).
- opos_inc = (inrate << FRAC_BITS) / outrate;
+ opos_inc = (inrate << FRAC_BITS_LOW) / outrate;
ilast0 = ilast1 = 0;
icur0 = icur1 = 0;
@@ -220,7 +230,7 @@ int LinearRateConverter<stereo, reverseStereo>::flow(AudioStream &input, st_samp
while (obuf < oend) {
// read enough input samples so that opos < 0
- while ((frac_t)FRAC_ONE <= opos) {
+ while ((frac_t)FRAC_ONE_LOW <= opos) {
// Check if we have to refill the buffer
if (inLen == 0) {
inPtr = inBuf;
@@ -235,17 +245,17 @@ int LinearRateConverter<stereo, reverseStereo>::flow(AudioStream &input, st_samp
ilast1 = icur1;
icur1 = *inPtr++;
}
- opos -= FRAC_ONE;
+ opos -= FRAC_ONE_LOW;
}
// Loop as long as the outpos trails behind, and as long as there is
// still space in the output buffer.
- while (opos < (frac_t)FRAC_ONE && obuf < oend) {
+ while (opos < (frac_t)FRAC_ONE_LOW && obuf < oend) {
// interpolate
st_sample_t out0, out1;
- out0 = (st_sample_t)(ilast0 + (((icur0 - ilast0) * opos + FRAC_HALF) >> FRAC_BITS));
+ out0 = (st_sample_t)(ilast0 + (((icur0 - ilast0) * opos + FRAC_HALF_LOW) >> FRAC_BITS_LOW));
out1 = (stereo ?
- (st_sample_t)(ilast1 + (((icur1 - ilast1) * opos + FRAC_HALF) >> FRAC_BITS)) :
+ (st_sample_t)(ilast1 + (((icur1 - ilast1) * opos + FRAC_HALF_LOW) >> FRAC_BITS_LOW)) :
out0);
// output left channel
@@ -333,7 +343,7 @@ public:
template<bool stereo, bool reverseStereo>
RateConverter *makeRateConverter(st_rate_t inrate, st_rate_t outrate) {
if (inrate != outrate) {
- if ((inrate % outrate) == 0) {
+ if ((inrate % outrate) == 0 && (inrate < 65536)) {
return new SimpleRateConverter<stereo, reverseStereo>(inrate, outrate);
} else {
return new LinearRateConverter<stereo, reverseStereo>(inrate, outrate);
diff --git a/audio/rate_arm.cpp b/audio/rate_arm.cpp
index 4ad8d71a34..7765266673 100644
--- a/audio/rate_arm.cpp
+++ b/audio/rate_arm.cpp
@@ -68,6 +68,16 @@ namespace Audio {
*/
#define INTERMEDIATE_BUFFER_SIZE 512
+/**
+ * The default fractional type in frac.h (with 16 fractional bits) limits
+ * the rate conversion code to 65536Hz audio: we need to able to handle
+ * 96kHz audio, so we use fewer fractional bits in this code.
+ */
+enum {
+ FRAC_BITS_LOW = 15,
+ FRAC_ONE_LOW = (1L << FRAC_BITS_LOW),
+ FRAC_HALF_LOW = (1L << (FRAC_BITS_LOW-1))
+};
/**
* Audio rate converter based on simple resampling. Used when no
@@ -287,17 +297,18 @@ LinearRateConverter<stereo, reverseStereo>::LinearRateConverter(st_rate_t inrate
error("Input and Output rates must be different to use rate effect");
}
- if (inrate >= 65536 || outrate >= 65536) {
- error("rate effect can only handle rates < 65536");
+ if (inrate >= 131072 || outrate >= 131072) {
+ error("rate effect can only handle rates < 131072");
}
- lr.opos = FRAC_ONE;
+ lr.opos = FRAC_ONE_LOW;
/* increment */
- incr = (inrate << FRAC_BITS) / outrate;
+ incr = (inrate << FRAC_BITS_LOW) / outrate;
lr.opos_inc = incr;
+ // FIXME: Does 32768 here need changing to 65536 or 0? Compare to rate.cpp code...
lr.ilast[0] = lr.ilast[1] = 32768;
lr.icur[0] = lr.icur[1] = 0;
@@ -438,7 +449,7 @@ public:
*/
RateConverter *makeRateConverter(st_rate_t inrate, st_rate_t outrate, bool stereo, bool reverseStereo) {
if (inrate != outrate) {
- if ((inrate % outrate) == 0) {
+ if ((inrate % outrate) == 0 && (inrate < 65536)) {
if (stereo) {
if (reverseStereo)
return new SimpleRateConverter<true, true>(inrate, outrate);
diff --git a/audio/rate_arm_asm.s b/audio/rate_arm_asm.s
index a727209d39..bb01c614c2 100644
--- a/audio/rate_arm_asm.s
+++ b/audio/rate_arm_asm.s
@@ -441,17 +441,17 @@ LinearRate_M_part2:
LDRSH r4, [r3] @ r4 = obuf[0]
LDRSH r5, [r3,#2] @ r5 = obuf[1]
- MOV r6, r6, ASR #16 @ r6 = tmp0 = tmp1 >>= 16
+ MOV r6, r6, ASR #15 @ r6 = tmp0 = tmp1 >>= 15
MUL r7, r12,r6 @ r7 = tmp0*vol_l
MUL r6, r14,r6 @ r6 = tmp1*vol_r
- ADDS r7, r7, r4, LSL #16 @ r7 = obuf[0]<<16 + tmp0*vol_l
+ ADDS r7, r7, r4, LSL #15 @ r7 = obuf[0]<<15 + tmp0*vol_l
RSCVS r7, r10, #0x80000000 @ Clamp r7
- ADDS r6, r6, r5, LSL #16 @ r6 = obuf[1]<<16 + tmp1*vol_r
+ ADDS r6, r6, r5, LSL #15 @ r6 = obuf[1]<<15 + tmp1*vol_r
RSCVS r6, r10, #0x80000000 @ Clamp r6
- MOV r7, r7, LSR #16 @ Shift back to halfword
- MOV r6, r6, LSR #16 @ Shift back to halfword
+ MOV r7, r7, LSR #15 @ Shift back to halfword
+ MOV r6, r6, LSR #15 @ Shift back to halfword
LDR r5, [r2,#12] @ r5 = opos_inc
STRH r7, [r3],#2 @ Store output value
@@ -538,23 +538,23 @@ LinearRate_S_part2:
LDR r7, [r2,#24] @ r7 = ilast[1]<<16 + 32768
LDRSH r5, [r2,#18] @ r5 = icur[1]
LDRSH r10,[r3] @ r10= obuf[0]
- MOV r6, r6, ASR #16 @ r6 = tmp1 >>= 16
+ MOV r6, r6, ASR #15 @ r6 = tmp1 >>= 15
SUB r5, r5, r7, ASR #16 @ r5 = icur[1] - ilast[1]
MLA r7, r4, r5, r7 @ r7 = (icur[1]-ilast[1])*opos_frac+ilast[1]
LDRSH r5, [r3,#2] @ r5 = obuf[1]
- MOV r7, r7, ASR #16 @ r7 = tmp0 >>= 16
+ MOV r7, r7, ASR #15 @ r7 = tmp0 >>= 15
MUL r7, r12,r7 @ r7 = tmp0*vol_l
MUL r6, r14,r6 @ r6 = tmp1*vol_r
- ADDS r7, r7, r10, LSL #16 @ r7 = obuf[0]<<16 + tmp0*vol_l
+ ADDS r7, r7, r10, LSL #15 @ r7 = obuf[0]<<15 + tmp0*vol_l
MOV r4, #0
RSCVS r7, r4, #0x80000000 @ Clamp r7
- ADDS r6, r6, r5, LSL #16 @ r6 = obuf[1]<<16 + tmp1*vol_r
+ ADDS r6, r6, r5, LSL #15 @ r6 = obuf[1]<<15 + tmp1*vol_r
RSCVS r6, r4, #0x80000000 @ Clamp r6
- MOV r7, r7, LSR #16 @ Shift back to halfword
- MOV r6, r6, LSR #16 @ Shift back to halfword
+ MOV r7, r7, LSR #15 @ Shift back to halfword
+ MOV r6, r6, LSR #15 @ Shift back to halfword
LDR r5, [r2,#12] @ r5 = opos_inc
STRH r7, [r3],#2 @ Store output value
@@ -641,23 +641,23 @@ LinearRate_R_part2:
LDR r7, [r2,#24] @ r7 = ilast[1]<<16 + 32768
LDRSH r5, [r2,#18] @ r5 = icur[1]
LDRSH r10,[r3,#2] @ r10= obuf[1]
- MOV r6, r6, ASR #16 @ r6 = tmp1 >>= 16
+ MOV r6, r6, ASR #15 @ r6 = tmp1 >>= 15
SUB r5, r5, r7, ASR #16 @ r5 = icur[1] - ilast[1]
MLA r7, r4, r5, r7 @ r7 = (icur[1]-ilast[1])*opos_frac+ilast[1]
LDRSH r5, [r3] @ r5 = obuf[0]
- MOV r7, r7, ASR #16 @ r7 = tmp0 >>= 16
+ MOV r7, r7, ASR #15 @ r7 = tmp0 >>= 15
MUL r7, r12,r7 @ r7 = tmp0*vol_l
MUL r6, r14,r6 @ r6 = tmp1*vol_r
- ADDS r7, r7, r10, LSL #16 @ r7 = obuf[1]<<16 + tmp0*vol_l
+ ADDS r7, r7, r10, LSL #15 @ r7 = obuf[1]<<15 + tmp0*vol_l
MOV r4, #0
RSCVS r7, r4, #0x80000000 @ Clamp r7
- ADDS r6, r6, r5, LSL #16 @ r6 = obuf[0]<<16 + tmp1*vol_r
+ ADDS r6, r6, r5, LSL #15 @ r6 = obuf[0]<<15 + tmp1*vol_r
RSCVS r6, r4, #0x80000000 @ Clamp r6
- MOV r7, r7, LSR #16 @ Shift back to halfword
- MOV r6, r6, LSR #16 @ Shift back to halfword
+ MOV r7, r7, LSR #15 @ Shift back to halfword
+ MOV r6, r6, LSR #15 @ Shift back to halfword
LDR r5, [r2,#12] @ r5 = opos_inc
STRH r6, [r3],#2 @ Store output value
diff --git a/audio/softsynth/fluidsynth.cpp b/audio/softsynth/fluidsynth.cpp
index 9b64d70f2b..860bf5b5cb 100644
--- a/audio/softsynth/fluidsynth.cpp
+++ b/audio/softsynth/fluidsynth.cpp
@@ -31,6 +31,9 @@
#include "audio/musicplugin.h"
#include "audio/mpu401.h"
#include "audio/softsynth/emumidi.h"
+#if defined(IPHONE_IOS7) && defined(IPHONE_SANDBOXED)
+#include "backends/platform/ios7/ios7_common.h"
+#endif
#include <fluidsynth.h>
@@ -179,7 +182,18 @@ int MidiDriver_FluidSynth::open() {
const char *soundfont = ConfMan.get("soundfont").c_str();
+#if defined(IPHONE_IOS7) && defined(IPHONE_SANDBOXED)
+ // HACK: Due to the sandbox on non-jailbroken iOS devices, we need to deal
+ // with the chroot filesystem. All the path selected by the user are
+ // relative to the Document directory. So, we need to adjust the path to
+ // reflect that.
+ Common::String soundfont_fullpath = iOS7_getDocumentsDir();
+ soundfont_fullpath += soundfont;
+ _soundFont = fluid_synth_sfload(_synth, soundfont_fullpath.c_str(), 1);
+#else
_soundFont = fluid_synth_sfload(_synth, soundfont, 1);
+#endif
+
if (_soundFont == -1)
error("Failed loading custom sound font '%s'", soundfont);
diff --git a/audio/softsynth/fmtowns_pc98/towns_audio.cpp b/audio/softsynth/fmtowns_pc98/towns_audio.cpp
index 7fa55ef6c1..42824d8423 100644
--- a/audio/softsynth/fmtowns_pc98/towns_audio.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_audio.cpp
@@ -83,7 +83,7 @@ public:
bool _activeOutput;
private:
- void setupLoop(uint32 loopStart, uint32 len);
+ void setupLoop(uint32 loopStart, uint32 loopLen);
void setNote(uint8 note, TownsAudio_WaveTable *w, bool stepLimit = false);
void setVelo(uint8 velo);
@@ -104,10 +104,10 @@ private:
uint8 _panRight;
int8 *_data;
- int8 *_dataEnd;
- int8 *_loopEnd;
+ uint32 _loopStart;
uint32 _loopLen;
+ uint32 _dataEnd;
uint16 _stepNote;
uint16 _stepPitch;
@@ -187,6 +187,7 @@ private:
int intf_pcmPlayEffect(va_list &args);
int intf_pcmChanOff(va_list &args);
int intf_pcmEffectPlaying(va_list &args);
+ int intf_pcmDisableAllChannels(va_list &args);
int intf_fmKeyOn(va_list &args);
int intf_fmKeyOff(va_list &args);
int intf_fmSetPanPos(va_list &args);
@@ -335,7 +336,7 @@ TownsAudioInterfaceInternal::TownsAudioInterfaceInternal(Audio::Mixer *mixer, To
INTCB(pcmChanOff),
// 40
INTCB(pcmEffectPlaying),
- INTCB(notImpl),
+ INTCB(pcmDisableAllChannels),
INTCB(notImpl),
INTCB(notImpl),
// 44
@@ -784,6 +785,8 @@ int TownsAudioInterfaceInternal::intf_loadWaveTable(va_list &args) {
if (_waveTablesTotalDataSize + w.size > 65504)
return 5;
+ callback(41);
+
for (int i = 0; i < _numWaveTables; i++) {
if (_waveTables[i].id == w.id)
return 10;
@@ -800,6 +803,7 @@ int TownsAudioInterfaceInternal::intf_loadWaveTable(va_list &args) {
int TownsAudioInterfaceInternal::intf_unloadWaveTable(va_list &args) {
int id = va_arg(args, int);
+ callback(41);
if (id == -1) {
for (int i = 0; i < 128; i++)
@@ -817,8 +821,8 @@ int TownsAudioInterfaceInternal::intf_unloadWaveTable(va_list &args) {
memcpy(&_waveTables[i], &_waveTables[i + 1], sizeof(TownsAudio_WaveTable));
return 0;
}
- return 9;
}
+ return 9;
}
}
@@ -876,6 +880,12 @@ int TownsAudioInterfaceInternal::intf_pcmEffectPlaying(va_list &args) {
return _pcmChan[chan]._activeEffect ? 1 : 0;
}
+int TownsAudioInterfaceInternal::intf_pcmDisableAllChannels(va_list &args) {
+ for (int i = 0; i < 8; ++i)
+ _pcmChan[i]._activeOutput = false;
+ return 0;
+}
+
int TownsAudioInterfaceInternal::intf_fmKeyOn(va_list &args) {
int chan = va_arg(args, int);
int note = va_arg(args, int);
@@ -1571,7 +1581,7 @@ void TownsAudio_PcmChannel::clear() {
_loopLen = 0;
_pos = 0;
- _loopEnd = 0;
+ _loopStart = 0;
_step = 0;
_stepNote = 0x4000;
@@ -1592,7 +1602,8 @@ void TownsAudio_PcmChannel::clear() {
void TownsAudio_PcmChannel::loadData(TownsAudio_WaveTable *w) {
_data = w->data;
- _dataEnd = w->data + w->size;
+ _dataEnd = w->size << 11;
+ _pos = 0;
}
void TownsAudio_PcmChannel::loadData(uint8 *buffer, uint32 size) {
@@ -1604,7 +1615,7 @@ void TownsAudio_PcmChannel::loadData(uint8 *buffer, uint32 size) {
*dst++ = *src & 0x80 ? (*src++ & 0x7f) : -*src++;
_data = _extData;
- _dataEnd = _extData + size;
+ _dataEnd = size << 11;
_pos = 0;
}
@@ -1643,7 +1654,7 @@ int TownsAudio_PcmChannel::initInstrument(uint8 &note, TownsAudio_WaveTable *&ta
}
void TownsAudio_PcmChannel::keyOn(uint8 note, uint8 velo, TownsAudio_WaveTable *w) {
- setupLoop(w->loopStart, w->loopLen);
+ setupLoop(w->loopLen ? w->loopStart : w->size, w->loopLen);
setNote(note, w, _reserved);
setVelo(velo);
@@ -1744,9 +1755,10 @@ void TownsAudio_PcmChannel::updateOutput() {
if (_activeKey || _activeEffect) {
_pos += _step;
- if (&_data[_pos >> 11] >= _loopEnd) {
- if (_loopLen) {
- _pos -= _loopLen;
+ if (_pos >= _dataEnd) {
+ if (_loopStart != _dataEnd) {
+ _pos = _loopStart;
+ _dataEnd = _loopLen;
} else {
_pos = 0;
_activeKey = _activeEffect = false;
@@ -1763,10 +1775,9 @@ int32 TownsAudio_PcmChannel::currentSampleRight() {
return (_activeOutput && _panRight) ? (((_data[_pos >> 11] * _tl) * _panRight) >> 3) : 0;
}
-void TownsAudio_PcmChannel::setupLoop(uint32 loopStart, uint32 len) {
- _loopLen = len << 11;
- _loopEnd = _loopLen ? &_data[(loopStart + _loopLen) >> 11] : _dataEnd;
- _pos = loopStart;
+void TownsAudio_PcmChannel::setupLoop(uint32 loopStart, uint32 loopLen) {
+ _loopStart = loopStart << 11;
+ _loopLen = loopLen << 11;
}
void TownsAudio_PcmChannel::setNote(uint8 note, TownsAudio_WaveTable *w, bool stepLimit) {
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_euphony.cpp b/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
index fca3d19912..aea714f68f 100644
--- a/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
@@ -25,283 +25,167 @@
#include "common/util.h"
#include "common/textconsole.h"
-TownsEuphonyDriver::TownsEuphonyDriver(Audio::Mixer *mixer) : _activeChannels(0), _sustainChannels(0),
- _assignedChannels(0), _paraCount(0), _command(0), _tEnable(0), _tMode(0), _tOrdr(0), _tLevel(0),
- _tTranspose(0), _musicPos(0), _musicStart(0), _playing(false), _eventBuffer(0), _bufferedEventsCount(0),
- _tempoControlMode(0), _timerSetting(0), _tempoDiff(0), _timeStampBase(0), _elapsedEvents(0), _loop(false),
- _endOfTrack(false), _suspendParsing(false), _musicTrackSize(0) {
- _para[0] = _para[1] = 0;
- _intf = new TownsAudioInterface(mixer, this);
+EuphonyPlayer::EuphonyPlayer(Audio::Mixer *mixer) : _partConfig_enable(0), _partConfig_type(0), _partConfig_ordr(0), _partConfig_volume(0),
+ _partConfig_transpose(0), _musicPos(0), _musicStart(0), _playing(false), _savedEventsChain(0),
+ _tempoControlMode(0), _timerSetting(0), _tempoMode1PulseCounter(0), _parseToBar(0), _tempoMode1UpdateF8(0), _loop(false),
+ _endOfTrack(false), _paused(false), _musicTrackSize(0) {
+ _drivers[0] = _eupDriver = new EuphonyDriver(mixer, this);
+ _drivers[1] = new Type0Driver(this);
+ _drivers[2] = 0;
resetTempo();
}
-TownsEuphonyDriver::~TownsEuphonyDriver() {
- delete _intf;
- delete[] _activeChannels;
- delete[] _sustainChannels;
- delete[] _assignedChannels;
- delete[] _eventBuffer;
- delete[] _tEnable;
- delete[] _tMode;
- delete[] _tOrdr;
- delete[] _tLevel;
- delete[] _tTranspose;
-}
-
-bool TownsEuphonyDriver::init() {
- if (!_intf->init())
- return false;
+EuphonyPlayer::~EuphonyPlayer() {
+ for (int i = 0; i < 3; i++)
+ delete _drivers[i];
- delete[] _activeChannels;
- delete[] _sustainChannels;
- delete[] _assignedChannels;
- delete[] _eventBuffer;
- delete[] _tEnable;
- delete[] _tMode;
- delete[] _tOrdr;
- delete[] _tLevel;
- delete[] _tTranspose;
-
- _activeChannels = new int8[16];
- _sustainChannels = new int8[16];
- _assignedChannels = new ActiveChannel[128];
- _eventBuffer = new DlEvent[64];
-
- _tEnable = new uint8[32];
- _tMode = new uint8[32];
- _tOrdr = new uint8[32];
- _tLevel = new int8[32];
- _tTranspose = new int8[32];
-
- reset();
+ while (_savedEventsChain) {
+ SavedEvent *evt = _savedEventsChain;
+ _savedEventsChain = _savedEventsChain->next;
+ delete evt;
+ }
- return true;
+ delete[] _partConfig_enable;
+ delete[] _partConfig_type;
+ delete[] _partConfig_ordr;
+ delete[] _partConfig_volume;
+ delete[] _partConfig_transpose;
}
-void TownsEuphonyDriver::reset() {
- _intf->callback(0);
-
- _intf->callback(74);
- _intf->callback(70, 0);
- _intf->callback(75, 3);
-
- setTimerA(true, 1);
- setTimerA(false, 1);
- setTimerB(true, 221);
-
- _paraCount = _command = _para[0] = _para[1] = 0;
- memset(_sustainChannels, 0, 16);
- memset(_activeChannels, -1, 16);
- for (int i = 0; i < 128; i++) {
- _assignedChannels[i].chan = _assignedChannels[i].next = -1;
- _assignedChannels[i].note = _assignedChannels[i].sub = 0;
+bool EuphonyPlayer::init() {
+ for (int i = 0; i < 3; i++) {
+ if (_drivers[i]) {
+ if (!_drivers[i]->init()) {
+ warning("EuphonyPlayer:: Driver initialization failed: %d", i);
+ delete _drivers[i];
+ _drivers[i] = 0;
+ }
+ }
}
+
+ if (!_drivers[0] || !_drivers[1])
+ return false;
- int e = 0;
- for (int i = 0; i < 6; i++)
- assignChannel(i, e++);
- for (int i = 0x40; i < 0x48; i++)
- assignChannel(i, e++);
-
- resetTables();
-
- memset(_eventBuffer, 0, 64 * sizeof(DlEvent));
- _bufferedEventsCount = 0;
-
- _playing = _endOfTrack = _suspendParsing = _loop = false;
- _elapsedEvents = 0;
- _tempoDiff = 0;
-
- resetTempo();
-
- if (_tempoControlMode == 1) {
- //if (///)
- // return;
- setTempoIntern(_defaultTempo);
- } else {
- setTempoIntern(_defaultTempo);
+ while (_savedEventsChain) {
+ SavedEvent *evt = _savedEventsChain;
+ _savedEventsChain = _savedEventsChain->next;
+ delete evt;
}
- resetControl();
-}
+ delete[] _partConfig_enable;
+ delete[] _partConfig_type;
+ delete[] _partConfig_ordr;
+ delete[] _partConfig_volume;
+ delete[] _partConfig_transpose;
-void TownsEuphonyDriver::loadInstrument(int chanType, int id, const uint8 *data) {
- _intf->callback(5, chanType, id, data);
-}
+ _partConfig_enable = new uint8[32];
+ _partConfig_type = new uint8[32];
+ _partConfig_ordr = new uint8[32];
+ _partConfig_volume = new int8[32];
+ _partConfig_transpose = new int8[32];
-void TownsEuphonyDriver::loadWaveTable(const uint8 *data) {
- _intf->callback(34, data);
-}
-
-void TownsEuphonyDriver::unloadWaveTable(int id) {
- _intf->callback(35, id);
-}
-
-void TownsEuphonyDriver::reserveSoundEffectChannels(int num) {
- _intf->callback(33, num);
- uint32 volMask = 0;
-
- if (num > 8)
- return;
-
- for (uint32 v = 1 << 13; num; num--) {
- volMask |= v;
- v >>= 1;
- }
-
- _intf->setSoundEffectChanMask(volMask);
-}
+ reset();
-int TownsEuphonyDriver::setMusicTempo(int tempo) {
- if (tempo > 250)
- return 3;
- _defaultTempo = tempo;
- _trackTempo = tempo;
- setTempoIntern(tempo);
- return 0;
+ return true;
}
-int TownsEuphonyDriver::startMusicTrack(const uint8 *data, int trackSize, int startTick) {
+int EuphonyPlayer::startTrack(const uint8 *data, int trackSize, int barLen) {
if (_playing)
return 2;
_musicPos = _musicStart = data;
- _defaultBaseTickLen = _baseTickLen = startTick;
+ _defaultBarLength = _barLength = barLen;
_musicTrackSize = trackSize;
- _timeStampBase = _timeStampDest = 0;
- _tickCounter = 0;
+ _parseToBar = _bar = 0;
+ _beat = 0;
_playing = true;
return 0;
}
-void TownsEuphonyDriver::setMusicLoop(bool loop) {
- _loop = loop;
-}
-
-void TownsEuphonyDriver::stopParser() {
+void EuphonyPlayer::stop() {
if (_playing) {
_playing = false;
- _pulseCount = 0;
+ _playerUpdatesLeft = 0;
_endOfTrack = false;
- flushEventBuffer();
- resetControl();
+ clearHangingNotes();
+ resetAllControls();
}
}
-void TownsEuphonyDriver::continueParsing() {
- _suspendParsing = false;
-}
-
-void TownsEuphonyDriver::playSoundEffect(int chan, int note, int velo, const uint8 *data) {
- _intf->callback(37, chan, note, velo, data);
-}
-
-void TownsEuphonyDriver::stopSoundEffect(int chan) {
- _intf->callback(39, chan);
-}
-
-bool TownsEuphonyDriver::soundEffectIsPlaying(int chan) {
- return _intf->callback(40, chan) ? true : false;
-}
-
-void TownsEuphonyDriver::chanPanPos(int chan, int mode) {
- _intf->callback(3, chan, mode);
-}
-
-void TownsEuphonyDriver::chanPitch(int chan, int pitch) {
- _intf->callback(7, chan, pitch);
+void EuphonyPlayer::pause() {
+ _paused = true;
+ clearHangingNotes();
+ allPartsOff();
}
-void TownsEuphonyDriver::chanVolume(int chan, int vol) {
- _intf->callback(8, chan, vol);
+void EuphonyPlayer::resume() {
+ _paused = false;
}
-void TownsEuphonyDriver::setOutputVolume(int mode, int volLeft, int volRight) {
- _intf->callback(67, mode, volLeft, volRight);
-}
-
-int TownsEuphonyDriver::configChan_enable(int tableEntry, int val) {
- if (tableEntry > 31)
+int EuphonyPlayer::setTempo(int tempo) {
+ if (tempo > 250)
return 3;
- _tEnable[tableEntry] = val;
+ _defaultTempo = tempo;
+ _trackTempo = tempo;
+ sendTempo(tempo);
return 0;
}
-int TownsEuphonyDriver::configChan_setMode(int tableEntry, int val) {
- if (tableEntry > 31)
+void EuphonyPlayer::setLoopStatus(bool loop) {
+ _loop = loop;
+}
+
+int EuphonyPlayer::configPart_enable(int part, int val) {
+ uint8 enable = val & 0xff;
+ if (part > 31 || ((enable + 1) & 0xff) > 1)
return 3;
- _tMode[tableEntry] = val;
+ _partConfig_enable[part] = enable;
return 0;
}
-int TownsEuphonyDriver::configChan_remap(int tableEntry, int val) {
- if (tableEntry > 31)
+int EuphonyPlayer::configPart_setType(int part, int val) {
+ uint8 type = val & 0xff;
+ if (part > 31 || ((type + 1) & 0xff) > 8)
return 3;
- if (val < 16)
- _tOrdr[tableEntry] = val;
+ _partConfig_type[part] = type;
return 0;
}
-int TownsEuphonyDriver::configChan_adjustVolume(int tableEntry, int val) {
- if (tableEntry > 31)
+int EuphonyPlayer::configPart_remap(int part, int val) {
+ uint8 remap = val & 0xff;
+ if (part > 31 || ((remap + 1) & 0xff) > 16)
return 3;
- if (val <= 40)
- _tLevel[tableEntry] = (int8)(val & 0xff);
+ _partConfig_ordr[part] = remap;
return 0;
}
-int TownsEuphonyDriver::configChan_setTranspose(int tableEntry, int val) {
- if (tableEntry > 31)
+int EuphonyPlayer::configPart_adjustVolume(int part, int val) {
+ int8 adjvol = val & 0xff;
+ if (part > 31 || adjvol < -40 || adjvol > 40)
return 3;
- if (val <= 40)
- _tTranspose[tableEntry] = (int8)(val & 0xff);
+ _partConfig_volume[part] = adjvol;
return 0;
}
-int TownsEuphonyDriver::assignChannel(int chan, int tableEntry) {
- if (tableEntry > 15 || chan > 127 || chan < 0)
+int EuphonyPlayer::configPart_setTranspose(int part, int val) {
+ int8 trans = val & 0xff;
+ if (part > 31 || trans < -40 || trans > 40)
return 3;
-
- ActiveChannel *a = &_assignedChannels[chan];
- if (a->chan == tableEntry)
- return 0;
-
- if (a->chan != -1) {
- int8 *b = &_activeChannels[a->chan];
- while (*b != chan) {
- b = &_assignedChannels[*b].next;
- if (*b == -1 && *b != chan)
- return 3;
- }
-
- *b = a->next;
-
- if (a->note)
- _intf->callback(2, chan);
-
- a->chan = a->next = -1;
- a->note = 0;
- }
-
- a->next = _activeChannels[tableEntry];
- _activeChannels[tableEntry] = chan;
- a->chan = tableEntry;
- a->note = a->sub = 0;
-
+ _partConfig_transpose[part] = trans;
return 0;
}
-void TownsEuphonyDriver::timerCallback(int timerId) {
+void EuphonyPlayer::timerCallback(int timerId) {
switch (timerId) {
case 0:
- updatePulseCount();
- while (_pulseCount > 0) {
- --_pulseCount;
- updateTimeStampBase();
+ updatePulseCounters();
+ while (_playerUpdatesLeft) {
+ --_playerUpdatesLeft;
+ updateBeat();
if (!_playing)
continue;
- updateEventBuffer();
+ updateHangingNotes();
updateParser();
updateCheckEot();
}
@@ -311,175 +195,156 @@ void TownsEuphonyDriver::timerCallback(int timerId) {
}
}
-void TownsEuphonyDriver::setMusicVolume(int volume) {
- _intf->setMusicVolume(volume);
-}
+void EuphonyPlayer::reset() {
+ _eupDriver->reset();
+ _eupDriver->setTimerA(true, 1);
+ _eupDriver->setTimerA(false, 1);
+ _eupDriver->setTimerB(true, 221);
-void TownsEuphonyDriver::setSoundEffectVolume(int volume) {
- _intf->setSoundEffectVolume(volume);
-}
-
-void TownsEuphonyDriver::resetTables() {
- memset(_tEnable, 0xff, 32);
- memset(_tMode, 0xff, 16);
- memset(_tMode + 16, 0, 16);
- for (int i = 0; i < 32; i++)
- _tOrdr[i] = i & 0x0f;
- memset(_tLevel, 0, 32);
- memset(_tTranspose, 0, 32);
-}
-
-void TownsEuphonyDriver::resetTempo() {
- _defaultBaseTickLen = _baseTickLen = 0x33;
- _pulseCount = 0;
- _extraTimingControlRemainder = 0;
- _extraTimingControl = 16;
- _tempoModifier = 0;
- _timeStampDest = 0;
- _deltaTicks = 0;
- _tickCounter = 0;
- _defaultTempo = 90;
- _trackTempo = 90;
-}
+ resetPartConfig();
-void TownsEuphonyDriver::setTempoIntern(int tempo) {
- tempo = CLIP(tempo + _tempoModifier, 0, 500);
- if (_tempoControlMode == 0) {
- _timerSetting = 34750 / (tempo + 30);
- _extraTimingControl = 16;
-
- while (_timerSetting < 126) {
- _timerSetting <<= 1;
- _extraTimingControl <<= 1;
- }
-
- while (_timerSetting > 383) {
- _timerSetting >>= 1;
- _extraTimingControl >>= 1;
- }
+ while (_savedEventsChain) {
+ SavedEvent *evt = _savedEventsChain;
+ _savedEventsChain = _savedEventsChain->next;
+ delete evt;
+ }
- setTimerA(true, -(_timerSetting - 2));
+ _playing = _endOfTrack = _paused = _loop = false;
+ _tempoMode1UpdateF8 = 0;
+ _tempoMode1PulseCounter = 0;
- } else if (_tempoControlMode == 1) {
- _timerSetting = 312500 / (tempo + 30);
- _extraTimingControl = 16;
- while (_timerSetting < 1105) {
- _timerSetting <<= 1;
- _extraTimingControl <<= 1;
- }
+ resetTempo();
- } else if (_tempoControlMode == 2) {
- _timerSetting = 625000 / (tempo + 30);
- _extraTimingControlRemainder = 0;
+ if (_tempoControlMode == 1) {
+ //if (///)
+ // return;
+ sendTempo(_defaultTempo);
+ } else {
+ sendTempo(_defaultTempo);
}
+
+ resetAllControls();
}
-void TownsEuphonyDriver::setTimerA(bool enable, int tempo) {
- _intf->callback(21, enable ? 255 : 0, tempo);
+void EuphonyPlayer::resetPartConfig() {
+ memset(_partConfig_enable, 0xff, 32);
+ memset(_partConfig_type, 0xff, 16);
+ memset(_partConfig_type + 16, 0, 16);
+ for (int i = 0; i < 32; i++)
+ _partConfig_ordr[i] = i & 0x0f;
+ memset(_partConfig_volume, 0, 32);
+ memset(_partConfig_transpose, 0, 32);
}
-void TownsEuphonyDriver::setTimerB(bool enable, int tempo) {
- _intf->callback(22, enable ? 255 : 0, tempo);
+void EuphonyPlayer::resetTempo() {
+ _defaultBarLength = _barLength = 0x33;
+ _playerUpdatesLeft = 0;
+ _updatesPerPulseRemainder = 0;
+ _updatesPerPulse = 0x10;
+ _tempoModifier = 0;
+ _bar = 0;
+ _deltaTicks = 0;
+ _beat = 0;
+ _defaultTempo = 90;
+ _trackTempo = 90;
}
-void TownsEuphonyDriver::updatePulseCount() {
- int tc = _extraTimingControl + _extraTimingControlRemainder;
- _extraTimingControlRemainder = tc & 0x0f;
+void EuphonyPlayer::updatePulseCounters() {
+ int tc = _updatesPerPulse + _updatesPerPulseRemainder;
+ _updatesPerPulseRemainder = tc & 0x0f;
tc >>= 4;
- _tempoDiff -= tc;
+ _tempoMode1PulseCounter -= tc;
- while (_tempoDiff < 0) {
- _elapsedEvents++;
- _tempoDiff += 4;
+ while (_tempoMode1PulseCounter < 0) {
+ _tempoMode1UpdateF8++;
+ _tempoMode1PulseCounter += 4;
}
- if (_playing && !_suspendParsing)
- _pulseCount += tc;
+ if (_playing && !_paused)
+ _playerUpdatesLeft += tc;
}
-void TownsEuphonyDriver::updateTimeStampBase() {
- static const uint16 table[] = { 0x180, 0xC0, 0x80, 0x60, 0x40, 0x30, 0x20, 0x18 };
- if ((uint32)(table[_baseTickLen >> 4] * ((_baseTickLen & 0x0f) + 1)) > ++_tickCounter)
+void EuphonyPlayer::updateBeat() {
+ static const uint16 beatLengthTable[] = { 0x180, 0xC0, 0x80, 0x60, 0x40, 0x30, 0x20, 0x18 };
+ uint8 beatsPersBar = (_barLength & 0x0f) + 1;
+ uint8 beatNoteValue = _barLength >> 4;
+
+ if ((uint32)(beatLengthTable[beatNoteValue] * beatsPersBar) > ++_beat)
return;
- ++_timeStampDest;
- _tickCounter = 0;
+
+ ++_bar;
+ _beat = 0;
_deltaTicks = 0;
}
-void TownsEuphonyDriver::updateParser() {
+void EuphonyPlayer::updateParser() {
for (bool loop = true; loop;) {
uint8 cmd = _musicPos[0];
if (cmd == 0xff || cmd == 0xf7) {
- jumpNextLoop();
+ proceedToNextEvent();
} else if (cmd < 0x90) {
_endOfTrack = true;
- flushEventBuffer();
+ clearHangingNotes();
loop = false;
- } else if (_timeStampBase > _timeStampDest) {
+ } else if (_parseToBar > _bar) {
loop = false;
} else {
- if (_timeStampBase == _timeStampDest) {
- uint16 timeStamp = READ_LE_UINT16(&_musicPos[2]);
- uint8 l = (timeStamp & 0xff) + (timeStamp & 0xff);
- timeStamp = ((timeStamp & 0xff00) | l) >> 1;
- if (timeStamp > _tickCounter)
+ if (_parseToBar == _bar) {
+ uint16 parseToBeat = ((_musicPos[3] << 8) | ((_musicPos[2] << 1) & 0xff)) >> 1;
+ if (parseToBeat > _beat)
loop = false;
}
if (loop) {
- if (parseNext())
+ if (parseEvent())
loop = false;
}
}
}
}
-void TownsEuphonyDriver::updateCheckEot() {
- if (!_endOfTrack || _bufferedEventsCount)
+void EuphonyPlayer::updateCheckEot() {
+ if (!_endOfTrack || _savedEventsChain)
return;
- stopParser();
-}
-
-bool TownsEuphonyDriver::parseNext() {
-#define OPC(x) &TownsEuphonyDriver::evt##x
- static const EuphonyOpcode opcodes[] = {
- OPC(NotImpl),
- OPC(SetupNote),
- OPC(PolyphonicAftertouch),
- OPC(ControlPitch),
- OPC(InstrumentChanAftertouch),
- OPC(InstrumentChanAftertouch),
- OPC(ControlPitch)
+ stop();
+}
+
+bool EuphonyPlayer::parseEvent() {
+#define EVENT(x) &EuphonyPlayer::event_##x
+ static const EuphonyEvent events[] = {
+ EVENT(notImpl),
+ EVENT(noteOn),
+ EVENT(polyphonicAftertouch),
+ EVENT(controlChange_pitchWheel),
+ EVENT(programChange_channelAftertouch),
+ EVENT(programChange_channelAftertouch),
+ EVENT(controlChange_pitchWheel),
+
+ EVENT(sysex),
+ EVENT(advanceBar),
+ EVENT(notImpl),
+ EVENT(notImpl),
+ EVENT(setTempo),
+ EVENT(notImpl),
+ EVENT(typeOrdrChange)
};
-#undef OPC
+#undef EVENT
uint cmd = _musicPos[0];
if (cmd != 0xfe && cmd != 0xfd) {
- if (cmd >= 0xf0) {
- cmd &= 0x0f;
- if (cmd == 0)
- evtLoadInstrument();
- else if (cmd == 2)
- evtAdvanceTimestampOffset();
- else if (cmd == 8)
- evtTempo();
- else if (cmd == 12)
- evtModeOrdrChange();
- jumpNextLoop();
- return false;
-
- } else if (!(this->*opcodes[(cmd - 0x80) >> 4])()) {
- jumpNextLoop();
+ bool result = (cmd >= 0xf0) ? (this->*events[((cmd - 0xf0) >> 1) + 7])() : (this->*events[(cmd - 0x80) >> 4])();
+ if (!result) {
+ proceedToNextEvent();
return false;
}
}
if (cmd == 0xfd) {
- _suspendParsing = true;
+ _paused = true;
return true;
}
@@ -490,299 +355,208 @@ bool TownsEuphonyDriver::parseNext() {
_endOfTrack = false;
_musicPos = _musicStart;
- _timeStampBase = _timeStampDest = _tickCounter = 0;
- _baseTickLen = _defaultBaseTickLen;
+ _parseToBar = _bar = _beat = 0;
+ _barLength = _defaultBarLength;
return false;
}
-void TownsEuphonyDriver::jumpNextLoop() {
+void EuphonyPlayer::proceedToNextEvent() {
_musicPos += 6;
if (_musicPos >= _musicStart + _musicTrackSize)
_musicPos = _musicStart;
}
-void TownsEuphonyDriver::updateEventBuffer() {
- DlEvent *e = _eventBuffer;
- for (int i = _bufferedEventsCount; i; e++) {
- if (e->evt == 0)
- continue;
+void EuphonyPlayer::updateHangingNotes() {
+ SavedEvent *l = 0;
+ SavedEvent *e = _savedEventsChain;
+
+ while (e) {
if (--e->len) {
- --i;
+ l = e;
+ e = e->next;
continue;
}
- processBufferNote(e->mode, e->evt, e->note, e->velo);
- e->evt = 0;
- --i;
- --_bufferedEventsCount;
- }
-}
-void TownsEuphonyDriver::flushEventBuffer() {
- DlEvent *e = _eventBuffer;
- for (int i = _bufferedEventsCount; i; e++) {
- if (e->evt == 0)
- continue;
- processBufferNote(e->mode, e->evt, e->note, e->velo);
- e->evt = 0;
- --i;
- --_bufferedEventsCount;
+ SavedEvent *n = e->next;
+ if (l)
+ l->next = n;
+ if (_savedEventsChain == e)
+ _savedEventsChain = n;
+
+ sendNoteEvent(e->type, e->evt, e->note, e->velo);
+ delete e;
+
+ e = n;
}
}
-void TownsEuphonyDriver::processBufferNote(int mode, int evt, int note, int velo) {
- if (!velo)
- evt &= 0x8f;
- sendEvent(mode, evt);
- sendEvent(mode, note);
- sendEvent(mode, velo);
+void EuphonyPlayer::clearHangingNotes() {
+ while (_savedEventsChain) {
+ SavedEvent *e = _savedEventsChain;
+ _savedEventsChain = _savedEventsChain->next;
+ sendNoteEvent(e->type, e->evt, e->note, e->velo);
+ delete e;
+ }
}
-void TownsEuphonyDriver::resetControl() {
+void EuphonyPlayer::resetAllControls() {
for (int i = 0; i < 32; i++) {
- if (_tOrdr[i] > 15) {
+ if (_partConfig_ordr[i] > 15) {
for (int ii = 0; ii < 16; ii++)
- resetControlIntern(_tMode[i], ii);
+ sendControllerReset(_partConfig_type[i], ii);
} else {
- resetControlIntern(_tMode[i], _tOrdr[i]);
+ sendControllerReset(_partConfig_type[i], _partConfig_ordr[i]);
}
}
}
-void TownsEuphonyDriver::resetControlIntern(int mode, int chan) {
- sendEvent(mode, 0xb0 | chan);
- sendEvent(mode, 0x40);
- sendEvent(mode, 0);
- sendEvent(mode, 0xb0 | chan);
- sendEvent(mode, 0x7b);
- sendEvent(mode, 0);
- sendEvent(mode, 0xb0 | chan);
- sendEvent(mode, 0x79);
- sendEvent(mode, 0x40);
+void EuphonyPlayer::allPartsOff() {
+ for (int i = 0; i < 32; i++) {
+ if (_partConfig_ordr[i] > 15) {
+ for (int ii = 0; ii < 16; ii++)
+ sendAllNotesOff(_partConfig_type[i], ii);
+ } else {
+ sendAllNotesOff(_partConfig_type[i], _partConfig_ordr[i]);
+ }
+ }
}
-uint8 TownsEuphonyDriver::appendEvent(uint8 evt, uint8 chan) {
- if (evt >= 0x80 && evt < 0xf0 && _tOrdr[chan] < 16)
- return (evt & 0xf0) | _tOrdr[chan];
+uint8 EuphonyPlayer::appendEvent(uint8 evt, uint8 chan) {
+ if (evt >= 0x80 && evt < 0xf0 && _partConfig_ordr[chan] < 16)
+ return (evt & 0xf0) | _partConfig_ordr[chan];
return evt;
}
-void TownsEuphonyDriver::sendEvent(uint8 mode, uint8 command) {
- if (mode == 0) {
- // warning("TownsEuphonyDriver: Mode 0 not implemented");
-
- } else if (mode == 0x10) {
- warning("TownsEuphonyDriver: Mode 0x10 not implemented");
-
- } else if (mode == 0xff) {
- if (command >= 0xf0) {
- _paraCount = 1;
- _command = 0;
- } else if (command >= 0x80) {
- _paraCount = 1;
- _command = command;
- } else if (_command >= 0x80) {
- switch ((_command - 0x80) >> 4) {
- case 0:
- if (_paraCount < 2) {
- _paraCount++;
- _para[0] = command;
- } else {
- _paraCount = 1;
- _para[1] = command;
- sendNoteOff();
- }
- break;
-
- case 1:
- if (_paraCount < 2) {
- _paraCount++;
- _para[0] = command;
- } else {
- _paraCount = 1;
- _para[1] = command;
- if (command)
- sendNoteOn();
- else
- sendNoteOff();
- }
- break;
-
- case 2:
- if (_paraCount < 2) {
- _paraCount++;
- _para[0] = command;
- } else {
- _paraCount = 1;
- }
- break;
-
- case 3:
- if (_paraCount < 2) {
- _paraCount++;
- _para[0] = command;
- } else {
- _paraCount = 1;
- _para[1] = command;
-
- if (_para[0] == 7)
- sendChanVolume();
- else if (_para[0] == 10)
- sendPanPosition();
- else if (_para[0] == 64)
- sendAllNotesOff();
- }
- break;
-
- case 4:
- _paraCount = 1;
- _para[0] = command;
- sendSetInstrument();
- break;
-
- case 5:
- _paraCount = 1;
- _para[0] = command;
- break;
-
- case 6:
- if (_paraCount < 2) {
- _paraCount++;
- _para[0] = command;
- } else {
- _paraCount = 1;
- _para[1] = command;
- sendPitch();
- }
- break;
- }
- }
- }
+bool EuphonyPlayer::event_notImpl() {
+ return false;
}
-bool TownsEuphonyDriver::evtSetupNote() {
+bool EuphonyPlayer::event_noteOn() {
if (_musicPos[1] > 31)
return false;
- if (!_tEnable[_musicPos[1]]) {
- jumpNextLoop();
+ if (!_partConfig_enable[_musicPos[1]]) {
+ proceedToNextEvent();
return (_musicPos[0] == 0xfe || _musicPos[0] == 0xfd) ? true : false;
}
uint8 evt = appendEvent(_musicPos[0], _musicPos[1]);
- uint8 mode = _tMode[_musicPos[1]];
+ uint8 type = _partConfig_type[_musicPos[1]];
uint8 note = _musicPos[4];
uint8 velo = _musicPos[5];
- sendEvent(mode, evt);
- sendEvent(mode, applyTranspose(note));
- sendEvent(mode, applyVolumeAdjust(velo));
+ sendEvent(type, evt);
+ sendEvent(type, applyTranspose(note));
+ sendEvent(type, applyVolumeAdjust(velo));
- jumpNextLoop();
+ proceedToNextEvent();
if (_musicPos[0] == 0xfe || _musicPos[0] == 0xfd)
return true;
velo = _musicPos[5];
- uint16 len = ((((_musicPos[1] << 4) | (_musicPos[2] << 8)) >> 4) & 0xff) | ((((_musicPos[3] << 4) | (_musicPos[4] << 8)) >> 4) << 8);
-
- int i = 0;
- for (; i < 64; i++) {
- if (_eventBuffer[i].evt == 0)
- break;
- }
+ uint16 len = (_musicPos[1] & 0x0f) | ((_musicPos[2] & 0x0f) << 4) | ((_musicPos[3] & 0x0f) << 8) | ((_musicPos[4] & 0x0f) << 12);
- if (i == 64) {
- processBufferNote(mode, evt, note, velo);
- } else {
- _eventBuffer[i].evt = evt;
- _eventBuffer[i].mode = mode;
- _eventBuffer[i].note = note;
- _eventBuffer[i].velo = velo;
- _eventBuffer[i].len = len ? len : 1;
- _bufferedEventsCount++;
- }
+ _savedEventsChain = new SavedEvent(evt, type, note, velo, len ? len : 1, _savedEventsChain);
return false;
}
-bool TownsEuphonyDriver::evtPolyphonicAftertouch() {
+bool EuphonyPlayer::event_polyphonicAftertouch() {
if (_musicPos[1] > 31)
return false;
- if (!_tEnable[_musicPos[1]])
+ if (!_partConfig_enable[_musicPos[1]])
return false;
uint8 evt = appendEvent(_musicPos[0], _musicPos[1]);
- uint8 mode = _tMode[_musicPos[1]];
+ uint8 type = _partConfig_type[_musicPos[1]];
- sendEvent(mode, evt);
- sendEvent(mode, applyTranspose(_musicPos[4]));
- sendEvent(mode, _musicPos[5]);
+ sendEvent(type, evt);
+ sendEvent(type, applyTranspose(_musicPos[4]));
+ sendEvent(type, _musicPos[5]);
return false;
}
-bool TownsEuphonyDriver::evtControlPitch() {
+bool EuphonyPlayer::event_controlChange_pitchWheel() {
if (_musicPos[1] > 31)
return false;
- if (!_tEnable[_musicPos[1]])
+ if (!_partConfig_enable[_musicPos[1]])
return false;
uint8 evt = appendEvent(_musicPos[0], _musicPos[1]);
- uint8 mode = _tMode[_musicPos[1]];
+ uint8 type = _partConfig_type[_musicPos[1]];
- sendEvent(mode, evt);
- sendEvent(mode, _musicPos[4]);
- sendEvent(mode, _musicPos[5]);
+ sendEvent(type, evt);
+ sendEvent(type, _musicPos[4]);
+ sendEvent(type, _musicPos[5]);
return false;
}
-bool TownsEuphonyDriver::evtInstrumentChanAftertouch() {
+bool EuphonyPlayer::event_programChange_channelAftertouch() {
if (_musicPos[1] > 31)
return false;
- if (!_tEnable[_musicPos[1]])
+ if (!_partConfig_enable[_musicPos[1]])
return false;
uint8 evt = appendEvent(_musicPos[0], _musicPos[1]);
- uint8 mode = _tMode[_musicPos[1]];
+ uint8 type = _partConfig_type[_musicPos[1]];
- sendEvent(mode, evt);
- sendEvent(mode, _musicPos[4]);
+ sendEvent(type, evt);
+ sendEvent(type, _musicPos[4]);
return false;
}
-bool TownsEuphonyDriver::evtLoadInstrument() {
+bool EuphonyPlayer::event_sysex() {
+ uint8 type = _partConfig_type[_musicPos[1]];
+ sendEvent(type, 0xF0);
+ proceedToNextEvent();
+
+ for (bool loop = true; loop; ) {
+ for (int i = 0; i < 6; i++) {
+ if (_musicPos[i] != 0xFF) {
+ sendEvent(type, _musicPos[i]);
+ if (_musicPos[i] >= 0x80) {
+ loop = false;
+ break;
+ }
+ }
+ }
+ if (loop)
+ proceedToNextEvent();
+ }
+
return false;
}
-bool TownsEuphonyDriver::evtAdvanceTimestampOffset() {
- ++_timeStampBase;
- _baseTickLen = _musicPos[1];
+bool EuphonyPlayer::event_advanceBar() {
+ ++_parseToBar;
+ _barLength = _musicPos[1];
return false;
}
-bool TownsEuphonyDriver::evtTempo() {
- uint8 l = _musicPos[4] << 1;
- _trackTempo = (l | (_musicPos[5] << 8)) >> 1;
- setTempoIntern(_trackTempo);
+bool EuphonyPlayer::event_setTempo() {
+ _trackTempo = ((_musicPos[5] << 8) | ((_musicPos[4] << 1) & 0xff)) >> 1;
+ sendTempo(_trackTempo);
return false;
}
-bool TownsEuphonyDriver::evtModeOrdrChange() {
+bool EuphonyPlayer::event_typeOrdrChange() {
if (_musicPos[1] > 31)
return false;
- if (!_tEnable[_musicPos[1]])
+ if (!_partConfig_enable[_musicPos[1]])
return false;
if (_musicPos[4] == 1)
- _tMode[_musicPos[1]] = _musicPos[5];
+ _partConfig_type[_musicPos[1]] = _musicPos[5];
else if (_musicPos[4] == 2)
- _tOrdr[_musicPos[1]] = _musicPos[5];
+ _partConfig_ordr[_musicPos[1]] = _musicPos[5];
return false;
}
-uint8 TownsEuphonyDriver::applyTranspose(uint8 in) {
- int out = _tTranspose[_musicPos[1]];
+uint8 EuphonyPlayer::applyTranspose(uint8 in) {
+ int out = _partConfig_transpose[_musicPos[1]];
if (!out)
return in;
out += (in & 0x7f);
@@ -796,61 +570,328 @@ uint8 TownsEuphonyDriver::applyTranspose(uint8 in) {
return out & 0xff;
}
-uint8 TownsEuphonyDriver::applyVolumeAdjust(uint8 in) {
- int out = _tLevel[_musicPos[1]];
+uint8 EuphonyPlayer::applyVolumeAdjust(uint8 in) {
+ int out = _partConfig_volume[_musicPos[1]];
out += (in & 0x7f);
out = CLIP(out, 1, 127);
return out & 0xff;
}
-void TownsEuphonyDriver::sendNoteOff() {
- int8 *chan = &_activeChannels[_command & 0x0f];
+void EuphonyPlayer::sendEvent(uint8 type, uint8 command) {
+ int drv = ((type >> 4) + 1) & 3;
+ if (_drivers[drv])
+ _drivers[drv]->send(command);
+}
+
+void EuphonyPlayer::sendNoteEvent(int type, int evt, int note, int velo) {
+ if (velo)
+ evt &= 0x8f;
+ sendEvent(type, evt);
+ sendEvent(type, note);
+ sendEvent(type, velo);
+}
+
+void EuphonyPlayer::sendControllerReset(int type, int part) {
+ sendEvent(type, 0xb0 | part);
+ sendEvent(type, 0x40);
+ sendEvent(type, 0);
+ sendEvent(type, 0xb0 | part);
+ sendEvent(type, 0x7b);
+ sendEvent(type, 0);
+ sendEvent(type, 0xb0 | part);
+ sendEvent(type, 0x79);
+ sendEvent(type, 0x40);
+}
+
+void EuphonyPlayer::sendAllNotesOff(int type, int part) {
+ sendEvent(type, 0xb0 | part);
+ sendEvent(type, 0x40);
+ sendEvent(type, 0);
+}
+
+void EuphonyPlayer::sendTempo(int tempo) {
+ tempo = CLIP(tempo + _tempoModifier, 0, 500);
+ if (_tempoControlMode == 0) {
+ _timerSetting = 34750 / (tempo + 30);
+ _updatesPerPulse = 0x10;
+
+ while (_timerSetting < 126) {
+ _timerSetting <<= 1;
+ _updatesPerPulse <<= 1;
+ }
+
+ while (_timerSetting > 383) {
+ _timerSetting >>= 1;
+ _updatesPerPulse >>= 1;
+ }
+
+ _eupDriver->setTimerA(true, -(_timerSetting - 2));
+
+ } else if (_tempoControlMode == 1) {
+ _timerSetting = 312500 / (tempo + 30);
+ _updatesPerPulse = 0x10;
+ while (_timerSetting < 1105) {
+ _timerSetting <<= 1;
+ _updatesPerPulse <<= 1;
+ }
+
+ } else if (_tempoControlMode == 2) {
+ _timerSetting = 625000 / (tempo + 30);
+ _updatesPerPulseRemainder = 0;
+ }
+}
+
+EuphonyDriver::EuphonyDriver(Audio::Mixer *mixer, EuphonyPlayer *pl) : EuphonyBaseDriver(), _channels(0), _partToChanMapping(0), _sustainChannels(0) {
+ _intf = new TownsAudioInterface(mixer, pl);
+}
+
+EuphonyDriver::~EuphonyDriver() {
+ delete _intf;
+ delete[] _partToChanMapping;
+ delete[] _sustainChannels;
+ delete[] _channels;
+}
+
+
+bool EuphonyDriver::init() {
+ if (!_intf->init())
+ return false;
+
+ delete[] _channels;
+ delete[] _partToChanMapping;
+ delete[] _sustainChannels;
+
+ _channels = new Channel[128];
+ _partToChanMapping = new int8[16];
+ _sustainChannels = new int8[16];
+
+ return true;
+}
+
+void EuphonyDriver::reset() {
+ _intf->callback(0);
+ _intf->callback(74);
+ _intf->callback(70, 0);
+ _intf->callback(75, 3);
+
+ _currentEvent.clear();
+ memset(_sustainChannels, 0, 16);
+ memset(_partToChanMapping, -1, 16);
+
+ for (int i = 0; i < 128; i++) {
+ _channels[i].part = _channels[i].next = -1;
+ _channels[i].note = _channels[i].pri = 0;
+ }
+
+ int e = 0;
+ for (int i = 0; i < 6; i++)
+ assignPartToChannel(i, e++);
+ for (int i = 0x40; i < 0x48; i++)
+ assignPartToChannel(i, e++);
+}
+
+int EuphonyDriver::assignPartToChannel(int chan, int part) {
+ if (part > 15 || chan > 127 || chan < 0)
+ return 3;
+
+ Channel *a = &_channels[chan];
+ if (a->part == part)
+ return 0;
+
+ if (a->part != -1) {
+ int8 *b = &_partToChanMapping[a->part];
+ while (*b != chan) {
+ b = &_channels[*b].next;
+ if (*b == -1 && *b != chan)
+ return 3;
+ }
+
+ *b = a->next;
+
+ if (a->note)
+ _intf->callback(2, chan);
+
+ a->part = a->next = -1;
+ a->note = 0;
+ }
+
+ a->next = _partToChanMapping[part];
+ _partToChanMapping[part] = chan;
+ a->part = part;
+ a->note = a->pri = 0;
+
+ return 0;
+}
+
+void EuphonyDriver::send(uint8 command) {
+ if (command >= 0x80) {
+ _currentEvent.clear();
+ _currentEvent.push_back(command >= 0xf0 ? 0 : command);
+ } else if (_currentEvent[0] >= 0x80) {
+ uint8 cmd = (_currentEvent[0] - 0x80) >> 4;
+ _currentEvent.push_back(command);
+
+ static const uint8 eventSize[] = { 3, 3, 3, 3, 2, 2, 3 };
+ if (_currentEvent.size() != eventSize[cmd])
+ return;
+
+ switch (cmd) {
+ case 0:
+ noteOff();
+ break;
+ case 1:
+ if (_currentEvent[2])
+ noteOn();
+ else
+ noteOff();
+ break;
+ case 3:
+ if (_currentEvent[1] == 7)
+ controlChange_volume();
+ else if (_currentEvent[1] == 10)
+ controlChange_panPos();
+ else if (_currentEvent[1] == 64)
+ controlChange_allNotesOff();
+ break;
+ case 4:
+ programChange();
+ break;
+ case 6:
+ pitchWheel();
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void EuphonyDriver::setTimerA(bool enable, int tempo) {
+ _intf->callback(21, enable ? 255 : 0, tempo);
+}
+
+void EuphonyDriver::setTimerB(bool enable, int tempo) {
+ _intf->callback(22, enable ? 255 : 0, tempo);
+}
+
+void EuphonyDriver::loadInstrument(int chanType, int id, const uint8 *data) {
+ _intf->callback(5, chanType, id, data);
+}
+
+void EuphonyDriver::setInstrument(int chan, int instrID) {
+ _intf->callback(4, chan, instrID);
+}
+
+void EuphonyDriver::loadWaveTable(const uint8 *data) {
+ _intf->callback(34, data);
+}
+
+void EuphonyDriver::unloadWaveTable(int id) {
+ _intf->callback(35, id);
+}
+
+void EuphonyDriver::reserveSoundEffectChannels(int num) {
+ _intf->callback(33, num);
+ uint32 volMask = 0;
+
+ if (num > 8)
+ return;
+
+ for (uint32 v = 1 << 13; num; num--) {
+ volMask |= v;
+ v >>= 1;
+ }
+
+ _intf->setSoundEffectChanMask(volMask);
+}
+
+void EuphonyDriver::playSoundEffect(int chan, int note, int velo, const uint8 *data) {
+ _intf->callback(37, chan, note, velo, data);
+}
+
+void EuphonyDriver::stopSoundEffect(int chan) {
+ _intf->callback(39, chan);
+}
+
+bool EuphonyDriver::soundEffectIsPlaying(int chan) {
+ return _intf->callback(40, chan) ? true : false;
+}
+
+void EuphonyDriver::channelPan(int chan, int mode) {
+ _intf->callback(3, chan, mode);
+}
+
+void EuphonyDriver::channelPitch(int chan, int pitch) {
+ _intf->callback(7, chan, pitch);
+}
+
+void EuphonyDriver::channelVolume(int chan, int vol) {
+ _intf->callback(8, chan, vol);
+}
+
+void EuphonyDriver::setOutputVolume(int mode, int volLeft, int volRight) {
+ _intf->callback(67, mode, volLeft, volRight);
+}
+
+void EuphonyDriver::cdaToggle(int a) {
+ _intf->callback(73, a);
+}
+
+void EuphonyDriver::setMusicVolume(int volume) {
+ _intf->setMusicVolume(volume);
+}
+
+void EuphonyDriver::setSoundEffectVolume(int volume) {
+ _intf->setSoundEffectVolume(volume);
+}
+
+void EuphonyDriver::noteOff() {
+ int8 *chan = &_partToChanMapping[_currentEvent[0] & 0x0f];
if (*chan == -1)
return;
- while (_assignedChannels[*chan].note != _para[0]) {
- chan = &_assignedChannels[*chan].next;
+ while (_channels[*chan].note != _currentEvent[1]) {
+ chan = &_channels[*chan].next;
if (*chan == -1)
return;
}
- if (_sustainChannels[_command & 0x0f]) {
- _assignedChannels[*chan].note |= 0x80;
+ if (_sustainChannels[_currentEvent[0] & 0x0f]) {
+ _channels[*chan].note |= 0x80;
} else {
- _assignedChannels[*chan].note = 0;
+ _channels[*chan].note = 0;
_intf->callback(2, *chan);
}
}
-void TownsEuphonyDriver::sendNoteOn() {
- if (!_para[0])
+void EuphonyDriver::noteOn() {
+ if (!_currentEvent[1])
return;
- int8 *chan = &_activeChannels[_command & 0x0f];
+ int8 *chan = &_partToChanMapping[_currentEvent[0] & 0x0f];
if (*chan == -1)
return;
do {
- _assignedChannels[*chan].sub++;
- chan = &_assignedChannels[*chan].next;
+ _channels[*chan].pri++;
+ chan = &_channels[*chan].next;
} while (*chan != -1);
- chan = &_activeChannels[_command & 0x0f];
+ chan = &_partToChanMapping[_currentEvent[0] & 0x0f];
int d = 0;
int c = 0;
bool found = false;
do {
- if (!_assignedChannels[*chan].note) {
+ if (!_channels[*chan].note) {
found = true;
break;
}
- if (d <= _assignedChannels[*chan].sub) {
+ if (d <= _channels[*chan].pri) {
c = *chan;
- d = _assignedChannels[*chan].sub;
+ d = _channels[*chan].pri;
}
- chan = &_assignedChannels[*chan].next;
+ chan = &_channels[*chan].next;
} while (*chan != -1);
if (found)
@@ -858,59 +899,72 @@ void TownsEuphonyDriver::sendNoteOn() {
else
_intf->callback(2, c);
- _assignedChannels[c].note = _para[0];
- _assignedChannels[c].sub = 0;
- _intf->callback(1, c, _para[0], _para[1]);
+ _channels[c].note = _currentEvent[1];
+ _channels[c].pri = 0;
+ _intf->callback(1, c, _currentEvent[1], _currentEvent[2]);
}
-void TownsEuphonyDriver::sendChanVolume() {
- int8 *chan = &_activeChannels[_command & 0x0f];
+void EuphonyDriver::controlChange_volume() {
+ int8 *chan = &_partToChanMapping[_currentEvent[0] & 0x0f];
while (*chan != -1) {
- _intf->callback(8, *chan, _para[1] & 0x7f);
- chan = &_assignedChannels[*chan].next;
+ _intf->callback(8, *chan, _currentEvent[2] & 0x7f);
+ chan = &_channels[*chan].next;
}
}
-void TownsEuphonyDriver::sendPanPosition() {
- int8 *chan = &_activeChannels[_command & 0x0f];
+void EuphonyDriver::controlChange_panPos() {
+ int8 *chan = &_partToChanMapping[_currentEvent[0] & 0x0f];
while (*chan != -1) {
- _intf->callback(3, *chan, _para[1] & 0x7f);
- chan = &_assignedChannels[*chan].next;
+ _intf->callback(3, *chan, _currentEvent[2] & 0x7f);
+ chan = &_channels[*chan].next;
}
}
-void TownsEuphonyDriver::sendAllNotesOff() {
- if (_para[1] > 63) {
- _sustainChannels[_command & 0x0f] = -1;
+void EuphonyDriver::controlChange_allNotesOff() {
+ if (_currentEvent[2] > 63) {
+ _sustainChannels[_currentEvent[0] & 0x0f] = -1;
return;
}
- _sustainChannels[_command & 0x0f] = 0;
- int8 *chan = &_activeChannels[_command & 0x0f];
+ _sustainChannels[_currentEvent[0] & 0x0f] = 0;
+ int8 *chan = &_partToChanMapping[_currentEvent[0] & 0x0f];
while (*chan != -1) {
- if (_assignedChannels[*chan].note & 0x80) {
- _assignedChannels[*chan].note = 0;
+ if (_channels[*chan].note & 0x80) {
+ _channels[*chan].note = 0;
_intf->callback(2, *chan);
}
- chan = &_assignedChannels[*chan].next;
+ chan = &_channels[*chan].next;
}
}
-void TownsEuphonyDriver::sendSetInstrument() {
- int8 *chan = &_activeChannels[_command & 0x0f];
+void EuphonyDriver::programChange() {
+ int8 *chan = &_partToChanMapping[_currentEvent[0] & 0x0f];
while (*chan != -1) {
- _intf->callback(4, *chan, _para[0]);
+ _intf->callback(4, *chan, _currentEvent[1]);
_intf->callback(7, *chan, 0);
- chan = &_assignedChannels[*chan].next;
+ chan = &_channels[*chan].next;
}
}
-void TownsEuphonyDriver::sendPitch() {
- int8 *chan = &_activeChannels[_command & 0x0f];
+void EuphonyDriver::pitchWheel() {
+ int8 *chan = &_partToChanMapping[_currentEvent[0] & 0x0f];
while (*chan != -1) {
- _para[0] += _para[0];
- int16 pitch = (((READ_LE_UINT16(_para)) >> 1) & 0x3fff) - 0x2000;
+ _currentEvent[1] += _currentEvent[1];
+ int16 pitch = ((((_currentEvent[2] << 8) | _currentEvent[1]) >> 1) & 0x3fff) - 0x2000;
_intf->callback(7, *chan, pitch);
- chan = &_assignedChannels[*chan].next;
+ chan = &_channels[*chan].next;
}
}
+
+Type0Driver::Type0Driver(EuphonyPlayer *pl) : EuphonyBaseDriver() {
+}
+
+Type0Driver::~Type0Driver() {
+}
+
+bool Type0Driver::init() {
+ return true;
+}
+
+void Type0Driver::send(uint8 command) {
+}
diff --git a/audio/softsynth/fmtowns_pc98/towns_euphony.h b/audio/softsynth/fmtowns_pc98/towns_euphony.h
index d77217884d..76aa153a37 100644
--- a/audio/softsynth/fmtowns_pc98/towns_euphony.h
+++ b/audio/softsynth/fmtowns_pc98/towns_euphony.h
@@ -24,160 +24,203 @@
#define TOWNS_EUP_H
#include "audio/softsynth/fmtowns_pc98/towns_audio.h"
+#include "common/array.h"
-class TownsEuphonyDriver : public TownsAudioInterfacePluginDriver {
+class EuphonyBaseDriver {
public:
- TownsEuphonyDriver(Audio::Mixer *mixer);
- virtual ~TownsEuphonyDriver();
+ EuphonyBaseDriver() {}
+ virtual ~EuphonyBaseDriver() {}
+
+ virtual bool init() { return true; }
+
+ virtual void send(uint8 command) = 0;
+};
+
+class EuphonyPlayer;
+
+class EuphonyDriver : public EuphonyBaseDriver {
+public:
+ EuphonyDriver(Audio::Mixer *mixer, EuphonyPlayer *pl);
+ ~EuphonyDriver();
bool init();
void reset();
+ int assignPartToChannel(int chan, int part);
+
+ void send(uint8 command);
+
+ void setTimerA(bool enable, int tempo);
+ void setTimerB(bool enable, int tempo);
+
void loadInstrument(int chanType, int id, const uint8 *data);
+ void setInstrument(int chan, int instrID);
void loadWaveTable(const uint8 *data);
void unloadWaveTable(int id);
- void reserveSoundEffectChannels(int num);
-
- int setMusicTempo(int tempo);
- int startMusicTrack(const uint8 *data, int trackSize, int startTick);
- void setMusicLoop(bool loop);
- void stopParser();
- bool parserIsPlaying() {return _playing; }
- void continueParsing();
+ void reserveSoundEffectChannels(int num);
void playSoundEffect(int chan, int note, int velo, const uint8 *data);
void stopSoundEffect(int chan);
bool soundEffectIsPlaying(int chan);
- void chanPanPos(int chan, int mode);
- void chanPitch(int chan, int pitch);
- void chanVolume(int chan, int vol);
+ void channelPan(int chan, int mode);
+ void channelPitch(int chan, int pitch);
+ void channelVolume(int chan, int vol);
void setOutputVolume(int chanType, int volLeft, int volRight);
+ void cdaToggle(int a);
- int configChan_enable(int tableEntry, int val);
- int configChan_setMode(int tableEntry, int val);
- int configChan_remap(int tableEntry, int val);
- int configChan_adjustVolume(int tableEntry, int val);
- int configChan_setTranspose(int tableEntry, int val);
+ void setMusicVolume(int volume);
+ void setSoundEffectVolume(int volume);
- int assignChannel(int chan, int tableEntry);
+private:
+ void noteOff();
+ void noteOn();
+ void controlChange_volume();
+ void controlChange_panPos();
+ void controlChange_allNotesOff();
+ void programChange();
+ void pitchWheel();
+
+ Common::Array<uint8> _currentEvent;
+ int8 *_partToChanMapping;
+ int8 *_sustainChannels;
- void timerCallback(int timerId);
+ struct Channel {
+ int8 part;
+ int8 next;
+ uint8 note;
+ uint8 pri;
+ } *_channels;
- void setMusicVolume(int volume);
- void setSoundEffectVolume(int volume);
+ TownsAudioInterface *_intf;
+};
- TownsAudioInterface *intf() {
- return _intf;
- }
+class Type0Driver : public EuphonyBaseDriver {
+public:
+ Type0Driver(EuphonyPlayer *pl);
+ ~Type0Driver();
-private:
- void resetTables();
+ bool init();
+
+ void send(uint8 command);
+};
+
+class EuphonyPlayer : public TownsAudioInterfacePluginDriver {
+public:
+ EuphonyPlayer(Audio::Mixer *mixer);
+ virtual ~EuphonyPlayer();
+
+ bool init();
+ int startTrack(const uint8 *data, int trackSize, int barLen);
+ void stop();
+ void pause();
+ void resume();
+
+ int setTempo(int tempo);
+ void setLoopStatus(bool loop);
+
+ bool isPlaying() {return _playing; }
+
+ int configPart_enable(int part, int val);
+ int configPart_setType(int part, int val);
+ int configPart_remap(int part, int val);
+ int configPart_adjustVolume(int part, int val);
+ int configPart_setTranspose(int part, int val);
+
+ void timerCallback(int timerId);
+
+ EuphonyDriver *driver() { return _eupDriver; }
+
+private:
+ void reset();
+ void resetPartConfig();
void resetTempo();
- void setTempoIntern(int tempo);
- void setTimerA(bool enable, int tempo);
- void setTimerB(bool enable, int tempo);
- void updatePulseCount();
- void updateTimeStampBase();
+ void updatePulseCounters();
+ void updateBeat();
void updateParser();
void updateCheckEot();
- bool parseNext();
- void jumpNextLoop();
-
- void updateEventBuffer();
- void flushEventBuffer();
- void processBufferNote(int mode, int evt, int note, int velo);
+ bool parseEvent();
+ void proceedToNextEvent();
- void resetControl();
- void resetControlIntern(int mode, int chan);
+ void updateHangingNotes();
+ void clearHangingNotes();
+
+ void resetAllControls();
+ void allPartsOff();
+
uint8 appendEvent(uint8 evt, uint8 chan);
- void sendEvent(uint8 mode, uint8 command);
-
- typedef bool(TownsEuphonyDriver::*EuphonyOpcode)();
- bool evtSetupNote();
- bool evtPolyphonicAftertouch();
- bool evtControlPitch();
- bool evtInstrumentChanAftertouch();
- bool evtLoadInstrument();
- bool evtAdvanceTimestampOffset();
- bool evtTempo();
- bool evtModeOrdrChange();
- bool evtNotImpl() {
- return false;
- }
+ typedef bool(EuphonyPlayer::*EuphonyEvent)();
+ bool event_notImpl();
+ bool event_noteOn();
+ bool event_polyphonicAftertouch();
+ bool event_controlChange_pitchWheel();
+ bool event_programChange_channelAftertouch();
+
+ bool event_sysex();
+ bool event_advanceBar();
+ bool event_setTempo();
+ bool event_typeOrdrChange();
uint8 applyTranspose(uint8 in);
uint8 applyVolumeAdjust(uint8 in);
- void sendNoteOff();
- void sendNoteOn();
- void sendChanVolume();
- void sendPanPosition();
- void sendAllNotesOff();
- void sendSetInstrument();
- void sendPitch();
+ void sendEvent(uint8 type, uint8 command);
+ void sendNoteEvent(int type, int evt, int note, int velo);
+ void sendControllerReset(int type, int part);
+ void sendAllNotesOff(int type, int part);
+ void sendTempo(int tempo);
- int8 *_activeChannels;
- int8 *_sustainChannels;
+ uint8 *_partConfig_enable;
+ uint8 *_partConfig_type;
+ uint8 *_partConfig_ordr;
+ int8 *_partConfig_volume;
+ int8 *_partConfig_transpose;
- struct ActiveChannel {
- int8 chan;
- int8 next;
- uint8 note;
- uint8 sub;
- } *_assignedChannels;
-
- uint8 *_tEnable;
- uint8 *_tMode;
- uint8 *_tOrdr;
- int8 *_tLevel;
- int8 *_tTranspose;
-
- struct DlEvent {
+ struct SavedEvent {
+ SavedEvent(int ev, int tp, int nt, int vl, int ln, SavedEvent *chain) : evt(ev), type(tp), note(nt), velo(vl), len(ln), next(chain) {}
uint8 evt;
- uint8 mode;
+ uint8 type;
uint8 note;
uint8 velo;
uint16 len;
- } *_eventBuffer;
- int _bufferedEventsCount;
-
- uint8 _para[2];
- uint8 _paraCount;
- uint8 _command;
-
- uint8 _defaultBaseTickLen;
- uint8 _baseTickLen;
- uint32 _pulseCount;
+ SavedEvent *next;
+ };
+
+ SavedEvent *_savedEventsChain;
+
+ uint8 _defaultBarLength;
+ uint8 _barLength;
+ int _playerUpdatesLeft;
int _tempoControlMode;
- int _extraTimingControlRemainder;
- int _extraTimingControl;
+ int _updatesPerPulseRemainder;
+ int _updatesPerPulse;
int _timerSetting;
- int8 _tempoDiff;
+ int8 _tempoMode1PulseCounter;
int _tempoModifier;
- uint32 _timeStampDest;
- uint32 _timeStampBase;
- int8 _elapsedEvents;
+ uint32 _bar;
+ uint32 _parseToBar;
+ int8 _tempoMode1UpdateF8;
uint8 _deltaTicks;
- uint32 _tickCounter;
+ uint32 _beat;
uint8 _defaultTempo;
int _trackTempo;
bool _loop;
bool _playing;
bool _endOfTrack;
- bool _suspendParsing;
+ bool _paused;
const uint8 *_musicStart;
const uint8 *_musicPos;
uint32 _musicTrackSize;
- TownsAudioInterface *_intf;
+ EuphonyDriver *_eupDriver;
+ EuphonyBaseDriver *_drivers[3];
};
#endif
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 b9799db618..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);
@@ -199,10 +195,10 @@ int MidiDriver_MT32::open() {
_initializing = true;
debug(4, _s("Initializing MT-32 Emulator"));
_controlFile = new Common::File();
- if (!_controlFile->open("MT32_CONTROL.ROM") && !_controlFile->open("CM32L_CONTROL.ROM"))
+ if (!_controlFile->open("CM32L_CONTROL.ROM") && !_controlFile->open("MT32_CONTROL.ROM"))
error("Error opening MT32_CONTROL.ROM / CM32L_CONTROL.ROM");
_pcmFile = new Common::File();
- if (!_pcmFile->open("MT32_PCM.ROM") && !_pcmFile->open("CM32L_PCM.ROM"))
+ if (!_pcmFile->open("CM32L_PCM.ROM") && !_pcmFile->open("MT32_PCM.ROM"))
error("Error opening MT32_PCM.ROM / CM32L_PCM.ROM");
_controlROM = MT32Emu::ROMImage::makeROMImage(_controlFile);
_pcmROM = MT32Emu::ROMImage::makeROMImage(_pcmFile);
@@ -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/audio/softsynth/mt32/ROMInfo.cpp b/audio/softsynth/mt32/ROMInfo.cpp
index 7c0127078b..f6817c1a4d 100644
--- a/audio/softsynth/mt32/ROMInfo.cpp
+++ b/audio/softsynth/mt32/ROMInfo.cpp
@@ -54,12 +54,21 @@ static const ROMInfo *getKnownROMInfoFromList(unsigned int index) {
const ROMInfo* ROMInfo::getROMInfo(Common::File *file) {
size_t fileSize = file->size();
+ Common::String fileName = file->getName();
+ fileName.toUppercase();
+ bool isCM32LROM = fileName.hasPrefix("CM32L_");
// We haven't added the SHA1 checksum code in ScummVM, as the file size
- // suffices for our needs for now.
+ // and ROM name suffices for our needs for now.
//const char *fileDigest = file->getSHA1();
for (int i = 0; getKnownROMInfoFromList(i) != NULL; i++) {
const ROMInfo *romInfo = getKnownROMInfoFromList(i);
if (fileSize == romInfo->fileSize /*&& !strcmp(fileDigest, romInfo->sha1Digest)*/) {
+ if (fileSize == 65536) {
+ // If we are looking for a CM-32L ROM, make sure we return the first matching
+ // CM-32L ROM from the list, instead of the first matching MT-32 ROM
+ if (isCM32LROM && romInfo->controlROMFeatures->isDefaultReverbMT32Compatible())
+ continue;
+ }
return romInfo;
}
}
diff --git a/audio/softsynth/opl/mame.cpp b/audio/softsynth/opl/mame.cpp
index 696169be09..eb08582da0 100644
--- a/audio/softsynth/opl/mame.cpp
+++ b/audio/softsynth/opl/mame.cpp
@@ -97,8 +97,8 @@ void OPL::generateSamples(int16 *buffer, int length) {
/* final output shift , limit minimum and maximum */
#define OPL_OUTSB (TL_BITS+3-16) /* OPL output final shift 16bit */
-#define OPL_MAXOUT (0x7fff<<OPL_OUTSB)
-#define OPL_MINOUT (-0x8000<<OPL_OUTSB)
+#define OPL_MAXOUT (0x7fff<<OPL_OUTSB)
+#define OPL_MINOUT (-(0x8000<<OPL_OUTSB))
/* -------------------- quality selection --------------------- */
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 c7b089af09..3558fb5671 100644
--- a/backends/audiocd/sdl/sdl-audiocd.cpp
+++ b/backends/audiocd/sdl/sdl-audiocd.cpp
@@ -26,7 +26,7 @@
#include "backends/audiocd/sdl/sdl-audiocd.h"
-#if !SDL_VERSION_ATLEAST(1, 3, 0)
+#if !SDL_VERSION_ATLEAST(2, 0, 0)
#include "common/textconsole.h"
@@ -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;
@@ -136,6 +167,6 @@ void SdlAudioCDManager::updateCD() {
}
}
-#endif // !SDL_VERSION_ATLEAST(1, 3, 0)
+#endif // !SDL_VERSION_ATLEAST(2, 0, 0)
#endif
diff --git a/backends/audiocd/sdl/sdl-audiocd.h b/backends/audiocd/sdl/sdl-audiocd.h
index 783d4fe0f0..91895dac99 100644
--- a/backends/audiocd/sdl/sdl-audiocd.h
+++ b/backends/audiocd/sdl/sdl-audiocd.h
@@ -27,7 +27,7 @@
#include "backends/platform/sdl/sdl-sys.h"
-#if !SDL_VERSION_ATLEAST(1, 3, 0)
+#if !SDL_VERSION_ATLEAST(2, 0, 0)
/**
* The SDL audio cd manager. Implements real audio cd playback.
@@ -37,18 +37,21 @@ 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;
uint32 _cdEndTime, _cdStopTime;
};
-#endif // !SDL_VERSION_ATLEAST(1, 3, 0)
+#endif // !SDL_VERSION_ATLEAST(2, 0, 0)
#endif
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/dinguxsdl/dinguxsdl-events.cpp b/backends/events/dinguxsdl/dinguxsdl-events.cpp
index cc15f2666c..0492c569e1 100644
--- a/backends/events/dinguxsdl/dinguxsdl-events.cpp
+++ b/backends/events/dinguxsdl/dinguxsdl-events.cpp
@@ -175,7 +175,10 @@ bool DINGUXSdlEventSource::remapKey(SDL_Event &ev, Common::Event &event) {
return true;
} else if (ev.key.keysym.sym == BUT_SELECT) { // virtual keyboard
#ifdef ENABLE_VKEYBD
- event.type = Common::EVENT_VIRTUAL_KEYBOARD;
+ if (ev.type == SDL_KEYDOWN)
+ event.type = Common::EVENT_VIRTUAL_KEYBOARD;
+
+ return true;
#endif
} else if (ev.key.keysym.sym == BUT_START) { // F5, menu in some games
ev.key.keysym.sym = SDLK_F5;
diff --git a/backends/events/ps3sdl/ps3sdl-events.cpp b/backends/events/ps3sdl/ps3sdl-events.cpp
index 0f6e01857b..1fc10559c2 100644
--- a/backends/events/ps3sdl/ps3sdl-events.cpp
+++ b/backends/events/ps3sdl/ps3sdl-events.cpp
@@ -126,8 +126,8 @@ bool PS3SdlEventSource::handleJoyButtonUp(SDL_Event &ev, Common::Event &event) {
* This pauses execution and keeps redrawing the screen until the XMB is closed.
*/
void PS3SdlEventSource::preprocessEvents(SDL_Event *event) {
- if (event->type == SDL_ACTIVEEVENT) {
- if (event->active.state == SDL_APPMOUSEFOCUS && !event->active.gain) {
+ if (event->type == SDL_WINDOWEVENT) {
+ if (event->window.event == SDL_WINDOWEVENT_LEAVE) {
// XMB opened
if (g_engine)
g_engine->pauseEngine(true);
@@ -145,9 +145,9 @@ void PS3SdlEventSource::preprocessEvents(SDL_Event *event) {
}
if (event->type == SDL_QUIT)
return;
- if (event->type != SDL_ACTIVEEVENT)
+ if (event->type != SDL_WINDOWEVENT)
continue;
- if (event->active.state == SDL_APPMOUSEFOCUS && event->active.gain) {
+ if (event->window.event == SDL_WINDOWEVENT_ENTER) {
// XMB closed
if (g_engine)
g_engine->pauseEngine(false);
diff --git a/backends/events/sdl/sdl-events.cpp b/backends/events/sdl/sdl-events.cpp
index 1e5119dbec..acc1ff5dce 100644
--- a/backends/events/sdl/sdl-events.cpp
+++ b/backends/events/sdl/sdl-events.cpp
@@ -111,7 +111,7 @@ int SdlEventSource::mapKey(SDLKey sdlKey, SDLMod mod, Uint16 unicode) {
Common::KeyCode key = SDLToOSystemKeycode(sdlKey);
if (key >= Common::KEYCODE_F1 && key <= Common::KEYCODE_F9) {
- return key - SDLK_F1 + Common::ASCII_F1;
+ return key - Common::KEYCODE_F1 + Common::ASCII_F1;
} else if (key >= Common::KEYCODE_KP0 && key <= Common::KEYCODE_KP9) {
return key - Common::KEYCODE_KP0 + '0';
} else if (key >= Common::KEYCODE_UP && key <= Common::KEYCODE_PAGEDOWN) {
@@ -314,7 +314,7 @@ Common::KeyCode SdlEventSource::SDLToOSystemKeycode(const SDLKey key) {
case SDLK_y: return Common::KEYCODE_y;
case SDLK_z: return Common::KEYCODE_z;
case SDLK_DELETE: return Common::KEYCODE_DELETE;
-#if SDL_VERSION_ATLEAST(1, 3, 0)
+#if SDL_VERSION_ATLEAST(2, 0, 0)
case SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_GRAVE): return Common::KEYCODE_TILDE;
#else
case SDLK_WORLD_16: return Common::KEYCODE_TILDE;
@@ -517,15 +517,17 @@ bool SdlEventSource::handleKeyDown(SDL_Event &ev, Common::Event &event) {
SDLModToOSystemKeyFlags(SDL_GetModState(), event);
+ SDLKey sdlKeycode = obtainKeycode(ev.key.keysym);
+
// Handle scroll lock as a key modifier
- if (ev.key.keysym.sym == SDLK_SCROLLOCK)
+ if (sdlKeycode == SDLK_SCROLLOCK)
_scrollLock = !_scrollLock;
if (_scrollLock)
event.kbd.flags |= Common::KBD_SCRL;
// Ctrl-m toggles mouse capture
- if (event.kbd.hasFlags(Common::KBD_CTRL) && ev.key.keysym.sym == 'm') {
+ if (event.kbd.hasFlags(Common::KBD_CTRL) && sdlKeycode == 'm') {
if (_graphicsManager) {
_graphicsManager->getWindow()->toggleMouseGrab();
}
@@ -534,26 +536,26 @@ bool SdlEventSource::handleKeyDown(SDL_Event &ev, Common::Event &event) {
#if defined(MACOSX)
// On Macintosh, Cmd-Q quits
- if ((ev.key.keysym.mod & KMOD_META) && ev.key.keysym.sym == 'q') {
+ if ((ev.key.keysym.mod & KMOD_META) && sdlKeycode == 'q') {
event.type = Common::EVENT_QUIT;
return true;
}
#elif defined(POSIX)
// On other *nix systems, Control-Q quits
- if ((ev.key.keysym.mod & KMOD_CTRL) && ev.key.keysym.sym == 'q') {
+ if ((ev.key.keysym.mod & KMOD_CTRL) && sdlKeycode == 'q') {
event.type = Common::EVENT_QUIT;
return true;
}
#else
- // Ctrl-z and Alt-X quit
- if ((event.kbd.hasFlags(Common::KBD_CTRL) && ev.key.keysym.sym == 'z') || (event.kbd.hasFlags(Common::KBD_ALT) && ev.key.keysym.sym == 'x')) {
+ // Ctrl-z quits
+ if ((event.kbd.hasFlags(Common::KBD_CTRL) && sdlKeycode == 'z')) {
event.type = Common::EVENT_QUIT;
return true;
}
#ifdef WIN32
// On Windows, also use the default Alt-F4 quit combination
- if ((ev.key.keysym.mod & KMOD_ALT) && ev.key.keysym.sym == SDLK_F4) {
+ if ((ev.key.keysym.mod & KMOD_ALT) && sdlKeycode == SDLK_F4) {
event.type = Common::EVENT_QUIT;
return true;
}
@@ -561,7 +563,7 @@ bool SdlEventSource::handleKeyDown(SDL_Event &ev, Common::Event &event) {
#endif
// Ctrl-u toggles mute
- if ((ev.key.keysym.mod & KMOD_CTRL) && ev.key.keysym.sym == 'u') {
+ if ((ev.key.keysym.mod & KMOD_CTRL) && sdlKeycode == 'u') {
event.type = Common::EVENT_MUTE;
return true;
}
@@ -570,8 +572,8 @@ bool SdlEventSource::handleKeyDown(SDL_Event &ev, Common::Event &event) {
return true;
event.type = Common::EVENT_KEYDOWN;
- event.kbd.keycode = SDLToOSystemKeycode(ev.key.keysym.sym);
- event.kbd.ascii = mapKey(ev.key.keysym.sym, (SDLMod)ev.key.keysym.mod, obtainUnicode(ev.key.keysym));
+ event.kbd.keycode = SDLToOSystemKeycode(sdlKeycode);
+ event.kbd.ascii = mapKey(sdlKeycode, (SDLMod)ev.key.keysym.mod, obtainUnicode(ev.key.keysym));
return true;
}
@@ -580,6 +582,7 @@ bool SdlEventSource::handleKeyUp(SDL_Event &ev, Common::Event &event) {
if (remapKey(ev, event))
return true;
+ SDLKey sdlKeycode = obtainKeycode(ev.key.keysym);
SDLMod mod = SDL_GetModState();
// Check if this is an event handled by handleKeyDown(), and stop if it is
@@ -587,35 +590,30 @@ bool SdlEventSource::handleKeyUp(SDL_Event &ev, Common::Event &event) {
// Check if the Ctrl key is down, so that we can trap cases where the
// user has the Ctrl key down, and has just released a special key
if (mod & KMOD_CTRL) {
- if (ev.key.keysym.sym == 'm' || // Ctrl-m toggles mouse capture
+ if (sdlKeycode == 'm' || // Ctrl-m toggles mouse capture
#if defined(MACOSX)
// Meta - Q, handled below
#elif defined(POSIX)
- ev.key.keysym.sym == 'q' || // On other *nix systems, Control-Q quits
+ sdlKeycode == 'q' || // On other *nix systems, Control-Q quits
#else
- ev.key.keysym.sym == 'z' || // Ctrl-z quit
+ sdlKeycode == 'z' || // Ctrl-z quit
#endif
- ev.key.keysym.sym == 'u') // Ctrl-u toggles mute
+ sdlKeycode == 'u') // Ctrl-u toggles mute
return false;
}
// Same for other keys (Meta and Alt)
#if defined(MACOSX)
- if ((mod & KMOD_META) && ev.key.keysym.sym == 'q')
+ if ((mod & KMOD_META) && sdlKeycode == 'q')
return false; // On Macintosh, Cmd-Q quits
-#elif defined(POSIX)
- // Control Q has already been handled above
-#else
- if ((mod & KMOD_ALT) && ev.key.keysym.sym == 'x')
- return false; // Alt-x quit
#endif
// If we reached here, this isn't an event handled by handleKeyDown(), thus
// continue normally
event.type = Common::EVENT_KEYUP;
- event.kbd.keycode = SDLToOSystemKeycode(ev.key.keysym.sym);
- event.kbd.ascii = mapKey(ev.key.keysym.sym, (SDLMod)ev.key.keysym.mod, 0);
+ event.kbd.keycode = SDLToOSystemKeycode(sdlKeycode);
+ event.kbd.ascii = mapKey(sdlKeycode, (SDLMod)ev.key.keysym.mod, 0);
// Ctrl-Alt-<key> will change the GFX mode
SDLModToOSystemKeyFlags(mod, event);
@@ -737,16 +735,16 @@ bool SdlEventSource::handleJoyButtonUp(SDL_Event &ev, Common::Event &event) {
bool SdlEventSource::handleJoyAxisMotion(SDL_Event &ev, Common::Event &event) {
int axis = ev.jaxis.value;
- if ( axis > JOY_DEADZONE) {
+ if (axis > JOY_DEADZONE) {
axis -= JOY_DEADZONE;
event.type = Common::EVENT_MOUSEMOVE;
- } else if ( axis < -JOY_DEADZONE ) {
+ } else if (axis < -JOY_DEADZONE) {
axis += JOY_DEADZONE;
event.type = Common::EVENT_MOUSEMOVE;
} else
axis = 0;
- if ( ev.jaxis.axis == JOY_XAXIS) {
+ if (ev.jaxis.axis == JOY_XAXIS) {
#ifdef JOY_ANALOG
_km.x_vel = axis / 2000;
_km.x_down_count = 0;
@@ -759,7 +757,6 @@ bool SdlEventSource::handleJoyAxisMotion(SDL_Event &ev, Common::Event &event) {
_km.x_down_count = 0;
}
#endif
-
} else if (ev.jaxis.axis == JOY_YAXIS) {
#ifndef JOY_INVERT_Y
axis = -axis;
@@ -874,10 +871,63 @@ bool SdlEventSource::handleResizeEvent(Common::Event &event, int w, int h) {
return false;
}
+SDLKey SdlEventSource::obtainKeycode(const SDL_keysym keySym) {
+#if !SDL_VERSION_ATLEAST(2, 0, 0) && defined(WIN32) && !defined(_WIN32_WCE)
+ // WORKAROUND: SDL 1.2 on Windows does not use the user configured keyboard layout,
+ // resulting in "keySym.sym" values to always be those expected for an US keyboard.
+ // For example, SDL returns SDLK_Q when pressing the 'A' key on an AZERTY keyboard.
+ // This defeats the purpose of keycodes which is to be able to refer to a key without
+ // knowing where it is physically located.
+ // We work around this issue by querying the currently active Windows keyboard layout
+ // using the scancode provided by SDL.
+
+ if (keySym.sym >= SDLK_0 && keySym.sym <= SDLK_9) {
+ // The keycode returned by SDL is kept for the number keys.
+ // Querying the keyboard layout for those would return the base key values
+ // for AZERTY keyboards, which are not numbers. For example, SDLK_1 would
+ // map to SDLK_AMPERSAND. This is theoretically correct but practically unhelpful,
+ // because it makes it impossible to handle key combinations such as "ctrl-1".
+ return keySym.sym;
+ }
+
+ int vk = MapVirtualKey(keySym.scancode, MAPVK_VSC_TO_VK);
+ if (vk) {
+ int ch = (MapVirtualKey(vk, MAPVK_VK_TO_CHAR) & 0x7FFF);
+ // The top bit of the result of MapVirtualKey with MAPVK_VSC_TO_VK signals
+ // a dead key was pressed. In that case we keep the value of the accent alone.
+ if (ch) {
+ if (ch >= 'A' && ch <= 'Z') {
+ // Windows returns uppercase ASCII whereas SDL expects lowercase
+ return (SDLKey)(SDLK_a + (ch - 'A'));
+ } else {
+ return (SDLKey)ch;
+ }
+ }
+ }
+#endif
+
+ return keySym.sym;
+}
+
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/events/sdl/sdl-events.h b/backends/events/sdl/sdl-events.h
index caa60c1354..7e590aed3c 100644
--- a/backends/events/sdl/sdl-events.h
+++ b/backends/events/sdl/sdl-events.h
@@ -148,6 +148,11 @@ protected:
*/
uint32 obtainUnicode(const SDL_keysym keySym);
+ /**
+ * Extracts the keycode for the specified key sym.
+ */
+ SDLKey obtainKeycode(const SDL_keysym keySym);
+
#if SDL_VERSION_ATLEAST(2, 0, 0)
/**
* Whether _fakeKeyUp contains an event we need to send.
diff --git a/backends/fs/abstract-fs.h b/backends/fs/abstract-fs.h
index 34a8120caa..dcfdc08975 100644
--- a/backends/fs/abstract-fs.h
+++ b/backends/fs/abstract-fs.h
@@ -84,6 +84,20 @@ protected:
public:
/**
+ * Construct a FSNode object from an AbstractFSNode object.
+ *
+ * This is a helper to create Common::FSNode objects when the backend's
+ * FileSystemFactory cannot create the given AbstractFSNode object itself.
+ * All other code is supposed to use Common::FSNode's constructor itself.
+ *
+ * @param realNode Pointer to a heap allocated instance. FSNode will take
+ * ownership of the pointer.
+ */
+ static Common::FSNode makeFSNode(AbstractFSNode *realNode) {
+ return Common::FSNode(realNode);
+ }
+
+ /**
* Destructor.
*/
virtual ~AbstractFSNode() {}
diff --git a/backends/fs/chroot/chroot-fs-factory.cpp b/backends/fs/chroot/chroot-fs-factory.cpp
new file mode 100644
index 0000000000..db5655ffce
--- /dev/null
+++ b/backends/fs/chroot/chroot-fs-factory.cpp
@@ -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.
+ *
+ */
+
+#if defined(POSIX)
+
+#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
+#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h
+#define FORBIDDEN_SYMBOL_EXCEPTION_mkdir
+#define FORBIDDEN_SYMBOL_EXCEPTION_exit //Needed for IRIX's unistd.h
+
+#include "backends/fs/chroot/chroot-fs-factory.h"
+#include "backends/fs/chroot/chroot-fs.h"
+
+ChRootFilesystemFactory::ChRootFilesystemFactory(const Common::String &root)
+ : _root(root) {
+}
+
+AbstractFSNode *ChRootFilesystemFactory::makeRootFileNode() const {
+ return new ChRootFilesystemNode(_root, "/");
+}
+
+AbstractFSNode *ChRootFilesystemFactory::makeCurrentDirectoryFileNode() const {
+ char buf[MAXPATHLEN];
+ if (getcwd(buf, MAXPATHLEN) == NULL) {
+ return NULL;
+ }
+
+ if (Common::String(buf).hasPrefix(_root + Common::String("/"))) {
+ return new ChRootFilesystemNode(_root, buf + _root.size());
+ }
+
+ return new ChRootFilesystemNode(_root, "/");
+}
+
+AbstractFSNode *ChRootFilesystemFactory::makeFileNodePath(const Common::String &path) const {
+ assert(!path.empty());
+ return new ChRootFilesystemNode(_root, path);
+}
+
+#endif
diff --git a/backends/fs/chroot/chroot-fs-factory.h b/backends/fs/chroot/chroot-fs-factory.h
new file mode 100644
index 0000000000..d53e5af398
--- /dev/null
+++ b/backends/fs/chroot/chroot-fs-factory.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_FS_CHROOT_CHROOT_FS_FACTORY_H
+#define BACKENDS_FS_CHROOT_CHROOT_FS_FACTORY_H
+
+#include "backends/fs/fs-factory.h"
+
+/**
+ * FIXME: Warning, using this factory in your backend may silently break some
+ * features. Instances are, for example, the FluidSynth code, and the POSIX
+ * plugin code.
+ */
+class ChRootFilesystemFactory : public FilesystemFactory {
+public:
+ explicit ChRootFilesystemFactory(const Common::String &root);
+
+ virtual AbstractFSNode *makeRootFileNode() const;
+ virtual AbstractFSNode *makeCurrentDirectoryFileNode() const;
+ virtual AbstractFSNode *makeFileNodePath(const Common::String &path) const;
+
+private:
+ const Common::String _root;
+};
+
+#endif /* BACKENDS_FS_CHROOT_CHROOT_FS_FACTORY_H */
diff --git a/backends/fs/chroot/chroot-fs.cpp b/backends/fs/chroot/chroot-fs.cpp
new file mode 100644
index 0000000000..2cbb4af9d6
--- /dev/null
+++ b/backends/fs/chroot/chroot-fs.cpp
@@ -0,0 +1,124 @@
+/* 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(POSIX)
+
+// Re-enable some forbidden symbols to avoid clashes with stat.h and unistd.h.
+// Also with clock() in sys/time.h in some Mac OS X SDKs.
+#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
+#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h
+#define FORBIDDEN_SYMBOL_EXCEPTION_mkdir
+#define FORBIDDEN_SYMBOL_EXCEPTION_getenv
+#define FORBIDDEN_SYMBOL_EXCEPTION_exit //Needed for IRIX's unistd.h
+
+#include "backends/fs/chroot/chroot-fs.h"
+
+ChRootFilesystemNode::ChRootFilesystemNode(const Common::String &root, POSIXFilesystemNode *node) {
+ _root = Common::normalizePath(root, '/');
+ _realNode = node;
+}
+
+ChRootFilesystemNode::ChRootFilesystemNode(const Common::String &root, const Common::String &path) {
+ _root = Common::normalizePath(root, '/');
+ _realNode = new POSIXFilesystemNode(addPathComponent(root, path));
+}
+
+ChRootFilesystemNode::~ChRootFilesystemNode() {
+ delete _realNode;
+}
+
+bool ChRootFilesystemNode::exists() const {
+ return _realNode->exists();
+}
+
+Common::String ChRootFilesystemNode::getDisplayName() const {
+ return getName();
+}
+
+Common::String ChRootFilesystemNode::getName() const {
+ return _realNode->AbstractFSNode::getDisplayName();
+}
+
+Common::String ChRootFilesystemNode::getPath() const {
+ Common::String path = _realNode->getPath();
+ if (path.size() > _root.size()) {
+ return Common::String(path.c_str() + _root.size());
+ }
+ return Common::String("/");
+}
+
+bool ChRootFilesystemNode::isDirectory() const {
+ return _realNode->isDirectory();
+}
+
+bool ChRootFilesystemNode::isReadable() const {
+ return _realNode->isReadable();
+}
+
+bool ChRootFilesystemNode::isWritable() const {
+ return _realNode->isWritable();
+}
+
+AbstractFSNode *ChRootFilesystemNode::getChild(const Common::String &n) const {
+ return new ChRootFilesystemNode(_root, (POSIXFilesystemNode *)_realNode->getChild(n));
+}
+
+bool ChRootFilesystemNode::getChildren(AbstractFSList &list, ListMode mode, bool hidden) const {
+ AbstractFSList tmp;
+ if (!_realNode->getChildren(tmp, mode, hidden)) {
+ return false;
+ }
+
+ for (AbstractFSList::iterator i=tmp.begin(); i!=tmp.end(); ++i) {
+ list.push_back(new ChRootFilesystemNode(_root, (POSIXFilesystemNode *) *i));
+ }
+
+ return true;
+}
+
+AbstractFSNode *ChRootFilesystemNode::getParent() const {
+ if (getPath() == "/") return 0;
+ return new ChRootFilesystemNode(_root, (POSIXFilesystemNode *)_realNode->getParent());
+}
+
+Common::SeekableReadStream *ChRootFilesystemNode::createReadStream() {
+ return _realNode->createReadStream();
+}
+
+Common::WriteStream *ChRootFilesystemNode::createWriteStream() {
+ return _realNode->createWriteStream();
+}
+
+Common::String ChRootFilesystemNode::addPathComponent(const Common::String &path, const Common::String &component) {
+ const char sep = '/';
+ if (path.lastChar() == sep && component.firstChar() == sep) {
+ return Common::String::format("%s%s", path.c_str(), component.c_str() + 1);
+ }
+
+ if (path.lastChar() == sep || component.firstChar() == sep) {
+ return Common::String::format("%s%s", path.c_str(), component.c_str());
+ }
+
+ return Common::String::format("%s%c%s", path.c_str(), sep, component.c_str());
+}
+
+#endif
diff --git a/backends/fs/chroot/chroot-fs.h b/backends/fs/chroot/chroot-fs.h
new file mode 100644
index 0000000000..9ff913be31
--- /dev/null
+++ b/backends/fs/chroot/chroot-fs.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 BACKENDS_FS_CHROOT_CHROOT_FS_H
+#define BACKENDS_FS_CHROOT_CHROOT_FS_H
+
+#include "backends/fs/posix/posix-fs.h"
+
+class ChRootFilesystemNode : public AbstractFSNode {
+ Common::String _root;
+ POSIXFilesystemNode *_realNode;
+
+ ChRootFilesystemNode(const Common::String &root, POSIXFilesystemNode *);
+
+public:
+ ChRootFilesystemNode(const Common::String &root, const Common::String &path);
+ virtual ~ChRootFilesystemNode();
+
+ virtual bool exists() const;
+ virtual Common::String getDisplayName() const;
+ virtual Common::String getName() const;
+ virtual Common::String getPath() const;
+ virtual bool isDirectory() const;
+ virtual bool isReadable() const;
+ virtual bool isWritable() const;
+
+ virtual AbstractFSNode *getChild(const Common::String &n) const;
+ virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const;
+ virtual AbstractFSNode *getParent() const;
+
+ virtual Common::SeekableReadStream *createReadStream();
+ virtual Common::WriteStream *createWriteStream();
+
+private:
+ static Common::String addPathComponent(const Common::String &path, const Common::String &component);
+};
+
+#endif /* BACKENDS_FS_CHROOT_CHROOT_FS_H */
diff --git a/backends/fs/posix/posix-fs.cpp b/backends/fs/posix/posix-fs.cpp
index 4baf9f14fe..1a6c4e40a5 100644
--- a/backends/fs/posix/posix-fs.cpp
+++ b/backends/fs/posix/posix-fs.cpp
@@ -38,6 +38,7 @@
#include <sys/stat.h>
#include <dirent.h>
#include <stdio.h>
+#include <errno.h>
#ifdef __OS2__
#define INCL_DOS
@@ -251,4 +252,67 @@ Common::WriteStream *POSIXFilesystemNode::createWriteStream() {
return StdioStream::makeFromPath(getPath(), true);
}
+namespace Posix {
+
+bool assureDirectoryExists(const Common::String &dir, const char *prefix) {
+ struct stat sb;
+
+ // Check whether the prefix exists if one is supplied.
+ if (prefix) {
+ if (stat(prefix, &sb) != 0) {
+ return false;
+ } else if (!S_ISDIR(sb.st_mode)) {
+ return false;
+ }
+ }
+
+ // Obtain absolute path.
+ Common::String path;
+ if (prefix) {
+ path = prefix;
+ path += '/';
+ path += dir;
+ } else {
+ path = dir;
+ }
+
+ path = Common::normalizePath(path, '/');
+
+ const Common::String::iterator end = path.end();
+ Common::String::iterator cur = path.begin();
+ if (*cur == '/')
+ ++cur;
+
+ do {
+ if (cur + 1 != end) {
+ if (*cur != '/') {
+ continue;
+ }
+
+ // It is kind of ugly and against the purpose of Common::String to
+ // insert 0s inside, but this is just for a local string and
+ // simplifies the code a lot.
+ *cur = '\0';
+ }
+
+ if (mkdir(path.c_str(), 0755) != 0) {
+ if (errno == EEXIST) {
+ if (stat(path.c_str(), &sb) != 0) {
+ return false;
+ } else if (!S_ISDIR(sb.st_mode)) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ *cur = '/';
+ } while (cur++ != end);
+
+ return true;
+}
+
+} // End of namespace Posix
+
#endif //#if defined(POSIX)
diff --git a/backends/fs/posix/posix-fs.h b/backends/fs/posix/posix-fs.h
index bd07749010..0703ac5bf5 100644
--- a/backends/fs/posix/posix-fs.h
+++ b/backends/fs/posix/posix-fs.h
@@ -81,4 +81,18 @@ private:
virtual void setFlags();
};
+namespace Posix {
+
+/**
+ * Assure that a directory path exists.
+ *
+ * @param dir The path which is required to exist.
+ * @param prefix An (optional) prefix which should not be created if non existent.
+ * prefix is prepended to dir if supplied.
+ * @return true in case the directoy exists (or was created), false otherwise.
+ */
+bool assureDirectoryExists(const Common::String &dir, const char *prefix = nullptr);
+
+} // End of namespace Posix
+
#endif
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 5821856c30..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,18 +47,21 @@ 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),
_overlayVisible(false), _cursor(nullptr),
_cursorX(0), _cursorY(0), _cursorDisplayX(0),_cursorDisplayY(0), _cursorHotspotX(0), _cursorHotspotY(0),
_cursorHotspotXScaled(0), _cursorHotspotYScaled(0), _cursorWidthScaled(0), _cursorHeightScaled(0),
- _cursorKeyColor(0), _cursorVisible(false), _cursorDontScale(false), _cursorPaletteEnabled(false)
+ _cursorKeyColor(0), _cursorVisible(false), _cursorDontScale(false), _cursorPaletteEnabled(false),
+ _forceRedraw(false), _scissorOverride(3)
#ifdef USE_OSD
, _osdAlpha(0), _osdFadeStartTime(0), _osd(nullptr)
#endif
{
memset(_gamePalette, 0, sizeof(_gamePalette));
+ g_context.reset();
}
OpenGLGraphicsManager::~OpenGLGraphicsManager() {
@@ -66,6 +71,9 @@ OpenGLGraphicsManager::~OpenGLGraphicsManager() {
#ifdef USE_OSD
delete _osd;
#endif
+#if !USE_FORCED_GLES
+ ShaderManager::destroy();
+#endif
}
bool OpenGLGraphicsManager::hasFeature(OSystem::Feature f) {
@@ -214,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.
@@ -266,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()) {
@@ -343,7 +351,10 @@ void OpenGLGraphicsManager::fillScreen(uint32 col) {
}
void OpenGLGraphicsManager::setShakePos(int shakeOffset) {
- _gameScreenShakeOffset = shakeOffset;
+ if (_gameScreenShakeOffset != shakeOffset) {
+ _gameScreenShakeOffset = shakeOffset;
+ _forceRedraw = true;
+ }
}
void OpenGLGraphicsManager::updateScreen() {
@@ -351,17 +362,47 @@ void OpenGLGraphicsManager::updateScreen() {
return;
}
+ // We only update the screen when there actually have been any changes.
+ if ( !_forceRedraw
+ && !_gameScreen->isDirty()
+ && !(_overlayVisible && _overlay->isDirty())
+ && !(_cursorVisible && _cursor && _cursor->isDirty())
+ && _osdAlpha == 0) {
+ return;
+ }
+ _forceRedraw = false;
+
+ // Update changes to textures.
+ _gameScreen->updateGLTexture();
+ if (_cursor) {
+ _cursor->updateGLTexture();
+ }
+ _overlay->updateGLTexture();
+ _osd->updateGLTexture();
+
// Clear the screen buffer.
- GLCALL(glClear(GL_COLOR_BUFFER_BIT));
+ 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.
+ _backBuffer.enableScissorTest(false);
+ GL_CALL(glClear(GL_COLOR_BUFFER_BIT));
+ _backBuffer.enableScissorTest(true);
+
+ --_scissorOverride;
+ } else {
+ 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.
@@ -370,42 +411,14 @@ void OpenGLGraphicsManager::updateScreen() {
// visible.
const GLfloat cursorOffset = _overlayVisible ? 0 : shakeOffset;
- _cursor->draw(_cursorDisplayX - _cursorHotspotXScaled,
- _cursorDisplayY - _cursorHotspotYScaled + cursorOffset,
- _cursorWidthScaled, _cursorHeightScaled);
- }
-
- // Fourth step: Draw black borders around the game screen when no overlay
- // is visible. This makes sure that the mouse cursor etc. is only drawn
- // in the actual game screen area in this case.
- if (!_overlayVisible) {
- GLCALL(glColor4f(0.0f, 0.0f, 0.0f, 1.0f));
-
- GLCALL(glDisable(GL_TEXTURE_2D));
- GLCALL(glDisableClientState(GL_TEXTURE_COORD_ARRAY));
-
- // Top border.
- drawRect(0, 0, _outputScreenWidth, _displayY);
-
- // Left border.
- drawRect(0, 0, _displayX, _outputScreenHeight);
-
- // Bottom border.
- const int y = _displayY + _displayHeight;
- drawRect(0, y, _outputScreenWidth, _outputScreenHeight - y);
-
- // Right border.
- const int x = _displayX + _displayWidth;
- drawRect(x, 0, _outputScreenWidth - x, _outputScreenHeight);
-
- GLCALL(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
- GLCALL(glEnable(GL_TEXTURE_2D));
-
- GLCALL(glColor4f(1.0f, 1.0f, 1.0f, 1.0f));
+ g_context.getActivePipeline()->drawTexture(_cursor->getGLTexture(),
+ _cursorDisplayX - _cursorHotspotXScaled,
+ _cursorDisplayY - _cursorHotspotYScaled + cursorOffset,
+ _cursorWidthScaled, _cursorHeightScaled);
}
#ifdef USE_OSD
- // Fifth step: Draw the OSD.
+ // Fourth step: Draw the OSD.
if (_osdAlpha > 0) {
Common::StackLock lock(_osdMutex);
@@ -422,15 +435,17 @@ 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
+
+ refreshScreen();
}
Graphics::Surface *OpenGLGraphicsManager::lockScreen() {
@@ -465,6 +480,10 @@ int16 OpenGLGraphicsManager::getOverlayHeight() {
void OpenGLGraphicsManager::showOverlay() {
_overlayVisible = true;
+ _forceRedraw = true;
+
+ // Allow drawing inside full screen area.
+ _backBuffer.enableScissorTest(false);
// Update cursor position.
setMousePosition(_cursorX, _cursorY);
@@ -472,6 +491,11 @@ void OpenGLGraphicsManager::showOverlay() {
void OpenGLGraphicsManager::hideOverlay() {
_overlayVisible = false;
+ _forceRedraw = true;
+
+ // Limit drawing to screen area.
+ _backBuffer.enableScissorTest(true);
+ _scissorOverride = 3;
// Update cursor position.
setMousePosition(_cursorX, _cursorY);
@@ -503,6 +527,12 @@ void OpenGLGraphicsManager::grabOverlay(void *buf, int pitch) {
}
bool OpenGLGraphicsManager::showMouse(bool visible) {
+ // In case the mouse cursor visibility changed we need to redraw the whole
+ // screen even when nothing else changed.
+ if (_cursorVisible != visible) {
+ _forceRedraw = true;
+ }
+
bool last = _cursorVisible;
_cursorVisible = visible;
return last;
@@ -537,11 +567,8 @@ void OpenGLGraphicsManager::warpMouse(int x, int y) {
return;
}
- x = (x * _displayWidth) / _gameScreen->getWidth();
- y = (y * _displayHeight) / _gameScreen->getHeight();
-
- x += _displayX;
- y += _displayY;
+ x = (x * _outputScreenWidth) / _gameScreen->getWidth();
+ y = (y * _outputScreenHeight) / _gameScreen->getHeight();
}
setMousePosition(x, y);
@@ -598,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);
}
@@ -744,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;
@@ -766,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);
}
}
@@ -790,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
@@ -805,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
@@ -825,39 +842,56 @@ 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();
+
+ // Initialize pipeline.
+ delete _pipeline;
+ _pipeline = nullptr;
+
+#if !USE_FORCED_GLES
+ if (g_context.shadersSupported) {
+ ShaderMan.notifyCreate();
+ _pipeline = new ShaderPipeline(ShaderMan.query(ShaderManager::kDefault));
+ }
+#endif
+
+#if !USE_FORCED_GLES2
+ if (_pipeline == nullptr) {
+ _pipeline = new FixedPipeline();
+ }
+#endif
+
+ g_context.setPipeline(_pipeline);
// 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));
+ GL_CALL(glDisable(GL_CULL_FACE));
+ GL_CALL(glDisable(GL_DEPTH_TEST));
+ GL_CALL(glDisable(GL_DITHER));
- // 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));
+ g_context.getActivePipeline()->setColor(1.0f, 1.0f, 1.0f, 1.0f);
+
+ 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).
- GLCALL(glEnable(GL_BLEND));
- GLCALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
+ _backBuffer.enableBlend(true);
+ // Setup scissor state accordingly.
+ _backBuffer.enableScissorTest(!_overlayVisible);
- // Enable rendering with vertex and coord arrays.
- GLCALL(glEnableClientState(GL_VERTEX_ARRAY));
- GLCALL(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
+ g_context.getActivePipeline()->setFramebuffer(&_backBuffer);
- GLCALL(glEnable(GL_TEXTURE_2D));
+ // Clear the whole screen for the first three frames to assure any
+ // leftovers are cleared.
+ _scissorOverride = 3;
// 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) {
@@ -871,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) {
@@ -922,22 +970,21 @@ void OpenGLGraphicsManager::adjustMousePosition(int16 &x, int16 &y) {
y = (y * _overlay->getHeight()) / _outputScreenHeight;
}
} else if (_gameScreen) {
- x -= _displayX;
- y -= _displayY;
-
const int16 width = _gameScreen->getWidth();
const int16 height = _gameScreen->getHeight();
- x = (x * width) / (int)_displayWidth;
- y = (y * height) / (int)_displayHeight;
-
- // Make sure we only supply valid coordinates.
- x = CLIP<int16>(x, 0, width - 1);
- y = CLIP<int16>(y, 0, height - 1);
+ x = (x * width) / (int)_outputScreenWidth;
+ y = (y * height) / (int)_outputScreenHeight;
}
}
void OpenGLGraphicsManager::setMousePosition(int x, int y) {
+ // Whenever the mouse position changed we force a screen redraw to reflect
+ // changes properly.
+ if (_cursorX != x || _cursorY != y) {
+ _forceRedraw = true;
+ }
+
_cursorX = x;
_cursorY = y;
@@ -945,14 +992,20 @@ void OpenGLGraphicsManager::setMousePosition(int x, int y) {
_cursorDisplayX = x;
_cursorDisplayY = y;
} else {
- _cursorDisplayX = CLIP<int>(x, _displayX, _displayX + _displayWidth - 1);
- _cursorDisplayY = CLIP<int>(y, _displayY, _displayY + _displayHeight - 1);
+ _cursorDisplayX = _displayX + (x * _displayWidth) / _outputScreenWidth;
+ _cursorDisplayY = _displayY + (y * _displayHeight) / _outputScreenHeight;
}
}
-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) {
@@ -960,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) {
@@ -995,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;
@@ -1004,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;
@@ -1034,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;
@@ -1052,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;
}
@@ -1096,8 +1155,21 @@ void OpenGLGraphicsManager::recalculateDisplayArea() {
_displayX = (_outputScreenWidth - _displayWidth ) / 2;
_displayY = (_outputScreenHeight - _displayHeight) / 2;
+ // Setup drawing limitation for game graphics.
+ // This invovles some trickery because OpenGL's viewport coordinate system
+ // is upside down compared to ours.
+ _backBuffer.setScissorBox(_displayX,
+ _outputScreenHeight - _displayHeight - _displayY,
+ _displayWidth,
+ _displayHeight);
+ // Clear the whole screen for the first three frames to remove leftovers.
+ _scissorOverride = 3;
+
// Update the cursor position to adjust for new display area.
setMousePosition(_cursorX, _cursorY);
+
+ // Force a redraw to assure screen is properly redrawn.
+ _forceRedraw = true;
}
void OpenGLGraphicsManager::updateCursorPalette() {
@@ -1111,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() {
@@ -1174,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.
@@ -1215,20 +1274,4 @@ void OpenGLGraphicsManager::saveScreenshot(const Common::String &filename) const
delete[] pixels;
}
-void OpenGLGraphicsManager::drawRect(GLfloat x, GLfloat y, GLfloat w, GLfloat h) {
- if (w < 0 || h < 0) {
- return;
- }
-
- const GLfloat vertices[4*2] = {
- x, y,
- x + w, y,
- x, y + h,
- x + w, y + h
- };
- GLCALL(glVertexPointer(2, GL_FLOAT, 0, vertices));
-
- GLCALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
-}
-
} // End of namespace OpenGL
diff --git a/backends/graphics/opengl/opengl-graphics.h b/backends/graphics/opengl/opengl-graphics.h
index cec970e0cc..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
@@ -263,6 +283,11 @@ protected:
virtual bool loadVideoMode(uint requestedWidth, uint requestedHeight, const Graphics::PixelFormat &format) = 0;
/**
+ * Refresh the screen contents.
+ */
+ virtual void refreshScreen() = 0;
+
+ /**
* Save a screenshot of the full display as BMP to the given file. This
* uses Common::DumpFile for writing the screenshot.
*
@@ -276,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.
@@ -343,7 +398,7 @@ private:
/**
* The virtual game screen.
*/
- Texture *_gameScreen;
+ Surface *_gameScreen;
/**
* The game palette if in CLUT8 mode.
@@ -362,7 +417,7 @@ private:
/**
* The overlay screen.
*/
- Texture *_overlay;
+ Surface *_overlay;
/**
* Whether the overlay is visible or not.
@@ -381,7 +436,7 @@ private:
/**
* The cursor image.
*/
- Texture *_cursor;
+ Surface *_cursor;
/**
* X coordinate of the cursor in phyiscal coordinates.
@@ -464,10 +519,19 @@ private:
*/
byte _cursorPalette[3 * 256];
+ //
+ // Misc
+ //
+
+ /**
+ * Whether the screen contents shall be forced to redrawn.
+ */
+ bool _forceRedraw;
+
/**
- * Draws a rectangle
+ * Number of frames glClear shall ignore scissor testing.
*/
- void drawRect(GLfloat x, GLfloat y, GLfloat w, GLfloat h);
+ uint _scissorOverride;
#ifdef USE_OSD
//
@@ -483,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 a3524b28d2..4495128f32 100644
--- a/backends/graphics/opengl/opengl-sys.h
+++ b/backends/graphics/opengl/opengl-sys.h
@@ -20,38 +20,150 @@
*
*/
-#ifndef BACKENDS_GRAPHICS_OPENGL_OPENGL_H
-#define BACKENDS_GRAPHICS_OPENGL_OPENGL_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.
+#ifndef BACKENDS_GRAPHICS_OPENGL_OPENGL_SYS_H
+#define BACKENDS_GRAPHICS_OPENGL_OPENGL_SYS_H
#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 a2b172f14a..7ea1860d93 100644
--- a/backends/graphics/openglsdl/openglsdl-graphics.cpp
+++ b/backends/graphics/openglsdl/openglsdl-graphics.cpp
@@ -21,6 +21,7 @@
*/
#include "backends/graphics/openglsdl/openglsdl-graphics.h"
+#include "backends/events/sdl/sdl-events.h"
#include "common/textconsole.h"
#include "common/config-manager.h"
@@ -44,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);
@@ -99,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() {
@@ -209,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());
@@ -236,13 +341,6 @@ void OpenGLSdlGraphicsManager::updateScreen() {
}
OpenGLGraphicsManager::updateScreen();
-
- // Swap OpenGL buffers
-#if SDL_VERSION_ATLEAST(2, 0, 0)
- SDL_GL_SwapWindow(_window->getSDLWindow());
-#else
- SDL_GL_SwapBuffers();
-#endif
}
void OpenGLSdlGraphicsManager::notifyVideoExpose() {
@@ -251,6 +349,7 @@ void OpenGLSdlGraphicsManager::notifyVideoExpose() {
void OpenGLSdlGraphicsManager::notifyResize(const uint width, const uint height) {
#if SDL_VERSION_ATLEAST(2, 0, 0)
setActualScreenSize(width, height);
+ _eventSource->resetKeyboadEmulation(width - 1, height - 1);
#else
if (!_ignoreResizeEvents && _hwScreen && !(_hwScreen->flags & SDL_FULLSCREEN)) {
// We save that we handled a resize event here. We need to know this
@@ -301,6 +400,19 @@ bool OpenGLSdlGraphicsManager::loadVideoMode(uint requestedWidth, uint requested
return setupMode(requestedWidth, requestedHeight);
}
+void OpenGLSdlGraphicsManager::refreshScreen() {
+ // Swap OpenGL buffers
+#if SDL_VERSION_ATLEAST(2, 0, 0)
+ SDL_GL_SwapWindow(_window->getSDLWindow());
+#else
+ SDL_GL_SwapBuffers();
+#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.
@@ -374,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.
@@ -395,6 +512,7 @@ bool OpenGLSdlGraphicsManager::setupMode(uint width, uint height) {
int actualWidth, actualHeight;
getWindowDimensions(&actualWidth, &actualHeight);
setActualScreenSize(actualWidth, actualHeight);
+ _eventSource->resetKeyboadEmulation(actualWidth - 1, actualHeight - 1);
return true;
#else
// WORKAROUND: Working around infamous SDL bugs when switching
@@ -440,6 +558,7 @@ bool OpenGLSdlGraphicsManager::setupMode(uint width, uint height) {
if (_hwScreen) {
notifyContextCreate(rgba8888, rgba8888);
setActualScreenSize(_hwScreen->w, _hwScreen->h);
+ _eventSource->resetKeyboadEmulation(_hwScreen->w - 1, _hwScreen->h - 1);
}
// Ignore resize events (from SDL) for a few frames, if this isn't
diff --git a/backends/graphics/openglsdl/openglsdl-graphics.h b/backends/graphics/openglsdl/openglsdl-graphics.h
index 845880eb14..51edcb4363 100644
--- a/backends/graphics/openglsdl/openglsdl-graphics.h
+++ b/backends/graphics/openglsdl/openglsdl-graphics.h
@@ -65,10 +65,15 @@ protected:
virtual void setInternalMousePosition(int x, int y);
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 9cb14525ee..5b591e77ff 100644
--- a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp
+++ b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp
@@ -32,6 +32,7 @@
#include "common/textconsole.h"
#include "common/translation.h"
#include "common/util.h"
+#include "common/frac.h"
#ifdef USE_RGB_COLOR
#include "common/list.h"
#endif
@@ -125,7 +126,9 @@ SurfaceSdlGraphicsManager::SurfaceSdlGraphicsManager(SdlEventSource *sdlEventSou
_hwscreen(0),
#if SDL_VERSION_ATLEAST(2, 0, 0)
_renderer(nullptr), _screenTexture(nullptr),
-#else
+ _viewport(), _windowWidth(1), _windowHeight(1),
+#endif
+#if defined(WIN32) && !SDL_VERSION_ATLEAST(2, 0, 0)
_originalBitsPerPixel(0),
#endif
_screen(0), _tmpscreen(0),
@@ -799,8 +802,9 @@ bool SurfaceSdlGraphicsManager::loadGFXMode() {
} else
#endif
{
- // Save the original bpp to be able to restore the video mode on unload
-#if !SDL_VERSION_ATLEAST(2, 0, 0)
+#if defined(WIN32) && !SDL_VERSION_ATLEAST(2, 0, 0)
+ // Save the original bpp to be able to restore the video mode on
+ // unload. See _originalBitsPerPixel documentation.
if (_originalBitsPerPixel == 0) {
const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
_originalBitsPerPixel = videoInfo->vfmt->BitsPerPixel;
@@ -889,9 +893,14 @@ bool SurfaceSdlGraphicsManager::loadGFXMode() {
SDL_SetColorKey(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, kOSDColorKey);
#endif
+#if !SDL_VERSION_ATLEAST(2, 0, 0)
+ // For SDL2 the output resolution might differ from the requested
+ // resolution. We handle resetting the keyboard emulation properly inside
+ // our SDL_SetVideoMode wrapper for SDL2.
_eventSource->resetKeyboadEmulation(
_videoMode.screenWidth * _videoMode.scaleFactor - 1,
effectiveScreenHeight() - 1);
+#endif
// Distinguish 555 and 565 mode
if (_hwscreen->format->Rmask == 0x7C00)
@@ -940,9 +949,10 @@ void SurfaceSdlGraphicsManager::unloadGFXMode() {
#endif
DestroyScalers();
-#if !SDL_VERSION_ATLEAST(2, 0, 0)
- // Reset video mode to original
- // This will ensure that any new graphic manager will use the initial BPP when listing available modes
+#if defined(WIN32) && !SDL_VERSION_ATLEAST(2, 0, 0)
+ // Reset video mode to original.
+ // This will ensure that any new graphic manager will use the initial BPP
+ // when listing available modes. See _originalBitsPerPixel documentation.
if (_originalBitsPerPixel != 0)
SDL_SetVideoMode(_videoMode.screenWidth, _videoMode.screenHeight, _originalBitsPerPixel, _videoMode.fullscreen ? (SDL_FULLSCREEN | SDL_SWSURFACE) : SDL_SWSURFACE);
#endif
@@ -1756,22 +1766,30 @@ void SurfaceSdlGraphicsManager::setMousePos(int x, int y) {
}
void SurfaceSdlGraphicsManager::warpMouse(int x, int y) {
- int y1 = y;
-
// Don't change actual mouse position, when mouse is outside of our window (in case of windowed mode)
if (!_window->hasMouseFocus()) {
setMousePos(x, y); // but change game cursor position
return;
}
+ int x1 = x, y1 = y;
if (_videoMode.aspectRatioCorrection && !_overlayVisible)
- y1 = real2Aspect(y);
+ y1 = real2Aspect(y1);
if (_mouseCurState.x != x || _mouseCurState.y != y) {
- if (!_overlayVisible)
- _window->warpMouseInWindow(x * _videoMode.scaleFactor, y1 * _videoMode.scaleFactor);
- else
- _window->warpMouseInWindow(x, y1);
+ if (!_overlayVisible) {
+ x1 *= _videoMode.scaleFactor;
+ y1 *= _videoMode.scaleFactor;
+ }
+
+#if SDL_VERSION_ATLEAST(2, 0, 0)
+ // Transform our coordinates in "virtual" output coordinate space into
+ // actual output coordinate space.
+ x1 = x1 * _windowWidth / _videoMode.hardwareWidth;
+ y1 = y1 * _windowHeight / _videoMode.hardwareHeight;
+#endif
+
+ _window->warpMouseInWindow(x1, y1);
// SDL_WarpMouse() generates a mouse movement event, so
// setMousePos() would be called eventually. However, the
@@ -2029,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() {
@@ -2070,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);
@@ -2352,7 +2368,25 @@ void SurfaceSdlGraphicsManager::notifyVideoExpose() {
_forceFull = true;
}
+#ifdef USE_SDL_RESIZABLE_WINDOW
+void SurfaceSdlGraphicsManager::notifyResize(const uint width, const uint height) {
+#if SDL_VERSION_ATLEAST(2, 0, 0)
+ setWindowResolution(width, height);
+#endif
+}
+#endif
+
void SurfaceSdlGraphicsManager::transformMouseCoordinates(Common::Point &point) {
+#if SDL_VERSION_ATLEAST(2, 0, 0)
+ // In SDL2 the actual output resolution might be different from what we
+ // requested. Thus, we transform the coordinates from actual output
+ // coordinate space into the "virtual" output coordinate space.
+ // Please note that we ignore the possible existence of black bars here,
+ // this avoids the feeling of stickyness to black bars.
+ point.x = point.x * _videoMode.hardwareWidth / _windowWidth;
+ point.y = point.y * _videoMode.hardwareHeight / _windowHeight;
+#endif
+
if (!_overlayVisible) {
point.x /= _videoMode.scaleFactor;
point.y /= _videoMode.scaleFactor;
@@ -2377,10 +2411,51 @@ void SurfaceSdlGraphicsManager::deinitializeRenderer() {
_window->destroyWindow();
}
+void SurfaceSdlGraphicsManager::setWindowResolution(int width, int height) {
+ _windowWidth = width;
+ _windowHeight = height;
+
+ // We expect full screen resolution as inputs coming from the event system.
+ _eventSource->resetKeyboadEmulation(_windowWidth - 1, _windowHeight - 1);
+
+ // Calculate the "viewport" for the actual area we draw in. In fullscreen
+ // we can easily get a different resolution than what we requested. In
+ // this case, we add black bars if necessary to assure the aspect ratio
+ // is preserved.
+ const frac_t outputAspect = intToFrac(_windowWidth) / _windowHeight;
+ const frac_t desiredAspect = intToFrac(_videoMode.hardwareWidth) / _videoMode.hardwareHeight;
+
+ _viewport.w = _windowWidth;
+ _viewport.h = _windowHeight;
+
+ // Adjust one dimension for mantaining the aspect ratio.
+ if (abs(outputAspect - desiredAspect) >= (int)(FRAC_ONE / 1000)) {
+ if (outputAspect < desiredAspect) {
+ _viewport.h = _videoMode.hardwareHeight * _windowWidth / _videoMode.hardwareWidth;
+ } else if (outputAspect > desiredAspect) {
+ _viewport.w = _videoMode.hardwareWidth * _windowHeight / _videoMode.hardwareHeight;
+ }
+ }
+
+ _viewport.x = (_windowWidth - _viewport.w) / 2;
+ _viewport.y = (_windowHeight - _viewport.h) / 2;
+
+ // Force a full redraw because we changed the viewport.
+ _forceFull = true;
+}
+
SDL_Surface *SurfaceSdlGraphicsManager::SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags) {
deinitializeRenderer();
- if (!_window->createWindow(width, height, (flags & SDL_FULLSCREEN) ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0)) {
+ uint32 createWindowFlags = 0;
+#ifdef USE_SDL_RESIZABLE_WINDOW
+ createWindowFlags |= SDL_WINDOW_RESIZABLE;
+#endif
+ if ((flags & SDL_FULLSCREEN) != 0) {
+ createWindowFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
+ }
+
+ if (!_window->createWindow(width, height, createWindowFlags)) {
return nullptr;
}
@@ -2390,6 +2465,9 @@ SDL_Surface *SurfaceSdlGraphicsManager::SDL_SetVideoMode(int width, int height,
return nullptr;
}
+ SDL_GetWindowSize(_window->getSDLWindow(), &_windowWidth, &_windowHeight);
+ setWindowResolution(_windowWidth, _windowHeight);
+
_screenTexture = SDL_CreateTexture(_renderer, SDL_PIXELFORMAT_RGB565, SDL_TEXTUREACCESS_STREAMING, width, height);
if (!_screenTexture) {
deinitializeRenderer();
@@ -2409,7 +2487,7 @@ void SurfaceSdlGraphicsManager::SDL_UpdateRects(SDL_Surface *screen, int numrect
SDL_UpdateTexture(_screenTexture, nullptr, screen->pixels, screen->pitch);
SDL_RenderClear(_renderer);
- SDL_RenderCopy(_renderer, _screenTexture, NULL, NULL);
+ SDL_RenderCopy(_renderer, _screenTexture, NULL, &_viewport);
SDL_RenderPresent(_renderer);
}
#endif // SDL_VERSION_ATLEAST(2, 0, 0)
diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.h b/backends/graphics/surfacesdl/surfacesdl-graphics.h
index 2431ce8664..25d6ff041c 100644
--- a/backends/graphics/surfacesdl/surfacesdl-graphics.h
+++ b/backends/graphics/surfacesdl/surfacesdl-graphics.h
@@ -39,6 +39,15 @@
#define USE_SDL_DEBUG_FOCUSRECT
#endif
+// We have (some) support for resizable windows when SDL2 is used. However
+// the overlay still uses the resolution setup with SDL_SetVideoMode. This
+// makes the GUI look subpar when the user resizes the window. In addition
+// we do not adapt the scale factor right now. Thus, we disable this code
+// path for now.
+#if SDL_VERSION_ATLEAST(2, 0, 0) && 0
+#define USE_SDL_RESIZABLE_WINDOW
+#endif
+
#if !defined(_WIN32_WCE) && !defined(__SYMBIAN32__)
// Uncomment this to enable the 'on screen display' code.
#define USE_OSD 1
@@ -143,6 +152,9 @@ public:
// SdlGraphicsManager interface
virtual void notifyVideoExpose();
+#ifdef USE_SDL_RESIZABLE_WINDOW
+ virtual void notifyResize(const uint width, const uint height);
+#endif
virtual void transformMouseCoordinates(Common::Point &point);
virtual void notifyMousePos(Common::Point mouse);
@@ -171,7 +183,10 @@ protected:
* around this API to keep the code paths as close as possible. */
SDL_Renderer *_renderer;
SDL_Texture *_screenTexture;
+ SDL_Rect _viewport;
+ int _windowWidth, _windowHeight;
void deinitializeRenderer();
+ void setWindowResolution(int width, int height);
SDL_Surface *SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags);
void SDL_UpdateRects(SDL_Surface *screen, int numrects, SDL_Rect *rects);
@@ -236,8 +251,22 @@ protected:
};
VideoState _videoMode, _oldVideoMode;
- // Original BPP to restore the video mode on unload
+#if defined(WIN32) && !SDL_VERSION_ATLEAST(2, 0, 0)
+ /**
+ * Original BPP to restore the video mode on unload.
+ *
+ * This is required to make listing video modes for the OpenGL output work
+ * on Windows 8+. On these systems OpenGL modes are only available for
+ * 32bit formats. However, we setup a 16bit format and thus mode listings
+ * for OpenGL will return an empty list afterwards.
+ *
+ * In theory we might require this behavior on non-Win32 platforms too.
+ * However, SDL sometimes gives us invalid pixel formats for X11 outputs
+ * causing crashes when trying to setup the original pixel format.
+ * See bug #7038 "IRIX: X BadMatch when trying to start any 640x480 game".
+ */
uint8 _originalBitsPerPixel;
+#endif
/** Force full redraw on next updateScreen */
bool _forceFull;
diff --git a/backends/midi/timidity.cpp b/backends/midi/timidity.cpp
index d10b808bdb..497138850a 100644
--- a/backends/midi/timidity.cpp
+++ b/backends/midi/timidity.cpp
@@ -316,6 +316,7 @@ int MidiDriver_TIMIDITY::connect_to_server(const char* hostname, unsigned short
if (connect(fd, (struct sockaddr *)&in, sizeof(in)) < 0) {
warning("TiMidity: connect(): %s", strerror(errno));
+ ::close(fd);
return -1;
}
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/mixer/sdl/sdl-mixer.cpp b/backends/mixer/sdl/sdl-mixer.cpp
index dc0c853808..0ca3231892 100644
--- a/backends/mixer/sdl/sdl-mixer.cpp
+++ b/backends/mixer/sdl/sdl-mixer.cpp
@@ -30,8 +30,10 @@
#include "common/config-manager.h"
#include "common/textconsole.h"
-#ifdef GP2X
+#if defined(GP2X)
#define SAMPLES_PER_SEC 11025
+#elif defined(PLAYSTATION3)
+#define SAMPLES_PER_SEC 48000
#else
#define SAMPLES_PER_SEC 44100
#endif
@@ -78,34 +80,49 @@ void SdlMixerManager::init() {
if (SDL_OpenAudio(&fmt, &_obtained) != 0) {
warning("Could not open audio device: %s", SDL_GetError());
+ // The mixer is not marked as ready
_mixer = new Audio::MixerImpl(g_system, desired.freq);
- assert(_mixer);
- _mixer->setReady(false);
- } else {
- debug(1, "Output sample rate: %d Hz", _obtained.freq);
- if (_obtained.freq != desired.freq)
- warning("SDL mixer output sample rate: %d differs from desired: %d", _obtained.freq, desired.freq);
+ return;
+ }
+
+ // The obtained sample format is not supported by the mixer, call
+ // SDL_OpenAudio again with NULL as the second argument to force
+ // SDL to do resampling to the desired audio spec.
+ if (_obtained.format != desired.format) {
+ debug(1, "SDL mixer sound format: %d differs from desired: %d", _obtained.format, desired.format);
+ SDL_CloseAudio();
+
+ if (SDL_OpenAudio(&fmt, NULL) != 0) {
+ warning("Could not open audio device: %s", SDL_GetError());
+
+ // The mixer is not marked as ready
+ _mixer = new Audio::MixerImpl(g_system, desired.freq);
+ return;
+ }
- debug(1, "Output buffer size: %d samples", _obtained.samples);
- if (_obtained.samples != desired.samples)
- warning("SDL mixer output buffer size: %d differs from desired: %d", _obtained.samples, desired.samples);
+ _obtained = desired;
+ }
+
+ debug(1, "Output sample rate: %d Hz", _obtained.freq);
+ if (_obtained.freq != desired.freq)
+ warning("SDL mixer output sample rate: %d differs from desired: %d", _obtained.freq, desired.freq);
- if (_obtained.format != desired.format)
- warning("SDL mixer sound format: %d differs from desired: %d", _obtained.format, desired.format);
+ debug(1, "Output buffer size: %d samples", _obtained.samples);
+ if (_obtained.samples != desired.samples)
+ warning("SDL mixer output buffer size: %d differs from desired: %d", _obtained.samples, desired.samples);
#ifndef __SYMBIAN32__
- // The SymbianSdlMixerManager does stereo->mono downmixing,
- // but otherwise we require stereo output.
- if (_obtained.channels != 2)
- error("SDL mixer output requires stereo output device");
+ // The SymbianSdlMixerManager does stereo->mono downmixing,
+ // but otherwise we require stereo output.
+ if (_obtained.channels != 2)
+ error("SDL mixer output requires stereo output device");
#endif
- _mixer = new Audio::MixerImpl(g_system, _obtained.freq);
- assert(_mixer);
- _mixer->setReady(true);
+ _mixer = new Audio::MixerImpl(g_system, _obtained.freq);
+ assert(_mixer);
+ _mixer->setReady(true);
- startAudio();
- }
+ startAudio();
}
SDL_AudioSpec SdlMixerManager::getAudioSpec(uint32 outputRate) {
diff --git a/backends/mixer/sdl13/sdl13-mixer.cpp b/backends/mixer/sdl13/sdl13-mixer.cpp
deleted file mode 100644
index dc38242bde..0000000000
--- a/backends/mixer/sdl13/sdl13-mixer.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#include "common/scummsys.h"
-
-#if defined(SDL_BACKEND)
-
-#include "backends/mixer/sdl13/sdl13-mixer.h"
-#include "common/debug.h"
-#include "common/system.h"
-#include "common/config-manager.h"
-#include "common/textconsole.h"
-
-#ifdef GP2X
-#define SAMPLES_PER_SEC 11025
-#else
-#define SAMPLES_PER_SEC 44100
-#endif
-
-Sdl13MixerManager::Sdl13MixerManager()
- :
- SdlMixerManager(),
- _device(0) {
-
-}
-
-Sdl13MixerManager::~Sdl13MixerManager() {
- _mixer->setReady(false);
-
- SDL_CloseAudioDevice(_device);
-
- delete _mixer;
-}
-
-void Sdl13MixerManager::init() {
- // Start SDL Audio subsystem
- if (SDL_InitSubSystem(SDL_INIT_AUDIO) == -1) {
- error("Could not initialize SDL: %s", SDL_GetError());
- }
-
- // Get the desired audio specs
- SDL_AudioSpec desired = getAudioSpec(SAMPLES_PER_SEC);
-
- // Start SDL audio with the desired specs
- _device = SDL_OpenAudioDevice(NULL, 0, &desired, &_obtained,
- SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
-
- if (_device <= 0) {
- warning("Could not open audio device: %s", SDL_GetError());
-
- _mixer = new Audio::MixerImpl(g_system, desired.freq);
- assert(_mixer);
- _mixer->setReady(false);
- } else {
- debug(1, "Output sample rate: %d Hz", _obtained.freq);
-
- _mixer = new Audio::MixerImpl(g_system, _obtained.freq);
- assert(_mixer);
- _mixer->setReady(true);
-
- startAudio();
- }
-}
-
-void Sdl13MixerManager::startAudio() {
- // Start the sound system
- SDL_PauseAudioDevice(_device, 0);
-}
-
-void Sdl13MixerManager::suspendAudio() {
- SDL_CloseAudioDevice(_device);
- _audioSuspended = true;
-}
-
-int Sdl13MixerManager::resumeAudio() {
- if (!_audioSuspended)
- return -2;
-
- _device = SDL_OpenAudioDevice(NULL, 0, &_obtained, NULL, 0);
- if (_device <= 0) {
- return -1;
- }
-
- SDL_PauseAudioDevice(_device, 0);
- _audioSuspended = false;
- return 0;
-}
-
-#endif
diff --git a/backends/module.mk b/backends/module.mk
index e5e2905781..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.
@@ -72,13 +79,11 @@ MODULE_OBJS += \
plugins/sdl/sdl-provider.o \
timer/sdl/sdl-timer.o
-# SDL 1.3 removed audio CD support
-ifndef USE_SDL13
+# SDL 2 removed audio CD support
ifndef USE_SDL2
MODULE_OBJS += \
audiocd/sdl/sdl-audiocd.o
endif
-endif
ifdef USE_OPENGL
MODULE_OBJS += \
@@ -90,6 +95,8 @@ ifdef POSIX
MODULE_OBJS += \
fs/posix/posix-fs.o \
fs/posix/posix-fs-factory.o \
+ fs/chroot/chroot-fs-factory.o \
+ fs/chroot/chroot-fs.o \
plugins/posix/posix-provider.o \
saves/posix/posix-saves.o \
taskbar/unity/unity-taskbar.o
@@ -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 \
@@ -125,8 +141,12 @@ MODULE_OBJS += \
fs/posix/posix-fs.o \
fs/posix/posix-fs-factory.o \
fs/ps3/ps3-fs-factory.o \
- events/ps3sdl/ps3sdl-events.o \
- mixer/sdl13/sdl13-mixer.o
+ events/ps3sdl/ps3sdl-events.o
+endif
+
+ifdef USE_LINUXCD
+MODULE_OBJS += \
+ audiocd/linux/linux-audiocd.o
endif
ifeq ($(BACKEND),tizen)
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/gfx.cpp b/backends/platform/android/gfx.cpp
index d7713f99d8..f847296892 100644
--- a/backends/platform/android/gfx.cpp
+++ b/backends/platform/android/gfx.cpp
@@ -469,7 +469,7 @@ void OSystem_Android::updateScreen() {
GLCALL(glTranslatex(0, -_shake_offset << 16, 0));
}
-// TODO this doesnt work on those sucky drivers, do it differently
+// TODO this doesn't work on those sucky drivers, do it differently
// if (_show_overlay)
// GLCALL(glColor4ub(0x9f, 0x9f, 0x9f, 0x9f));
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/dc/vmsave.cpp b/backends/platform/dc/vmsave.cpp
index 5f5cdff24f..75fc1ed0df 100644
--- a/backends/platform/dc/vmsave.cpp
+++ b/backends/platform/dc/vmsave.cpp
@@ -165,30 +165,7 @@ static bool tryDelete(const char *filename, int vm)
return true;
}
-static bool matches(const char *glob, const char *name)
-{
- while(*glob)
- if(*glob == '*') {
- while(*glob == '*')
- glob++;
- do {
- if((*name == *glob || *glob == '?') &&
- matches(glob, name))
- return true;
- } while(*name++);
- return false;
- } else if(!*name)
- return false;
- else if(*glob == '?' || *glob == *name) {
- glob++;
- name++;
- }
- else
- return false;
- return !*name;
-}
-
-static void tryList(const char *glob, int vm, Common::StringArray &list)
+static void tryList(const Common::String &glob, int vm, Common::StringArray &list)
{
struct vmsinfo info;
struct superblock super;
@@ -205,7 +182,7 @@ static void tryList(const char *glob, int vm, Common::StringArray &list)
char buf[16];
strncpy(buf, (char *)de.entry+4, 12);
buf[12] = 0;
- if (matches(glob, buf))
+ if (Common::matchString(buf, glob.c_str()))
list.push_back(buf);
}
}
@@ -425,7 +402,7 @@ Common::StringArray VMSaveManager::listSavefiles(const Common::String &pattern)
Common::StringArray list;
for (int i=0; i<24; i++)
- tryList(pattern.c_str(), i, list);
+ tryList(pattern, i, list);
return list;
}
diff --git a/backends/platform/dingux/README.GCW0 b/backends/platform/dingux/README.GCW0
new file mode 100644
index 0000000000..1b7e30e266
--- /dev/null
+++ b/backends/platform/dingux/README.GCW0
@@ -0,0 +1,35 @@
+[ScummVM-GCW0 README]
+
+Controls
+========
+- Dpad/analog joy: move mouse cursor
+- A: left mouse button click
+- B: right mouse button click
+- X: '0' key
+- Y: '.' key (skips dialogue line in some engines)
+- Left Trigger: open global menu
+- Right Trigger: opens virtual keyboard
+- Select: ESC button, scene skip in some engines
+- Start: F5 key, game menu in some engines
+
+Installation from binaries
+==========================
+Copy over scummvm.opk file
+
+Building from binaries
+======================
+It's pretty simple if you are running Linux on an x86/amd64 machine:
+1. Download and install the GCW0 toolchain (http://www.gcw-zero.com/develop)
+2. Download ScummVM sources and uncompress them
+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
new file mode 100755
index 0000000000..7a31d4fd27
--- /dev/null
+++ b/backends/platform/dingux/build.gcw0.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+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 && make -j6 gcw-opk && ls -l scummvm.opk
diff --git a/backends/platform/dingux/dingux.mk b/backends/platform/dingux/dingux.mk
index 1333e89ff8..dc87e41241 100644
--- a/backends/platform/dingux/dingux.mk
+++ b/backends/platform/dingux/dingux.mk
@@ -55,13 +55,30 @@ endif
$(CP) $(srcdir)/dists/gcw0/default.gcw0.desktop $(gcw0_bundle)/
$(CP) $(srcdir)/dists/gcw0/scummvmrc $(gcw0_bundle)/
$(CP) $(srcdir)/dists/gcw0/scummvm.sh $(gcw0_bundle)/
+ $(CP) $(srcdir)/backends/platform/dingux/README.GCW0 $(gcw0_bundle)/README.man.txt
+ echo >> $(gcw0_bundle)/README.man.txt
+ echo '[General README]' >> $(gcw0_bundle)/README.man.txt
+ echo >> $(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
+
+GeneralUser\ GS\ FluidSynth\ v1.44.sf2: GeneralUser_GS_1.44-FluidSynth.zip
+ unzip -n GeneralUser_GS_1.44-FluidSynth.zip
+ mv "GeneralUser GS 1.44 FluidSynth/GeneralUser GS FluidSynth v1.44.sf2" .
+ mv "GeneralUser GS 1.44 FluidSynth/README.txt" README.soundfont
+ mv "GeneralUser GS 1.44 FluidSynth/LICENSE.txt" LICENSE.soundfont
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/ios7/README.md b/backends/platform/ios7/README.md
new file mode 100644
index 0000000000..f7d828ee94
--- /dev/null
+++ b/backends/platform/ios7/README.md
@@ -0,0 +1,150 @@
+# ScummVM for iOS 7.1+ #
+
+This is a quick fix of the latest ScummVM (1.8.0) for iOS 7.1. It has been tested on real iPhone 6S+, and iPad Pro, and also on all the available Xcode simulators.
+
+I tried to use all the latest iOS features to replace the old code. For instance, it uses gesture recognizers most of the time, it supports the new iPhones 6 / 6+ / 6s / 6s+ resolution, and you can copy your game files using iTunes.
+
+## Compilation ##
+
+First, clone the repository:
+```
+$ git clone https://github.com/scummvm/scummvm.git
+```
+
+### Compilation from Xcode ###
+
+This is the recommended way to compile ScummVM, and the only one which makes it possible to run ScummVM on a non-jailbroken device!
+
+The next step is to compile the **create_project** tool. Open the Xcode project you'll found in the **devtools/create\_project/xcode/** directory. Once compiled, copy the binary somewhere in your *PATH*, and create a **build** directory somewhere on your harddisk. It is recommended to create this directory next to the cloned repository (they share the same parent).
+
+Execute the following commands in a terminal:
+```
+$ cd path_to_the_build_directory
+$ create_project path_to_scummvm_repository --xcode --enable-fluidsynth --disable-jpeg --disable-bink --disable-16bit --disable-mt32emu --disable-nasm --disable-opengl --disable-theora --disable-taskbar
+```
+
+This will create an Xcode project for ScummVM, for both the OS X, and the iOS target.
+
+Now, download the external libraries from http://bsr43.free.fr/scummvm/ScummVM-iOS-libraries.zip. Unzip the archive in your **build** directory. Please make sure that the **lib**, and **include** directories are at the root of the **build** directory, not in a subdirectory.
+
+Now, your **build** directory should contain:
+* a generated **engines** directory,
+* a generated **scummvm.xcodeproj** project,
+* an **include** directory,
+* a **lib** directory.
+
+You are ready to compile ScummVM: open the **scummvm.xcodeproj** project, and build it.
+
+### Compilation from command line ###
+
+For jailbroken devices, it is also possible to compile the project from command line. You'll need a working toolchain, and some tools, like **ldid**, to fake the code signature.
+
+Here is a script to download, and compile all the required tools. This script has been wrote for Debian 8.2, and should be run as root.
+
+```
+#!/bin/bash
+
+if [ $UID -ne 0 ]; then
+ echo "This script should be run by the root user"
+ exit 1
+fi
+
+# Install the Clang compiler
+apt-get install -y clang-3.4 libclang-3.4-dev llvm-3.4 libtool bison flex automake subversion git pkg-config wget libssl-dev uuid-dev libxml2-dev || exit 1
+
+# Add LLVM to the linker library path
+echo /usr/lib/llvm-3.4/lib > /etc/ld.so.conf.d/libllvm-3.4.conf
+ldconfig
+
+# Add symlinks for the LLVM headers
+ln -s /usr/lib/llvm-3.4/bin/llvm-config /usr/bin/llvm-config || exit 1
+ln -s /usr/include/llvm-3.4/llvm /usr/include/llvm || exit 1
+ln -s /usr/include/llvm-c-3.4/llvm-c /usr/include/llvm-c || exit 1
+ln -s /usr/bin/clang-3.4 /usr/bin/clang || exit 1
+ln -s /usr/bin/clang++-3.4 /usr/bin/clang++ || exit 1
+
+# Build the linker
+svn checkout http://ios-toolchain-based-on-clang-for-linux.googlecode.com/svn/trunk/cctools-porting || exit 1
+cd cctools-porting
+sed -i'' 's/proz -k=20 --no-curses/wget/g' cctools-ld64.sh
+./cctools-ld64.sh || exit 1
+
+cd cctools-855-ld64-236.3
+./autogen.sh || exit 1
+./configure --prefix=/usr/local --target=arm-apple-darwin11 || exit 1
+make || exit 1
+make install || exit 1
+cd ../..
+
+# Install ios-tools
+wget https://ios-toolchain-based-on-clang-for-linux.googlecode.com/files/iphonesdk-utils-2.0.tar.gz || exit 1
+tar xzf iphonesdk-utils-2.0.tar.gz
+cd iphonesdk-utils-2.0
+patch -p0 <<_EOF
+*** genLocalization2/getLocalizedStringFromFile.cpp 2015-04-02 04:45:39.309837816 +0530
+--- genLocalization2/getLocalizedStringFromFile.cpp 2015-04-02 04:45:11.525700021 +0530
+***************
+*** 113,115 ****
+ clang::HeaderSearch headerSearch(headerSearchOptions,
+- fileManager,
+ *pDiagnosticsEngine,
+--- 113,115 ----
+ clang::HeaderSearch headerSearch(headerSearchOptions,
++ sourceManager,
+ *pDiagnosticsEngine,
+***************
+*** 129,134 ****
+ false);
+- clang::HeaderSearch headerSearch(fileManager,
+ *pDiagnosticsEngine,
+ languageOptions,
+- pTargetInfo);
+ ApplyHeaderSearchOptions(headerSearch, headerSearchOptions, languageOptions, pTargetInfo->getTriple());
+--- 129,134 ----
+ false);
++ clang::HeaderSearch headerSearch(fileManager);/*,
+ *pDiagnosticsEngine,
+ languageOptions,
++ pTargetInfo);*/
+ ApplyHeaderSearchOptions(headerSearch, headerSearchOptions, languageOptio
+_EOF
+
+./autogen.sh || exit 1
+CC=clang CXX=clang++ ./configure --prefix=/usr/local || exit 1
+make || exit 1
+make install || exit 1
+
+# Install the iOS SDK 8.1
+mkdir -p /usr/share/ios-sdk
+cd /usr/share/ios-sdk
+wget http://iphone.howett.net/sdks/dl/iPhoneOS8.1.sdk.tbz2 || exit 1
+tar xjf iPhoneOS8.1.sdk.tbz2
+rm iPhoneOS8.1.sdk.tbz2
+```
+
+Now, in order to compile ScummVM, execute the following commands:
+```
+$ export SDKROOT=/usr/share/ios-sdk/iPhoneOS8.1.sdk
+$ export CC=ios-clang
+$ export CXX=ios-clang++
+$ ./configure --host=ios7 --disable-mt32emu --enable-release
+$ make ios7bundle
+```
+
+At the end of the compilation, you'll find a **ScummVM.app** application: copy it over SSH, and reboot your device.
+
+## Usage ##
+
+The game data files can be copied on the iOS device using iTunes. Once done, add your games in ScummVM as usual.
+
+Here is a list of the in-game gestures:
+
+|Gesture|Description|
+|-------|-----------|
+|Two fingers swipe down|Display the ScummVM menu for loading, saving, etc.|
+|Two fingers swipe right|Enable / disable the touchpad mode|
+|Two fingers swipe up|Enable / disable the mouse-click-and-drag mode|
+|Two fingers tap|Simulate a right click. You should tap with one finger, and then tap with another while keeping your first finger on the screen.|
+|Two fingers double-tap|Skip the cinematic / video|
+
+The iOS keyboard is visible when the device is in portrait mode, and hidden in landscape mode.
diff --git a/backends/graphics/opengl/extensions.h b/backends/platform/ios7/ios7_app_delegate.h
index 87452429e2..08696c7b61 100644
--- a/backends/graphics/opengl/extensions.h
+++ b/backends/platform/ios7/ios7_app_delegate.h
@@ -20,22 +20,19 @@
*
*/
-#ifndef BACKENDS_GRAPHICS_OPENGL_EXTENSIONS_H
-#define BACKENDS_GRAPHICS_OPENGL_EXTENSIONS_H
+#ifndef BACKENDS_PLATFORM_IOS7_IOS7_APP_DELEGATE_H
+#define BACKENDS_PLATFORM_IOS7_IOS7_APP_DELEGATE_H
-namespace OpenGL {
+#include <UIKit/UIKit.h>
-/**
- * Checks for availability of extensions we want to use and initializes them
- * when available.
- */
-void initializeGLExtensions();
+@class iPhoneView;
-/**
- * Whether non power of two textures are supported
- */
-extern bool g_extNPOTSupported;
-} // End of namespace OpenGL
+@interface iOS7AppDelegate : NSObject<UIApplicationDelegate>
+
++ (iOS7AppDelegate *)iOS7AppDelegate;
++ (iPhoneView *)iPhoneView;
+
+@end
#endif
diff --git a/backends/platform/ios7/ios7_app_delegate.mm b/backends/platform/ios7/ios7_app_delegate.mm
new file mode 100644
index 0000000000..88d0a8925e
--- /dev/null
+++ b/backends/platform/ios7/ios7_app_delegate.mm
@@ -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.
+ *
+ */
+
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+#include "backends/platform/ios7/ios7_app_delegate.h"
+#include "backends/platform/ios7/ios7_scummvm_view_controller.h"
+#include "backends/platform/ios7/ios7_video.h"
+
+@implementation iOS7AppDelegate {
+ UIWindow *_window;
+ iOS7ScummVMViewController *_controller;
+ iPhoneView *_view;
+}
+
+- (id)init {
+ if (self = [super init]) {
+ _window = nil;
+ _view = nil;
+ }
+ return self;
+}
+
+- (void)mainLoop:(id)param {
+ @autoreleasepool {
+ iOS7_main(iOS7_argc, iOS7_argv);
+ }
+
+ exit(0);
+}
+
+- (void)applicationDidFinishLaunching:(UIApplication *)application {
+ CGRect rect = [[UIScreen mainScreen] bounds];
+
+#ifdef IPHONE_SANDBOXED
+ // Create the directory for savegames
+ NSFileManager *fm = [NSFileManager defaultManager];
+ NSString *documentPath = [NSString stringWithUTF8String:iOS7_getDocumentsDir()];
+ NSString *savePath = [documentPath stringByAppendingPathComponent:@"Savegames"];
+ if (![fm fileExistsAtPath:savePath]) {
+ [fm createDirectoryAtPath:savePath withIntermediateDirectories:YES attributes:nil error:nil];
+ }
+#endif
+
+ _window = [[UIWindow alloc] initWithFrame:rect];
+ [_window retain];
+
+ _controller = [[iOS7ScummVMViewController alloc] init];
+
+ _view = [[iPhoneView alloc] initWithFrame:rect];
+ _view.multipleTouchEnabled = YES;
+ _controller.view = _view;
+
+ [_window setRootViewController:_controller];
+ [_window makeKeyAndVisible];
+
+ [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(didRotate:)
+ name:@"UIDeviceOrientationDidChangeNotification"
+ object:nil];
+
+ [NSThread detachNewThreadSelector:@selector(mainLoop:) toTarget:self withObject:nil];
+}
+
+- (void)applicationWillResignActive:(UIApplication *)application {
+ [_view applicationSuspend];
+}
+
+- (void)applicationDidBecomeActive:(UIApplication *)application {
+ [_view applicationResume];
+}
+
+- (void)didRotate:(NSNotification *)notification {
+ UIDeviceOrientation screenOrientation = [[UIDevice currentDevice] orientation];
+ [_view deviceOrientationChanged:screenOrientation];
+}
+
++ (iOS7AppDelegate *)iOS7AppDelegate {
+ UIApplication *app = [UIApplication sharedApplication];
+ return (iOS7AppDelegate *) app.delegate;
+}
+
++ (iPhoneView *)iPhoneView {
+ iOS7AppDelegate *appDelegate = [self iOS7AppDelegate];
+ return appDelegate->_view;
+}
+
+@end
+
+const char *iOS7_getDocumentsDir() {
+ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+ NSString *documentsDirectory = [paths objectAtIndex:0];
+ return [documentsDirectory UTF8String];
+}
diff --git a/backends/platform/ios7/ios7_common.h b/backends/platform/ios7/ios7_common.h
new file mode 100644
index 0000000000..12740d4ae9
--- /dev/null
+++ b/backends/platform/ios7/ios7_common.h
@@ -0,0 +1,131 @@
+/* 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_PLATFORM_IOS7_IOS7_COMMON_H
+#define BACKENDS_PLATFORM_IOS7_IOS7_COMMON_H
+
+#include "graphics/surface.h"
+
+// #define ENABLE_IOS7_SCALERS
+
+
+enum InputEvent {
+ kInputMouseDown,
+ kInputMouseUp,
+ kInputMouseDragged,
+ kInputMouseSecondDragged,
+ kInputMouseSecondDown,
+ kInputMouseSecondUp,
+ kInputOrientationChanged,
+ kInputKeyPressed,
+ kInputApplicationSuspended,
+ kInputApplicationResumed,
+ kInputSwipe,
+ kInputTap
+};
+
+enum ScreenOrientation {
+ kScreenOrientationPortrait,
+ kScreenOrientationLandscape,
+ kScreenOrientationFlippedLandscape
+};
+
+enum UIViewSwipeDirection {
+ kUIViewSwipeUp = 1,
+ kUIViewSwipeDown = 2,
+ kUIViewSwipeLeft = 4,
+ kUIViewSwipeRight = 8
+};
+
+enum UIViewTapDescription {
+ kUIViewTapSingle = 1,
+ kUIViewTapDouble = 2
+};
+
+enum GraphicsModes {
+ kGraphicsModeLinear = 0,
+ kGraphicsModeNone = 1,
+
+ kGraphicsMode2xSaI,
+ kGraphicsModeSuper2xSaI,
+ kGraphicsModeSuperEagle,
+ kGraphicsModeAdvMame2x,
+ kGraphicsModeAdvMame3x,
+ kGraphicsModeHQ2x,
+ kGraphicsModeHQ3x,
+ kGraphicsModeTV2x,
+ kGraphicsModeDotMatrix
+};
+
+struct VideoContext {
+ VideoContext() : asprectRatioCorrection(), screenWidth(), screenHeight(), overlayVisible(false),
+ overlayWidth(), overlayHeight(), mouseX(), mouseY(),
+ mouseHotspotX(), mouseHotspotY(), mouseWidth(), mouseHeight(),
+ mouseIsVisible(), graphicsMode(kGraphicsModeNone), shakeOffsetY() {
+ }
+
+ // Game screen state
+ bool asprectRatioCorrection;
+ uint screenWidth, screenHeight;
+ Graphics::Surface screenTexture;
+
+ // Overlay state
+ bool overlayVisible;
+ uint overlayWidth, overlayHeight;
+ Graphics::Surface overlayTexture;
+
+ // Mouse cursor state
+ uint mouseX, mouseY;
+ int mouseHotspotX, mouseHotspotY;
+ uint mouseWidth, mouseHeight;
+ bool mouseIsVisible;
+ Graphics::Surface mouseTexture;
+
+ // Misc state
+ GraphicsModes graphicsMode;
+ int shakeOffsetY;
+};
+
+struct InternalEvent {
+ InternalEvent() : type(), value1(), value2() {}
+ InternalEvent(InputEvent t, int v1, int v2) : type(t), value1(v1), value2(v2) {}
+
+ InputEvent type;
+ int value1, value2;
+};
+
+// On the ObjC side
+
+extern int iOS7_argc;
+extern char **iOS7_argv;
+
+void iOS7_updateScreen();
+bool iOS7_fetchEvent(InternalEvent *event);
+bool iOS7_isBigDevice();
+
+void iOS7_main(int argc, char **argv);
+const char *iOS7_getDocumentsDir();
+bool iOS7_touchpadModeEnabled();
+
+uint getSizeNextPOT(uint size);
+
+#endif
diff --git a/backends/platform/ios7/ios7_keyboard.h b/backends/platform/ios7/ios7_keyboard.h
new file mode 100644
index 0000000000..1f917cc8c5
--- /dev/null
+++ b/backends/platform/ios7/ios7_keyboard.h
@@ -0,0 +1,44 @@
+/* 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_PLATFORM_IOS7_IOS7_KEYBOARD_H
+#define BACKENDS_PLATFORM_IOS7_IOS7_KEYBOARD_H
+
+#include <UIKit/UIKit.h>
+#include <UIKit/UITextView.h>
+
+@interface SoftKeyboard : UIView<UITextViewDelegate> {
+ id inputDelegate;
+ UITextView *inputView;
+}
+
+- (id)initWithFrame:(CGRect)frame;
+- (UITextView *)inputView;
+- (void)setInputDelegate:(id)delegate;
+- (void)handleKeyPress:(unichar)c;
+
+- (void)showKeyboard;
+- (void)hideKeyboard;
+
+@end
+
+#endif
diff --git a/backends/platform/ios7/ios7_keyboard.mm b/backends/platform/ios7/ios7_keyboard.mm
new file mode 100644
index 0000000000..9476b96ad4
--- /dev/null
+++ b/backends/platform/ios7/ios7_keyboard.mm
@@ -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 "backends/platform/ios7/ios7_keyboard.h"
+
+@interface UITextInputTraits
+- (void)setAutocorrectionType:(int)type;
+- (void)setAutocapitalizationType:(int)type;
+- (void)setEnablesReturnKeyAutomatically:(BOOL)val;
+@end
+
+@interface TextInputHandler : UITextView {
+ SoftKeyboard *softKeyboard;
+}
+
+- (id)initWithKeyboard:(SoftKeyboard *)keyboard;
+
+@end
+
+
+@implementation TextInputHandler
+
+- (id)initWithKeyboard:(SoftKeyboard *)keyboard {
+ self = [super initWithFrame:CGRectMake(0.0f, 0.0f, 0.0f, 0.0f)];
+ softKeyboard = keyboard;
+
+ [self setAutocorrectionType:UITextAutocorrectionTypeNo];
+ [self setAutocapitalizationType:UITextAutocapitalizationTypeNone];
+ [self setEnablesReturnKeyAutomatically:NO];
+
+ return self;
+}
+
+@end
+
+
+@implementation SoftKeyboard
+
+- (id)initWithFrame:(CGRect)frame {
+ self = [super initWithFrame:frame];
+ inputDelegate = nil;
+ inputView = [[TextInputHandler alloc] initWithKeyboard:self];
+ inputView.delegate = self;
+ return self;
+}
+
+- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
+ unichar c;
+ if (text.length) {
+ c = [text characterAtIndex:0];
+ }
+ else {
+ c = '\b';
+ }
+ [inputDelegate handleKeyPress:c];
+ return YES;
+}
+
+- (UITextView *)inputView {
+ return inputView;
+}
+
+- (void)setInputDelegate:(id)delegate {
+ inputDelegate = delegate;
+}
+
+- (void)handleKeyPress:(unichar)c {
+ [inputDelegate handleKeyPress:c];
+}
+
+- (void)showKeyboard {
+ [inputView becomeFirstResponder];
+}
+
+- (void)hideKeyboard {
+ [inputView endEditing:YES];
+}
+
+@end
diff --git a/backends/platform/ios7/ios7_main.mm b/backends/platform/ios7/ios7_main.mm
new file mode 100644
index 0000000000..c36cc08aaa
--- /dev/null
+++ b/backends/platform/ios7/ios7_main.mm
@@ -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.
+ *
+ */
+
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
+#include <UIKit/UIKit.h>
+#include <Foundation/NSThread.h>
+
+#include "backends/platform/ios7/ios7_video.h"
+
+
+int iOS7_argc;
+char **iOS7_argv;
+
+int main(int argc, char **argv) {
+ int returnCode;
+
+ @autoreleasepool {
+ iOS7_argc = argc;
+ iOS7_argv = argv;
+
+ returnCode = UIApplicationMain(argc, argv, @"UIApplication", @"iOS7AppDelegate");
+ }
+
+ return returnCode;
+}
+
diff --git a/backends/platform/ios7/ios7_osys_events.cpp b/backends/platform/ios7/ios7_osys_events.cpp
new file mode 100644
index 0000000000..3621c084db
--- /dev/null
+++ b/backends/platform/ios7/ios7_osys_events.cpp
@@ -0,0 +1,576 @@
+/* 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 "gui/message.h"
+#include "common/translation.h"
+
+#include "backends/platform/ios7/ios7_osys_main.h"
+
+static const int kQueuedInputEventDelay = 50;
+
+bool OSystem_iOS7::pollEvent(Common::Event &event) {
+ //printf("pollEvent()\n");
+
+ long curTime = getMillis();
+
+ if (_timerCallback && (curTime >= _timerCallbackNext)) {
+ _timerCallback(_timerCallbackTimer);
+ _timerCallbackNext = curTime + _timerCallbackTimer;
+ }
+
+ if (_queuedInputEvent.type != Common::EVENT_INVALID && curTime >= _queuedEventTime) {
+ event = _queuedInputEvent;
+ _queuedInputEvent.type = Common::EVENT_INVALID;
+ return true;
+ }
+
+ InternalEvent internalEvent;
+
+ if (iOS7_fetchEvent(&internalEvent)) {
+ switch (internalEvent.type) {
+ case kInputMouseDown:
+ if (!handleEvent_mouseDown(event, internalEvent.value1, internalEvent.value2))
+ return false;
+ break;
+
+ case kInputMouseUp:
+ if (!handleEvent_mouseUp(event, internalEvent.value1, internalEvent.value2))
+ return false;
+ break;
+
+ case kInputMouseDragged:
+ if (!handleEvent_mouseDragged(event, internalEvent.value1, internalEvent.value2))
+ return false;
+ break;
+
+ case kInputOrientationChanged:
+ handleEvent_orientationChanged(internalEvent.value1);
+ return false;
+
+ case kInputApplicationSuspended:
+ handleEvent_applicationSuspended();
+ return false;
+
+ case kInputApplicationResumed:
+ handleEvent_applicationResumed();
+ return false;
+
+ case kInputMouseSecondDragged:
+ if (!handleEvent_mouseSecondDragged(event, internalEvent.value1, internalEvent.value2))
+ return false;
+ break;
+ case kInputMouseSecondDown:
+ _secondaryTapped = true;
+ if (!handleEvent_secondMouseDown(event, internalEvent.value1, internalEvent.value2))
+ return false;
+ break;
+ case kInputMouseSecondUp:
+ _secondaryTapped = false;
+ if (!handleEvent_secondMouseUp(event, internalEvent.value1, internalEvent.value2))
+ return false;
+ break;
+
+ case kInputKeyPressed:
+ handleEvent_keyPressed(event, internalEvent.value1);
+ break;
+
+ case kInputSwipe:
+ if (!handleEvent_swipe(event, internalEvent.value1, internalEvent.value2))
+ return false;
+ break;
+
+ case kInputTap:
+ if (!handleEvent_tap(event, (UIViewTapDescription) internalEvent.value1, internalEvent.value2))
+ return false;
+ break;
+
+ default:
+ break;
+ }
+
+ return true;
+ }
+ return false;
+}
+
+bool OSystem_iOS7::handleEvent_mouseDown(Common::Event &event, int x, int y) {
+ //printf("Mouse down at (%u, %u)\n", x, y);
+
+ // Workaround: kInputMouseSecondToggled isn't always sent when the
+ // secondary finger is lifted. Need to make sure we get out of that mode.
+ _secondaryTapped = false;
+
+ if (_touchpadModeEnabled) {
+ _lastPadX = x;
+ _lastPadY = y;
+ } else
+ warpMouse(x, y);
+
+ if (_mouseClickAndDragEnabled) {
+ event.type = Common::EVENT_LBUTTONDOWN;
+ event.mouse.x = _videoContext->mouseX;
+ event.mouse.y = _videoContext->mouseY;
+ return true;
+ } else {
+ _lastMouseDown = getMillis();
+ }
+ return false;
+}
+
+bool OSystem_iOS7::handleEvent_mouseUp(Common::Event &event, int x, int y) {
+ //printf("Mouse up at (%u, %u)\n", x, y);
+
+ if (_secondaryTapped) {
+ _secondaryTapped = false;
+ if (!handleEvent_secondMouseUp(event, x, y))
+ return false;
+ } else if (_mouseClickAndDragEnabled) {
+ event.type = Common::EVENT_LBUTTONUP;
+ event.mouse.x = _videoContext->mouseX;
+ event.mouse.y = _videoContext->mouseY;
+ } else {
+ if (getMillis() - _lastMouseDown < 250) {
+ event.type = Common::EVENT_LBUTTONDOWN;
+ event.mouse.x = _videoContext->mouseX;
+ event.mouse.y = _videoContext->mouseY;
+
+ _queuedInputEvent.type = Common::EVENT_LBUTTONUP;
+ _queuedInputEvent.mouse.x = _videoContext->mouseX;
+ _queuedInputEvent.mouse.y = _videoContext->mouseY;
+ _lastMouseTap = getMillis();
+ _queuedEventTime = _lastMouseTap + kQueuedInputEventDelay;
+ } else
+ return false;
+ }
+
+ return true;
+}
+
+bool OSystem_iOS7::handleEvent_secondMouseDown(Common::Event &event, int x, int y) {
+ _lastSecondaryDown = getMillis();
+ _gestureStartX = x;
+ _gestureStartY = y;
+
+ if (_mouseClickAndDragEnabled) {
+ event.type = Common::EVENT_LBUTTONUP;
+ event.mouse.x = _videoContext->mouseX;
+ event.mouse.y = _videoContext->mouseY;
+
+ _queuedInputEvent.type = Common::EVENT_RBUTTONDOWN;
+ _queuedInputEvent.mouse.x = _videoContext->mouseX;
+ _queuedInputEvent.mouse.y = _videoContext->mouseY;
+ } else
+ return false;
+
+ return true;
+}
+
+bool OSystem_iOS7::handleEvent_secondMouseUp(Common::Event &event, int x, int y) {
+ int curTime = getMillis();
+
+ if (curTime - _lastSecondaryDown < 400) {
+ //printf("Right tap!\n");
+ if (curTime - _lastSecondaryTap < 400 && !_videoContext->overlayVisible) {
+ //printf("Right escape!\n");
+ event.type = Common::EVENT_KEYDOWN;
+ _queuedInputEvent.type = Common::EVENT_KEYUP;
+
+ event.kbd.flags = _queuedInputEvent.kbd.flags = 0;
+ event.kbd.keycode = _queuedInputEvent.kbd.keycode = Common::KEYCODE_ESCAPE;
+ event.kbd.ascii = _queuedInputEvent.kbd.ascii = Common::ASCII_ESCAPE;
+ _queuedEventTime = curTime + kQueuedInputEventDelay;
+ _lastSecondaryTap = 0;
+ } else if (!_mouseClickAndDragEnabled) {
+ //printf("Rightclick!\n");
+ event.type = Common::EVENT_RBUTTONDOWN;
+ event.mouse.x = _videoContext->mouseX;
+ event.mouse.y = _videoContext->mouseY;
+ _queuedInputEvent.type = Common::EVENT_RBUTTONUP;
+ _queuedInputEvent.mouse.x = _videoContext->mouseX;
+ _queuedInputEvent.mouse.y = _videoContext->mouseY;
+ _lastSecondaryTap = curTime;
+ _queuedEventTime = curTime + kQueuedInputEventDelay;
+ } else {
+ //printf("Right nothing!\n");
+ return false;
+ }
+ }
+ if (_mouseClickAndDragEnabled) {
+ event.type = Common::EVENT_RBUTTONUP;
+ event.mouse.x = _videoContext->mouseX;
+ event.mouse.y = _videoContext->mouseY;
+ }
+
+ return true;
+}
+
+bool OSystem_iOS7::handleEvent_mouseDragged(Common::Event &event, int x, int y) {
+ if (_lastDragPosX == x && _lastDragPosY == y)
+ return false;
+
+ _lastDragPosX = x;
+ _lastDragPosY = y;
+
+ //printf("Mouse dragged at (%u, %u)\n", x, y);
+ int mouseNewPosX;
+ int mouseNewPosY;
+ if (_touchpadModeEnabled) {
+ int deltaX = _lastPadX - x;
+ int deltaY = _lastPadY - y;
+ _lastPadX = x;
+ _lastPadY = y;
+
+ mouseNewPosX = (int)(_videoContext->mouseX - deltaX / 0.5f);
+ mouseNewPosY = (int)(_videoContext->mouseY - deltaY / 0.5f);
+
+ int widthCap = _videoContext->overlayVisible ? _videoContext->overlayWidth : _videoContext->screenWidth;
+ int heightCap = _videoContext->overlayVisible ? _videoContext->overlayHeight : _videoContext->screenHeight;
+
+ if (mouseNewPosX < 0)
+ mouseNewPosX = 0;
+ else if (mouseNewPosX > widthCap)
+ mouseNewPosX = widthCap;
+
+ if (mouseNewPosY < 0)
+ mouseNewPosY = 0;
+ else if (mouseNewPosY > heightCap)
+ mouseNewPosY = heightCap;
+
+ } else {
+ mouseNewPosX = x;
+ mouseNewPosY = y;
+ }
+
+ event.type = Common::EVENT_MOUSEMOVE;
+ event.mouse.x = mouseNewPosX;
+ event.mouse.y = mouseNewPosY;
+ warpMouse(mouseNewPosX, mouseNewPosY);
+
+ return true;
+}
+
+bool OSystem_iOS7::handleEvent_mouseSecondDragged(Common::Event &event, int x, int y) {
+ if (_gestureStartX == -1 || _gestureStartY == -1) {
+ return false;
+ }
+
+ static const int kNeededLength = 100;
+ static const int kMaxDeviation = 20;
+
+ int vecX = (x - _gestureStartX);
+ int vecY = (y - _gestureStartY);
+
+ int absX = abs(vecX);
+ int absY = abs(vecY);
+
+ //printf("(%d, %d)\n", vecX, vecY);
+
+ if (absX >= kNeededLength || absY >= kNeededLength) { // Long enough gesture to react upon.
+ _gestureStartX = -1;
+ _gestureStartY = -1;
+
+ if (absX < kMaxDeviation && vecY >= kNeededLength) {
+ // Swipe down
+ event.type = Common::EVENT_MAINMENU;
+ _queuedInputEvent.type = Common::EVENT_INVALID;
+
+ _queuedEventTime = getMillis() + kQueuedInputEventDelay;
+ return true;
+ }
+
+ if (absX < kMaxDeviation && -vecY >= kNeededLength) {
+ // Swipe up
+ _mouseClickAndDragEnabled = !_mouseClickAndDragEnabled;
+ const char *dialogMsg;
+ if (_mouseClickAndDragEnabled) {
+ _touchpadModeEnabled = false;
+ dialogMsg = _("Mouse-click-and-drag mode enabled.");
+ } else
+ dialogMsg = _("Mouse-click-and-drag mode disabled.");
+ GUI::TimedMessageDialog dialog(dialogMsg, 1500);
+ dialog.runModal();
+ return false;
+ }
+
+ if (absY < kMaxDeviation && vecX >= kNeededLength) {
+ // Swipe right
+ _touchpadModeEnabled = !_touchpadModeEnabled;
+ const char *dialogMsg;
+ if (_touchpadModeEnabled)
+ dialogMsg = _("Touchpad mode enabled.");
+ else
+ dialogMsg = _("Touchpad mode disabled.");
+ GUI::TimedMessageDialog dialog(dialogMsg, 1500);
+ dialog.runModal();
+ return false;
+
+ }
+
+ if (absY < kMaxDeviation && -vecX >= kNeededLength) {
+ // Swipe left
+ return false;
+ }
+ }
+
+ return false;
+}
+
+void OSystem_iOS7::handleEvent_orientationChanged(int orientation) {
+ //printf("Orientation: %i\n", orientation);
+
+ ScreenOrientation newOrientation;
+ switch (orientation) {
+ case 1:
+ newOrientation = kScreenOrientationPortrait;
+ break;
+ case 3:
+ newOrientation = kScreenOrientationLandscape;
+ break;
+ case 4:
+ newOrientation = kScreenOrientationFlippedLandscape;
+ break;
+ default:
+ return;
+ }
+
+ if (_screenOrientation != newOrientation) {
+ _screenOrientation = newOrientation;
+ rebuildSurface();
+ }
+}
+
+void OSystem_iOS7::rebuildSurface() {
+ updateOutputSurface();
+
+ dirtyFullScreen();
+ if (_videoContext->overlayVisible) {
+ dirtyFullOverlayScreen();
+ }
+ updateScreen();
+}
+
+void OSystem_iOS7::handleEvent_applicationSuspended() {
+ suspendLoop();
+}
+
+void OSystem_iOS7::handleEvent_applicationResumed() {
+ rebuildSurface();
+}
+
+void OSystem_iOS7::handleEvent_keyPressed(Common::Event &event, int keyPressed) {
+ int ascii = keyPressed;
+ //printf("key: %i\n", keyPressed);
+
+ // We remap some of the iPhone keyboard keys.
+ // The first ten here are the row of symbols below the numeric keys.
+ switch (keyPressed) {
+ case 45:
+ keyPressed = Common::KEYCODE_F1;
+ ascii = Common::ASCII_F1;
+ break;
+ case 47:
+ keyPressed = Common::KEYCODE_F2;
+ ascii = Common::ASCII_F2;
+ break;
+ case 58:
+ keyPressed = Common::KEYCODE_F3;
+ ascii = Common::ASCII_F3;
+ break;
+ case 59:
+ keyPressed = Common::KEYCODE_F4;
+ ascii = Common::ASCII_F4;
+ break;
+ case 40:
+ keyPressed = Common::KEYCODE_F5;
+ ascii = Common::ASCII_F5;
+ break;
+ case 41:
+ keyPressed = Common::KEYCODE_F6;
+ ascii = Common::ASCII_F6;
+ break;
+ case 36:
+ keyPressed = Common::KEYCODE_F7;
+ ascii = Common::ASCII_F7;
+ break;
+ case 38:
+ keyPressed = Common::KEYCODE_F8;
+ ascii = Common::ASCII_F8;
+ break;
+ case 64:
+ keyPressed = Common::KEYCODE_F9;
+ ascii = Common::ASCII_F9;
+ break;
+ case 34:
+ keyPressed = Common::KEYCODE_F10;
+ ascii = Common::ASCII_F10;
+ break;
+ case 10:
+ keyPressed = Common::KEYCODE_RETURN;
+ ascii = Common::ASCII_RETURN;
+ break;
+ }
+ event.type = Common::EVENT_KEYDOWN;
+ _queuedInputEvent.type = Common::EVENT_KEYUP;
+
+ event.kbd.flags = _queuedInputEvent.kbd.flags = 0;
+ event.kbd.keycode = _queuedInputEvent.kbd.keycode = (Common::KeyCode)keyPressed;
+ event.kbd.ascii = _queuedInputEvent.kbd.ascii = ascii;
+ _queuedEventTime = getMillis() + kQueuedInputEventDelay;
+}
+
+bool OSystem_iOS7::handleEvent_swipe(Common::Event &event, int direction, int touches) {
+ if (touches == 1) {
+ Common::KeyCode keycode = Common::KEYCODE_INVALID;
+ switch (_screenOrientation) {
+ case kScreenOrientationPortrait:
+ switch ((UIViewSwipeDirection)direction) {
+ case kUIViewSwipeUp:
+ keycode = Common::KEYCODE_UP;
+ break;
+ case kUIViewSwipeDown:
+ keycode = Common::KEYCODE_DOWN;
+ break;
+ case kUIViewSwipeLeft:
+ keycode = Common::KEYCODE_LEFT;
+ break;
+ case kUIViewSwipeRight:
+ keycode = Common::KEYCODE_RIGHT;
+ break;
+ default:
+ return false;
+ }
+ break;
+ case kScreenOrientationLandscape:
+ switch ((UIViewSwipeDirection)direction) {
+ case kUIViewSwipeUp:
+ keycode = Common::KEYCODE_LEFT;
+ break;
+ case kUIViewSwipeDown:
+ keycode = Common::KEYCODE_RIGHT;
+ break;
+ case kUIViewSwipeLeft:
+ keycode = Common::KEYCODE_DOWN;
+ break;
+ case kUIViewSwipeRight:
+ keycode = Common::KEYCODE_UP;
+ break;
+ default:
+ return false;
+ }
+ break;
+ case kScreenOrientationFlippedLandscape:
+ switch ((UIViewSwipeDirection)direction) {
+ case kUIViewSwipeUp:
+ keycode = Common::KEYCODE_RIGHT;
+ break;
+ case kUIViewSwipeDown:
+ keycode = Common::KEYCODE_LEFT;
+ break;
+ case kUIViewSwipeLeft:
+ keycode = Common::KEYCODE_UP;
+ break;
+ case kUIViewSwipeRight:
+ keycode = Common::KEYCODE_DOWN;
+ break;
+ default:
+ return false;
+ }
+ break;
+ }
+
+ event.kbd.keycode = _queuedInputEvent.kbd.keycode = keycode;
+ event.kbd.ascii = _queuedInputEvent.kbd.ascii = 0;
+ event.type = Common::EVENT_KEYDOWN;
+ _queuedInputEvent.type = Common::EVENT_KEYUP;
+ event.kbd.flags = _queuedInputEvent.kbd.flags = 0;
+ _queuedEventTime = getMillis() + kQueuedInputEventDelay;
+
+ return true;
+ }
+ else if (touches == 2) {
+ switch ((UIViewSwipeDirection)direction) {
+ case kUIViewSwipeUp: {
+ _mouseClickAndDragEnabled = !_mouseClickAndDragEnabled;
+ const char *dialogMsg;
+ if (_mouseClickAndDragEnabled) {
+ _touchpadModeEnabled = false;
+ dialogMsg = _("Mouse-click-and-drag mode enabled.");
+ } else
+ dialogMsg = _("Mouse-click-and-drag mode disabled.");
+ GUI::TimedMessageDialog dialog(dialogMsg, 1500);
+ dialog.runModal();
+ return false;
+ }
+
+ case kUIViewSwipeDown: {
+ // Swipe down
+ event.type = Common::EVENT_MAINMENU;
+ _queuedInputEvent.type = Common::EVENT_INVALID;
+ _queuedEventTime = getMillis() + kQueuedInputEventDelay;
+ return true;
+ }
+
+ case kUIViewSwipeRight: {
+ // Swipe right
+ _touchpadModeEnabled = !_touchpadModeEnabled;
+ const char *dialogMsg;
+ if (_touchpadModeEnabled)
+ dialogMsg = _("Touchpad mode enabled.");
+ else
+ dialogMsg = _("Touchpad mode disabled.");
+ GUI::TimedMessageDialog dialog(dialogMsg, 1500);
+ dialog.runModal();
+ return false;
+ }
+
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+bool OSystem_iOS7::handleEvent_tap(Common::Event &event, UIViewTapDescription type, int touches) {
+ if (touches == 1) {
+ if (type == kUIViewTapDouble) {
+ event.type = Common::EVENT_RBUTTONDOWN;
+ _queuedInputEvent.type = Common::EVENT_RBUTTONUP;
+ _queuedEventTime = getMillis() + kQueuedInputEventDelay;
+ return true;
+ }
+ }
+ else if (touches == 2) {
+ if (type == kUIViewTapDouble) {
+ event.kbd.keycode = _queuedInputEvent.kbd.keycode = Common::KEYCODE_ESCAPE;
+ event.kbd.ascii = _queuedInputEvent.kbd.ascii = Common::ASCII_ESCAPE;
+ event.type = Common::EVENT_KEYDOWN;
+ _queuedInputEvent.type = Common::EVENT_KEYUP;
+ event.kbd.flags = _queuedInputEvent.kbd.flags = 0;
+ _queuedEventTime = getMillis() + kQueuedInputEventDelay;
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/backends/platform/ios7/ios7_osys_main.cpp b/backends/platform/ios7/ios7_osys_main.cpp
new file mode 100644
index 0000000000..25d9cbed15
--- /dev/null
+++ b/backends/platform/ios7/ios7_osys_main.cpp
@@ -0,0 +1,395 @@
+/* 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 <unistd.h>
+#include <pthread.h>
+#include <string.h>
+
+#include <sys/time.h>
+#include <QuartzCore/QuartzCore.h>
+
+#include "common/scummsys.h"
+#include "common/util.h"
+#include "common/rect.h"
+#include "common/file.h"
+#include "common/fs.h"
+
+#include "base/main.h"
+
+#include "backends/saves/default/default-saves.h"
+#include "backends/timer/default/default-timer.h"
+#include "backends/fs/chroot/chroot-fs-factory.h"
+#include "backends/fs/posix/posix-fs.h"
+#include "audio/mixer.h"
+#include "audio/mixer_intern.h"
+
+#include "graphics/scaler.h"
+#include "graphics/scaler/aspect.h"
+
+#include "backends/platform/ios7/ios7_osys_main.h"
+
+
+const OSystem::GraphicsMode OSystem_iOS7::s_supportedGraphicsModes[] = {
+ { "none", "No filtering", kGraphicsModeNone },
+ { "linear", "Linear filtering", kGraphicsModeLinear },
+
+#ifdef ENABLE_IOS7_SCALERS
+#ifdef USE_SCALERS
+// {"2x", "2x", GFX_DOUBLESIZE},
+// {"3x", "3x", GFX_TRIPLESIZE},
+ { "2xsai", "2xSAI", kGraphicsMode2xSaI},
+ {"super2xsai", "Super2xSAI", kGraphicsModeSuper2xSaI},
+ {"supereagle", "SuperEagle", kGraphicsModeSuperEagle},
+ {"advmame2x", "AdvMAME2x", kGraphicsModeAdvMame2x},
+ {"advmame3x", "AdvMAME3x", kGraphicsModeAdvMame3x},
+#ifdef USE_HQ_SCALERS
+ {"hq2x", "HQ2x", kGraphicsModeHQ2x},
+ {"hq3x", "HQ3x", kGraphicsModeHQ3x},
+#endif
+ {"tv2x", "TV2x", kGraphicsModeTV2x},
+ {"dotmatrix", "DotMatrix", kGraphicsModeDotMatrix},
+#endif
+#endif
+ { 0, 0, 0 }
+};
+
+AQCallbackStruct OSystem_iOS7::s_AudioQueue;
+SoundProc OSystem_iOS7::s_soundCallback = NULL;
+void *OSystem_iOS7::s_soundParam = NULL;
+
+#ifdef IPHONE_SANDBOXED
+class SandboxedSaveFileManager : public DefaultSaveFileManager {
+ Common::String _sandboxRootPath;
+public:
+
+ SandboxedSaveFileManager(Common::String sandboxRootPath, Common::String defaultSavepath)
+ : DefaultSaveFileManager(defaultSavepath), _sandboxRootPath(sandboxRootPath) {
+ }
+
+ virtual bool removeSavefile(const Common::String &filename) override {
+ Common::String chrootedFile = getSavePath() + "/" + filename;
+ Common::String realFilePath = _sandboxRootPath + chrootedFile;
+
+ if (remove(realFilePath.c_str()) != 0) {
+ if (errno == EACCES)
+ setError(Common::kWritePermissionDenied, "Search or write permission denied: "+chrootedFile);
+
+ if (errno == ENOENT)
+ setError(Common::kPathDoesNotExist, "removeSavefile: '"+chrootedFile+"' does not exist or path is invalid");
+ return false;
+ } else {
+ return true;
+ }
+ }
+};
+#endif
+
+OSystem_iOS7::OSystem_iOS7() :
+ _mixer(NULL), _lastMouseTap(0), _queuedEventTime(0),
+ _mouseNeedTextureUpdate(false), _secondaryTapped(false), _lastSecondaryTap(0),
+ _screenOrientation(kScreenOrientationFlippedLandscape), _mouseClickAndDragEnabled(false),
+ _gestureStartX(-1), _gestureStartY(-1), _fullScreenIsDirty(false), _fullScreenOverlayIsDirty(false),
+ _mouseDirty(false), _timeSuspended(0), _lastDragPosX(-1), _lastDragPosY(-1), _screenChangeCount(0),
+ _lastErrorMessage(NULL), _mouseCursorPaletteEnabled(false), _gfxTransactionError(kTransactionSuccess) {
+ _queuedInputEvent.type = Common::EVENT_INVALID;
+ _touchpadModeEnabled = !iOS7_isBigDevice();
+#ifdef IPHONE_SANDBOXED
+ _chrootBasePath = iOS7_getDocumentsDir();
+ _fsFactory = new ChRootFilesystemFactory(_chrootBasePath);
+#else
+ _fsFactory = new POSIXFilesystemFactory();
+#endif
+ initVideoContext();
+
+ memset(_gamePalette, 0, sizeof(_gamePalette));
+ memset(_gamePaletteRGBA5551, 0, sizeof(_gamePaletteRGBA5551));
+ memset(_mouseCursorPalette, 0, sizeof(_mouseCursorPalette));
+}
+
+OSystem_iOS7::~OSystem_iOS7() {
+ AudioQueueDispose(s_AudioQueue.queue, true);
+
+ delete _mixer;
+ // Prevent accidental freeing of the screen texture here. This needs to be
+ // checked since we might use the screen texture as framebuffer in the case
+ // of hi-color games for example. Otherwise this can lead to a double free.
+ if (_framebuffer.getPixels() != _videoContext->screenTexture.getPixels())
+ _framebuffer.free();
+ _mouseBuffer.free();
+}
+
+bool OSystem_iOS7::touchpadModeEnabled() const {
+ return _touchpadModeEnabled;
+}
+
+int OSystem_iOS7::timerHandler(int t) {
+ DefaultTimerManager *tm = (DefaultTimerManager *)g_system->getTimerManager();
+ tm->handler();
+ return t;
+}
+
+void OSystem_iOS7::initBackend() {
+#ifdef IPHONE_SANDBOXED
+ _savefileManager = new SandboxedSaveFileManager(_chrootBasePath, "/Savegames");
+#else
+ _savefileManager = new DefaultSaveFileManager(SCUMMVM_SAVE_PATH);
+#endif
+
+ _timerManager = new DefaultTimerManager();
+
+ gettimeofday(&_startTime, NULL);
+
+ setupMixer();
+
+ setTimerCallback(&OSystem_iOS7::timerHandler, 10);
+
+ EventsBaseBackend::initBackend();
+}
+
+bool OSystem_iOS7::hasFeature(Feature f) {
+ switch (f) {
+ case kFeatureCursorPalette:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+void OSystem_iOS7::setFeatureState(Feature f, bool enable) {
+ switch (f) {
+ case kFeatureCursorPalette:
+ if (_mouseCursorPaletteEnabled != enable) {
+ _mouseNeedTextureUpdate = true;
+ _mouseDirty = true;
+ _mouseCursorPaletteEnabled = enable;
+ }
+ break;
+ case kFeatureAspectRatioCorrection:
+ _videoContext->asprectRatioCorrection = enable;
+ break;
+
+ default:
+ break;
+ }
+}
+
+bool OSystem_iOS7::getFeatureState(Feature f) {
+ switch (f) {
+ case kFeatureCursorPalette:
+ return _mouseCursorPaletteEnabled;
+ case kFeatureAspectRatioCorrection:
+ return _videoContext->asprectRatioCorrection;
+
+ default:
+ return false;
+ }
+}
+
+void OSystem_iOS7::suspendLoop() {
+ bool done = false;
+ uint32 startTime = getMillis();
+
+ stopSoundsystem();
+
+ InternalEvent event;
+ while (!done) {
+ if (iOS7_fetchEvent(&event))
+ if (event.type == kInputApplicationResumed)
+ done = true;
+ usleep(100000);
+ }
+
+ startSoundsystem();
+
+ _timeSuspended += getMillis() - startTime;
+}
+
+uint32 OSystem_iOS7::getMillis(bool skipRecord) {
+ CFTimeInterval timeInSeconds = CACurrentMediaTime();
+ return (uint32) (timeInSeconds * 1000.0);
+}
+
+void OSystem_iOS7::delayMillis(uint msecs) {
+ //printf("delayMillis(%d)\n", msecs);
+ usleep(msecs * 1000);
+}
+
+OSystem::MutexRef OSystem_iOS7::createMutex(void) {
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+
+ pthread_mutex_t *mutex = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t));
+ if (pthread_mutex_init(mutex, &attr) != 0) {
+ printf("pthread_mutex_init() failed!\n");
+ free(mutex);
+ return NULL;
+ }
+
+ return (MutexRef)mutex;
+}
+
+void OSystem_iOS7::lockMutex(MutexRef mutex) {
+ if (pthread_mutex_lock((pthread_mutex_t *) mutex) != 0) {
+ printf("pthread_mutex_lock() failed!\n");
+ }
+}
+
+void OSystem_iOS7::unlockMutex(MutexRef mutex) {
+ if (pthread_mutex_unlock((pthread_mutex_t *) mutex) != 0) {
+ printf("pthread_mutex_unlock() failed!\n");
+ }
+}
+
+void OSystem_iOS7::deleteMutex(MutexRef mutex) {
+ if (pthread_mutex_destroy((pthread_mutex_t *) mutex) != 0) {
+ printf("pthread_mutex_destroy() failed!\n");
+ } else {
+ free(mutex);
+ }
+}
+
+
+void OSystem_iOS7::setTimerCallback(TimerProc callback, int interval) {
+ //printf("setTimerCallback()\n");
+
+ if (callback != NULL) {
+ _timerCallbackTimer = interval;
+ _timerCallbackNext = getMillis() + interval;
+ _timerCallback = callback;
+ } else
+ _timerCallback = NULL;
+}
+
+void OSystem_iOS7::quit() {
+}
+
+void OSystem_iOS7::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;
+}
+
+Audio::Mixer *OSystem_iOS7::getMixer() {
+ assert(_mixer);
+ return _mixer;
+}
+
+OSystem_iOS7 *OSystem_iOS7::sharedInstance() {
+ static OSystem_iOS7 *instance = new OSystem_iOS7();
+ return instance;
+}
+
+Common::String OSystem_iOS7::getDefaultConfigFileName() {
+#ifdef IPHONE_SANDBOXED
+ Common::String path = "/Preferences";
+ return path;
+#else
+ return SCUMMVM_PREFS_PATH;
+#endif
+}
+
+void OSystem_iOS7::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) {
+ // Get URL of the Resource directory of the .app bundle
+ CFURLRef fileUrl = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle());
+ if (fileUrl) {
+ // Try to convert the URL to an absolute path
+ UInt8 buf[MAXPATHLEN];
+ if (CFURLGetFileSystemRepresentation(fileUrl, true, buf, sizeof(buf))) {
+ // Success: Add it to the search path
+ Common::String bundlePath((const char *)buf);
+#ifdef IPHONE_SANDBOXED
+ POSIXFilesystemNode *posixNode = new POSIXFilesystemNode(bundlePath);
+ s.add("__IOS_BUNDLE__", new Common::FSDirectory(AbstractFSNode::makeFSNode(posixNode)), priority);
+#else
+ s.add("__IOS_BUNDLE__", new Common::FSDirectory(bundlePath), priority);
+#endif
+ }
+ CFRelease(fileUrl);
+ }
+}
+
+void OSystem_iOS7::logMessage(LogMessageType::Type type, const char *message) {
+ FILE *output = 0;
+
+ if (type == LogMessageType::kInfo || type == LogMessageType::kDebug)
+ output = stdout;
+ else
+ output = stderr;
+
+ if (type == LogMessageType::kError) {
+ free(_lastErrorMessage);
+ _lastErrorMessage = strdup(message);
+ }
+
+ fputs(message, output);
+ fflush(output);
+}
+
+bool iOS7_touchpadModeEnabled() {
+ OSystem_iOS7 *sys = (OSystem_iOS7 *) g_system;
+ return sys && sys->touchpadModeEnabled();
+}
+
+void iOS7_main(int argc, char **argv) {
+
+ //OSystem_iOS7::migrateApp();
+
+ FILE *newfp = fopen("/var/mobile/.scummvm.log", "a");
+ if (newfp != NULL) {
+ fclose(stdout);
+ fclose(stderr);
+ *stdout = *newfp;
+ *stderr = *newfp;
+ setbuf(stdout, NULL);
+ setbuf(stderr, NULL);
+
+ //extern int gDebugLevel;
+ //gDebugLevel = 10;
+ }
+
+#ifdef IPHONE_SANDBOXED
+ chdir(iOS7_getDocumentsDir());
+#else
+ system("mkdir " SCUMMVM_ROOT_PATH);
+ system("mkdir " SCUMMVM_SAVE_PATH);
+
+ chdir("/var/mobile/");
+#endif
+
+ g_system = OSystem_iOS7::sharedInstance();
+ assert(g_system);
+
+ // Invoke the actual ScummVM main entry point:
+ scummvm_main(argc, (const char *const *) argv);
+ g_system->quit(); // TODO: Consider removing / replacing this!
+}
diff --git a/backends/platform/ios7/ios7_osys_main.h b/backends/platform/ios7/ios7_osys_main.h
new file mode 100644
index 0000000000..174c160bd6
--- /dev/null
+++ b/backends/platform/ios7/ios7_osys_main.h
@@ -0,0 +1,237 @@
+/* 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_PLATFORM_IOS7_IOS7_OSYS_MAIN_H
+#define BACKENDS_PLATFORM_IOS7_IOS7_OSYS_MAIN_H
+
+#include "graphics/surface.h"
+#include "backends/platform/ios7/ios7_common.h"
+#include "backends/base-backend.h"
+#include "common/events.h"
+#include "audio/mixer_intern.h"
+#include "backends/fs/posix/posix-fs-factory.h"
+#include "graphics/colormasks.h"
+#include "graphics/palette.h"
+
+#include <AudioToolbox/AudioQueue.h>
+
+#define AUDIO_BUFFERS 3
+#define WAVE_BUFFER_SIZE 2048
+#define AUDIO_SAMPLE_RATE 44100
+
+#define SCUMMVM_ROOT_PATH "/var/mobile/Library/ScummVM"
+#define SCUMMVM_SAVE_PATH SCUMMVM_ROOT_PATH "/Savegames"
+#define SCUMMVM_PREFS_PATH SCUMMVM_ROOT_PATH "/Preferences"
+
+typedef void (*SoundProc)(void *param, byte *buf, int len);
+typedef int (*TimerProc)(int interval);
+
+struct AQCallbackStruct {
+ AudioQueueRef queue;
+ uint32 frameCount;
+ AudioQueueBufferRef buffers[AUDIO_BUFFERS];
+ AudioStreamBasicDescription dataFormat;
+};
+
+class OSystem_iOS7 : public EventsBaseBackend, public PaletteManager {
+protected:
+ static const OSystem::GraphicsMode s_supportedGraphicsModes[];
+ static AQCallbackStruct s_AudioQueue;
+ static SoundProc s_soundCallback;
+ static void *s_soundParam;
+
+ Audio::MixerImpl *_mixer;
+
+ VideoContext *_videoContext;
+
+ Graphics::Surface _framebuffer;
+
+ // For signaling that screen format set up might have failed.
+ TransactionError _gfxTransactionError;
+
+ // For use with the game texture
+ uint16 _gamePalette[256];
+ // For use with the mouse texture
+ uint16 _gamePaletteRGBA5551[256];
+
+ struct timeval _startTime;
+ uint32 _timeSuspended;
+
+ bool _mouseCursorPaletteEnabled;
+ uint16 _mouseCursorPalette[256];
+ Graphics::Surface _mouseBuffer;
+ uint16 _mouseKeyColor;
+ bool _mouseDirty;
+ bool _mouseNeedTextureUpdate;
+
+ long _lastMouseDown;
+ long _lastMouseTap;
+ long _queuedEventTime;
+ Common::Event _queuedInputEvent;
+ bool _secondaryTapped;
+ long _lastSecondaryDown;
+ long _lastSecondaryTap;
+ int _gestureStartX, _gestureStartY;
+ bool _mouseClickAndDragEnabled;
+ bool _touchpadModeEnabled;
+ int _lastPadX;
+ int _lastPadY;
+ int _lastDragPosX;
+ int _lastDragPosY;
+
+ int _timerCallbackNext;
+ int _timerCallbackTimer;
+ TimerProc _timerCallback;
+
+ Common::Array<Common::Rect> _dirtyRects;
+ Common::Array<Common::Rect> _dirtyOverlayRects;
+ ScreenOrientation _screenOrientation;
+ bool _fullScreenIsDirty;
+ bool _fullScreenOverlayIsDirty;
+ int _screenChangeCount;
+
+ char *_lastErrorMessage;
+
+#ifdef IPHONE_SANDBOXED
+ Common::String _chrootBasePath;
+#endif
+
+public:
+
+ OSystem_iOS7();
+ virtual ~OSystem_iOS7();
+
+ static OSystem_iOS7 *sharedInstance();
+
+ virtual void initBackend();
+
+ virtual bool hasFeature(Feature f);
+ virtual void setFeatureState(Feature f, bool enable);
+ virtual bool getFeatureState(Feature f);
+ virtual const GraphicsMode *getSupportedGraphicsModes() const;
+ virtual int getDefaultGraphicsMode() const;
+ virtual bool setGraphicsMode(int mode);
+ virtual int getGraphicsMode() const;
+ virtual void initSize(uint width, uint height, const Graphics::PixelFormat *format);
+
+ virtual void beginGFXTransaction();
+ virtual TransactionError endGFXTransaction();
+
+ virtual int16 getHeight();
+ virtual int16 getWidth();
+
+ bool touchpadModeEnabled() const;
+
+#ifdef USE_RGB_COLOR
+ virtual Graphics::PixelFormat getScreenFormat() const { return _framebuffer.format; }
+ virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const;
+#endif
+
+ virtual PaletteManager *getPaletteManager() { return this; }
+protected:
+ // PaletteManager API
+ virtual void setPalette(const byte *colors, uint start, uint num);
+ virtual void grabPalette(byte *colors, uint start, uint num);
+
+public:
+ virtual void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h);
+ virtual void updateScreen();
+ virtual Graphics::Surface *lockScreen();
+ virtual void unlockScreen();
+ virtual void setShakePos(int shakeOffset);
+
+ virtual void showOverlay();
+ virtual void hideOverlay();
+ virtual void clearOverlay();
+ virtual void grabOverlay(void *buf, int pitch);
+ virtual void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h);
+ virtual int16 getOverlayHeight();
+ virtual int16 getOverlayWidth();
+ virtual Graphics::PixelFormat getOverlayFormat() const { return Graphics::createPixelFormat<5551>(); }
+
+ virtual bool showMouse(bool visible);
+
+ virtual void warpMouse(int x, int y);
+ virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor = 255, bool dontScale = false, const Graphics::PixelFormat *format = NULL);
+ virtual void setCursorPalette(const byte *colors, uint start, uint num);
+
+ virtual bool pollEvent(Common::Event &event);
+ virtual uint32 getMillis(bool skipRecord = false);
+ virtual void delayMillis(uint msecs);
+
+ virtual MutexRef createMutex(void);
+ virtual void lockMutex(MutexRef mutex);
+ virtual void unlockMutex(MutexRef mutex);
+ virtual void deleteMutex(MutexRef mutex);
+
+ static void mixCallback(void *sys, byte *samples, int len);
+ virtual void setupMixer(void);
+ virtual void setTimerCallback(TimerProc callback, int interval);
+ virtual int getScreenChangeID() const { return _screenChangeCount; }
+ virtual void quit();
+
+ virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0);
+ virtual void getTimeAndDate(TimeDate &t) const;
+
+ virtual Audio::Mixer *getMixer();
+
+ void startSoundsystem();
+ void stopSoundsystem();
+
+ virtual Common::String getDefaultConfigFileName();
+
+ virtual void logMessage(LogMessageType::Type type, const char *message);
+ virtual void fatalError() override;
+
+protected:
+ void initVideoContext();
+ void updateOutputSurface();
+
+ void internUpdateScreen();
+ void dirtyFullScreen();
+ void dirtyFullOverlayScreen();
+ void suspendLoop();
+ void drawDirtyRect(const Common::Rect &dirtyRect);
+ void updateMouseTexture();
+ static void AQBufferCallback(void *in, AudioQueueRef inQ, AudioQueueBufferRef outQB);
+ static int timerHandler(int t);
+
+ bool handleEvent_swipe(Common::Event &event, int direction, int touches);
+ bool handleEvent_tap(Common::Event &event, UIViewTapDescription type, int touches);
+ void handleEvent_keyPressed(Common::Event &event, int keyPressed);
+ void handleEvent_orientationChanged(int orientation);
+ void handleEvent_applicationSuspended();
+ void handleEvent_applicationResumed();
+
+ bool handleEvent_mouseDown(Common::Event &event, int x, int y);
+ bool handleEvent_mouseUp(Common::Event &event, int x, int y);
+
+ bool handleEvent_secondMouseDown(Common::Event &event, int x, int y);
+ bool handleEvent_secondMouseUp(Common::Event &event, int x, int y);
+
+ bool handleEvent_mouseDragged(Common::Event &event, int x, int y);
+ bool handleEvent_mouseSecondDragged(Common::Event &event, int x, int y);
+
+ void rebuildSurface();
+};
+
+#endif
diff --git a/backends/platform/ios7/ios7_osys_sound.cpp b/backends/platform/ios7/ios7_osys_sound.cpp
new file mode 100644
index 0000000000..07e9458711
--- /dev/null
+++ b/backends/platform/ios7/ios7_osys_sound.cpp
@@ -0,0 +1,105 @@
+/* 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 "backends/platform/ios7/ios7_osys_main.h"
+
+void OSystem_iOS7::AQBufferCallback(void *in, AudioQueueRef inQ, AudioQueueBufferRef outQB) {
+ //printf("AQBufferCallback()\n");
+ if (s_AudioQueue.frameCount > 0 && s_soundCallback != NULL) {
+ outQB->mAudioDataByteSize = 4 * s_AudioQueue.frameCount;
+ s_soundCallback(s_soundParam, (byte *)outQB->mAudioData, outQB->mAudioDataByteSize);
+ AudioQueueEnqueueBuffer(inQ, outQB, 0, NULL);
+ } else {
+ AudioQueueStop(s_AudioQueue.queue, false);
+ }
+}
+
+void OSystem_iOS7::mixCallback(void *sys, byte *samples, int len) {
+ OSystem_iOS7 *this_ = (OSystem_iOS7 *)sys;
+ assert(this_);
+
+ if (this_->_mixer) {
+ this_->_mixer->mixCallback(samples, len);
+ }
+}
+
+void OSystem_iOS7::setupMixer() {
+ _mixer = new Audio::MixerImpl(this, AUDIO_SAMPLE_RATE);
+
+ s_soundCallback = mixCallback;
+ s_soundParam = this;
+
+ startSoundsystem();
+}
+
+void OSystem_iOS7::startSoundsystem() {
+ s_AudioQueue.dataFormat.mSampleRate = AUDIO_SAMPLE_RATE;
+ s_AudioQueue.dataFormat.mFormatID = kAudioFormatLinearPCM;
+ s_AudioQueue.dataFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
+ s_AudioQueue.dataFormat.mBytesPerPacket = 4;
+ s_AudioQueue.dataFormat.mFramesPerPacket = 1;
+ s_AudioQueue.dataFormat.mBytesPerFrame = 4;
+ s_AudioQueue.dataFormat.mChannelsPerFrame = 2;
+ s_AudioQueue.dataFormat.mBitsPerChannel = 16;
+ s_AudioQueue.frameCount = WAVE_BUFFER_SIZE;
+
+ if (AudioQueueNewOutput(&s_AudioQueue.dataFormat, AQBufferCallback, &s_AudioQueue, 0, kCFRunLoopCommonModes, 0, &s_AudioQueue.queue)) {
+ printf("Couldn't set the AudioQueue callback!\n");
+ _mixer->setReady(false);
+ return;
+ }
+
+ uint32 bufferBytes = s_AudioQueue.frameCount * s_AudioQueue.dataFormat.mBytesPerFrame;
+
+ for (int i = 0; i < AUDIO_BUFFERS; i++) {
+ if (AudioQueueAllocateBuffer(s_AudioQueue.queue, bufferBytes, &s_AudioQueue.buffers[i])) {
+ printf("Error allocating AudioQueue buffer!\n");
+ _mixer->setReady(false);
+ return;
+ }
+
+ AQBufferCallback(&s_AudioQueue, s_AudioQueue.queue, s_AudioQueue.buffers[i]);
+ }
+
+ AudioQueueSetParameter(s_AudioQueue.queue, kAudioQueueParam_Volume, 1.0);
+ if (AudioQueueStart(s_AudioQueue.queue, NULL)) {
+ printf("Error starting the AudioQueue!\n");
+ _mixer->setReady(false);
+ return;
+ }
+
+ _mixer->setReady(true);
+}
+
+void OSystem_iOS7::stopSoundsystem() {
+ AudioQueueStop(s_AudioQueue.queue, true);
+
+ for (int i = 0; i < AUDIO_BUFFERS; i++) {
+ AudioQueueFreeBuffer(s_AudioQueue.queue, s_AudioQueue.buffers[i]);
+ }
+
+ AudioQueueDispose(s_AudioQueue.queue, true);
+ _mixer->setReady(false);
+}
diff --git a/backends/platform/ios7/ios7_osys_video.mm b/backends/platform/ios7/ios7_osys_video.mm
new file mode 100644
index 0000000000..6784cf46f5
--- /dev/null
+++ b/backends/platform/ios7/ios7_osys_video.mm
@@ -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.
+ *
+ */
+
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
+#include "backends/platform/ios7/ios7_osys_main.h"
+#include "backends/platform/ios7/ios7_video.h"
+
+#include "graphics/conversion.h"
+#include "backends/platform/ios7/ios7_app_delegate.h"
+
+@interface iOS7AlertHandler : NSObject<UIAlertViewDelegate>
+@end
+
+@implementation iOS7AlertHandler
+
+- (void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex {
+ OSystem_iOS7::sharedInstance()->quit();
+ exit(1);
+}
+
+@end
+
+static void displayAlert(void *ctx) {
+ UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Fatal Error"
+ message:[NSString stringWithCString:(const char *)ctx encoding:NSUTF8StringEncoding]
+ delegate:[[iOS7AlertHandler alloc] init]
+ cancelButtonTitle:@"OK"
+ otherButtonTitles:nil];
+ [alert show];
+ [alert autorelease];
+}
+
+void OSystem_iOS7::fatalError() {
+ if (_lastErrorMessage) {
+ dispatch_async_f(dispatch_get_main_queue(), _lastErrorMessage, displayAlert);
+ for(;;);
+ }
+ else {
+ OSystem::fatalError();
+ }
+}
+
+void OSystem_iOS7::initVideoContext() {
+ _videoContext = [[iOS7AppDelegate iPhoneView] getVideoContext];
+}
+
+const OSystem::GraphicsMode *OSystem_iOS7::getSupportedGraphicsModes() const {
+ return s_supportedGraphicsModes;
+}
+
+int OSystem_iOS7::getDefaultGraphicsMode() const {
+ return kGraphicsModeNone;
+}
+
+bool OSystem_iOS7::setGraphicsMode(int mode) {
+ switch (mode) {
+ case kGraphicsModeNone:
+ case kGraphicsModeLinear:
+ case kGraphicsMode2xSaI:
+ case kGraphicsModeSuper2xSaI:
+ case kGraphicsModeSuperEagle:
+ case kGraphicsModeAdvMame2x:
+ case kGraphicsModeAdvMame3x:
+ case kGraphicsModeHQ2x:
+ case kGraphicsModeHQ3x:
+ case kGraphicsModeTV2x:
+ case kGraphicsModeDotMatrix:
+ _videoContext->graphicsMode = (GraphicsModes)mode;
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+int OSystem_iOS7::getGraphicsMode() const {
+ return _videoContext->graphicsMode;
+}
+
+#ifdef USE_RGB_COLOR
+Common::List<Graphics::PixelFormat> OSystem_iOS7::getSupportedFormats() const {
+ Common::List<Graphics::PixelFormat> list;
+ // RGB565
+ list.push_back(Graphics::createPixelFormat<565>());
+ // CLUT8
+ list.push_back(Graphics::PixelFormat::createFormatCLUT8());
+ return list;
+}
+#endif
+
+void OSystem_iOS7::initSize(uint width, uint height, const Graphics::PixelFormat *format) {
+ //printf("initSize(%u, %u, %p)\n", width, height, (const void *)format);
+
+ _videoContext->screenWidth = width;
+ _videoContext->screenHeight = height;
+ _videoContext->shakeOffsetY = 0;
+
+ // In case we use the screen texture as frame buffer we reset the pixels
+ // pointer here to avoid freeing the screen texture.
+ if (_framebuffer.getPixels() == _videoContext->screenTexture.getPixels())
+ _framebuffer.setPixels(0);
+
+ // Create the screen texture right here. We need to do this here, since
+ // when a game requests hi-color mode, we actually set the framebuffer
+ // to the texture buffer to avoid an additional copy step.
+ [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(createScreenTexture) withObject:nil waitUntilDone: YES];
+
+ // In case the client code tries to set up a non supported mode, we will
+ // fall back to CLUT8 and set the transaction error accordingly.
+ if (format && format->bytesPerPixel != 1 && *format != _videoContext->screenTexture.format) {
+ format = 0;
+ _gfxTransactionError = kTransactionFormatNotSupported;
+ }
+
+ if (!format || format->bytesPerPixel == 1) {
+ _framebuffer.create(width, height, Graphics::PixelFormat::createFormatCLUT8());
+ } else {
+#if 0
+ printf("bytesPerPixel: %u RGBAlosses: %u,%u,%u,%u RGBAshifts: %u,%u,%u,%u\n", format->bytesPerPixel,
+ format->rLoss, format->gLoss, format->bLoss, format->aLoss,
+ format->rShift, format->gShift, format->bShift, format->aShift);
+#endif
+ // We directly draw on the screen texture in hi-color mode. Thus
+ // we copy over its settings here and just replace the width and
+ // height to avoid any problems.
+ _framebuffer = _videoContext->screenTexture;
+ _framebuffer.w = width;
+ _framebuffer.h = height;
+ }
+
+ _fullScreenIsDirty = false;
+ dirtyFullScreen();
+ _mouseCursorPaletteEnabled = false;
+}
+
+void OSystem_iOS7::beginGFXTransaction() {
+ _gfxTransactionError = kTransactionSuccess;
+}
+
+OSystem::TransactionError OSystem_iOS7::endGFXTransaction() {
+ _screenChangeCount++;
+ updateOutputSurface();
+ [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(setGraphicsMode) withObject:nil waitUntilDone: YES];
+
+ return _gfxTransactionError;
+}
+
+void OSystem_iOS7::updateOutputSurface() {
+ [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(initSurface) withObject:nil waitUntilDone: YES];
+}
+
+int16 OSystem_iOS7::getHeight() {
+ return _videoContext->screenHeight;
+}
+
+int16 OSystem_iOS7::getWidth() {
+ return _videoContext->screenWidth;
+}
+
+void OSystem_iOS7::setPalette(const byte *colors, uint start, uint num) {
+ //printf("setPalette(%p, %u, %u)\n", colors, start, num);
+ assert(start + num <= 256);
+ const byte *b = colors;
+
+ for (uint i = start; i < start + num; ++i) {
+ _gamePalette[i] = Graphics::RGBToColor<Graphics::ColorMasks<565> >(b[0], b[1], b[2]);
+ _gamePaletteRGBA5551[i] = Graphics::RGBToColor<Graphics::ColorMasks<5551> >(b[0], b[1], b[2]);
+ b += 3;
+ }
+
+ dirtyFullScreen();
+
+ // Automatically update the mouse texture when the palette changes while the
+ // cursor palette is disabled.
+ if (!_mouseCursorPaletteEnabled && _mouseBuffer.format.bytesPerPixel == 1)
+ _mouseDirty = _mouseNeedTextureUpdate = true;
+}
+
+void OSystem_iOS7::grabPalette(byte *colors, uint start, uint num) {
+ //printf("grabPalette(%p, %u, %u)\n", colors, start, num);
+ assert(start + num <= 256);
+ byte *b = colors;
+
+ for (uint i = start; i < start + num; ++i) {
+ Graphics::colorToRGB<Graphics::ColorMasks<565> >(_gamePalette[i], b[0], b[1], b[2]);
+ b += 3;
+ }
+}
+
+void OSystem_iOS7::copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) {
+ //printf("copyRectToScreen(%p, %d, %i, %i, %i, %i)\n", buf, pitch, x, y, w, h);
+ //Clip the coordinates
+ const byte *src = (const byte *)buf;
+ if (x < 0) {
+ w += x;
+ src -= x;
+ x = 0;
+ }
+
+ if (y < 0) {
+ h += y;
+ src -= y * pitch;
+ y = 0;
+ }
+
+ if (w > (int)_framebuffer.w - x) {
+ w = _framebuffer.w - x;
+ }
+
+ if (h > (int)_framebuffer.h - y) {
+ h = _framebuffer.h - y;
+ }
+
+ if (w <= 0 || h <= 0)
+ return;
+
+ if (!_fullScreenIsDirty) {
+ _dirtyRects.push_back(Common::Rect(x, y, x + w, y + h));
+ }
+
+ byte *dst = (byte *)_framebuffer.getBasePtr(x, y);
+ if (_framebuffer.pitch == pitch && _framebuffer.w == w) {
+ memcpy(dst, src, h * pitch);
+ } else {
+ do {
+ memcpy(dst, src, w * _framebuffer.format.bytesPerPixel);
+ src += pitch;
+ dst += _framebuffer.pitch;
+ } while (--h);
+ }
+}
+
+void OSystem_iOS7::updateScreen() {
+ if (_dirtyRects.size() == 0 && _dirtyOverlayRects.size() == 0 && !_mouseDirty)
+ return;
+
+ //printf("updateScreen(): %i dirty rects.\n", _dirtyRects.size());
+
+ internUpdateScreen();
+ _mouseDirty = false;
+ _fullScreenIsDirty = false;
+ _fullScreenOverlayIsDirty = false;
+
+ iOS7_updateScreen();
+}
+
+void OSystem_iOS7::internUpdateScreen() {
+ if (_mouseNeedTextureUpdate) {
+ updateMouseTexture();
+ _mouseNeedTextureUpdate = false;
+ }
+
+ while (_dirtyRects.size()) {
+ Common::Rect dirtyRect = _dirtyRects.remove_at(_dirtyRects.size() - 1);
+
+ //printf("Drawing: (%i, %i) -> (%i, %i)\n", dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom);
+ drawDirtyRect(dirtyRect);
+ // TODO: Implement dirty rect code
+ //updateHardwareSurfaceForRect(dirtyRect);
+ }
+
+ if (_videoContext->overlayVisible) {
+ // TODO: Implement dirty rect code
+ _dirtyOverlayRects.clear();
+ /*while (_dirtyOverlayRects.size()) {
+ Common::Rect dirtyRect = _dirtyOverlayRects.remove_at(_dirtyOverlayRects.size() - 1);
+
+ //printf("Drawing: (%i, %i) -> (%i, %i)\n", dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom);
+ drawDirtyOverlayRect(dirtyRect);
+ }*/
+ }
+}
+
+void OSystem_iOS7::drawDirtyRect(const Common::Rect &dirtyRect) {
+ // We only need to do a color look up for CLUT8
+ if (_framebuffer.format.bytesPerPixel != 1)
+ return;
+
+ int h = dirtyRect.bottom - dirtyRect.top;
+ int w = dirtyRect.right - dirtyRect.left;
+
+ const byte *src = (const byte *)_framebuffer.getBasePtr(dirtyRect.left, dirtyRect.top);
+ byte *dstRaw = (byte *)_videoContext->screenTexture.getBasePtr(dirtyRect.left, dirtyRect.top);
+
+ // When we use CLUT8 do a color look up
+ for (int y = h; y > 0; y--) {
+ uint16 *dst = (uint16 *)dstRaw;
+ for (int x = w; x > 0; x--)
+ *dst++ = _gamePalette[*src++];
+
+ dstRaw += _videoContext->screenTexture.pitch;
+ src += _framebuffer.pitch - w;
+ }
+}
+
+Graphics::Surface *OSystem_iOS7::lockScreen() {
+ //printf("lockScreen()\n");
+ return &_framebuffer;
+}
+
+void OSystem_iOS7::unlockScreen() {
+ //printf("unlockScreen()\n");
+ dirtyFullScreen();
+}
+
+void OSystem_iOS7::setShakePos(int shakeOffset) {
+ //printf("setShakePos(%i)\n", shakeOffset);
+ _videoContext->shakeOffsetY = shakeOffset;
+ [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(setViewTransformation) withObject:nil waitUntilDone: YES];
+ // HACK: We use this to force a redraw.
+ _mouseDirty = true;
+}
+
+void OSystem_iOS7::showOverlay() {
+ //printf("showOverlay()\n");
+ _videoContext->overlayVisible = true;
+ dirtyFullOverlayScreen();
+ updateScreen();
+ [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(updateMouseCursorScaling) withObject:nil waitUntilDone: YES];
+ [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(clearColorBuffer) withObject:nil waitUntilDone: YES];
+}
+
+void OSystem_iOS7::hideOverlay() {
+ //printf("hideOverlay()\n");
+ _videoContext->overlayVisible = false;
+ _dirtyOverlayRects.clear();
+ dirtyFullScreen();
+ [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(updateMouseCursorScaling) withObject:nil waitUntilDone: YES];
+ [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(clearColorBuffer) withObject:nil waitUntilDone: YES];
+}
+
+void OSystem_iOS7::clearOverlay() {
+ //printf("clearOverlay()\n");
+ bzero(_videoContext->overlayTexture.getPixels(), _videoContext->overlayTexture.h * _videoContext->overlayTexture.pitch);
+ dirtyFullOverlayScreen();
+}
+
+void OSystem_iOS7::grabOverlay(void *buf, int pitch) {
+ //printf("grabOverlay()\n");
+ int h = _videoContext->overlayHeight;
+
+ byte *dst = (byte *)buf;
+ const byte *src = (const byte *)_videoContext->overlayTexture.getPixels();
+ do {
+ memcpy(dst, src, _videoContext->overlayWidth * sizeof(uint16));
+ src += _videoContext->overlayTexture.pitch;
+ dst += pitch;
+ } while (--h);
+}
+
+void OSystem_iOS7::copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) {
+ //printf("copyRectToOverlay(%p, pitch=%i, x=%i, y=%i, w=%i, h=%i)\n", (const void *)buf, pitch, x, y, w, h);
+ const byte *src = (const byte *)buf;
+
+ //Clip the coordinates
+ if (x < 0) {
+ w += x;
+ src -= x * sizeof(uint16);
+ x = 0;
+ }
+
+ if (y < 0) {
+ h += y;
+ src -= y * pitch;
+ y = 0;
+ }
+
+ if (w > (int)_videoContext->overlayWidth - x)
+ w = _videoContext->overlayWidth - x;
+
+ if (h > (int)_videoContext->overlayHeight - y)
+ h = _videoContext->overlayHeight - y;
+
+ if (w <= 0 || h <= 0)
+ return;
+
+ if (!_fullScreenOverlayIsDirty) {
+ _dirtyOverlayRects.push_back(Common::Rect(x, y, x + w, y + h));
+ }
+
+ byte *dst = (byte *)_videoContext->overlayTexture.getBasePtr(x, y);
+ do {
+ memcpy(dst, src, w * sizeof(uint16));
+ src += pitch;
+ dst += _videoContext->overlayTexture.pitch;
+ } while (--h);
+}
+
+int16 OSystem_iOS7::getOverlayHeight() {
+ return _videoContext->overlayHeight;
+}
+
+int16 OSystem_iOS7::getOverlayWidth() {
+ return _videoContext->overlayWidth;
+}
+
+bool OSystem_iOS7::showMouse(bool visible) {
+ //printf("showMouse(%d)\n", visible);
+ bool last = _videoContext->mouseIsVisible;
+ _videoContext->mouseIsVisible = visible;
+ _mouseDirty = true;
+
+ return last;
+}
+
+void OSystem_iOS7::warpMouse(int x, int y) {
+ //printf("warpMouse(%d, %d)\n", x, y);
+ _videoContext->mouseX = x;
+ _videoContext->mouseY = y;
+ [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(notifyMouseMove) withObject:nil waitUntilDone: YES];
+ _mouseDirty = true;
+}
+
+void OSystem_iOS7::dirtyFullScreen() {
+ if (!_fullScreenIsDirty) {
+ _dirtyRects.clear();
+ _dirtyRects.push_back(Common::Rect(0, 0, _videoContext->screenWidth, _videoContext->screenHeight));
+ _fullScreenIsDirty = true;
+ }
+}
+
+void OSystem_iOS7::dirtyFullOverlayScreen() {
+ if (!_fullScreenOverlayIsDirty) {
+ _dirtyOverlayRects.clear();
+ _dirtyOverlayRects.push_back(Common::Rect(0, 0, _videoContext->overlayWidth, _videoContext->overlayHeight));
+ _fullScreenOverlayIsDirty = true;
+ }
+}
+
+void OSystem_iOS7::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) {
+ //printf("setMouseCursor(%p, %u, %u, %i, %i, %u, %d, %p)\n", (const void *)buf, w, h, hotspotX, hotspotY, keycolor, dontScale, (const void *)format);
+
+ const Graphics::PixelFormat pixelFormat = format ? *format : Graphics::PixelFormat::createFormatCLUT8();
+#if 0
+ printf("bytesPerPixel: %u RGBAlosses: %u,%u,%u,%u RGBAshifts: %u,%u,%u,%u\n", pixelFormat.bytesPerPixel,
+ pixelFormat.rLoss, pixelFormat.gLoss, pixelFormat.bLoss, pixelFormat.aLoss,
+ pixelFormat.rShift, pixelFormat.gShift, pixelFormat.bShift, pixelFormat.aShift);
+#endif
+ assert(pixelFormat.bytesPerPixel == 1 || pixelFormat.bytesPerPixel == 2);
+
+ if (_mouseBuffer.w != w || _mouseBuffer.h != h || _mouseBuffer.format != pixelFormat || !_mouseBuffer.getPixels())
+ _mouseBuffer.create(w, h, pixelFormat);
+
+ _videoContext->mouseWidth = w;
+ _videoContext->mouseHeight = h;
+
+ _videoContext->mouseHotspotX = hotspotX;
+ _videoContext->mouseHotspotY = hotspotY;
+
+ _mouseKeyColor = keycolor;
+
+ memcpy(_mouseBuffer.getPixels(), buf, h * _mouseBuffer.pitch);
+
+ _mouseDirty = true;
+ _mouseNeedTextureUpdate = true;
+}
+
+void OSystem_iOS7::setCursorPalette(const byte *colors, uint start, uint num) {
+ //printf("setCursorPalette(%p, %u, %u)\n", (const void *)colors, start, num);
+ assert(start + num <= 256);
+
+ for (uint i = start; i < start + num; ++i, colors += 3)
+ _mouseCursorPalette[i] = Graphics::RGBToColor<Graphics::ColorMasks<5551> >(colors[0], colors[1], colors[2]);
+
+ // FIXME: This is just stupid, our client code seems to assume that this
+ // automatically enables the cursor palette.
+ _mouseCursorPaletteEnabled = true;
+
+ if (_mouseCursorPaletteEnabled)
+ _mouseDirty = _mouseNeedTextureUpdate = true;
+}
+
+void OSystem_iOS7::updateMouseTexture() {
+ uint texWidth = getSizeNextPOT(_videoContext->mouseWidth);
+ uint texHeight = getSizeNextPOT(_videoContext->mouseHeight);
+
+ Graphics::Surface &mouseTexture = _videoContext->mouseTexture;
+ if (mouseTexture.w != texWidth || mouseTexture.h != texHeight)
+ mouseTexture.create(texWidth, texHeight, Graphics::createPixelFormat<5551>());
+
+ if (_mouseBuffer.format.bytesPerPixel == 1) {
+ const uint16 *palette;
+ if (_mouseCursorPaletteEnabled)
+ palette = _mouseCursorPalette;
+ else
+ palette = _gamePaletteRGBA5551;
+
+ uint16 *mouseBuf = (uint16 *)mouseTexture.getPixels();
+ for (uint x = 0; x < _videoContext->mouseWidth; ++x) {
+ for (uint y = 0; y < _videoContext->mouseHeight; ++y) {
+ const byte color = *(const byte *)_mouseBuffer.getBasePtr(x, y);
+ if (color != _mouseKeyColor)
+ mouseBuf[y * texWidth + x] = palette[color] | 0x1;
+ else
+ mouseBuf[y * texWidth + x] = 0x0;
+ }
+ }
+ } else {
+ if (crossBlit((byte *)mouseTexture.getPixels(), (const byte *)_mouseBuffer.getPixels(), mouseTexture.pitch,
+ _mouseBuffer.pitch, _mouseBuffer.w, _mouseBuffer.h, mouseTexture.format, _mouseBuffer.format)) {
+ if (!_mouseBuffer.format.aBits()) {
+ // Apply color keying since the original cursor had no alpha channel.
+ const uint16 *src = (const uint16 *)_mouseBuffer.getPixels();
+ uint8 *dstRaw = (uint8 *)mouseTexture.getPixels();
+
+ for (uint y = 0; y < _mouseBuffer.h; ++y, dstRaw += mouseTexture.pitch) {
+ uint16 *dst = (uint16 *)dstRaw;
+ for (uint x = 0; x < _mouseBuffer.w; ++x, ++dst) {
+ if (*src++ == _mouseKeyColor)
+ *dst &= ~1;
+ else
+ *dst |= 1;
+ }
+ }
+ }
+ } else {
+ // TODO: Log this!
+ // Make the cursor all transparent... we really need a better fallback ;-).
+ memset(mouseTexture.getPixels(), 0, mouseTexture.h * mouseTexture.pitch);
+ }
+ }
+
+ [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(updateMouseCursor) withObject:nil waitUntilDone: YES];
+}
diff --git a/backends/platform/ios7/ios7_scummvm_view_controller.h b/backends/platform/ios7/ios7_scummvm_view_controller.h
new file mode 100644
index 0000000000..39168aaee7
--- /dev/null
+++ b/backends/platform/ios7/ios7_scummvm_view_controller.h
@@ -0,0 +1,33 @@
+/* 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_PLATFORM_IOS7_IOS7_SCUMMVM_VIEW_CONTROLLER_H
+#define BACKENDS_PLATFORM_IOS7_IOS7_SCUMMVM_VIEW_CONTROLLER_H
+
+#include <UIKit/UIKit.h>
+
+
+@interface iOS7ScummVMViewController : UIViewController
+
+@end
+
+#endif
diff --git a/backends/platform/ios7/ios7_scummvm_view_controller.mm b/backends/platform/ios7/ios7_scummvm_view_controller.mm
new file mode 100644
index 0000000000..e78fc91f93
--- /dev/null
+++ b/backends/platform/ios7/ios7_scummvm_view_controller.mm
@@ -0,0 +1,32 @@
+/* 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/ios7/ios7_scummvm_view_controller.h"
+
+
+@implementation iOS7ScummVMViewController
+
+- (BOOL)prefersStatusBarHidden {
+ return YES;
+}
+
+@end
diff --git a/backends/platform/ios7/ios7_video.h b/backends/platform/ios7/ios7_video.h
new file mode 100644
index 0000000000..9c5d92a970
--- /dev/null
+++ b/backends/platform/ios7/ios7_video.h
@@ -0,0 +1,131 @@
+/* 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_PLATFORM_IOS7_IOS7_VIDEO_H
+#define BACKENDS_PLATFORM_IOS7_IOS7_VIDEO_H
+
+#include <UIKit/UIKit.h>
+#include <Foundation/Foundation.h>
+#include <QuartzCore/QuartzCore.h>
+
+#include <OpenGLES/EAGL.h>
+#include <OpenGLES/ES2/gl.h>
+#include <OpenGLES/ES2/glext.h>
+
+#include "backends/platform/ios7/ios7_keyboard.h"
+#include "backends/platform/ios7/ios7_common.h"
+
+#include "common/list.h"
+#include "graphics/scaler.h"
+
+typedef struct {
+ GLfloat x, y;
+ GLfloat u,v;
+} GLVertex;
+
+@interface iPhoneView : UIView {
+ VideoContext _videoContext;
+
+ Common::List<InternalEvent> _events;
+ NSLock *_eventLock;
+ SoftKeyboard *_keyboardView;
+
+ EAGLContext *_context;
+ GLuint _viewRenderbuffer;
+ GLuint _viewFramebuffer;
+ GLuint _screenTexture;
+ GLuint _overlayTexture;
+ GLuint _mouseCursorTexture;
+
+ GLuint _vertexShader;
+ GLuint _fragmentShader;
+
+ GLuint _vertexBuffer;
+
+ GLuint _screenSizeSlot;
+ GLuint _textureSlot;
+ GLuint _shakeSlot;
+
+ GLuint _positionSlot;
+ GLuint _textureCoordSlot;
+
+ GLint _renderBufferWidth;
+ GLint _renderBufferHeight;
+
+ GLVertex _gameScreenCoords[4];
+ CGRect _gameScreenRect;
+
+ GLVertex _overlayCoords[4];
+ CGRect _overlayRect;
+
+ GLVertex _mouseCoords[4];
+
+ GLint _mouseHotspotX, _mouseHotspotY;
+ GLint _mouseWidth, _mouseHeight;
+ GLfloat _mouseScaleX, _mouseScaleY;
+
+ int _scaledShakeOffsetY;
+
+ UITouch *_firstTouch;
+ UITouch *_secondTouch;
+
+#ifdef ENABLE_IOS7_SCALERS
+ uint8_t *_scalerMemorySrc;
+ uint8_t *_scalerMemoryDst;
+ size_t _scalerMemorySrcSize;
+ size_t _scalerMemoryDstSize;
+ int _scalerScale;
+ ScalerProc *_scaler;
+#endif
+}
+
+- (id)initWithFrame:(struct CGRect)frame;
+
+- (VideoContext *)getVideoContext;
+
+- (void)createScreenTexture;
+- (void)initSurface;
+- (void)setViewTransformation;
+
+- (void)setGraphicsMode;
+
+- (void)updateSurface;
+- (void)updateMainSurface;
+- (void)updateOverlaySurface;
+- (void)updateMouseSurface;
+- (void)clearColorBuffer;
+
+- (void)notifyMouseMove;
+- (void)updateMouseCursorScaling;
+- (void)updateMouseCursor;
+
+- (void)deviceOrientationChanged:(UIDeviceOrientation)orientation;
+
+- (void)applicationSuspend;
+
+- (void)applicationResume;
+
+- (bool)fetchEvent:(InternalEvent *)event;
+
+@end
+
+#endif
diff --git a/backends/platform/ios7/ios7_video.mm b/backends/platform/ios7/ios7_video.mm
new file mode 100644
index 0000000000..5c0434d43e
--- /dev/null
+++ b/backends/platform/ios7/ios7_video.mm
@@ -0,0 +1,1002 @@
+/* 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 "backends/platform/ios7/ios7_video.h"
+
+#include "graphics/colormasks.h"
+#include "common/system.h"
+#include "backends/platform/ios7/ios7_app_delegate.h"
+
+static int g_needsScreenUpdate = 0;
+
+#if 0
+static long g_lastTick = 0;
+static int g_frames = 0;
+#endif
+
+#define printOpenGLError() printOglError(__FILE__, __LINE__)
+
+int printOglError(const char *file, int line) {
+ int retCode = 0;
+
+ // returns 1 if an OpenGL error occurred, 0 otherwise.
+ GLenum glErr = glGetError();
+ while (glErr != GL_NO_ERROR) {
+ fprintf(stderr, "glError: %u (%s: %d)\n", glErr, file, line);
+ retCode = 1;
+ glErr = glGetError();
+ }
+ return retCode;
+}
+
+bool iOS7_isBigDevice() {
+ return UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad;
+}
+
+void iOS7_updateScreen() {
+ //printf("Mouse: (%i, %i)\n", mouseX, mouseY);
+ if (!g_needsScreenUpdate) {
+ g_needsScreenUpdate = 1;
+ [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(updateSurface) withObject:nil waitUntilDone: NO];
+ }
+}
+
+bool iOS7_fetchEvent(InternalEvent *event) {
+ return [[iOS7AppDelegate iPhoneView] fetchEvent:event];
+}
+
+uint getSizeNextPOT(uint size) {
+ if ((size & (size - 1)) || !size) {
+ int log = 0;
+
+ while (size >>= 1)
+ ++log;
+
+ size = (2 << log);
+ }
+
+ return size;
+}
+
+@implementation iPhoneView
+
++ (Class)layerClass {
+ return [CAEAGLLayer class];
+}
+
+- (VideoContext *)getVideoContext {
+ return &_videoContext;
+}
+
+- (void)createContext {
+ CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
+
+ eaglLayer.opaque = YES;
+ eaglLayer.drawableProperties = @{
+ kEAGLDrawablePropertyRetainedBacking: @NO,
+ kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGB565
+ };
+
+ _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
+
+ // In case creating the OpenGL ES context failed, we will error out here.
+ if (_context == nil) {
+ fprintf(stderr, "Could not create OpenGL ES context\n");
+ exit(-1);
+ }
+
+ if ([EAGLContext setCurrentContext:_context]) {
+ // glEnableClientState(GL_TEXTURE_COORD_ARRAY); printOpenGLError();
+ // glEnableClientState(GL_VERTEX_ARRAY); printOpenGLError();
+ [self setupOpenGL];
+ }
+}
+
+- (void)setupOpenGL {
+ [self setupFramebuffer];
+ [self createOverlaySurface];
+ [self compileShaders];
+ [self setupVBOs];
+ [self setupTextures];
+
+ [self finishGLSetup];
+}
+
+- (void)finishGLSetup {
+ glViewport(0, 0, _renderBufferWidth, _renderBufferHeight); printOpenGLError();
+ glClearColor(0.0f, 0.0f, 0.0f, 1.0f); printOpenGLError();
+
+ glUniform2f(_screenSizeSlot, _renderBufferWidth, _renderBufferHeight);
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+}
+
+- (void)freeOpenGL {
+ [self deleteTextures];
+ [self deleteVBOs];
+ [self deleteShaders];
+ [self deleteFramebuffer];
+}
+
+- (void)rebuildFrameBuffer {
+ [self deleteFramebuffer];
+ [self setupFramebuffer];
+ [self finishGLSetup];
+}
+
+- (void)setupFramebuffer {
+ glGenRenderbuffers(1, &_viewRenderbuffer);
+ printOpenGLError();
+ glBindRenderbuffer(GL_RENDERBUFFER, _viewRenderbuffer);
+ printOpenGLError();
+ [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(id <EAGLDrawable>) self.layer];
+
+ glGenFramebuffers(1, &_viewFramebuffer);
+ printOpenGLError();
+ glBindFramebuffer(GL_FRAMEBUFFER, _viewFramebuffer);
+ printOpenGLError();
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _viewRenderbuffer);
+ printOpenGLError();
+
+ // Retrieve the render buffer size. This *should* match the frame size,
+ // i.e. g_fullWidth and g_fullHeight.
+ glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_renderBufferWidth);
+ printOpenGLError();
+ glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_renderBufferHeight);
+ printOpenGLError();
+
+ if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
+ NSLog(@"Failed to make complete framebuffer object %x.", glCheckFramebufferStatus(GL_FRAMEBUFFER));
+ return;
+ }
+}
+
+- (void)createOverlaySurface {
+ uint overlayWidth = (uint) MAX(_renderBufferWidth, _renderBufferHeight);
+ uint overlayHeight = (uint) MIN(_renderBufferWidth, _renderBufferHeight);
+
+ if (iOS7_isBigDevice()) {
+ // On really big displays, like the iPad Pro, we scale the interface down
+ // so that the controls are not too small..
+ while (overlayHeight > 1024) {
+ overlayWidth /= 2;
+ overlayHeight /= 2;
+ }
+ }
+ else {
+ // On small devices, we force the user interface to use the small theme
+ while (overlayHeight > 480) {
+ overlayWidth /= 2;
+ overlayHeight /= 2;
+ }
+ }
+
+ _videoContext.overlayWidth = overlayWidth;
+ _videoContext.overlayHeight = overlayHeight;
+
+ uint overlayTextureWidthPOT = getSizeNextPOT(overlayWidth);
+ uint overlayTextureHeightPOT = getSizeNextPOT(overlayHeight);
+
+ // Since the overlay size won't change the whole run, we can
+ // precalculate the texture coordinates for the overlay texture here
+ // and just use it later on.
+ GLfloat u = _videoContext.overlayWidth / (GLfloat) overlayTextureWidthPOT;
+ GLfloat v = _videoContext.overlayHeight / (GLfloat) overlayTextureHeightPOT;
+ _overlayCoords[0].x = 0; _overlayCoords[0].y = 0; _overlayCoords[0].u = 0; _overlayCoords[0].v = 0;
+ _overlayCoords[1].x = 0; _overlayCoords[1].y = 0; _overlayCoords[1].u = u; _overlayCoords[1].v = 0;
+ _overlayCoords[2].x = 0; _overlayCoords[2].y = 0; _overlayCoords[2].u = 0; _overlayCoords[2].v = v;
+ _overlayCoords[3].x = 0; _overlayCoords[3].y = 0; _overlayCoords[3].u = u; _overlayCoords[3].v = v;
+
+ _videoContext.overlayTexture.create((uint16) overlayTextureWidthPOT, (uint16) overlayTextureHeightPOT, Graphics::createPixelFormat<5551>());
+}
+
+- (void)deleteFramebuffer {
+ glDeleteRenderbuffers(1, &_viewRenderbuffer);
+ glDeleteFramebuffers(1, &_viewFramebuffer);
+}
+
+- (void)setupVBOs {
+ glGenBuffers(1, &_vertexBuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
+}
+
+- (void)deleteVBOs {
+ glDeleteBuffers(1, &_vertexBuffer);
+}
+
+- (GLuint)compileShader:(const char*)shaderPrg withType:(GLenum)shaderType {
+ GLuint shaderHandle = glCreateShader(shaderType);
+
+ int shaderPrgLength = strlen(shaderPrg);
+ glShaderSource(shaderHandle, 1, &shaderPrg, &shaderPrgLength);
+
+ glCompileShader(shaderHandle);
+
+ GLint compileSuccess;
+ glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess);
+ if (compileSuccess == GL_FALSE) {
+ GLchar messages[256];
+ glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]);
+ NSString *messageString = [NSString stringWithUTF8String:messages];
+ NSLog(@"%@", messageString);
+ exit(1);
+ }
+
+ return shaderHandle;
+}
+
+- (void)compileShaders {
+ const char *vertexPrg =
+ "uniform vec2 ScreenSize;"
+ "uniform float Shake;"
+ ""
+ "attribute vec2 Position;"
+ "attribute vec2 TexCoord;"
+ ""
+ "varying vec4 DestColor;"
+ "varying vec2 o_TexCoord;"
+ ""
+ "void main(void) {"
+ " DestColor = vec4(Position.x, Position.y, 0, 1);"
+ " o_TexCoord = TexCoord;"
+ " gl_Position = vec4((Position.x / ScreenSize.x) * 2.0 - 1.0, (1.0 - (Position.y + Shake) / ScreenSize.y) * 2.0 - 1.0, 0, 1);"
+ "}";
+
+ const char *fragmentPrg =
+ "uniform sampler2D Texture;"
+ ""
+ "varying lowp vec4 DestColor;"
+ "varying lowp vec2 o_TexCoord;"
+ ""
+ "void main(void) {"
+ " gl_FragColor = texture2D(Texture, o_TexCoord);"
+ "}";
+
+ _vertexShader = [self compileShader:vertexPrg withType:GL_VERTEX_SHADER];
+ _fragmentShader = [self compileShader:fragmentPrg withType:GL_FRAGMENT_SHADER];
+
+ GLuint programHandle = glCreateProgram();
+ glAttachShader(programHandle, _vertexShader);
+ glAttachShader(programHandle, _fragmentShader);
+ glLinkProgram(programHandle);
+
+ GLint linkSuccess;
+ glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess);
+ if (linkSuccess == GL_FALSE) {
+ printOpenGLError();
+ exit(1);
+ }
+
+ glUseProgram(programHandle);
+
+ _screenSizeSlot = (GLuint) glGetUniformLocation(programHandle, "ScreenSize");
+ _textureSlot = (GLuint) glGetUniformLocation(programHandle, "Texture");
+ _shakeSlot = (GLuint) glGetUniformLocation(programHandle, "Shake");
+
+ _positionSlot = (GLuint) glGetAttribLocation(programHandle, "Position");
+ _textureCoordSlot = (GLuint) glGetAttribLocation(programHandle, "TexCoord");
+
+ glEnableVertexAttribArray(_positionSlot);
+ glEnableVertexAttribArray(_textureCoordSlot);
+
+ glUniform1i(_textureSlot, 0); printOpenGLError();
+}
+
+- (void)deleteShaders {
+ glDeleteShader(_vertexShader);
+ glDeleteShader(_fragmentShader);
+}
+
+- (void)setupTextures {
+ glGenTextures(1, &_screenTexture); printOpenGLError();
+ glGenTextures(1, &_overlayTexture); printOpenGLError();
+ glGenTextures(1, &_mouseCursorTexture); printOpenGLError();
+
+ [self setGraphicsMode];
+}
+
+- (void)deleteTextures {
+ if (_screenTexture) {
+ glDeleteTextures(1, &_screenTexture); printOpenGLError();
+ _screenTexture = 0;
+ }
+ if (_overlayTexture) {
+ glDeleteTextures(1, &_overlayTexture); printOpenGLError();
+ _overlayTexture = 0;
+ }
+ if (_mouseCursorTexture) {
+ glDeleteTextures(1, &_mouseCursorTexture); printOpenGLError();
+ _mouseCursorTexture = 0;
+ }
+}
+
+- (void)setupGestureRecognizers {
+ UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeRight:)];
+ swipeRight.direction = UISwipeGestureRecognizerDirectionRight;
+ swipeRight.numberOfTouchesRequired = 2;
+ swipeRight.delaysTouchesBegan = NO;
+ swipeRight.delaysTouchesEnded = NO;
+
+ UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeLeft:)];
+ swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft;
+ swipeLeft.numberOfTouchesRequired = 2;
+ swipeLeft.delaysTouchesBegan = NO;
+ swipeLeft.delaysTouchesEnded = NO;
+
+ UISwipeGestureRecognizer *swipeUp = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeUp:)];
+ swipeUp.direction = UISwipeGestureRecognizerDirectionUp;
+ swipeUp.numberOfTouchesRequired = 2;
+ swipeUp.delaysTouchesBegan = NO;
+ swipeUp.delaysTouchesEnded = NO;
+
+ UISwipeGestureRecognizer *swipeDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeDown:)];
+ swipeDown.direction = UISwipeGestureRecognizerDirectionDown;
+ swipeDown.numberOfTouchesRequired = 2;
+ swipeDown.delaysTouchesBegan = NO;
+ swipeDown.delaysTouchesEnded = NO;
+
+ UITapGestureRecognizer *doubleTapTwoFingers = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersDoubleTap:)];
+ doubleTapTwoFingers.numberOfTapsRequired = 2;
+ doubleTapTwoFingers.numberOfTouchesRequired = 2;
+ doubleTapTwoFingers.delaysTouchesBegan = NO;
+ doubleTapTwoFingers.delaysTouchesEnded = NO;
+
+ [self addGestureRecognizer:swipeRight];
+ [self addGestureRecognizer:swipeLeft];
+ [self addGestureRecognizer:swipeUp];
+ [self addGestureRecognizer:swipeDown];
+ [self addGestureRecognizer:doubleTapTwoFingers];
+
+ [swipeRight release];
+ [swipeLeft release];
+ [swipeUp release];
+ [swipeDown release];
+ [doubleTapTwoFingers release];
+}
+
+- (id)initWithFrame:(struct CGRect)frame {
+ self = [super initWithFrame: frame];
+
+#if defined(USE_SCALERS) || defined(USE_HQ_SCALERS)
+ InitScalers(565);
+#endif
+
+ [self setupGestureRecognizers];
+
+ [self setContentScaleFactor:[[UIScreen mainScreen] scale]];
+
+#ifdef ENABLE_IOS7_SCALERS
+ _scalerMemorySrc = NULL;
+ _scalerMemoryDst = NULL;
+ _scalerMemorySrcSize = 0;
+ _scalerMemoryDstSize = 0;
+ _scaler = NULL;
+ _scalerScale = 1;
+#endif
+
+ _keyboardView = nil;
+ _screenTexture = 0;
+ _overlayTexture = 0;
+ _mouseCursorTexture = 0;
+
+ _scaledShakeOffsetY = 0;
+
+ _firstTouch = NULL;
+ _secondTouch = NULL;
+
+ _eventLock = [[NSLock alloc] init];
+
+ memset(_gameScreenCoords, 0, sizeof(GLVertex) * 4);
+ memset(_overlayCoords, 0, sizeof(GLVertex) * 4);
+ memset(_mouseCoords, 0, sizeof(GLVertex) * 4);
+
+ // Initialize the OpenGL ES context
+ [self createContext];
+
+ return self;
+}
+
+- (void)dealloc {
+ [_keyboardView release];
+
+ _videoContext.screenTexture.free();
+ _videoContext.overlayTexture.free();
+ _videoContext.mouseTexture.free();
+
+#ifdef ENABLE_IOS7_SCALERS
+ free(_scalerMemorySrc);
+ free(_scalerMemoryDst);
+#endif
+
+ [_eventLock release];
+ [super dealloc];
+}
+
+- (void)setFilterModeForTexture:(GLuint)tex {
+ if (!tex)
+ return;
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, tex); printOpenGLError();
+
+ GLint filter = GL_LINEAR;
+
+ switch (_videoContext.graphicsMode) {
+ case kGraphicsModeNone:
+ filter = GL_NEAREST;
+ break;
+
+ case kGraphicsModeLinear:
+ case kGraphicsMode2xSaI:
+ case kGraphicsModeSuper2xSaI:
+ case kGraphicsModeSuperEagle:
+ case kGraphicsModeAdvMame2x:
+ case kGraphicsModeAdvMame3x:
+ case kGraphicsModeHQ2x:
+ case kGraphicsModeHQ3x:
+ case kGraphicsModeTV2x:
+ case kGraphicsModeDotMatrix:
+ filter = GL_LINEAR;
+ break;
+ }
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); printOpenGLError();
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); printOpenGLError();
+ // We use GL_CLAMP_TO_EDGE here to avoid artifacts when linear filtering
+ // is used. If we would not use this for example the cursor in Loom would
+ // have a line/border artifact on the right side of the covered rect.
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); printOpenGLError();
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); printOpenGLError();
+}
+
+#ifdef ENABLE_IOS7_SCALERS
+- (void)setScaler {
+ ScalerProc *scaler = NULL;
+ int scalerScale = 1;
+
+ switch (_videoContext.graphicsMode) {
+ case kGraphicsModeLinear:
+ break;
+
+ case kGraphicsModeNone:
+ break;
+#ifdef USE_SCALERS
+ case kGraphicsMode2xSaI:
+ scaler = _2xSaI;
+ scalerScale = 2;
+ break;
+
+ case kGraphicsModeSuper2xSaI:
+ scaler = Super2xSaI;
+ scalerScale = 2;
+ break;
+
+ case kGraphicsModeSuperEagle:
+ scaler = SuperEagle;
+ scalerScale = 2;
+ break;
+
+ case kGraphicsModeAdvMame2x:
+ scaler = AdvMame2x;
+ scalerScale = 2;
+ break;
+
+ case kGraphicsModeAdvMame3x:
+ scaler = AdvMame3x;
+ scalerScale = 3;
+ break;
+
+#ifdef USE_HQ_SCALERS
+ case kGraphicsModeHQ2x:
+ scaler = HQ2x;
+ scalerScale = 2;
+ break;
+
+ case kGraphicsModeHQ3x:
+ scaler = HQ3x;
+ scalerScale = 3;
+ break;
+#endif
+
+ case kGraphicsModeTV2x:
+ scaler = TV2x;
+ scalerScale = 2;
+ break;
+
+ case kGraphicsModeDotMatrix:
+ scaler = DotMatrix;
+ scalerScale = 2;
+ break;
+#endif
+
+ default:
+ break;
+ }
+
+ _scaler = scaler;
+ _scalerScale = scalerScale;
+}
+#endif
+
+- (void)setGraphicsMode {
+ [self setFilterModeForTexture:_screenTexture];
+ [self setFilterModeForTexture:_overlayTexture];
+ [self setFilterModeForTexture:_mouseCursorTexture];
+#ifdef ENABLE_IOS7_SCALERS
+ [self setScaler];
+#endif
+}
+
+- (void)updateSurface {
+ if (!g_needsScreenUpdate) {
+ return;
+ }
+ g_needsScreenUpdate = 0;
+
+ glClear(GL_COLOR_BUFFER_BIT); printOpenGLError();
+
+ [self updateMainSurface];
+
+ if (_videoContext.overlayVisible)
+ [self updateOverlaySurface];
+
+ if (_videoContext.mouseIsVisible)
+ [self updateMouseSurface];
+
+ [_context presentRenderbuffer:GL_RENDERBUFFER];
+ glFinish();
+}
+
+- (void)notifyMouseMove {
+ const GLint mouseX = (GLint)(_videoContext.mouseX * _mouseScaleX) - _mouseHotspotX;
+ const GLint mouseY = (GLint)(_videoContext.mouseY * _mouseScaleY) - _mouseHotspotY;
+
+ _mouseCoords[0].x = _mouseCoords[2].x = mouseX;
+ _mouseCoords[0].y = _mouseCoords[1].y = mouseY;
+ _mouseCoords[1].x = _mouseCoords[3].x = mouseX + _mouseWidth;
+ _mouseCoords[2].y = _mouseCoords[3].y = mouseY + _mouseHeight;
+}
+
+- (void)updateMouseCursorScaling {
+ CGRect *rect;
+ int maxWidth, maxHeight;
+
+ if (!_videoContext.overlayVisible) {
+ rect = &_gameScreenRect;
+ maxWidth = _videoContext.screenWidth;
+ maxHeight = _videoContext.screenHeight;
+ } else {
+ rect = &_overlayRect;
+ maxWidth = _videoContext.overlayWidth;
+ maxHeight = _videoContext.overlayHeight;
+ }
+
+ if (!maxWidth || !maxHeight) {
+ printf("WARNING: updateMouseCursorScaling called when screen was not ready (%d)!\n", _videoContext.overlayVisible);
+ return;
+ }
+
+ _mouseScaleX = CGRectGetWidth(*rect) / (GLfloat)maxWidth;
+ _mouseScaleY = CGRectGetHeight(*rect) / (GLfloat)maxHeight;
+
+ _mouseWidth = (GLint)(_videoContext.mouseWidth * _mouseScaleX);
+ _mouseHeight = (GLint)(_videoContext.mouseHeight * _mouseScaleY);
+
+ _mouseHotspotX = (GLint)(_videoContext.mouseHotspotX * _mouseScaleX);
+ _mouseHotspotY = (GLint)(_videoContext.mouseHotspotY * _mouseScaleY);
+
+ // We subtract the screen offset to the hotspot here to simplify the
+ // screen offset handling in the mouse code. Note the subtraction here
+ // makes sure that the offset actually gets added to the mouse position,
+ // since the hotspot offset is substracted from the position.
+ _mouseHotspotX -= (GLint)CGRectGetMinX(*rect);
+ _mouseHotspotY -= (GLint)CGRectGetMinY(*rect);
+
+ // FIXME: For now we also adapt the mouse position here. In reality we
+ // would be better off to also adjust the event position when switching
+ // from overlay to game screen or vica versa.
+ [self notifyMouseMove];
+}
+
+- (void)updateMouseCursor {
+ [self updateMouseCursorScaling];
+
+ _mouseCoords[1].u = _mouseCoords[3].u = (_videoContext.mouseWidth - 1) / (GLfloat)_videoContext.mouseTexture.w;
+ _mouseCoords[2].v = _mouseCoords[3].v = (_videoContext.mouseHeight - 1) / (GLfloat)_videoContext.mouseTexture.h;
+
+ [self setFilterModeForTexture:_mouseCursorTexture];
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _videoContext.mouseTexture.w, _videoContext.mouseTexture.h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, _videoContext.mouseTexture.getPixels()); printOpenGLError();
+}
+
+- (void)updateMainSurface {
+ glBufferData(GL_ARRAY_BUFFER, sizeof(GLVertex) * 4, _gameScreenCoords, GL_STATIC_DRAW);
+ glVertexAttribPointer(_positionSlot, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), 0);
+ glVertexAttribPointer(_textureCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), (GLvoid *) (sizeof(GLfloat) * 2));
+
+ [self setFilterModeForTexture:_screenTexture];
+
+ // Unfortunately we have to update the whole texture every frame, since glTexSubImage2D is actually slower in all cases
+ // due to the iPhone internals having to convert the whole texture back from its internal format when used.
+ // In the future we could use several tiled textures instead.
+#ifdef ENABLE_IOS7_SCALERS
+ if (_scaler) {
+ size_t neededSrcMemorySize = (size_t) (_videoContext.screenTexture.pitch * (_videoContext.screenTexture.h + 4));
+ size_t neededDstMemorySize = (size_t) (_videoContext.screenTexture.pitch * (_videoContext.screenTexture.h + 4) * _scalerScale * _scalerScale);
+ if (neededSrcMemorySize != _scalerMemorySrcSize) {
+ _scalerMemorySrc = (uint8_t *) realloc(_scalerMemorySrc, neededSrcMemorySize);
+ _scalerMemorySrcSize = neededSrcMemorySize;
+ }
+ if (neededDstMemorySize != _scalerMemoryDstSize) {
+ _scalerMemoryDst = (uint8_t *) realloc(_scalerMemoryDst, neededDstMemorySize);
+ _scalerMemoryDstSize = neededDstMemorySize;
+ }
+
+ // Clear two lines before
+ memset(_scalerMemorySrc, 0, (size_t) (_videoContext.screenTexture.pitch * 2));
+ // Copy original buffer
+ memcpy(_scalerMemorySrc + _videoContext.screenTexture.pitch * 2, _videoContext.screenTexture.getPixels(), _videoContext.screenTexture.pitch * _videoContext.screenTexture.h);
+ // Clear two lines after
+ memset(_scalerMemorySrc + _videoContext.screenTexture.pitch * (2 + _videoContext.screenTexture.h), 0, (size_t) (_videoContext.screenTexture.pitch * 2));
+ // Apply scaler
+ _scaler(_scalerMemorySrc + _videoContext.screenTexture.pitch * 2,
+ _videoContext.screenTexture.pitch,
+ _scalerMemoryDst,
+ (uint32) (_videoContext.screenTexture.pitch * _scalerScale),
+ _videoContext.screenTexture.w,
+ _videoContext.screenTexture.h);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _videoContext.screenTexture.w * _scalerScale, _videoContext.screenTexture.h * _scalerScale, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, _scalerMemoryDst); printOpenGLError();
+ }
+ else {
+#endif
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _videoContext.screenTexture.w, _videoContext.screenTexture.h, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, _videoContext.screenTexture.getPixels()); printOpenGLError();
+#ifdef ENABLE_IOS7_SCALERS
+ }
+#endif
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError();
+}
+
+- (void)updateOverlaySurface {
+ glBufferData(GL_ARRAY_BUFFER, sizeof(GLVertex) * 4, _overlayCoords, GL_STATIC_DRAW);
+ glVertexAttribPointer(_positionSlot, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), 0);
+ glVertexAttribPointer(_textureCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), (GLvoid *) (sizeof(GLfloat) * 2));
+
+ [self setFilterModeForTexture:_overlayTexture];
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _videoContext.overlayTexture.w, _videoContext.overlayTexture.h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, _videoContext.overlayTexture.getPixels()); printOpenGLError();
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError();
+}
+
+- (void)updateMouseSurface {
+ glBufferData(GL_ARRAY_BUFFER, sizeof(GLVertex) * 4, _mouseCoords, GL_STATIC_DRAW);
+ glVertexAttribPointer(_positionSlot, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), 0);
+ glVertexAttribPointer(_textureCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), (GLvoid *) (sizeof(GLfloat) * 2));
+
+ glBindTexture(GL_TEXTURE_2D, _mouseCursorTexture); printOpenGLError();
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError();
+}
+
+- (void)createScreenTexture {
+ const uint screenTexWidth = getSizeNextPOT(_videoContext.screenWidth);
+ const uint screenTexHeight = getSizeNextPOT(_videoContext.screenHeight);
+
+ _gameScreenCoords[1].u = _gameScreenCoords[3].u = _videoContext.screenWidth / (GLfloat)screenTexWidth;
+ _gameScreenCoords[2].v = _gameScreenCoords[3].v = _videoContext.screenHeight / (GLfloat)screenTexHeight;
+
+ _videoContext.screenTexture.create((uint16) screenTexWidth, (uint16) screenTexHeight, Graphics::createPixelFormat<565>());
+}
+
+- (void)initSurface {
+ if (_context) {
+ [self rebuildFrameBuffer];
+ }
+
+ BOOL isLandscape = (self.bounds.size.width > self.bounds.size.height); // UIDeviceOrientationIsLandscape([[UIDevice currentDevice] orientation]);
+
+ int screenWidth, screenHeight;
+ if (isLandscape) {
+ screenWidth = MAX(_renderBufferWidth, _renderBufferHeight);
+ screenHeight = MIN(_renderBufferWidth, _renderBufferHeight);
+ }
+ else {
+ screenWidth = MIN(_renderBufferWidth, _renderBufferHeight);
+ screenHeight = MAX(_renderBufferWidth, _renderBufferHeight);
+ }
+
+ glBindRenderbuffer(GL_RENDERBUFFER, _viewRenderbuffer); printOpenGLError();
+
+ [self clearColorBuffer];
+
+ GLfloat adjustedWidth = _videoContext.screenWidth;
+ GLfloat adjustedHeight = _videoContext.screenHeight;
+ if (_videoContext.asprectRatioCorrection) {
+ if (_videoContext.screenWidth == 320 && _videoContext.screenHeight == 200)
+ adjustedHeight = 240;
+ else if (_videoContext.screenWidth == 640 && _videoContext.screenHeight == 400)
+ adjustedHeight = 480;
+ }
+
+ float overlayPortraitRatio;
+
+ if (isLandscape) {
+ GLfloat gameScreenRatio = adjustedWidth / adjustedHeight;
+ GLfloat screenRatio = (GLfloat)screenWidth / (GLfloat)screenHeight;
+
+ // These are the width/height according to the portrait layout!
+ int rectWidth, rectHeight;
+ int xOffset, yOffset;
+
+ if (gameScreenRatio < screenRatio) {
+ // When the game screen ratio is less than the screen ratio
+ // we need to scale the width, since the game screen was higher
+ // compared to the width than our output screen is.
+ rectWidth = (int)(screenHeight * gameScreenRatio);
+ rectHeight = screenHeight;
+ xOffset = (screenWidth - rectWidth) / 2;
+ yOffset = 0;
+ } else {
+ // When the game screen ratio is bigger than the screen ratio
+ // we need to scale the height, since the game screen was wider
+ // compared to the height than our output screen is.
+ rectWidth = screenWidth;
+ rectHeight = (int)(screenWidth / gameScreenRatio);
+ xOffset = 0;
+ yOffset = (screenHeight - rectHeight) / 2;
+ }
+
+ [_keyboardView hideKeyboard];
+
+ //printf("Rect: %i, %i, %i, %i\n", xOffset, yOffset, rectWidth, rectHeight);
+ _gameScreenRect = CGRectMake(xOffset, yOffset, rectWidth, rectHeight);
+ overlayPortraitRatio = 1.0f;
+ } else {
+ GLfloat ratio = adjustedHeight / adjustedWidth;
+ int height = (int)(screenWidth * ratio);
+ //printf("Making rect (%u, %u)\n", screenWidth, height);
+ _gameScreenRect = CGRectMake(0, 0, screenWidth, height);
+
+ CGRect keyFrame = CGRectMake(0.0f, 0.0f, 0.0f, 0.0f);
+ if (_keyboardView == nil) {
+ _keyboardView = [[SoftKeyboard alloc] initWithFrame:keyFrame];
+ [_keyboardView setInputDelegate:self];
+ [self addSubview:[_keyboardView inputView]];
+ [self addSubview: _keyboardView];
+ }
+
+ [_keyboardView showKeyboard];
+ overlayPortraitRatio = (_videoContext.overlayHeight * ratio) / _videoContext.overlayWidth;
+ }
+ _overlayRect = CGRectMake(0, 0, screenWidth, screenHeight * overlayPortraitRatio);
+
+ _gameScreenCoords[0].x = _gameScreenCoords[2].x = CGRectGetMinX(_gameScreenRect);
+ _gameScreenCoords[0].y = _gameScreenCoords[1].y = CGRectGetMinY(_gameScreenRect);
+ _gameScreenCoords[1].x = _gameScreenCoords[3].x = CGRectGetMaxX(_gameScreenRect);
+ _gameScreenCoords[2].y = _gameScreenCoords[3].y = CGRectGetMaxY(_gameScreenRect);
+
+ _overlayCoords[1].x = _overlayCoords[3].x = CGRectGetMaxX(_overlayRect);
+ _overlayCoords[2].y = _overlayCoords[3].y = CGRectGetMaxY(_overlayRect);
+
+ [self setViewTransformation];
+ [self updateMouseCursorScaling];
+}
+
+- (void)setViewTransformation {
+ // Scale the shake offset according to the overlay size. We need this to
+ // adjust the overlay mouse click coordinates when an offset is set.
+ _scaledShakeOffsetY = (int)(_videoContext.shakeOffsetY / (GLfloat)_videoContext.screenHeight * CGRectGetHeight(_overlayRect));
+
+ glUniform1f(_shakeSlot, _scaledShakeOffsetY);
+}
+
+- (void)clearColorBuffer {
+ // The color buffer is triple-buffered, so we clear it multiple times right away to avid doing any glClears later.
+ int clearCount = 5;
+ while (clearCount-- > 0) {
+ glClear(GL_COLOR_BUFFER_BIT); printOpenGLError();
+ [_context presentRenderbuffer:GL_RENDERBUFFER];
+ glFinish();
+ }
+}
+
+- (void)addEvent:(InternalEvent)event {
+ [_eventLock lock];
+ _events.push_back(event);
+ [_eventLock unlock];
+}
+
+- (bool)fetchEvent:(InternalEvent *)event {
+ [_eventLock lock];
+ if (_events.empty()) {
+ [_eventLock unlock];
+ return false;
+ }
+
+ *event = *_events.begin();
+ _events.pop_front();
+ [_eventLock unlock];
+ return true;
+}
+
+- (bool)getMouseCoords:(CGPoint)point eventX:(int *)x eventY:(int *)y {
+ // We scale the input according to our scale factor to get actual screen
+ // coordinates.
+ point.x *= self.contentScaleFactor;
+ point.y *= self.contentScaleFactor;
+
+ CGRect *area;
+ int width, height, offsetY;
+ if (_videoContext.overlayVisible) {
+ area = &_overlayRect;
+ width = _videoContext.overlayWidth;
+ height = _videoContext.overlayHeight;
+ offsetY = _scaledShakeOffsetY;
+ } else {
+ area = &_gameScreenRect;
+ width = _videoContext.screenWidth;
+ height = _videoContext.screenHeight;
+ offsetY = _videoContext.shakeOffsetY;
+ }
+
+ point.x = (point.x - CGRectGetMinX(*area)) / CGRectGetWidth(*area);
+ point.y = (point.y - CGRectGetMinY(*area)) / CGRectGetHeight(*area);
+
+ *x = (int)(point.x * width);
+ // offsetY describes the translation of the screen in the upward direction,
+ // thus we need to add it here.
+ *y = (int)(point.y * height + offsetY);
+
+ if (!iOS7_touchpadModeEnabled()) {
+ // Clip coordinates
+ if (*x < 0 || *x > width || *y < 0 || *y > height)
+ return false;
+ }
+
+ return true;
+}
+
+- (void)deviceOrientationChanged:(UIDeviceOrientation)orientation {
+ [self addEvent:InternalEvent(kInputOrientationChanged, orientation, 0)];
+}
+
+- (UITouch *)secondTouchOtherTouchThan:(UITouch *)touch in:(NSSet *)set {
+ NSArray *all = [set allObjects];
+ for (UITouch *t in all) {
+ if (t != touch) {
+ return t;
+ }
+ }
+ return nil;
+}
+
+- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
+ int x, y;
+
+ NSSet *allTouches = [event allTouches];
+ if (allTouches.count == 1) {
+ _firstTouch = [allTouches anyObject];
+ CGPoint point = [_firstTouch locationInView:self];
+ if (![self getMouseCoords:point eventX:&x eventY:&y])
+ return;
+
+ [self addEvent:InternalEvent(kInputMouseDown, x, y)];
+ }
+ else if (allTouches.count == 2) {
+ _secondTouch = [self secondTouchOtherTouchThan:_firstTouch in:allTouches];
+ if (_secondTouch) {
+ CGPoint point = [_secondTouch locationInView:self];
+ if (![self getMouseCoords:point eventX:&x eventY:&y])
+ return;
+
+ [self addEvent:InternalEvent(kInputMouseSecondDown, x, y)];
+ }
+ }
+}
+
+- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
+ int x, y;
+
+ NSSet *allTouches = [event allTouches];
+ for (UITouch *touch in allTouches) {
+ if (touch == _firstTouch) {
+ CGPoint point = [touch locationInView:self];
+ if (![self getMouseCoords:point eventX:&x eventY:&y])
+ return;
+
+ [self addEvent:InternalEvent(kInputMouseDragged, x, y)];
+ } else if (touch == _secondTouch) {
+ CGPoint point = [touch locationInView:self];
+ if (![self getMouseCoords:point eventX:&x eventY:&y])
+ return;
+
+ [self addEvent:InternalEvent(kInputMouseSecondDragged, x, y)];
+ }
+ }
+}
+
+- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
+ int x, y;
+
+ NSSet *allTouches = [event allTouches];
+ if (allTouches.count == 1) {
+ UITouch *touch = [allTouches anyObject];
+ CGPoint point = [touch locationInView:self];
+ if (![self getMouseCoords:point eventX:&x eventY:&y]) {
+ return;
+ }
+
+ [self addEvent:InternalEvent(kInputMouseUp, x, y)];
+ }
+ else if (allTouches.count == 2) {
+ UITouch *touch = [[allTouches allObjects] objectAtIndex:1];
+ CGPoint point = [touch locationInView:self];
+ if (![self getMouseCoords:point eventX:&x eventY:&y])
+ return;
+
+ [self addEvent:InternalEvent(kInputMouseSecondUp, x, y)];
+ }
+ _firstTouch = nil;
+ _secondTouch = nil;
+}
+
+- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
+ _firstTouch = nil;
+ _secondTouch = nil;
+}
+
+- (void)twoFingersSwipeRight:(UISwipeGestureRecognizer *)recognizer {
+ [self addEvent:InternalEvent(kInputSwipe, kUIViewSwipeRight, 2)];
+}
+
+- (void)twoFingersSwipeLeft:(UISwipeGestureRecognizer *)recognizer {
+ [self addEvent:InternalEvent(kInputSwipe, kUIViewSwipeLeft, 2)];
+}
+
+- (void)twoFingersSwipeUp:(UISwipeGestureRecognizer *)recognizer {
+ [self addEvent:InternalEvent(kInputSwipe, kUIViewSwipeUp, 2)];
+}
+
+- (void)twoFingersSwipeDown:(UISwipeGestureRecognizer *)recognizer {
+ [self addEvent:InternalEvent(kInputSwipe, kUIViewSwipeDown, 2)];
+}
+
+- (void)twoFingersDoubleTap:(UITapGestureRecognizer *)recognizer {
+ [self addEvent:InternalEvent(kInputTap, kUIViewTapDouble, 2)];
+}
+
+- (void)handleKeyPress:(unichar)c {
+ [self addEvent:InternalEvent(kInputKeyPressed, c, 0)];
+}
+
+- (void)applicationSuspend {
+ [self addEvent:InternalEvent(kInputApplicationSuspended, 0, 0)];
+}
+
+- (void)applicationResume {
+ [self addEvent:InternalEvent(kInputApplicationResumed, 0, 0)];
+}
+
+@end
diff --git a/backends/platform/ios7/module.mk b/backends/platform/ios7/module.mk
new file mode 100644
index 0000000000..ad4f7fda5b
--- /dev/null
+++ b/backends/platform/ios7/module.mk
@@ -0,0 +1,17 @@
+MODULE := backends/platform/ios7
+
+MODULE_OBJS := \
+ ios7_osys_main.o \
+ ios7_osys_events.o \
+ ios7_osys_sound.o \
+ ios7_osys_video.o \
+ ios7_main.o \
+ ios7_video.o \
+ ios7_keyboard.o \
+ ios7_scummvm_view_controller.o \
+ ios7_app_delegate.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/iphone/iphone_keyboard.mm b/backends/platform/iphone/iphone_keyboard.mm
index 39d68aff81..85ba3520f2 100644
--- a/backends/platform/iphone/iphone_keyboard.mm
+++ b/backends/platform/iphone/iphone_keyboard.mm
@@ -20,7 +20,7 @@
*
*/
-#include "iphone_keyboard.h"
+#include "backends/platform/iphone/iphone_keyboard.h"
@interface UITextInputTraits
- (void)setAutocorrectionType:(int)type;
diff --git a/backends/platform/iphone/iphone_main.mm b/backends/platform/iphone/iphone_main.mm
index 3707f10a29..fc29615814 100644
--- a/backends/platform/iphone/iphone_main.mm
+++ b/backends/platform/iphone/iphone_main.mm
@@ -26,7 +26,7 @@
#include <UIKit/UIKit.h>
#include <Foundation/NSThread.h>
-#include "iphone_video.h"
+#include "backends/platform/iphone/iphone_video.h"
void iphone_main(int argc, char *argv[]);
diff --git a/backends/platform/iphone/iphone_video.h b/backends/platform/iphone/iphone_video.h
index 7dbf3c57ab..26c32183ce 100644
--- a/backends/platform/iphone/iphone_video.h
+++ b/backends/platform/iphone/iphone_video.h
@@ -31,8 +31,8 @@
#include <OpenGLES/ES1/gl.h>
#include <OpenGLES/ES1/glext.h>
-#include "iphone_keyboard.h"
-#include "iphone_common.h"
+#include "backends/platform/iphone/iphone_keyboard.h"
+#include "backends/platform/iphone/iphone_common.h"
#include "common/list.h"
diff --git a/backends/platform/iphone/iphone_video.mm b/backends/platform/iphone/iphone_video.mm
index 5048b57328..9e521de179 100644
--- a/backends/platform/iphone/iphone_video.mm
+++ b/backends/platform/iphone/iphone_video.mm
@@ -23,7 +23,7 @@
// Disable symbol overrides so that we can use system headers.
#define FORBIDDEN_SYMBOL_ALLOW_ALL
-#include "iphone_video.h"
+#include "backends/platform/iphone/iphone_video.h"
#include "graphics/colormasks.h"
diff --git a/backends/platform/iphone/osys_events.cpp b/backends/platform/iphone/osys_events.cpp
index 95ca25a2d2..617f6b8843 100644
--- a/backends/platform/iphone/osys_events.cpp
+++ b/backends/platform/iphone/osys_events.cpp
@@ -26,7 +26,7 @@
#include "gui/message.h"
#include "common/translation.h"
-#include "osys_main.h"
+#include "backends/platform/iphone/osys_main.h"
static const int kQueuedInputEventDelay = 50;
diff --git a/backends/platform/iphone/osys_main.cpp b/backends/platform/iphone/osys_main.cpp
index 0ce21b44c1..36b3482d7e 100644
--- a/backends/platform/iphone/osys_main.cpp
+++ b/backends/platform/iphone/osys_main.cpp
@@ -41,7 +41,7 @@
#include "audio/mixer.h"
#include "audio/mixer_intern.h"
-#include "osys_main.h"
+#include "backends/platform/iphone/osys_main.h"
const OSystem::GraphicsMode OSystem_IPHONE::s_supportedGraphicsModes[] = {
@@ -90,7 +90,7 @@ int OSystem_IPHONE::timerHandler(int t) {
}
void OSystem_IPHONE::initBackend() {
-#ifdef IPHONE_OFFICIAL
+#ifdef IPHONE_SANDBOXED
_savefileManager = new DefaultSaveFileManager(iPhone_getDocumentsDir());
#else
_savefileManager = new DefaultSaveFileManager(SCUMMVM_SAVE_PATH);
@@ -252,7 +252,7 @@ OSystem *OSystem_IPHONE_create() {
}
Common::String OSystem_IPHONE::getDefaultConfigFileName() {
-#ifdef IPHONE_OFFICIAL
+#ifdef IPHONE_SANDBOXED
Common::String path = iPhone_getDocumentsDir();
path += "/Preferences";
return path;
@@ -305,7 +305,7 @@ void iphone_main(int argc, char *argv[]) {
//gDebugLevel = 10;
}
-#ifdef IPHONE_OFFICIAL
+#ifdef IPHONE_SANDBOXED
chdir(iPhone_getDocumentsDir());
#else
system("mkdir " SCUMMVM_ROOT_PATH);
diff --git a/backends/platform/iphone/osys_main.h b/backends/platform/iphone/osys_main.h
index 0159eee1be..390566322c 100644
--- a/backends/platform/iphone/osys_main.h
+++ b/backends/platform/iphone/osys_main.h
@@ -24,7 +24,7 @@
#define BACKENDS_PLATFORM_IPHONE_OSYS_MAIN_H
#include "graphics/surface.h"
-#include "iphone_common.h"
+#include "backends/platform/iphone/iphone_common.h"
#include "backends/base-backend.h"
#include "common/events.h"
#include "audio/mixer_intern.h"
diff --git a/backends/platform/iphone/osys_sound.cpp b/backends/platform/iphone/osys_sound.cpp
index bfee06c6f2..34c1cbff34 100644
--- a/backends/platform/iphone/osys_sound.cpp
+++ b/backends/platform/iphone/osys_sound.cpp
@@ -23,7 +23,7 @@
// Disable symbol overrides so that we can use system headers.
#define FORBIDDEN_SYMBOL_ALLOW_ALL
-#include "osys_main.h"
+#include "backends/platform/iphone/osys_main.h"
void OSystem_IPHONE::AQBufferCallback(void *in, AudioQueueRef inQ, AudioQueueBufferRef outQB) {
//printf("AQBufferCallback()\n");
diff --git a/backends/platform/iphone/osys_video.mm b/backends/platform/iphone/osys_video.mm
index c76f432dda..fa5c729a1c 100644
--- a/backends/platform/iphone/osys_video.mm
+++ b/backends/platform/iphone/osys_video.mm
@@ -23,8 +23,8 @@
// Disable symbol overrides so that we can use system headers.
#define FORBIDDEN_SYMBOL_ALLOW_ALL
-#include "osys_main.h"
-#include "iphone_video.h"
+#include "backends/platform/iphone/osys_main.h"
+#include "backends/platform/iphone/iphone_video.h"
#include "graphics/conversion.h"
diff --git a/backends/platform/maemo/debian/changelog b/backends/platform/maemo/debian/changelog
index 49e8de69d6..e4c5c58ccd 100644
--- a/backends/platform/maemo/debian/changelog
+++ b/backends/platform/maemo/debian/changelog
@@ -1,3 +1,21 @@
+scummvm (1.9.0~git) unstable; urgency=low
+
+ * Development snapshot
+
+ -- 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
+
+ -- Tarek Soliman <tsoliman@scummvm.org> Fri, 26 Feb 2016 21:11:20 -0600
+
scummvm (1.7.0) unstable; urgency=low
* 1.7.0 release
diff --git a/backends/platform/maemo/debian/rules b/backends/platform/maemo/debian/rules
index 2aa7f339c9..0e72c8aa9a 100755
--- a/backends/platform/maemo/debian/rules
+++ b/backends/platform/maemo/debian/rules
@@ -6,8 +6,8 @@ build: scummvm
scummvm:
dh_testdir
- ./configure --host=maemo
- $(MAKE)
+ ./configure --host=maemo $(CONFIGURE_EXTRA_ARGS)
+ $(MAKE) $(MAKE_EXTRA_ARGS)
clean:
dh_testdir
@@ -48,7 +48,19 @@ install: build
install -m0644 backends/vkeybd/packs/vkeybd_default.zip debian/scummvm/opt/scummvm/share
install -m0644 backends/vkeybd/packs/vkeybd_small.zip debian/scummvm/opt/scummvm/share
# for optified version we can also add engine datafiles
- install -m0644 dists/engine-data/drascula.dat dists/engine-data/hugo.dat dists/engine-data/kyra.dat dists/engine-data/lure.dat dists/engine-data/queen.tbl dists/engine-data/sky.cpt dists/engine-data/teenagent.dat dists/engine-data/tony.dat dists/engine-data/toon.dat debian/scummvm/opt/scummvm/share
+ install -m0644 dists/engine-data/access.dat debian/scummvm/opt/scummvm/share
+ install -m0644 dists/engine-data/drascula.dat debian/scummvm/opt/scummvm/share
+ install -m0644 dists/engine-data/hugo.dat debian/scummvm/opt/scummvm/share
+ install -m0644 dists/engine-data/kyra.dat debian/scummvm/opt/scummvm/share
+ install -m0644 dists/engine-data/lure.dat debian/scummvm/opt/scummvm/share
+ install -m0644 dists/engine-data/mort.dat debian/scummvm/opt/scummvm/share
+ install -m0644 dists/engine-data/neverhood.dat debian/scummvm/opt/scummvm/share
+ install -m0644 dists/engine-data/queen.tbl debian/scummvm/opt/scummvm/share
+ install -m0644 dists/engine-data/sky.cpt debian/scummvm/opt/scummvm/share
+ install -m0644 dists/engine-data/teenagent.dat debian/scummvm/opt/scummvm/share
+ install -m0644 dists/engine-data/tony.dat debian/scummvm/opt/scummvm/share
+ install -m0644 dists/engine-data/toon.dat debian/scummvm/opt/scummvm/share
+ install -m0644 dists/engine-data/wintermute.zip debian/scummvm/opt/scummvm/share
install -m0644 -d debian/scummvm/usr/share/doc/scummvm
install -m0644 AUTHORS COPYING COPYING.BSD COPYING.FREEFONT COPYING.LGPL COPYRIGHT NEWS README debian/scummvm/usr/share/doc/scummvm
diff --git a/backends/platform/maemo/maemo.cpp b/backends/platform/maemo/maemo.cpp
index 5fdcddac43..dc1054940e 100644
--- a/backends/platform/maemo/maemo.cpp
+++ b/backends/platform/maemo/maemo.cpp
@@ -52,31 +52,31 @@ OSystem_SDL_Maemo::~OSystem_SDL_Maemo() {
#ifdef ENABLE_KEYMAPPER
static void registerDefaultKeyBindings(Common::KeymapperDefaultBindings *_keymapperDefaultBindings, Model _model) {
- _keymapperDefaultBindings->setDefaultBinding("gui", "REM", "HOME");
- _keymapperDefaultBindings->setDefaultBinding("global", "REM", "HOME");
+ _keymapperDefaultBindings->setDefaultBinding("gui", "REMP", "HOME");
+ _keymapperDefaultBindings->setDefaultBinding("global", "REMP", "HOME");
if (_model.hasMenuKey && _model.hasHwKeyboard) {
- _keymapperDefaultBindings->setDefaultBinding("gui", "FUL", "FULLSCREEN");
- _keymapperDefaultBindings->setDefaultBinding("global", "FUL", "FULLSCREEN");
+ _keymapperDefaultBindings->setDefaultBinding("gui", "FULS", "FULLSCREEN");
+ _keymapperDefaultBindings->setDefaultBinding("global", "FULS", "FULLSCREEN");
}
if (_model.hasHwKeyboard) {
- _keymapperDefaultBindings->setDefaultBinding("gui", "VIR", "C+ZOOMMINUS");
- _keymapperDefaultBindings->setDefaultBinding("global", "VIR", "C+ZOOMMINUS");
+ _keymapperDefaultBindings->setDefaultBinding("gui", "VIRT", "C+ZOOMMINUS");
+ _keymapperDefaultBindings->setDefaultBinding("global", "VIRT", "C+ZOOMMINUS");
} else {
- _keymapperDefaultBindings->setDefaultBinding("gui", "VIR", "FULLSCREEN");
- _keymapperDefaultBindings->setDefaultBinding("global", "VIR", "FULLSCREEN");
+ _keymapperDefaultBindings->setDefaultBinding("gui", "VIRT", "FULLSCREEN");
+ _keymapperDefaultBindings->setDefaultBinding("global", "VIRT", "FULLSCREEN");
}
if (_model.hasMenuKey )
- _keymapperDefaultBindings->setDefaultBinding("global", "MEN", "MENU");
+ _keymapperDefaultBindings->setDefaultBinding("global", "MENU", "MENU");
else
- _keymapperDefaultBindings->setDefaultBinding("global", "MEN", "S+C+M");
+ _keymapperDefaultBindings->setDefaultBinding("global", "MENU", "S+C+M");
- _keymapperDefaultBindings->setDefaultBinding("gui", "CLO", "ESCAPE");
+ _keymapperDefaultBindings->setDefaultBinding("gui", "CLOS", "ESCAPE");
- _keymapperDefaultBindings->setDefaultBinding("maemo", "RCL", "ZOOMPLUS");
- _keymapperDefaultBindings->setDefaultBinding("maemo", "CLK", "ZOOMMINUS");
+ _keymapperDefaultBindings->setDefaultBinding("maemo", "RCLK", "ZOOMPLUS");
+ _keymapperDefaultBindings->setDefaultBinding("maemo", "CLKM", "ZOOMMINUS");
}
#endif
diff --git a/backends/platform/psp/README.PSP b/backends/platform/psp/README.PSP
index d92202bf4e..9467d4b993 100644
--- a/backends/platform/psp/README.PSP
+++ b/backends/platform/psp/README.PSP
@@ -1,4 +1,4 @@
-ScummVM-PSP 1.8.0git README
+ScummVM-PSP 1.9.0git README
==============================================================================
Installation
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/amigaos/amigaos.mk b/backends/platform/sdl/amigaos/amigaos.mk
index 5cec9c1588..15a2e9f93f 100644
--- a/backends/platform/sdl/amigaos/amigaos.mk
+++ b/backends/platform/sdl/amigaos/amigaos.mk
@@ -10,4 +10,15 @@ amigaosdist: $(EXECUTABLE)
ifdef DIST_FILES_ENGINEDATA
cp $(DIST_FILES_ENGINEDATA) $(AMIGAOSPATH)/extras/
endif
+ cat ${srcdir}/README | sed -f ${srcdir}/dists/amiga/convertRM.sed > README.conv
+# AmigaOS's shell is not happy with indented comments, thus don't do it.
+# AREXX seems to have problems when ${srcdir} is '.'. It will break with a
+# "Program not found" error. Therefore we copy the script to the cwd and
+# remove it again, once it has finished.
+ cp ${srcdir}/dists/amiga/RM2AG.rx .
+ rx RM2AG.rx README.conv
+ cp README.guide $(AMIGAOSPATH)
+ rm RM2AG.rx
+ rm README.conv
+ rm README.guide
cp $(DIST_FILES_DOCS) $(AMIGAOSPATH)
diff --git a/backends/platform/sdl/macosx/appmenu_osx.mm b/backends/platform/sdl/macosx/appmenu_osx.mm
index d083fb8483..feea40bc06 100644
--- a/backends/platform/sdl/macosx/appmenu_osx.mm
+++ b/backends/platform/sdl/macosx/appmenu_osx.mm
@@ -28,12 +28,22 @@
#include <Cocoa/Cocoa.h>
-// Apple removed setAppleMenu from the header files in 10.4,
-// but as the method still exists we declare it ourselves here.
+// Apple added setAppleMenu in 10.5 and removed it in 10.6.
+// But as the method still exists we declare it ourselves here.
// Yes, this works :)
@interface NSApplication(MissingFunction)
- (void)setAppleMenu:(NSMenu *)menu;
@end
+// However maybe we should conditionally use it depending on the system on which we run ScummVM (and not
+// the one on which we compile) to only do it on OS X 10.5.
+// Here is the relevant bit from the release notes for 10.6:
+// In Leopard and earlier, apps that tried to construct a menu bar without a nib would get an undesirable
+// stubby application menu that could not be removed. To work around this problem on Leopard, you can call
+// the undocumented setAppleMenu: method and pass it the application menu, like so:
+// [NSApp setAppleMenu:[[[NSApp mainMenu] itemAtIndex:0] submenu]];
+// In SnowLeopard, this workaround is unnecessary and should not be used. Under SnowLeopard, the first menu
+// is always identified as the application menu.
+
NSString *constructNSStringFromCString(const char *rawCString, CFStringEncoding stringEncoding) {
return (NSString *)CFStringCreateWithCString(NULL, rawCString, stringEncoding);
@@ -46,13 +56,14 @@ void replaceApplicationMenuItems() {
NSMenu *windowMenu;
NSMenuItem *menuItem;
- // For some reason [[NSApp mainMenu] removeAllItems] doesn't work and crashes, so we need
- // to remove the SDL generated menus one by one
- [[NSApp mainMenu] removeItemAtIndex:0]; // Remove application menu
- [[NSApp mainMenu] removeItemAtIndex:0]; // Remove "Windows" menu
+ // We cannot use [[NSApp mainMenu] removeAllItems] as removeAllItems was added in OS X 10.6
+ // So remove the SDL generated menus one by one instead.
+ while ([[NSApp mainMenu] numberOfItems] > 0) {
+ [[NSApp mainMenu] removeItemAtIndex:0];
+ }
// Create new application menu
- appleMenu = [[NSMenu alloc] initWithTitle:@""];
+ appleMenu = [[NSMenu alloc] initWithTitle:@"ScummVM"];
NSString *nsString = NULL;
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 a711c3a96b..e2a642b288 100644
--- a/backends/platform/sdl/posix/posix.cpp
+++ b/backends/platform/sdl/posix/posix.cpp
@@ -33,14 +33,18 @@
#include "backends/platform/sdl/posix/posix.h"
#include "backends/saves/posix/posix-saves.h"
#include "backends/fs/posix/posix-fs-factory.h"
+#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>
-
OSystem_POSIX::OSystem_POSIX(Common::String baseConfigName)
:
_baseConfigName(baseConfigName) {
@@ -82,11 +86,54 @@ bool OSystem_POSIX::hasFeature(Feature f) {
Common::String OSystem_POSIX::getDefaultConfigFileName() {
Common::String configFile;
- // On POSIX type systems, by default we store the config file inside
- // to the HOME directory of the user.
- const char *home = getenv("HOME");
- if (home != NULL && (strlen(home) + 1 + _baseConfigName.size()) < MAXPATHLEN) {
- configFile = Common::String::format("%s/%s", home, _baseConfigName.c_str());
+ Common::String prefix;
+#ifdef MACOSX
+ prefix = getenv("HOME");
+#elif !defined(SAMSUNGTV)
+ const char *envVar;
+ // Our old configuration file path for POSIX systems was ~/.scummvmrc.
+ // If that file exists, we still use it.
+ envVar = getenv("HOME");
+ if (envVar && *envVar) {
+ configFile = envVar;
+ configFile += '/';
+ configFile += ".scummvmrc";
+
+ if (configFile.size() < MAXPATHLEN) {
+ struct stat sb;
+ if (stat(configFile.c_str(), &sb) == 0) {
+ return configFile;
+ }
+ }
+ }
+
+ // On POSIX systems we follow the XDG Base Directory Specification for
+ // where to store files. The version we based our code upon can be found
+ // over here: http://standards.freedesktop.org/basedir-spec/basedir-spec-0.8.html
+ envVar = getenv("XDG_CONFIG_HOME");
+ if (!envVar || !*envVar) {
+ envVar = getenv("HOME");
+ if (!envVar) {
+ return 0;
+ }
+
+ if (Posix::assureDirectoryExists(".config", envVar)) {
+ prefix = envVar;
+ prefix += "/.config";
+ }
+ } else {
+ prefix = envVar;
+ }
+
+ if (!prefix.empty() && Posix::assureDirectoryExists("scummvm", prefix.c_str())) {
+ prefix += "/scummvm";
+ }
+#endif
+
+ if (!prefix.empty() && (prefix.size() + 1 + _baseConfigName.size()) < MAXPATHLEN) {
+ configFile = prefix;
+ configFile += '/';
+ configFile += _baseConfigName;
} else {
configFile = _baseConfigName;
}
@@ -99,58 +146,43 @@ Common::WriteStream *OSystem_POSIX::createLogFile() {
// of a failure, we know that no log file is open.
_logFilePath.clear();
- const char *home = getenv("HOME");
- if (home == NULL)
+ const char *prefix = nullptr;
+ Common::String logFile;
+#ifdef MACOSX
+ prefix = getenv("HOME");
+ if (prefix == nullptr) {
return 0;
+ }
- Common::String logFile(home);
-#ifdef MACOSX
- logFile += "/Library";
-#else
- logFile += "/.scummvm";
-#endif
-#ifdef SAMSUNGTV
+ logFile = "Library/Logs";
+#elif SAMSUNGTV
+ prefix = nullptr;
logFile = "/mtd_ram";
-#endif
-
- struct stat sb;
-
- // Check whether the dir exists
- if (stat(logFile.c_str(), &sb) == -1) {
- // The dir does not exist, or stat failed for some other reason.
- if (errno != ENOENT)
+#else
+ // On POSIX systems we follow the XDG Base Directory Specification for
+ // where to store files. The version we based our code upon can be found
+ // over here: http://standards.freedesktop.org/basedir-spec/basedir-spec-0.8.html
+ prefix = getenv("XDG_CACHE_HOME");
+ if (prefix == nullptr || !*prefix) {
+ prefix = getenv("HOME");
+ if (prefix == nullptr) {
return 0;
+ }
- // If the problem was that the path pointed to nothing, try
- // to create the dir.
- if (mkdir(logFile.c_str(), 0755) != 0)
- return 0;
- } else if (!S_ISDIR(sb.st_mode)) {
- // Path is no directory. Oops
- return 0;
+ logFile = ".cache/";
}
-#ifdef MACOSX
- logFile += "/Logs";
-#else
- logFile += "/logs";
+ logFile += "scummvm/logs";
#endif
- // Check whether the dir exists
- if (stat(logFile.c_str(), &sb) == -1) {
- // The dir does not exist, or stat failed for some other reason.
- if (errno != ENOENT)
- return 0;
-
- // If the problem was that the path pointed to nothing, try
- // to create the dir.
- if (mkdir(logFile.c_str(), 0755) != 0)
- return 0;
- } else if (!S_ISDIR(sb.st_mode)) {
- // Path is no directory. Oops
+ if (!Posix::assureDirectoryExists(logFile, prefix)) {
return 0;
}
+ if (prefix) {
+ logFile = Common::String::format("%s/%s", prefix, logFile.c_str());
+ }
+
logFile += "/scummvm.log";
Common::FSNode file(logFile);
@@ -212,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 01a01528cd..0514d30191 100644
--- a/backends/platform/sdl/posix/posix.h
+++ b/backends/platform/sdl/posix/posix.h
@@ -28,7 +28,7 @@
class OSystem_POSIX : public OSystem_SDL {
public:
// Let the subclasses be able to change _baseConfigName in the constructor
- OSystem_POSIX(Common::String baseConfigName = ".scummvmrc");
+ OSystem_POSIX(Common::String baseConfigName = "scummvm.ini");
virtual ~OSystem_POSIX() {}
virtual bool hasFeature(Feature f);
@@ -59,6 +59,8 @@ protected:
virtual Common::String getDefaultConfigFileName();
virtual Common::WriteStream *createLogFile();
+
+ virtual AudioCDManager *createAudioCDManager();
};
#endif
diff --git a/backends/platform/sdl/ps3/ps3.cpp b/backends/platform/sdl/ps3/ps3.cpp
index f111379794..0bb8300014 100644
--- a/backends/platform/sdl/ps3/ps3.cpp
+++ b/backends/platform/sdl/ps3/ps3.cpp
@@ -31,7 +31,6 @@
#include "backends/saves/default/default-saves.h"
#include "backends/fs/ps3/ps3-fs-factory.h"
#include "backends/events/ps3sdl/ps3sdl-events.h"
-#include "backends/mixer/sdl13/sdl13-mixer.h"
#include <dirent.h>
#include <sys/stat.h>
@@ -68,14 +67,6 @@ void OSystem_PS3::initBackend() {
if (_savefileManager == 0)
_savefileManager = new DefaultSaveFileManager(PREFIX "/saves");
- // Create the mixer manager
- if (_mixer == 0) {
- _mixerManager = new Sdl13MixerManager();
-
- // Setup and start mixer
- _mixerManager->init();
- }
-
// Event source
if (_eventSource == 0)
_eventSource = new PS3SdlEventSource();
diff --git a/backends/platform/sdl/raspberrypi/README.RASPBERRYPI b/backends/platform/sdl/raspberrypi/README.RASPBERRYPI
new file mode 100644
index 0000000000..ab0e674c31
--- /dev/null
+++ b/backends/platform/sdl/raspberrypi/README.RASPBERRYPI
@@ -0,0 +1,77 @@
+ScummVM-RASPBERRYPI README
+==============================================================================
+
+Notes
+============
+
+This version of ScummVM uses SDL2 hardware accelerated graphics, be it
+plain SDL2 which in turn uses dispmanx/gles2 or by using gles1 via an
+SDL2-configured GLES1 context.
+
+Requirements
+============
+- Raspberry Pi 1 or 2 microcomputer.
+- Raspbian (Debian) installed on SD card. Other distros may be supported if
+ they include the VideoCore runtime libraries that Raspbian includes.
+-An attached keyboard and mouse, or alternatively joystick.
+
+Controls
+============
+
+The standard ScummVM keyboard and mouse controls are used as in any other
+GNU/Linux based system.
+Use the --joystick parameter if you want to use a joystick instead of the
+intended mouse for playing the games (not recommended).
+
+Installation from binaries
+==============================
+
+We have at least three methods to get the binaries into the Raspbian SD:
+
+1) Since Debian (Raspbian) includes an ssh service by default, I recommend
+keeping the SD card on the Raspberry Pi, and using scp to copy the package over
+to your home directory in the Debian filesystem.
+
+scp scummvm-rpi_<version>.zip pi@<raspberrypi_ip>:/home/pi
+
+2) If your RaspberryPi has internet access, you can simply use wget to
+download the package to your home folder:
+
+cd ~/
+wget <package_link>
+
+3) You could also connect the Raspbian SD card to your main PC and, after
+mounting it (or being automounted as it would be in most desktop GNU/Linux
+systems), copy the package file manually to your home directory.
+How to mount an SD and copy files to it is beyond the scope of this README.
+
+Once we have the package file in our home directory using one of the three
+aforementioned methods, we would need to uncompress it:
+
+unzip scummvm-rpi_<version>.zip
+
+As a result, a directory containing the scummvm along with this README will be
+created.
+We can run it by simply changing to our scummvm directory and executing the
+scummvm file.
+
+cd scummvm-rpi
+./scummvm
+
+I recommend copying the games to /home/pi/scummvm-rpi. Adding the games via the menu
+works as in any other system ScummVM runs on.
+
+Building from sources
+==============================
+
+Recommended method is building by cross-compiling on a GNU/Linux X86-based computer.
+You can find concise instructions for this on the ScummVM wiki:
+
+http://wiki.scummvm.org/index.php/Compiling_ScummVM/RPI
+
+The configure script is disabling scalers because we prefer dispmanx for that, which
+makes scalers unnecessary on a CPU limited platform like this, timestamps because most people
+doesn't have an RTC on the Raspberry Pi, and event recorder to save SD card write cycles.
+All these are automatically disabled when we crosscompile by passing "--host=raspberrypi".
+
+Enjoy!
diff --git a/backends/platform/sdl/sdl-sys.h b/backends/platform/sdl/sdl-sys.h
index 67ad84efd3..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.
@@ -112,7 +127,7 @@ typedef struct { int FAKE; } FAKE_FILE;
#endif
// In a moment of brilliance Xlib.h included by SDL_syswm.h #defines the
-// following names. In a moment of mental breakdown, which occured upon
+// following names. In a moment of mental breakdown, which occurred upon
// gazing at Xlib.h, LordHoto decided to undefine them to prevent havoc.
#ifdef Status
#undef Status
@@ -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 6d4dede212..c55753194b 100644
--- a/backends/platform/sdl/sdl.cpp
+++ b/backends/platform/sdl/sdl.cpp
@@ -36,8 +36,8 @@
#include "backends/saves/default/default-saves.h"
-// Audio CD support was removed with SDL 1.3
-#if SDL_VERSION_ATLEAST(1, 3, 0)
+// Audio CD support was removed with SDL 2.0
+#if SDL_VERSION_ATLEAST(2, 0, 0)
#include "backends/audiocd/default/default-audiocd.h"
#else
#include "backends/audiocd/sdl/sdl-audiocd.h"
@@ -245,15 +245,7 @@ void OSystem_SDL::initBackend() {
_timerManager = new SdlTimerManager();
#endif
- if (_audiocdManager == 0) {
- // Audio CD support was removed with SDL 1.3
-#if SDL_VERSION_ATLEAST(1, 3, 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-main.cpp b/backends/platform/sdl/win32/win32-main.cpp
index c6c15c00e8..4864347d81 100644
--- a/backends/platform/sdl/win32/win32-main.cpp
+++ b/backends/platform/sdl/win32/win32-main.cpp
@@ -43,7 +43,17 @@ int __stdcall WinMain(HINSTANCE /*hInst*/, HINSTANCE /*hPrevInst*/, LPSTR /*lpC
#if !SDL_VERSION_ATLEAST(2, 0, 0)
SDL_SetModuleHandle(GetModuleHandle(NULL));
#endif
+// HACK: __argc, __argv are broken and return zero when using mingwrt 4.0+ on MinGW
+// HACK: MinGW-w64 based toolchains neither feature _argc nor _argv. The 32 bit
+// incarnation only defines __MINGW32__. This leads to build breakage due to
+// missing declarations. Luckily MinGW-w64 based toolchains define
+// __MINGW64_VERSION_foo macros inside _mingw.h, which is included from all
+// system headers. Thus we abuse that to detect them.
+#if defined(__GNUC__) && defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
+ return main(_argc, _argv);
+#else
return main(__argc, __argv);
+#endif
}
int main(int argc, char *argv[]) {
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/AdaptAllMMPs.pl b/backends/platform/symbian/AdaptAllMMPs.pl
index 6b9f918a51..a836b764d2 100644
--- a/backends/platform/symbian/AdaptAllMMPs.pl
+++ b/backends/platform/symbian/AdaptAllMMPs.pl
@@ -56,6 +56,7 @@ chdir("../../../");
"mmp/scummvm_lastexpress.mmp",
"mmp/scummvm_mads.mmp",
"mmp/scummvm_prince.mmp",
+ "mmp/scummvm_sherlock.mmp",
"mmp/scummvm_sword25.mmp",
"mmp/scummvm_testbed.mmp",
"mmp/scummvm_zvision.mmp",
@@ -203,6 +204,7 @@ ParseModule("_lastexpress","lastexpress", \@section_empty);
ParseModule("_m4", "m4", \@section_empty);
ParseModule("_mads" ,"mads", \@section_empty);
ParseModule("_prince" ,"prince", \@section_empty);
+ParseModule("_sherlock" ,"sherlock", \@section_empty);
ParseModule("_sword25" ,"sword25", \@section_empty);
ParseModule("_testbed" ,"testbed", \@section_empty);
ParseModule("_zvision" ,"zvision", \@section_empty);
diff --git a/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl b/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl
index 8c19631524..10bcf0340a 100644
--- a/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl
+++ b/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl
@@ -1,36 +1,32 @@
##################################################################################################################
+#### sword25 ignored because of incompatible resolution 800*600
@WorkingEngines = qw(
- agos agi cine cge composer cruise draci dreamweb
- drascula hugo gob groovie hopkins kyra lastexpress
- lure made mohawk mortevielle neverhood parallaction
- pegasus queen saga sci scumm sky sword1 sword2
- teenagent tinsel toltecs tony toon touche tsage
- tucker voyeur wintermute
- access avalanche bbvs cge2 fullpipe mads prince
- testbed zvision
+ access agi agos avalanche bbvs cge cge2
+ cine composer cruise draci drascula
+ dreamweb fullpipe gob groovie hopkins
+ hugo kyra lastexpress lure made mads
+ mohawk mortevielle neverhood parallaction
+ pegasus prince queen saga sci scumm
+ sherlock sky sword1 sword2 teenagent
+ testbed tinsel toltecs tony toon touche
+ tsage tucker voyeur wintermute zvision
);
-
-#### sword25 yet not added
-
-#### In progress engines are :
-#### access avalanche bbvs cge2 fullpipe mads prince
-#### testbed zvision
@WorkingEngines_1st = qw(
- cine composer cruise drascula groovie
- lastexpress made parallaction queen saga
- scumm touche tucker wintermute voyeur
- access avalanche cge2 zvision
+ access agi agos cge2 cine composer cruise
+ drascula gob groovie kyra lastexpress made
+ neverhood parallaction queen saga scumm
+ touche tucker voyeur wintermute
);
@WorkingEngines_2nd = qw(
- agi agos cge draci dreamweb gob hopkins
- hugo kyra lure mohawk mortevielle neverhood
- pegasus sci sky sword1 sword2 teenagent
- tinsel tsage toltecs tony toon
- bbvs fullpipe mads prince testbed
+ avalanche bbvs cge draci dreamweb fullpipe
+ hopkins hugo lure mads mohawk mortevielle
+ pegasus prince sci sherlock sky sword1 sword2
+ teenagent testbed tinsel toltecs tony toon
+ tsage zvision
);
#### sword25 yet not added
diff --git a/backends/platform/symbian/README b/backends/platform/symbian/README
index 655ec5137a..47a3097ac0 100644
--- a/backends/platform/symbian/README
+++ b/backends/platform/symbian/README
@@ -1,7 +1,7 @@
ScummVM - ScummVM ported to EPOC/SymbianOS
- Copyright (C) 2008-2015 ScummVM Team
+ Copyright (C) 2008-2016 ScummVM Team
Copyright (C) 2013-2013 Fedor Strizhniou aka zanac
Copyright (C) 2003-2013 Lars 'AnotherGuest' Persson
Copyright (C) 2002-2008 Jurgen 'SumthinWicked' Braam
diff --git a/backends/platform/symbian/S60/ScummVM_S60.mmp.in b/backends/platform/symbian/S60/ScummVM_S60.mmp.in
index c4b0bf49df..14e586246a 100644
--- a/backends/platform/symbian/S60/ScummVM_S60.mmp.in
+++ b/backends/platform/symbian/S60/ScummVM_S60.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/S60/ScummVM_S60_App.mmp b/backends/platform/symbian/S60/ScummVM_S60_App.mmp
index f9bd30025c..e75059b4b7 100644
--- a/backends/platform/symbian/S60/ScummVM_S60_App.mmp
+++ b/backends/platform/symbian/S60/ScummVM_S60_App.mmp
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/S60v3/ScummVM_A0000658_S60v3.mmp.in b/backends/platform/symbian/S60v3/ScummVM_A0000658_S60v3.mmp.in
index c9e4769484..a669943933 100644
--- a/backends/platform/symbian/S60v3/ScummVM_A0000658_S60v3.mmp.in
+++ b/backends/platform/symbian/S60v3/ScummVM_A0000658_S60v3.mmp.in
@@ -3,7 +3,7 @@
* Copyright (C) 2003-2014 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
* Copyright (C) 2013-2014 Fedor Strizhniou Additional library porting, engine support, help files etc
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
@@ -36,7 +36,7 @@ TARGETPATH sys\bin
TARGETTYPE exe
OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char
// fixes error "section .data loaded at [...] overlaps section .text loaded at [...]"
-LINKEROPTION GCCE -Tdata 0xAA00000
+LINKEROPTION GCCE -Tdata 0xAA00000 --gc-sections --strip-all
UID 0x100039ce 0xA0000658
@@ -122,6 +122,7 @@ SOURCEPATH ..\..\..\..
// backend EPOC/SDL/ESDL specific includes
SOURCE backends\platform\sdl\sdl.cpp
+SOURCE backends\platform\sdl\sdl-window.cpp
SOURCE backends\audiocd\sdl\sdl-audiocd.cpp
SOURCE backends\audiocd\default\default-audiocd.cpp
SOURCE backends\fs\symbian\symbian-fs.cpp
diff --git a/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in b/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in
index f2d7b51a7a..ac8fc6b35a 100644
--- a/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in
+++ b/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in
@@ -3,7 +3,7 @@
* Copyright (C) 2003-2014 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
* Copyright (C) 2013-2014 Fedor Strizhniou Additional library porting, engine support, help files etc
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
@@ -37,7 +37,7 @@ TARGETTYPE exe
OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char
// fixes error "section .data loaded at [...] overlaps section .text loaded at [...]"
-LINKEROPTION GCCE -Tdata 0xAA00000
+LINKEROPTION GCCE -Tdata 0xAA00000 --gc-sections --strip-all
UID 0x100039ce 0xA0000657
@@ -123,6 +123,7 @@ SOURCEPATH ..\..\..\..
// backend EPOC/SDL/ESDL specific includes
SOURCE backends\platform\sdl\sdl.cpp
+SOURCE backends\platform\sdl\sdl-window.cpp
SOURCE backends\audiocd\sdl\sdl-audiocd.cpp
SOURCE backends\audiocd\default\default-audiocd.cpp
SOURCE backends\fs\symbian\symbian-fs.cpp
diff --git a/backends/platform/symbian/S80/ScummVM_S80.mmp.in b/backends/platform/symbian/S80/ScummVM_S80.mmp.in
index 0a7a755e47..e7ebe900bb 100644
--- a/backends/platform/symbian/S80/ScummVM_S80.mmp.in
+++ b/backends/platform/symbian/S80/ScummVM_S80.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/S80/ScummVM_S80_App.mmp b/backends/platform/symbian/S80/ScummVM_S80_App.mmp
index a949c10169..4b3fc052cf 100644
--- a/backends/platform/symbian/S80/ScummVM_S80_App.mmp
+++ b/backends/platform/symbian/S80/ScummVM_S80_App.mmp
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/S90/Scummvm_S90.mmp.in b/backends/platform/symbian/S90/Scummvm_S90.mmp.in
index eaf4673de8..e35cdb9107 100644
--- a/backends/platform/symbian/S90/Scummvm_S90.mmp.in
+++ b/backends/platform/symbian/S90/Scummvm_S90.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/S90/Scummvm_S90_App.mmp b/backends/platform/symbian/S90/Scummvm_S90_App.mmp
index e4426a3351..1716629ceb 100644
--- a/backends/platform/symbian/S90/Scummvm_S90_App.mmp
+++ b/backends/platform/symbian/S90/Scummvm_S90_App.mmp
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/UIQ2/ScummVM.rss b/backends/platform/symbian/UIQ2/ScummVM.rss
index b8b48cd8f7..13712e26c4 100644
--- a/backends/platform/symbian/UIQ2/ScummVM.rss
+++ b/backends/platform/symbian/UIQ2/ScummVM.rss
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/backends/platform/symbian/UIQ3/ScummVM.rss b/backends/platform/symbian/UIQ3/ScummVM.rss
index 612c52e0b2..5e133ac137 100644
--- a/backends/platform/symbian/UIQ3/ScummVM.rss
+++ b/backends/platform/symbian/UIQ3/ScummVM.rss
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/UIQ3/ScummVM_A0000658.rss b/backends/platform/symbian/UIQ3/ScummVM_A0000658.rss
index 612c52e0b2..5e133ac137 100644
--- a/backends/platform/symbian/UIQ3/ScummVM_A0000658.rss
+++ b/backends/platform/symbian/UIQ3/ScummVM_A0000658.rss
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/UIQ3/ScummVM_A0000658_UIQ3.mmp.in b/backends/platform/symbian/UIQ3/ScummVM_A0000658_UIQ3.mmp.in
index 7d580255bc..5e27b87433 100644
--- a/backends/platform/symbian/UIQ3/ScummVM_A0000658_UIQ3.mmp.in
+++ b/backends/platform/symbian/UIQ3/ScummVM_A0000658_UIQ3.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2009 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2009 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/UIQ3/ScummVM_UIQ3.mmp.in b/backends/platform/symbian/UIQ3/ScummVM_UIQ3.mmp.in
index 33a2276b0d..8568a51ec3 100644
--- a/backends/platform/symbian/UIQ3/ScummVM_UIQ3.mmp.in
+++ b/backends/platform/symbian/UIQ3/ScummVM_UIQ3.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/UIQ3/scummvm_A0000658_loc.rss b/backends/platform/symbian/UIQ3/scummvm_A0000658_loc.rss
index b79beddcb7..8f8ff5c3b0 100644
--- a/backends/platform/symbian/UIQ3/scummvm_A0000658_loc.rss
+++ b/backends/platform/symbian/UIQ3/scummvm_A0000658_loc.rss
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/help/ScummVM.rtf b/backends/platform/symbian/help/ScummVM.rtf
index 15b2105ecd..220eb76ecd 100644
--- a/backends/platform/symbian/help/ScummVM.rtf
+++ b/backends/platform/symbian/help/ScummVM.rtf
@@ -39,26 +39,28 @@ Synonyms;}{\*\cs33 \additive \super \sbasedon10 endnote reference;}{\s34\ql \fi-
\f1\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 \sbasedon0 \snext34 \sautoupd List Bullet;}{\s35\ql \fi-284\li568\ri0\sa120\widctlpar{\*\pn \pnlvlblt\ilvl10\ls2047\pnrnot0\pnf3\pnstart1\pnindent283\pnhang{\pntxtb \'b7}}
\nooverflow\faroman\ls2047\ilvl10\rin0\lin568\itap0 \f1\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 \sbasedon0 \snext35 \sautoupd List Bullet 2;}{\s36\ql \li0\ri0\sa120\widctlpar\tqc\tx4153\tqr\tx8306\nooverflow\faroman\rin0\lin0\itap0
\f1\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 \sbasedon0 \snext36 footer;}{\s37\ql \li284\ri0\sa120\widctlpar\nooverflow\faroman\rin0\lin284\itap0 \f1\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 \sbasedon0 \snext37 List Continue;}{
-\s38\ql \li566\ri0\sa120\widctlpar\nooverflow\faroman\rin0\lin566\itap0 \f1\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 \sbasedon0 \snext38 List Continue 2;}}{\*\listtable{\list\listtemplateid-737142542\listsimple{\listlevel\levelnfc0
-\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00.;}{\levelnumbers\'01;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1 \fi-360\li643\jclisttab\tx643 }{\listname ;}\listid-129}
-{\list\listtemplateid1907811784\listsimple{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0
-\fi-360\li643\jclisttab\tx643 }{\listname ;}\listid-125}{\list\listtemplateid1912741052\listsimple{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00.;}{\levelnumbers\'01;}\chbrdr
-\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1 \fi-360\li360\jclisttab\tx360 }{\listname ;}\listid-120}{\list\listtemplateid-51363132\listsimple{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0
-{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li360\jclisttab\tx360 }{\listname ;}\listid-119}{\list\listtemplateid947971744\listsimple{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0
-\levelfollow0\levelstartat0\levelspace0\levelindent0{\leveltext\'01*;}{\levelnumbers;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1 }{\listname ;}\listid-2}}{\*\listoverridetable{\listoverride\listid-120\listoverridecount0\ls1}
-{\listoverride\listid-129\listoverridecount0\ls2}{\listoverride\listid-119\listoverridecount0\ls3}{\listoverride\listid-125\listoverridecount0\ls4}{\listoverride\listid-120\listoverridecount0\ls5}{\listoverride\listid-129\listoverridecount0\ls6}
-{\listoverride\listid-119\listoverridecount0\ls7}{\listoverride\listid-125\listoverridecount0\ls8}{\listoverride\listid-120\listoverridecount0\ls9}{\listoverride\listid-129\listoverridecount0\ls10}{\listoverride\listid-119\listoverridecount0\ls11}
-{\listoverride\listid-125\listoverridecount0\ls12}{\listoverride\listid-120\listoverridecount0\ls13}{\listoverride\listid-129\listoverridecount0\ls14}{\listoverride\listid-119\listoverridecount0\ls15}{\listoverride\listid-125\listoverridecount0\ls16}
-{\listoverride\listid-120\listoverridecount0\ls17}{\listoverride\listid-129\listoverridecount0\ls18}{\listoverride\listid-119\listoverridecount0\ls19}{\listoverride\listid-125\listoverridecount0\ls20}{\listoverride\listid-120\listoverridecount0\ls21}
-{\listoverride\listid-129\listoverridecount0\ls22}{\listoverride\listid-119\listoverridecount0\ls23}{\listoverride\listid-125\listoverridecount0\ls24}{\listoverride\listid-120\listoverridecount0\ls25}{\listoverride\listid-129\listoverridecount0\ls26}
-{\listoverride\listid-119\listoverridecount0\ls27}{\listoverride\listid-125\listoverridecount0\ls28}{\listoverride\listid-120\listoverridecount0\ls29}{\listoverride\listid-129\listoverridecount0\ls30}{\listoverride\listid-119\listoverridecount0\ls31}
-{\listoverride\listid-125\listoverridecount0\ls32}{\listoverride\listid-120\listoverridecount0\ls33}{\listoverride\listid-129\listoverridecount0\ls34}{\listoverride\listid-119\listoverridecount0\ls35}{\listoverride\listid-125\listoverridecount0\ls36}
-{\listoverride\listid-120\listoverridecount0\ls37}{\listoverride\listid-129\listoverridecount0\ls38}{\listoverride\listid-119\listoverridecount0\ls39}{\listoverride\listid-125\listoverridecount0\ls40}{\listoverride\listid-2\listoverridecount1{\lfolevel
-\listoverrideformat{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelold\levelspace0\levelindent283{\leveltext\'01\u-3991 ?;}{\levelnumbers;}\f30\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-283\li283
-}}\ls41}{\listoverride\listid-2\listoverridecount1{\lfolevel\listoverrideformat{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelold\levelspace0\levelindent283{\leveltext\'01\u-3991 ?;}{\levelnumbers;}\f30\chbrdr
-\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-283\li283 }}\ls42}}{\info{\author Fedor}{\operator Fedor}{\creatim\yr2013\mo11\dy30\hr23\min4}{\revtim\yr2014\mo12\dy29\hr22\min52}{\version102}{\edmins95}{\nofpages8}{\nofwords1514}{\nofchars8634}
-{\*\company DEV}{\nofcharsws0}{\vern8249}}\margl1701\margr850\margt1134\margb1134 \deftab708\widowctrl\ftnbj\aenddoc\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\hyphcaps0\horzdoc\dghspace120\dgvspace120\dghorigin1701\dgvorigin1984\dghshow0
-\dgvshow3\jcompress\viewkind4\viewscale100\nolnhtadjtbl \fet0{\*\template E:\\Documents and Settings\\Administrator\\Application Data\\Microsoft\\\'d8\'e0\'e1\'eb\'ee\'ed\'fb\\cshelp2000.dot}\sectd \linex0\sectdefaultcl {\*\pnseclvl1
+\s38\ql \li566\ri0\sa120\widctlpar\nooverflow\faroman\rin0\lin566\itap0 \f1\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 \sbasedon0 \snext38 List Continue 2;}{\*\cs39 \additive \sbasedon10 x x-first x-last;}}{\*\listtable
+{\list\listtemplateid-737142542\listsimple{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00.;}{\levelnumbers\'01;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1 \fi-360\li643
+\jclisttab\tx643 }{\listname ;}\listid-129}{\list\listtemplateid1907811784\listsimple{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr
+\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li643\jclisttab\tx643 }{\listname ;}\listid-125}{\list\listtemplateid1912741052\listsimple{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0
+{\leveltext\'02\'00.;}{\levelnumbers\'01;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1 \fi-360\li360\jclisttab\tx360 }{\listname ;}\listid-120}{\list\listtemplateid-51363132\listsimple{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0
+\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li360\jclisttab\tx360 }{\listname ;}\listid-119}{\list\listtemplateid947971744\listsimple
+{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat0\levelspace0\levelindent0{\leveltext\'01*;}{\levelnumbers;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1 }{\listname ;}\listid-2}}{\*\listoverridetable
+{\listoverride\listid-120\listoverridecount0\ls1}{\listoverride\listid-129\listoverridecount0\ls2}{\listoverride\listid-119\listoverridecount0\ls3}{\listoverride\listid-125\listoverridecount0\ls4}{\listoverride\listid-120\listoverridecount0\ls5}
+{\listoverride\listid-129\listoverridecount0\ls6}{\listoverride\listid-119\listoverridecount0\ls7}{\listoverride\listid-125\listoverridecount0\ls8}{\listoverride\listid-120\listoverridecount0\ls9}{\listoverride\listid-129\listoverridecount0\ls10}
+{\listoverride\listid-119\listoverridecount0\ls11}{\listoverride\listid-125\listoverridecount0\ls12}{\listoverride\listid-120\listoverridecount0\ls13}{\listoverride\listid-129\listoverridecount0\ls14}{\listoverride\listid-119\listoverridecount0\ls15}
+{\listoverride\listid-125\listoverridecount0\ls16}{\listoverride\listid-120\listoverridecount0\ls17}{\listoverride\listid-129\listoverridecount0\ls18}{\listoverride\listid-119\listoverridecount0\ls19}{\listoverride\listid-125\listoverridecount0\ls20}
+{\listoverride\listid-120\listoverridecount0\ls21}{\listoverride\listid-129\listoverridecount0\ls22}{\listoverride\listid-119\listoverridecount0\ls23}{\listoverride\listid-125\listoverridecount0\ls24}{\listoverride\listid-120\listoverridecount0\ls25}
+{\listoverride\listid-129\listoverridecount0\ls26}{\listoverride\listid-119\listoverridecount0\ls27}{\listoverride\listid-125\listoverridecount0\ls28}{\listoverride\listid-120\listoverridecount0\ls29}{\listoverride\listid-129\listoverridecount0\ls30}
+{\listoverride\listid-119\listoverridecount0\ls31}{\listoverride\listid-125\listoverridecount0\ls32}{\listoverride\listid-120\listoverridecount0\ls33}{\listoverride\listid-129\listoverridecount0\ls34}{\listoverride\listid-119\listoverridecount0\ls35}
+{\listoverride\listid-125\listoverridecount0\ls36}{\listoverride\listid-120\listoverridecount0\ls37}{\listoverride\listid-129\listoverridecount0\ls38}{\listoverride\listid-119\listoverridecount0\ls39}{\listoverride\listid-125\listoverridecount0\ls40}
+{\listoverride\listid-120\listoverridecount0\ls41}{\listoverride\listid-129\listoverridecount0\ls42}{\listoverride\listid-119\listoverridecount0\ls43}{\listoverride\listid-125\listoverridecount0\ls44}{\listoverride\listid-120\listoverridecount0\ls45}
+{\listoverride\listid-129\listoverridecount0\ls46}{\listoverride\listid-119\listoverridecount0\ls47}{\listoverride\listid-125\listoverridecount0\ls48}{\listoverride\listid-2\listoverridecount1{\lfolevel\listoverrideformat{\listlevel\levelnfc23\levelnfcn23
+\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelold\levelspace0\levelindent283{\leveltext\'01\u-3991 ?;}{\levelnumbers;}\f30\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-283\li283 }}\ls49}{\listoverride\listid-2
+\listoverridecount1{\lfolevel\listoverrideformat{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelold\levelspace0\levelindent283{\leveltext\'01\u-3991 ?;}{\levelnumbers;}\f30\chbrdr\brdrnone\brdrcf1
+\chshdng0\chcfpat1\chcbpat1\fbias0 \fi-283\li283 }}\ls50}}{\info{\author Fedor}{\operator Fedor}{\creatim\yr2013\mo11\dy30\hr23\min4}{\revtim\yr2015\mo11\dy22\hr17\min27}{\version105}{\edmins185}{\nofpages8}{\nofwords1514}{\nofchars8634}{\*\company DEV}
+{\nofcharsws0}{\vern8249}}\margl1701\margr850\margt1134\margb1134 \deftab708\widowctrl\ftnbj\aenddoc\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\hyphcaps0\horzdoc\dghspace120\dgvspace120\dghorigin1701\dgvorigin1984\dghshow0\dgvshow3
+\jcompress\viewkind4\viewscale100\nolnhtadjtbl \fet0{\*\template E:\\Documents and Settings\\Administrator\\Application Data\\Microsoft\\\'d8\'e0\'e1\'eb\'ee\'ed\'fb\\cshelp2000.dot}\sectd \linex0\sectdefaultcl {\*\pnseclvl1
\pnucrm\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang{\pntxta )}}{\*\pnseclvl5
\pndec\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang
{\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}\pard\plain \s17\ql \li0\ri0\sa120\widctlpar\nooverflow\faroman\rin0\lin0\itap0 \i\f1\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {
@@ -70,20 +72,19 @@ Synonyms;}{\*\cs33 \additive \super \sbasedon10 endnote reference;}{\s34\ql \fi-
\par }\pard\plain \ql \li0\ri0\sa120\widctlpar\nooverflow\faroman\rin0\lin0\itap0 \f1\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {\f28
\par }\pard\plain \s2\ql \li0\ri0\sb120\sa120\keepn\widctlpar\brdrt\brdrs\brdrw30\brsp20 \brdrb\brdrs\brdrw30\brsp20 \tqr\tx9072\nooverflow\faroman\outlinelevel1\rin0\lin0\itap0 \b\f1\fs24\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {\b0\f28
About ScummVM Help
-\par {\pntext\pard\plain\s26 \f30\fs20\lang2057\langfe1033\langnp2057\langfenp1033 \loch\af30\dbch\af0\hich\f30 \'69\tab}}\pard\plain \s26\ql \fi-283\li283\ri0\sa120\widctlpar\brdrb\brdrs\brdrw15\brsp20 {\*\pn \pnlvlblt\ilvl0\ls41\pnrnot0
-\pnf30\pnstart1\pnindent283\pnhang{\pntxtb i}}\nooverflow\faroman\ls41\rin0\lin283\itap0 \f1\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {About ScummVM Help
+\par {\pntext\pard\plain\s26 \f30\fs20\lang2057\langfe1033\langnp2057\langfenp1033 \loch\af30\dbch\af0\hich\f30 \'69\tab}}\pard\plain \s26\ql \fi-283\li283\ri0\sa120\widctlpar\brdrb\brdrs\brdrw15\brsp20 {\*\pn \pnlvlblt\ilvl0\ls49\pnrnot0
+\pnf30\pnstart1\pnindent283\pnhang{\pntxtb i}}\nooverflow\faroman\ls49\rin0\lin283\itap0 \f1\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {About ScummVM Help
\par }\pard\plain \ql \li0\ri0\sa120\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\nooverflow\faroman\rin0\lin0\itap0 \f1\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {\f28
-\par }{
-This help file based on ScummVM forum thread with some elaborations(in Anotherguest section) and text correction. If you wish add some text or translate you may download and modify source document from https://sourceforge.net/projects/scummvms60git/ and t
-hen send me to fedor_qd@mail.ru
+\par }{This help file based on ScummVM forum thread with some elaborations(in Anotherguest section) and text correction. If you wish add some text or translate you may download and modify source document from https://sourceforge.net/projects/scummvms60git/ a
+nd then send me to fedor_qd@mail.ru
\par Feel free to replace, merge or write you own instead 1st, 2nd and 3rd guides. Other sections require strict translations. And don\rquote t forget add your name :-)
\par First guide contain help by Anotherguest, second - VincentJ, third - murgo. This doc created by Fedor Strizhniou.
\par Enjoys, cheers! Always yours =)}{\lang1059\langfe1033\langnp1059
\par }{\f29
\par }\pard\plain \s2\ql \li0\ri0\sb120\sa120\keepn\widctlpar\brdrt\brdrs\brdrw30\brsp20 \brdrb\brdrs\brdrw30\brsp20 \tqr\tx9072{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\nooverflow\faroman\outlinelevel1\rin0\lin0\itap0
\b\f1\fs24\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {\b0\f28 1st guide
-\par {\pntext\pard\plain\s26 \f30\fs20\lang2057\langfe1033\langnp2057\langfenp1033 \loch\af30\dbch\af0\hich\f30 \'69\tab}}\pard\plain \s26\ql \fi-283\li283\ri0\sa120\widctlpar\brdrb\brdrs\brdrw15\brsp20 {\*\pn \pnlvlblt\ilvl0\ls41\pnrnot0
-\pnf30\pnstart1\pnindent283\pnhang{\pntxtb i}}\nooverflow\faroman\ls41\rin0\lin283\itap0 \f1\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {Controls, Virtual keyboard, Shortcuts, ScummVM, Tips, S60, UIQ, UIQ3, S80, s80, S90, s90
+\par {\pntext\pard\plain\s26 \f30\fs20\lang2057\langfe1033\langnp2057\langfenp1033 \loch\af30\dbch\af0\hich\f30 \'69\tab}}\pard\plain \s26\ql \fi-283\li283\ri0\sa120\widctlpar\brdrb\brdrs\brdrw15\brsp20 {\*\pn \pnlvlblt\ilvl0\ls49\pnrnot0
+\pnf30\pnstart1\pnindent283\pnhang{\pntxtb i}}\nooverflow\faroman\ls49\rin0\lin283\itap0 \f1\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {Controls, Virtual keyboard, Shortcuts, ScummVM, Tips, S60, UIQ, UIQ3, S80, s80, S90, s90
\par }\pard\plain \ql \li0\ri0\sa120\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\nooverflow\faroman\rin0\lin0\itap0 \f1\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {\f28
\par }{UIQ3 devices: To the top right (holding the phone portrait) you four icons, from the top they are
\par
@@ -124,22 +125,22 @@ hen send me to fedor_qd@mail.ru
\par
\par What are these Joystick, Keyboard and Cursor modes anyway?
\par }{\f28
-\par }{Joystick mode sends SDL joystick events to ScummVM which acts as a mouse control in ScummVM. Cursor mode sends keyboard arrows instead, so for example it can be used to navigate
-through directorylist (one hand use perhaps!?) or save games etc. Keyboard mode is only available for S60 and enables multi-tap to enter text characters in save dialogs. These modes are implemented at the underlying SDL level, so this determines the types
- of events that ScummVM receives from SDL.
+\par }{Joystick mode sends SDL joystick events to ScummVM which acts as a mouse control in ScummVM. Cursor mode sends keyboard arrows instead, so for exampl
+e it can be used to navigate through directorylist (one hand use perhaps!?) or save games etc. Keyboard mode is only available for S60 and enables multi-tap to enter text characters in save dialogs. These modes are implemented at the underlying SDL level,
+ so this determines the types of events that ScummVM receives from SDL.
\par What are these Shrinked, Zoomed and Upscaled modes anyway?
\par
-\par Shrink displays the game on your screen but in a shrinked way, either in Port
-rait or Landscape mode, so not all the pixels can be seen. Zoom mode uses the maximum resolution of your phone displaying a smaller part of the game zoomed at 1:1 pixels. For scrolling in S60 Zoom mode: 0+Cursor keys to scroll around, 0+Ok button to cente
-r view. Upscale tries to fill the larger screens on S80/S90 devices in a better way for low resolution games. Currently it uses a pixel interpolation upscaling routine.
+\par Shrink displays the game on your screen but in a shrinked way, either in Portrait or Landscape mode, so not all the pixels ca
+n be seen. Zoom mode uses the maximum resolution of your phone displaying a smaller part of the game zoomed at 1:1 pixels. For scrolling in S60 Zoom mode: 0+Cursor keys to scroll around, 0+Ok button to center view. Upscale tries to fill the larger screens
+ on S80/S90 devices in a better way for low resolution games. Currently it uses a pixel interpolation upscaling routine.
\par
\par You can also use a bluetooth mouse with S60v3 devices to control your game. You need the bluetooth hid library from Hinkka http://koti.mbnet.fi/hinkka/Download.html to get it to work properly.
\par }{\f29
\par
\par }\pard\plain \s2\ql \li0\ri0\sb120\sa120\keepn\widctlpar\brdrt\brdrs\brdrw30\brsp20 \brdrb\brdrs\brdrw30\brsp20 \tqr\tx9072{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\nooverflow\faroman\outlinelevel1\rin0\lin0\itap0
\b\f1\fs24\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {\b0\f28 2nd guide
-\par {\pntext\pard\plain\s26 \f30\fs20\lang2057\langfe1033\langnp2057\langfenp1033 \loch\af30\dbch\af0\hich\f30 \'69\tab}}\pard\plain \s26\ql \fi-283\li283\ri0\sa120\widctlpar\brdrb\brdrs\brdrw15\brsp20 {\*\pn \pnlvlblt\ilvl0\ls41\pnrnot0
-\pnf30\pnstart1\pnindent283\pnhang{\pntxtb i}}\nooverflow\faroman\ls41\rin0\lin283\itap0 \f1\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {Controls, Virtual keyboard, Shortcuts, ScummVM, Tips, S60, s60
+\par {\pntext\pard\plain\s26 \f30\fs20\lang2057\langfe1033\langnp2057\langfenp1033 \loch\af30\dbch\af0\hich\f30 \'69\tab}}\pard\plain \s26\ql \fi-283\li283\ri0\sa120\widctlpar\brdrb\brdrs\brdrw15\brsp20 {\*\pn \pnlvlblt\ilvl0\ls49\pnrnot0
+\pnf30\pnstart1\pnindent283\pnhang{\pntxtb i}}\nooverflow\faroman\ls49\rin0\lin283\itap0 \f1\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {Controls, Virtual keyboard, Shortcuts, ScummVM, Tips, S60, s60
\par }\pard\plain \ql \li0\ri0\sa120\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\nooverflow\faroman\rin0\lin0\itap0 \f1\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {\f28
\par
\par }{More user-friendly guide for Nokia phones (based on N96 but should apply to most phones)
@@ -164,8 +165,8 @@ r view. Upscale tries to fill the larger screens on S80/S90 devices in a better
\par }{1 - Change Input.
\par This is the option you'll probably use the most. There are three settings; A,C and J.
\par
-\par A - This is the "Text Input" mode. It allows you to type directly into ScummVM as if you were using a keyboard. Type the same way you would when sending a text message o
-ff of your phone. Please note that the pointer is disabled when in this mode. Don't forget to exit Configuration Mode before typing!
+\par A - This is the "Text Input" mode. It allows you to type directly into ScummVM as if you were using a keyboard. Type the same way you would wh
+en sending a text message off of your phone. Please note that the pointer is disabled when in this mode. Don't forget to exit Configuration Mode before typing!
\par
\par C - This is the "Cursor" mode. This emulates the arrow keys of the keyboard. Some games require using this instead of the mouse (e.g. the destruction derby section towards the end of Full Throttle).
\par
@@ -180,9 +181,9 @@ ff of your phone. Please note that the pointer is disabled when in this mode. Do
\par Only applies to Landscape mode, simply swaps the screen output between having the phone tilted on its left side or on its right side.
\par
\par 4 - Toggle Zoom On and Off
-\par Zooms in on a portion of the screen. Handy for when you are looking through a screen fo
-r items or having trouble reading subtitles. Use the navigation buttons for panning around the play area. Don't forget you'll have to exit out of Configuration Mode before you can move the pointer again. Exiting Configuration Mode does not reset the zoom
-level.
+\par Zooms in on a portion of the screen. Handy for when you are
+looking through a screen for items or having trouble reading subtitles. Use the navigation buttons for panning around the play area. Don't forget you'll have to exit out of Configuration Mode before you can move the pointer again. Exiting Configuration Mo
+de does not reset the zoom level.
\par }{\f29
\par }{5 & 6 - Unused
\par
@@ -203,12 +204,13 @@ level.
\par
\par }\pard\plain \s2\ql \li0\ri0\sb120\sa120\keepn\widctlpar\brdrt\brdrs\brdrw30\brsp20 \brdrb\brdrs\brdrw30\brsp20 \tqr\tx9072{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\nooverflow\faroman\outlinelevel1\rin0\lin0\itap0
\b\f1\fs24\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {\b0\f28 3rd guide
-\par {\pntext\pard\plain\s26 \f30\fs20\lang2057\langfe1033\langnp2057\langfenp1033 \loch\af30\dbch\af0\hich\f30 \'69\tab}}\pard\plain \s26\ql \fi-283\li283\ri0\sa120\widctlpar\brdrb\brdrs\brdrw15\brsp20 {\*\pn \pnlvlblt\ilvl0\ls41\pnrnot0
-\pnf30\pnstart1\pnindent283\pnhang{\pntxtb i}}\nooverflow\faroman\ls41\rin0\lin283\itap0 \f1\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {Controls, Virtual keyboard, Shortcuts, ScummVM, Tips, S60, s60
+\par {\pntext\pard\plain\s26 \f30\fs20\lang2057\langfe1033\langnp2057\langfenp1033 \loch\af30\dbch\af0\hich\f30 \'69\tab}}\pard\plain \s26\ql \fi-283\li283\ri0\sa120\widctlpar\brdrb\brdrs\brdrw15\brsp20 {\*\pn \pnlvlblt\ilvl0\ls49\pnrnot0
+\pnf30\pnstart1\pnindent283\pnhang{\pntxtb i}}\nooverflow\faroman\ls49\rin0\lin283\itap0 \f1\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {Controls, Virtual keyboard, Shortcuts, ScummVM, Tips, S60, s60
\par }\pard\plain \ql \li0\ri0\sa120\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\nooverflow\faroman\rin0\lin0\itap0 \f1\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {\f28
\par
-\par }{ScummVM keys on Nokia e71 (most likely on any other qwerty-device, too), tested on version 0.14.0svn (Feb. 18 20
-09 05:56:07). Number keys are inserted by first pressing fn-key (leftmost key at bottom row on E71) and then pressing correct key (e.g. 5 is fn+g). You don't have to press both keys simultaneously.
+\par }{ScummVM keys on Nokia
+ e71 (most likely on any other qwerty-device, too), tested on version 0.14.0svn (Feb. 18 2009 05:56:07). Number keys are inserted by first pressing fn-key (leftmost key at bottom row on E71) and then pressing correct key (e.g. 5 is fn+g). You don't have t
+o press both keys simultaneously.
\par
\par Basic keys:
\par
@@ -258,8 +260,8 @@ level.
\par p -- punch (hand)
\par
\par AGI games (King's Quest, Police Quest etc.):
-\par The games work beautifully on the E71, but there's some stupid bugs (in input). I recall finding some debug keys and "last sentence" / "inventory" -keys in earlier version, but I can't find them any more. Also you can't turn on sirens in Police Quest, whi
-ch kinda makes it unplayable.
+\par The games work beautifully on the E71, but there's some stupid bugs (in input). I recall finding some debug keys and "last sentence" / "inventory" -keys in earlier version, bu
+t I can't find them any more. Also you can't turn on sirens in Police Quest, which kinda makes it unplayable.
\par
\par There's good side and bad side to each input mode:
\par Keyboard (I use this primarily)
@@ -280,8 +282,8 @@ ch kinda makes it unplayable.
\par }{\f28
\par }\pard\plain \s2\ql \li0\ri0\sb120\sa120\keepn\widctlpar\brdrt\brdrs\brdrw30\brsp20 \brdrb\brdrs\brdrw30\brsp20 \tqr\tx9072{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\nooverflow\faroman\outlinelevel1\rin0\lin0\itap0
\b\f1\fs24\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {ScummVM1 engines list
-\par {\pntext\pard\plain\s26 \f30\fs20\lang2057\langfe1033\langnp2057\langfenp1033 \loch\af30\dbch\af0\hich\f30 \'69\tab}}\pard\plain \s26\ql \fi-283\li283\ri0\sa120\widctlpar\brdrb\brdrs\brdrw15\brsp20 {\*\pn \pnlvlblt\ilvl0\ls42\pnrnot0
-\pnf30\pnstart1\pnindent283\pnhang{\pntxtb i}}\nooverflow\faroman\ls42\rin0\lin283\itap0 \f1\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {Supported engines
+\par {\pntext\pard\plain\s26 \f30\fs20\lang2057\langfe1033\langnp2057\langfenp1033 \loch\af30\dbch\af0\hich\f30 \'69\tab}}\pard\plain \s26\ql \fi-283\li283\ri0\sa120\widctlpar\brdrb\brdrs\brdrw15\brsp20 {\*\pn \pnlvlblt\ilvl0\ls50\pnrnot0
+\pnf30\pnstart1\pnindent283\pnhang{\pntxtb i}}\nooverflow\faroman\ls50\rin0\lin283\itap0 \f1\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {Supported engines
\par }\pard\plain \ql \li0\ri0\sa120\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\nooverflow\faroman\rin0\lin0\itap0 \f1\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {access
\par agi
\par agos
@@ -315,9 +317,10 @@ ch kinda makes it unplayable.
\par
\par }\pard\plain \s2\ql \li0\ri0\sb120\sa120\keepn\widctlpar\brdrt\brdrs\brdrw30\brsp20 \brdrb\brdrs\brdrw30\brsp20 \tqr\tx9072{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\nooverflow\faroman\outlinelevel1\rin0\lin0\itap0
\b\f1\fs24\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {ScummVM2 engines list
-\par {\pntext\pard\plain\s26 \f30\fs20\lang2057\langfe1033\langnp2057\langfenp1033 \loch\af30\dbch\af0\hich\f30 \'69\tab}}\pard\plain \s26\ql \fi-283\li283\ri0\sa120\widctlpar\brdrb\brdrs\brdrw15\brsp20 {\*\pn \pnlvlblt\ilvl0\ls42\pnrnot0
-\pnf30\pnstart1\pnindent283\pnhang{\pntxtb i}}\nooverflow\faroman\ls42\rin0\lin283\itap0 \f1\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {Supported engines
+\par {\pntext\pard\plain\s26 \f30\fs20\lang2057\langfe1033\langnp2057\langfenp1033 \loch\af30\dbch\af0\hich\f30 \'69\tab}}\pard\plain \s26\ql \fi-283\li283\ri0\sa120\widctlpar\brdrb\brdrs\brdrw15\brsp20 {\*\pn \pnlvlblt\ilvl0\ls50\pnrnot0
+\pnf30\pnstart1\pnindent283\pnhang{\pntxtb i}}\nooverflow\faroman\ls50\rin0\lin283\itap0 \f1\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {Supported engines
\par }\pard\plain \ql \li0\ri0\sa120\widctlpar\nooverflow\faroman\rin0\lin0\itap0 \f1\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {avalanche
+\par }{\cs39 bbvs}{
\par cge
\par composer
\par draci
@@ -336,6 +339,7 @@ ch kinda makes it unplayable.
\par prince
\par sci
\par \tab SCI32
+\par sherlock
\par sky
\par sword1
\par sword2
diff --git a/backends/platform/symbian/help/build_help.mk b/backends/platform/symbian/help/build_help.mk
index 7a18ad8252..b2910f9c11 100644
--- a/backends/platform/symbian/help/build_help.mk
+++ b/backends/platform/symbian/help/build_help.mk
@@ -18,12 +18,9 @@ clean :
del ScummVM.hlp
del ScummVM.hlp.hrh
-bld :
- cshlpcmp ScummVM.xml
-
ifeq (WINS,$(findstring WINS, $(PLATFORM)))
copy ScummVM.hlp $(EPOCROOT)epoc32\$(PLATFORM)\c\resource\help
endif
-freeze lib cleanlib final resource savespace releasables :
+bld freeze lib cleanlib final resource savespace releasables :
diff --git a/backends/platform/symbian/mmp/config.mmh b/backends/platform/symbian/mmp/config.mmh
index da91117cf6..8a81fd2b78 100644
--- a/backends/platform/symbian/mmp/config.mmh
+++ b/backends/platform/symbian/mmp/config.mmh
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
* Copyright (C) 2014 Fedor Strizhniou
*
* ScummVM is the legal property of its developers, whose names
diff --git a/backends/platform/symbian/mmp/scummvm_access.mmp.in b/backends/platform/symbian/mmp/scummvm_access.mmp.in
index 4f8b258ec0..8e1c85f3e3 100644
--- a/backends/platform/symbian/mmp/scummvm_access.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_access.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2013 The ScummVM project
+ * Copyright (C) 2005-2016 The ScummVM project
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_agi.mmp.in b/backends/platform/symbian/mmp/scummvm_agi.mmp.in
index e4bdae3e2f..dcea8f023b 100644
--- a/backends/platform/symbian/mmp/scummvm_agi.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_agi.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_agos.mmp.in b/backends/platform/symbian/mmp/scummvm_agos.mmp.in
index 8db7132a96..c5eb4d8ad4 100644
--- a/backends/platform/symbian/mmp/scummvm_agos.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_agos.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_avalanche.mmp.in b/backends/platform/symbian/mmp/scummvm_avalanche.mmp.in
index 6d44c66bf7..a9580c643e 100644
--- a/backends/platform/symbian/mmp/scummvm_avalanche.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_avalanche.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
* Copyright (C) 2013 Strizniou Fedor
*
* ScummVM is the legal property of its developers, whose names
diff --git a/backends/platform/symbian/mmp/scummvm_base.mmp.in b/backends/platform/symbian/mmp/scummvm_base.mmp.in
index 559d070452..58a56c95ac 100644
--- a/backends/platform/symbian/mmp/scummvm_base.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_base.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
@@ -38,6 +38,7 @@ TARGETTYPE lib
OPTION GCCE -I'/Symbian/S60_5th_Edition_SDK_v1.0/epoc32/include/png'
// Note: the LIB:*.lib statements are used by AdaptAllMMPs.pl, so don't remove them!
+MACRO USE_SYSTEM_REMOVE
//START_AUTO_MACROS_MASTER//
// empty base file, will be updated by Perl build scripts
@@ -99,6 +100,7 @@ SOURCEPATH ..\..\..\..\audio
//STOP_AUTO_OBJECTS_AUDIO_//
SOURCE softsynth\fmtowns_pc98\towns_pc98_fmsynth.cpp // Included since its excluded by filter
+SOURCE miles_mt32.cpp
#if defined (WINS)
SOURCE rate.cpp // WINS emulator version: add regular .cpp
diff --git a/backends/platform/symbian/mmp/scummvm_bbvs.mmp.in b/backends/platform/symbian/mmp/scummvm_bbvs.mmp.in
index 8f643377fc..864d019c97 100644
--- a/backends/platform/symbian/mmp/scummvm_bbvs.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_bbvs.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
* Copyright (C) 2014 Fedor Strizhniou - Epoc project file
*
* ScummVM is the legal property of its developers, whose names
diff --git a/backends/platform/symbian/mmp/scummvm_cge.mmp.in b/backends/platform/symbian/mmp/scummvm_cge.mmp.in
index 2b11ef94a6..bcfbec8a70 100644
--- a/backends/platform/symbian/mmp/scummvm_cge.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_cge.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_cge2.mmp.in b/backends/platform/symbian/mmp/scummvm_cge2.mmp.in
index 7c78f47bfd..f09a2b2427 100644
--- a/backends/platform/symbian/mmp/scummvm_cge2.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_cge2.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_cine.mmp.in b/backends/platform/symbian/mmp/scummvm_cine.mmp.in
index d0a9f86808..ff55b1bc1d 100644
--- a/backends/platform/symbian/mmp/scummvm_cine.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_cine.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_composer.mmp.in b/backends/platform/symbian/mmp/scummvm_composer.mmp.in
index 8761718a12..c974df098a 100644
--- a/backends/platform/symbian/mmp/scummvm_composer.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_composer.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_cruise.mmp.in b/backends/platform/symbian/mmp/scummvm_cruise.mmp.in
index a586a67c0d..134c924d2a 100644
--- a/backends/platform/symbian/mmp/scummvm_cruise.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_cruise.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_draci.mmp.in b/backends/platform/symbian/mmp/scummvm_draci.mmp.in
index 4101ce680f..66d111efb0 100644
--- a/backends/platform/symbian/mmp/scummvm_draci.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_draci.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_drascula.mmp.in b/backends/platform/symbian/mmp/scummvm_drascula.mmp.in
index 2ac3e6000f..b3128978c3 100644
--- a/backends/platform/symbian/mmp/scummvm_drascula.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_drascula.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_dreamweb.mmp.in b/backends/platform/symbian/mmp/scummvm_dreamweb.mmp.in
index a238904653..b7841ee9cb 100644
--- a/backends/platform/symbian/mmp/scummvm_dreamweb.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_dreamweb.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
* Copyright (C) 2013 Strizniou Fedor
*
* ScummVM is the legal property of its developers, whose names
diff --git a/backends/platform/symbian/mmp/scummvm_fullpipe.mmp.in b/backends/platform/symbian/mmp/scummvm_fullpipe.mmp.in
index aae44bda97..85bbfa69be 100644
--- a/backends/platform/symbian/mmp/scummvm_fullpipe.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_fullpipe.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
* Copyright (C) 2013 Strizniou Fedor
*
* ScummVM is the legal property of its developers, whose names
diff --git a/backends/platform/symbian/mmp/scummvm_gob.mmp.in b/backends/platform/symbian/mmp/scummvm_gob.mmp.in
index 1bb8982a9e..b91fbb68b7 100644
--- a/backends/platform/symbian/mmp/scummvm_gob.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_gob.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_groovie.mmp.in b/backends/platform/symbian/mmp/scummvm_groovie.mmp.in
index 199bb4c4a8..effff997df 100644
--- a/backends/platform/symbian/mmp/scummvm_groovie.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_groovie.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_hopkins.mmp.in b/backends/platform/symbian/mmp/scummvm_hopkins.mmp.in
index 59adffb1ea..4df1db9be6 100644
--- a/backends/platform/symbian/mmp/scummvm_hopkins.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_hopkins.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_hugo.mmp.in b/backends/platform/symbian/mmp/scummvm_hugo.mmp.in
index 6ccdb2e95e..c294588147 100644
--- a/backends/platform/symbian/mmp/scummvm_hugo.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_hugo.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_kyra.mmp.in b/backends/platform/symbian/mmp/scummvm_kyra.mmp.in
index 365c041b27..ad6dfebe71 100644
--- a/backends/platform/symbian/mmp/scummvm_kyra.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_kyra.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_lastexpress.mmp.in b/backends/platform/symbian/mmp/scummvm_lastexpress.mmp.in
index 4791307aa6..9c49fe7dcb 100644
--- a/backends/platform/symbian/mmp/scummvm_lastexpress.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_lastexpress.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_lure.mmp.in b/backends/platform/symbian/mmp/scummvm_lure.mmp.in
index 1cd46de184..4982576432 100644
--- a/backends/platform/symbian/mmp/scummvm_lure.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_lure.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_m4.mmp.in b/backends/platform/symbian/mmp/scummvm_m4.mmp.in
index e6621d812d..5a87e3fd14 100644
--- a/backends/platform/symbian/mmp/scummvm_m4.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_m4.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_made.mmp.in b/backends/platform/symbian/mmp/scummvm_made.mmp.in
index e8835b6428..ab809351c5 100644
--- a/backends/platform/symbian/mmp/scummvm_made.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_made.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_mads.mmp.in b/backends/platform/symbian/mmp/scummvm_mads.mmp.in
index eb1d20749e..65224af700 100644
--- a/backends/platform/symbian/mmp/scummvm_mads.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_mads.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
* Copyright (C) 2014 Fedor Strizhniou - Epoc project file
*
* ScummVM is the legal property of its developers, whose names
diff --git a/backends/platform/symbian/mmp/scummvm_mohawk.mmp.in b/backends/platform/symbian/mmp/scummvm_mohawk.mmp.in
index 694032ede6..ff3bce9767 100644
--- a/backends/platform/symbian/mmp/scummvm_mohawk.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_mohawk.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_mortevielle.mmp.in b/backends/platform/symbian/mmp/scummvm_mortevielle.mmp.in
index caf8e330f3..e04006ea85 100644
--- a/backends/platform/symbian/mmp/scummvm_mortevielle.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_mortevielle.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
* Copyright (C) 2013 Strizniou Fedor
*
* ScummVM is the legal property of its developers, whose names
diff --git a/backends/platform/symbian/mmp/scummvm_neverhood.mmp.in b/backends/platform/symbian/mmp/scummvm_neverhood.mmp.in
index db0f445089..05f195c2c4 100644
--- a/backends/platform/symbian/mmp/scummvm_neverhood.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_neverhood.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_parallaction.mmp.in b/backends/platform/symbian/mmp/scummvm_parallaction.mmp.in
index 7c5c4c8abd..933deec4b7 100644
--- a/backends/platform/symbian/mmp/scummvm_parallaction.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_parallaction.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_pegasus.mmp.in b/backends/platform/symbian/mmp/scummvm_pegasus.mmp.in
index fa65964f3f..e292764ed9 100644
--- a/backends/platform/symbian/mmp/scummvm_pegasus.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_pegasus.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_prince.mmp.in b/backends/platform/symbian/mmp/scummvm_prince.mmp.in
index 7dfec04f46..c0b8193c38 100644
--- a/backends/platform/symbian/mmp/scummvm_prince.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_prince.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2013 The ScummVM project
+ * Copyright (C) 2005-2016 The ScummVM project
* Copyright (C) 2014 Strizniou Fedor
*
* ScummVM is the legal property of its developers, whose names
diff --git a/backends/platform/symbian/mmp/scummvm_queen.mmp.in b/backends/platform/symbian/mmp/scummvm_queen.mmp.in
index 9280b94fea..106037e741 100644
--- a/backends/platform/symbian/mmp/scummvm_queen.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_queen.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_saga.mmp.in b/backends/platform/symbian/mmp/scummvm_saga.mmp.in
index 838ee18ccf..230b54ed07 100644
--- a/backends/platform/symbian/mmp/scummvm_saga.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_saga.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_sci.mmp.in b/backends/platform/symbian/mmp/scummvm_sci.mmp.in
index daed96856d..42c79c4ccf 100644
--- a/backends/platform/symbian/mmp/scummvm_sci.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_sci.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_scumm.mmp.in b/backends/platform/symbian/mmp/scummvm_scumm.mmp.in
index 91c6e79fde..c727a6f1be 100644
--- a/backends/platform/symbian/mmp/scummvm_scumm.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_scumm.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_sherlock.mmp.in b/backends/platform/symbian/mmp/scummvm_sherlock.mmp.in
new file mode 100644
index 0000000000..4c4117f39e
--- /dev/null
+++ b/backends/platform/symbian/mmp/scummvm_sherlock.mmp.in
@@ -0,0 +1,53 @@
+/* ScummVM - Graphic Adventure Engine
+ * Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
+ * Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
+ * Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
+ * Copyright (C) 2005-2016 The ScummVM Team
+ * Copyright (C) 2015 Strizniou Fedor
+ *
+ * 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.
+ *
+ */
+
+//
+// EPOC MMP makefile project for ScummVM
+//
+
+// *** Definitions
+
+TARGET scummvm_sherlock.lib
+TARGETTYPE lib
+#include "config.mmh"
+
+//START_AUTO_MACROS_SLAVE//
+
+ // empty base file, will be updated by Perl build scripts
+
+//STOP_AUTO_MACROS_SLAVE//
+
+// *** SOURCE files
+
+SOURCEPATH ..\..\..\..\engines\sherlock
+
+//START_AUTO_OBJECTS_SHERLOCK_//
+
+ // empty base file, will be updated by Perl build scripts
+
+//STOP_AUTO_OBJECTS_SHERLOCK_//
+
diff --git a/backends/platform/symbian/mmp/scummvm_sky.mmp.in b/backends/platform/symbian/mmp/scummvm_sky.mmp.in
index 51054597ef..621dcd8699 100644
--- a/backends/platform/symbian/mmp/scummvm_sky.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_sky.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_sword1.mmp.in b/backends/platform/symbian/mmp/scummvm_sword1.mmp.in
index 9ce462f517..0904732a1b 100644
--- a/backends/platform/symbian/mmp/scummvm_sword1.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_sword1.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_sword2.mmp.in b/backends/platform/symbian/mmp/scummvm_sword2.mmp.in
index bd4756c903..48aea59db3 100644
--- a/backends/platform/symbian/mmp/scummvm_sword2.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_sword2.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_sword25.mmp.in b/backends/platform/symbian/mmp/scummvm_sword25.mmp.in
index b395a25799..49e37e3140 100644
--- a/backends/platform/symbian/mmp/scummvm_sword25.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_sword25.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
* Copyright (C) 2013 Strizniou Fedor
*
* ScummVM is the legal property of its developers, whose names
diff --git a/backends/platform/symbian/mmp/scummvm_teenagent.mmp.in b/backends/platform/symbian/mmp/scummvm_teenagent.mmp.in
index fa976791c3..85091abf2c 100644
--- a/backends/platform/symbian/mmp/scummvm_teenagent.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_teenagent.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_testbed.mmp.in b/backends/platform/symbian/mmp/scummvm_testbed.mmp.in
index e15e02fe1c..3302bfe8af 100644
--- a/backends/platform/symbian/mmp/scummvm_testbed.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_testbed.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
* Copyright (C) 2013 Strizniou Fedor
*
* ScummVM is the legal property of its developers, whose names
diff --git a/backends/platform/symbian/mmp/scummvm_tinsel.mmp.in b/backends/platform/symbian/mmp/scummvm_tinsel.mmp.in
index 095e693372..21fe837a8a 100644
--- a/backends/platform/symbian/mmp/scummvm_tinsel.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_tinsel.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_toltecs.mmp.in b/backends/platform/symbian/mmp/scummvm_toltecs.mmp.in
index 5f92b2f376..00f2d2261d 100644
--- a/backends/platform/symbian/mmp/scummvm_toltecs.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_toltecs.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_tony.mmp.in b/backends/platform/symbian/mmp/scummvm_tony.mmp.in
index de1d497412..a05fba8842 100644
--- a/backends/platform/symbian/mmp/scummvm_tony.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_tony.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_toon.mmp.in b/backends/platform/symbian/mmp/scummvm_toon.mmp.in
index 49f0b0e19d..1f268b3c00 100644
--- a/backends/platform/symbian/mmp/scummvm_toon.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_toon.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_touche.mmp.in b/backends/platform/symbian/mmp/scummvm_touche.mmp.in
index 1ff5d66cb5..636b448168 100644
--- a/backends/platform/symbian/mmp/scummvm_touche.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_touche.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_tsage.mmp.in b/backends/platform/symbian/mmp/scummvm_tsage.mmp.in
index 6b57827e1e..d45a808628 100644
--- a/backends/platform/symbian/mmp/scummvm_tsage.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_tsage.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_tucker.mmp.in b/backends/platform/symbian/mmp/scummvm_tucker.mmp.in
index 3be99ab47d..68c81aebbb 100644
--- a/backends/platform/symbian/mmp/scummvm_tucker.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_tucker.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_voyeur.mmp.in b/backends/platform/symbian/mmp/scummvm_voyeur.mmp.in
index c31d3fcfa2..9e02567651 100644
--- a/backends/platform/symbian/mmp/scummvm_voyeur.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_voyeur.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_wintermute.mmp.in b/backends/platform/symbian/mmp/scummvm_wintermute.mmp.in
index 97fbd6e3ea..d5eef5d3a3 100644
--- a/backends/platform/symbian/mmp/scummvm_wintermute.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_wintermute.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/mmp/scummvm_zvision.mmp.in b/backends/platform/symbian/mmp/scummvm_zvision.mmp.in
index 838520799e..1bd34dfe38 100644
--- a/backends/platform/symbian/mmp/scummvm_zvision.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_zvision.mmp.in
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
* Copyright (C) 2013 Strizniou Fedor - Epoc project file
*
* ScummVM is the legal property of its developers, whose names
diff --git a/backends/platform/symbian/res/ScummVmAif.rss b/backends/platform/symbian/res/ScummVmAif.rss
index 8238bdd005..3bb86ca796 100644
--- a/backends/platform/symbian/res/ScummVmAif.rss
+++ b/backends/platform/symbian/res/ScummVmAif.rss
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/res/scummvm.rss b/backends/platform/symbian/res/scummvm.rss
index ae34e9fbaa..67af8b77d0 100644
--- a/backends/platform/symbian/res/scummvm.rss
+++ b/backends/platform/symbian/res/scummvm.rss
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/res/scummvm_A0000658.rss b/backends/platform/symbian/res/scummvm_A0000658.rss
index 3b31f9f0a0..2f478962de 100644
--- a/backends/platform/symbian/res/scummvm_A0000658.rss
+++ b/backends/platform/symbian/res/scummvm_A0000658.rss
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
diff --git a/backends/platform/symbian/src/ScummVm.hrh b/backends/platform/symbian/src/ScummVm.hrh
index f756912d96..927da51e3d 100644
--- a/backends/platform/symbian/src/ScummVm.hrh
+++ b/backends/platform/symbian/src/ScummVm.hrh
@@ -2,7 +2,7 @@
* Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
* Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
* Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2015 The ScummVM Team
+ * Copyright (C) 2005-2016 The ScummVM Team
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
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 9b23e3fe78..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.
@@ -127,7 +128,6 @@ void TizenGraphicsManager::setReady() {
void TizenGraphicsManager::updateScreen() {
if (!_initState) {
OpenGLGraphicsManager::updateScreen();
- eglSwapBuffers(_eglDisplay, _eglSurface);
}
}
@@ -203,3 +203,11 @@ bool TizenGraphicsManager::loadVideoMode(uint requestedWidth, uint requestedHeig
// using a fixed output size we do nothing like that here.
return true;
}
+
+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 f1d4498650..1798b078d8 100644
--- a/backends/platform/tizen/graphics.h
+++ b/backends/platform/tizen/graphics.h
@@ -61,6 +61,10 @@ protected:
bool loadVideoMode(uint requestedWidth, uint requestedHeight, const Graphics::PixelFormat &format);
+ 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/platform/wince/wince-sdl.cpp b/backends/platform/wince/wince-sdl.cpp
index c1b0c7f692..02853b548e 100644
--- a/backends/platform/wince/wince-sdl.cpp
+++ b/backends/platform/wince/wince-sdl.cpp
@@ -645,7 +645,7 @@ Common::String OSystem_WINCE3::getSystemLanguage() const {
const char *posixMappingTable[][3] = {
{"CAT", "ESP", "ca_ES"},
{"CSY", "CZE", "cs_CZ"},
- {"DAN", "DNK", "da_DA"},
+ {"DAN", "DNK", "da_DK"},
{"DEU", "DEU", "de_DE"},
{"ESN", "ESP", "es_ES"},
{"ESP", "ESP", "es_ES"},
@@ -657,7 +657,7 @@ Common::String OSystem_WINCE3::getSystemLanguage() const {
{"PLK", "POL", "pl_PL"},
{"PTB", "BRA", "pt_BR"},
{"RUS", "RUS", "ru_RU"},
- {"SVE", "SWE", "se_SE"},
+ {"SVE", "SWE", "sv_SE"},
{"UKR", "UKR", "uk_UA"},
{NULL, NULL, NULL}
};
diff --git a/backends/plugins/win32/win32-provider.cpp b/backends/plugins/win32/win32-provider.cpp
index 5f4d405da4..ae8a5f0472 100644
--- a/backends/plugins/win32/win32-provider.cpp
+++ b/backends/plugins/win32/win32-provider.cpp
@@ -77,7 +77,7 @@ public:
debug("Failed loading plugin '%s' (error code %d)", _filename.c_str(), (int32) GetLastError());
return false;
} else {
- debug(1, "Success loading plugin '%s', handle %08X", _filename.c_str(), (uint32) _dlHandle);
+ debug(1, "Success loading plugin '%s', handle %p", _filename.c_str(), _dlHandle);
}
return DynamicPlugin::loadPlugin();
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/saves/posix/posix-saves.cpp b/backends/saves/posix/posix-saves.cpp
index 96828320a6..2a7b4d3e9f 100644
--- a/backends/saves/posix/posix-saves.cpp
+++ b/backends/saves/posix/posix-saves.cpp
@@ -21,16 +21,19 @@
*/
-// Enable getenv, mkdir and time.h stuff
-#define FORBIDDEN_SYMBOL_EXCEPTION_getenv
-#define FORBIDDEN_SYMBOL_EXCEPTION_mkdir
+// Re-enable some forbidden symbols to avoid clashes with stat.h and unistd.h.
+// Also with clock() in sys/time.h in some Mac OS X SDKs.
#define FORBIDDEN_SYMBOL_EXCEPTION_time_h //On IRIX, sys/stat.h includes sys/time.h
+#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h
+#define FORBIDDEN_SYMBOL_EXCEPTION_mkdir
+#define FORBIDDEN_SYMBOL_EXCEPTION_getenv
#include "common/scummsys.h"
#if defined(POSIX) && !defined(DISABLE_DEFAULT_SAVEFILEMANAGER)
#include "backends/saves/posix/posix-saves.h"
+#include "backends/fs/posix/posix-fs.h"
#include "common/config-manager.h"
#include "common/savefile.h"
@@ -41,26 +44,70 @@
#include <errno.h>
#include <sys/stat.h>
-
-#ifdef MACOSX
-#define DEFAULT_SAVE_PATH "Documents/ScummVM Savegames"
-#else
-#define DEFAULT_SAVE_PATH ".scummvm"
-#endif
-
POSIXSaveFileManager::POSIXSaveFileManager() {
- // Register default savepath based on HOME
+ // Register default savepath.
#if defined(SAMSUNGTV)
ConfMan.registerDefault("savepath", "/mtd_wiselink/scummvm savegames");
#else
Common::String savePath;
+
+#if defined(MACOSX)
const char *home = getenv("HOME");
if (home && *home && strlen(home) < MAXPATHLEN) {
savePath = home;
- savePath += "/" DEFAULT_SAVE_PATH;
+ savePath += "/Documents/ScummVM Savegames";
+
ConfMan.registerDefault("savepath", savePath);
}
+#else
+ const char *envVar;
+
+ // Previously we placed our default savepath in HOME. If the directory
+ // still exists, we will use it for backwards compatability.
+ envVar = getenv("HOME");
+ if (envVar && *envVar) {
+ savePath = envVar;
+ savePath += "/.scummvm";
+
+ struct stat sb;
+ if (stat(savePath.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
+ savePath.clear();
+ }
+ }
+
+ if (savePath.empty()) {
+ Common::String prefix;
+
+ // On POSIX systems we follow the XDG Base Directory Specification for
+ // where to store files. The version we based our code upon can be found
+ // over here: http://standards.freedesktop.org/basedir-spec/basedir-spec-0.8.html
+ envVar = getenv("XDG_DATA_HOME");
+ if (!envVar || !*envVar) {
+ envVar = getenv("HOME");
+ if (envVar && *envVar) {
+ prefix = envVar;
+ savePath = ".local/share/";
+ }
+ } else {
+ prefix = envVar;
+ }
+
+ // Our default save path is '$XDG_DATA_HOME/scummvm/saves'
+ savePath += "scummvm/saves";
+
+ if (!Posix::assureDirectoryExists(savePath, prefix.c_str())) {
+ savePath.clear();
+ } else {
+ savePath = prefix + '/' + savePath;
+ }
+ }
+
+ if (!savePath.empty() && savePath.size() < MAXPATHLEN) {
+ ConfMan.registerDefault("savepath", savePath);
+ }
+#endif
+
// The user can override the savepath with the SCUMMVM_SAVEPATH
// environment variable. This is weaker than a --savepath on the
// command line, but overrides the default savepath.
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 d45253c676..b2810e55b4 100644
--- a/backends/taskbar/win32/win32-taskbar.cpp
+++ b/backends/taskbar/win32/win32-taskbar.cpp
@@ -28,10 +28,39 @@
#if defined(WIN32) && defined(USE_TASKBAR)
+// HACK: To get __MINGW64_VERSION_foo defines we need to manually include
+// _mingw.h in this file because we do not include any system headers at this
+// point on purpose. The defines are required to detect whether this is a
+// classic MinGW toolchain or a MinGW-w64 based one.
+#if defined(__MINGW32__)
+#include <_mingw.h>
+#endif
+
// Needed for taskbar functions
-#if defined(__GNUC__) && defined(__MINGW32__) && !defined(__MINGW64__)
+// HACK: MinGW-w64 based toolchains include the symbols we require in their
+// headers. The 32 bit incarnation only defines __MINGW32__. This leads to
+// build breakage due to clashes with our compat header. Luckily MinGW-w64
+// based toolchains define __MINGW64_VERSION_foo macros inside _mingw.h,
+// which is included from all system headers. Thus we abuse that to detect
+// them.
+#if defined(__GNUC__) && defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
#include "backends/taskbar/win32/mingw-compat.h"
#else
+ // We use functionality introduced with Win7 in this file.
+ // To assure that including the respective system headers gives us all
+ // required definitions we set Win7 as minimum version we target.
+ // See: https://msdn.microsoft.com/en-us/library/windows/desktop/aa383745%28v=vs.85%29.aspx#macros_for_conditional_declarations
+ #undef _WIN32_WINNT
+ #define _WIN32_WINNT _WIN32_WINNT_WIN7
+
+ // TODO: We might not need to include this file, the MSDN docs are
+ // not really helpful to decide whether we require it or not.
+ //
+ // Casing of the name is a bit of a mess. MinGW64 seems to use all
+ // lowercase, while MSDN docs suggest "SdkDdkVer.h". We are stuck with
+ // what MinGW64 uses...
+ #include <sdkddkver.h>
+
// We need certain functions that are excluded by default
#undef NONLS
#undef NOICONS
@@ -39,11 +68,6 @@
#if defined(ARRAYSIZE)
#undef ARRAYSIZE
#endif
-
- #if defined(_MSC_VER)
- // Default MSVC headers for ITaskbarList3 and IShellLink
- #include <SDKDDKVer.h>
- #endif
#endif
#include <shlobj.h>
@@ -61,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);
@@ -376,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 285fd632b7..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"
@@ -116,8 +117,9 @@ static const char HELP_STRING[] =
" --output-rate=RATE Select output sample rate in Hz (e.g. 22050)\n"
" --opl-driver=DRIVER Select AdLib (OPL) emulator (db, mame)\n"
" --aspect-ratio Enable aspect ratio correction\n"
- " --render-mode=MODE Enable additional render modes (cga, ega, hercGreen,\n"
- " hercAmber, amiga)\n"
+ " --render-mode=MODE Enable additional render modes (hercGreen, hercAmber,\n"
+ " cga, ega, vga, amiga, fmtowns, pc9821, pc9801, 2gs,\n"
+ " atari, macintosh)\n"
#ifdef ENABLE_EVENTRECORDER
" --record-mode=MODE Specify record mode for event recorder (record, playback,\n"
" passthrough [default])\n"
@@ -372,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/internal_version.h b/base/internal_version.h
index b6526c5c14..29aacf2d95 100644
--- a/base/internal_version.h
+++ b/base/internal_version.h
@@ -16,4 +16,4 @@
#define SCUMMVM_REVISION
#endif
-#define SCUMMVM_VERSION "1.8.0git" SCUMMVM_REVISION
+#define SCUMMVM_VERSION "1.9.0git" SCUMMVM_REVISION
diff --git a/base/main.cpp b/base/main.cpp
index 3ea38b547a..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,12 +151,24 @@ 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)
+ if (err.getCode() == Common::kNoError) {
+ // Set default values for all of the custom engine options
+ // Appareantly some engines query them in their constructor, thus we
+ // need to set this up before instance creation.
+ const ExtraGuiOptions engineOptions = (*plugin)->getExtraGuiOptions(Common::String());
+ for (uint i = 0; i < engineOptions.size(); i++) {
+ ConfMan.registerDefault(engineOptions[i].configOption, engineOptions[i].defaultState);
+ }
+
err = (*plugin)->createInstance(&system, &engine);
+ }
// Check for errors
if (!engine || err.getCode() != Common::kNoError) {
@@ -231,12 +246,6 @@ static Common::Error runGame(const EnginePlugin *plugin, OSystem &system, const
// Initialize any game-specific keymaps
engine->initKeymap();
- // Set default values for all of the custom engine options
- const ExtraGuiOptions engineOptions = (*plugin)->getExtraGuiOptions(Common::String());
- for (uint i = 0; i < engineOptions.size(); i++) {
- ConfMan.registerDefault(engineOptions[i].configOption, engineOptions[i].defaultState);
- }
-
// Inform backend that the engine is about to be run
system.engineInit();
@@ -379,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
@@ -455,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 6453073ae5..13cdd9f991 100644
--- a/common/algorithm.h
+++ b/common/algorithm.h
@@ -177,7 +177,8 @@ T sortChoosePivot(T first, T last) {
template<typename T, class StrictWeakOrdering>
T sortPartition(T first, T last, T pivot, StrictWeakOrdering &comp) {
--last;
- SWAP(*pivot, *last);
+ if (pivot != last)
+ SWAP(*pivot, *last);
T sorted;
for (sorted = first; first != last; ++first) {
@@ -188,7 +189,8 @@ T sortPartition(T first, T last, T pivot, StrictWeakOrdering &comp) {
}
}
- SWAP(*last, *sorted);
+ if (last != sorted)
+ SWAP(*last, *sorted);
return sorted;
}
@@ -268,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/archive.cpp b/common/archive.cpp
index 36d420561f..5a339900b6 100644
--- a/common/archive.cpp
+++ b/common/archive.cpp
@@ -48,7 +48,7 @@ int Archive::listMatchingMembers(ArchiveMemberList &list, const String &pattern)
int matches = 0;
ArchiveMemberList::const_iterator it = allNames.begin();
- for ( ; it != allNames.end(); ++it) {
+ for (; it != allNames.end(); ++it) {
// TODO: We match case-insenstivie for now, our API does not define whether that's ok or not though...
// For our use case case-insensitive is probably what we want to have though.
if ((*it)->getName().matchString(pattern, true, true)) {
@@ -64,7 +64,7 @@ int Archive::listMatchingMembers(ArchiveMemberList &list, const String &pattern)
SearchSet::ArchiveNodeList::iterator SearchSet::find(const String &name) {
ArchiveNodeList::iterator it = _list.begin();
- for ( ; it != _list.end(); ++it) {
+ for (; it != _list.end(); ++it) {
if (it->_name == name)
break;
}
@@ -73,7 +73,7 @@ SearchSet::ArchiveNodeList::iterator SearchSet::find(const String &name) {
SearchSet::ArchiveNodeList::const_iterator SearchSet::find(const String &name) const {
ArchiveNodeList::const_iterator it = _list.begin();
- for ( ; it != _list.end(); ++it) {
+ for (; it != _list.end(); ++it) {
if (it->_name == name)
break;
}
@@ -81,13 +81,13 @@ SearchSet::ArchiveNodeList::const_iterator SearchSet::find(const String &name) c
}
/*
- Keep the nodes sorted according to descending priorities.
- In case two or node nodes have the same priority, insertion
- order prevails.
+ Keep the nodes sorted according to descending priorities.
+ In case two or node nodes have the same priority, insertion
+ order prevails.
*/
void SearchSet::insert(const Node &node) {
ArchiveNodeList::iterator it = _list.begin();
- for ( ; it != _list.end(); ++it) {
+ for (; it != _list.end(); ++it) {
if (it->_priority < node._priority)
break;
}
@@ -131,8 +131,7 @@ void SearchSet::addSubDirectoriesMatching(const FSNode &directory, String origPa
++sep;
if (sep != origPattern.end())
nextPattern = String(sep, origPattern.end());
- }
- else {
+ } else {
pattern = origPattern;
}
@@ -211,7 +210,7 @@ bool SearchSet::hasFile(const String &name) const {
return false;
ArchiveNodeList::const_iterator it = _list.begin();
- for ( ; it != _list.end(); ++it) {
+ for (; it != _list.end(); ++it) {
if (it->_arc->hasFile(name))
return true;
}
@@ -223,7 +222,7 @@ int SearchSet::listMatchingMembers(ArchiveMemberList &list, const String &patter
int matches = 0;
ArchiveNodeList::const_iterator it = _list.begin();
- for ( ; it != _list.end(); ++it)
+ for (; it != _list.end(); ++it)
matches += it->_arc->listMatchingMembers(list, pattern);
return matches;
@@ -233,7 +232,7 @@ int SearchSet::listMembers(ArchiveMemberList &list) const {
int matches = 0;
ArchiveNodeList::const_iterator it = _list.begin();
- for ( ; it != _list.end(); ++it)
+ for (; it != _list.end(); ++it)
matches += it->_arc->listMembers(list);
return matches;
@@ -244,7 +243,7 @@ const ArchiveMemberPtr SearchSet::getMember(const String &name) const {
return ArchiveMemberPtr();
ArchiveNodeList::const_iterator it = _list.begin();
- for ( ; it != _list.end(); ++it) {
+ for (; it != _list.end(); ++it) {
if (it->_arc->hasFile(name))
return it->_arc->getMember(name);
}
@@ -257,7 +256,7 @@ SeekableReadStream *SearchSet::createReadStreamForMember(const String &name) con
return 0;
ArchiveNodeList::const_iterator it = _list.begin();
- for ( ; it != _list.end(); ++it) {
+ for (; it != _list.end(); ++it) {
SeekableReadStream *stream = it->_arc->createReadStreamForMember(name);
if (stream)
return stream;
@@ -268,7 +267,7 @@ SeekableReadStream *SearchSet::createReadStreamForMember(const String &name) con
SearchManager::SearchManager() {
- clear(); // Force a reset
+ clear(); // Force a reset
}
void SearchManager::clear() {
diff --git a/common/array.h b/common/array.h
index f240a9c2f5..04ec9f9ccb 100644
--- a/common/array.h
+++ b/common/array.h
@@ -141,6 +141,12 @@ public:
insert_aux(_storage + idx, array.begin(), array.end());
}
+ /**
+ * Inserts element before pos.
+ */
+ void insert(iterator pos, const T &element) {
+ insert_aux(pos, &element, &element + 1);
+ }
T remove_at(size_type idx) {
assert(idx < _size);
@@ -187,6 +193,14 @@ public:
_capacity = 0;
}
+ iterator erase(iterator pos) {
+ copy(pos + 1, _storage + _size, pos);
+ _size--;
+ // We also need to destroy the last object properly here.
+ _storage[_size].~T();
+ return pos;
+ }
+
bool empty() const {
return (_size == 0);
}
@@ -347,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/dcl.cpp b/common/dcl.cpp
index 5993c218cb..75a533aa9d 100644
--- a/common/dcl.cpp
+++ b/common/dcl.cpp
@@ -449,6 +449,8 @@ bool DecompressorDCL::unpack(SeekableReadStream *sourceStream, WriteStream *targ
}
if (_targetFixedSize) {
+ if (_bytesWritten != _targetSize)
+ warning("DCL-INFLATE Error: Inconsistent bytes written (%d) and target buffer size (%d)", _bytesWritten, _targetSize);
return _bytesWritten == _targetSize;
}
return true; // For targets featuring dynamic size we always succeed
@@ -468,7 +470,7 @@ bool decompressDCL(ReadStream *src, byte *dest, uint32 packedSize, uint32 unpack
// Read source into memory
src->read(sourceBufferPtr, packedSize);
- Common::MemoryReadStream *sourceStream = new MemoryReadStream(sourceBufferPtr, packedSize, DisposeAfterUse::NO);
+ Common::MemoryReadStream *sourceStream = new MemoryReadStream(sourceBufferPtr, packedSize, DisposeAfterUse::YES);
Common::MemoryWriteStream *targetStream = new MemoryWriteStream(dest, unpackedSize);
success = dcl.unpack(sourceStream, targetStream, unpackedSize, true);
diff --git a/common/dcl.h b/common/dcl.h
index f90bc23c8d..ade7ebd985 100644
--- a/common/dcl.h
+++ b/common/dcl.h
@@ -25,6 +25,7 @@
* PKWARE DCL ("explode") ("PKWARE data compression library") decompressor used in engines:
* - agos (exclusively for Simon 2 setup.shr file)
* - mohawk
+ * - neverhood
* - sci
*/
diff --git a/common/fs.h b/common/fs.h
index b5b88ba8cb..f516bf7a9c 100644
--- a/common/fs.h
+++ b/common/fs.h
@@ -57,7 +57,14 @@ class FSList : public Array<FSNode> {};
*/
class FSNode : public ArchiveMember {
private:
+ friend class ::AbstractFSNode;
SharedPtr<AbstractFSNode> _realNode;
+ /**
+ * Construct a FSNode from a backend's AbstractFSNode implementation.
+ *
+ * @param realNode Pointer to a heap allocated instance. FSNode will take
+ * ownership of the pointer.
+ */
FSNode(AbstractFSNode *realNode);
public:
diff --git a/common/gui_options.cpp b/common/gui_options.cpp
index d79bf1b82f..df880f4fee 100644
--- a/common/gui_options.cpp
+++ b/common/gui_options.cpp
@@ -53,15 +53,18 @@ const struct GameOpt {
{ GUIO_NOASPECT, "noAspect" },
- { GUIO_RENDERHERCGREEN, "hercGreen" },
- { GUIO_RENDERHERCAMBER, "hercAmber" },
- { GUIO_RENDERCGA, "cga" },
- { GUIO_RENDEREGA, "ega" },
- { GUIO_RENDERVGA, "vga" },
- { GUIO_RENDERAMIGA, "amiga" },
- { GUIO_RENDERFMTOWNS, "fmtowns" },
- { GUIO_RENDERPC9821, "pc9821" },
- { GUIO_RENDERPC9801, "pc9801" },
+ { GUIO_RENDERHERCGREEN, "hercGreen" },
+ { GUIO_RENDERHERCAMBER, "hercAmber" },
+ { GUIO_RENDERCGA, "cga" },
+ { GUIO_RENDEREGA, "ega" },
+ { GUIO_RENDERVGA, "vga" },
+ { GUIO_RENDERAMIGA, "amiga" },
+ { GUIO_RENDERFMTOWNS, "fmtowns" },
+ { GUIO_RENDERPC9821, "pc9821" },
+ { GUIO_RENDERPC9801, "pc9801" },
+ { GUIO_RENDERAPPLE2GS, "2gs" },
+ { GUIO_RENDERATARIST, "atari" },
+ { GUIO_RENDERMACINTOSH, "macintosh" },
{ GUIO_GAMEOPTIONS1, "gameOption1" },
{ GUIO_GAMEOPTIONS2, "gameOption2" },
@@ -70,6 +73,8 @@ const struct GameOpt {
{ GUIO_GAMEOPTIONS5, "gameOption5" },
{ 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 78e9cc7199..ec3eccd161 100644
--- a/common/gui_options.h
+++ b/common/gui_options.h
@@ -23,47 +23,52 @@
#ifndef COMMON_GUI_OPTIONS_H
#define COMMON_GUI_OPTIONS_H
-#define GUIO_NONE "\000"
-#define GUIO_NOSUBTITLES "\001"
-#define GUIO_NOMUSIC "\002"
-#define GUIO_NOSPEECH "\003"
-#define GUIO_NOSFX "\004"
-#define GUIO_NOMIDI "\005"
-#define GUIO_NOLAUNCHLOAD "\006"
+#define GUIO_NONE "\000"
+#define GUIO_NOSUBTITLES "\001"
+#define GUIO_NOMUSIC "\002"
+#define GUIO_NOSPEECH "\003"
+#define GUIO_NOSFX "\004"
+#define GUIO_NOMIDI "\005"
+#define GUIO_NOLAUNCHLOAD "\006"
-#define GUIO_MIDIPCSPK "\007"
-#define GUIO_MIDICMS "\010"
-#define GUIO_MIDIPCJR "\011"
-#define GUIO_MIDIADLIB "\012"
-#define GUIO_MIDIC64 "\013"
-#define GUIO_MIDIAMIGA "\014"
-#define GUIO_MIDIAPPLEIIGS "\015"
-#define GUIO_MIDITOWNS "\016"
-#define GUIO_MIDIPC98 "\017"
-#define GUIO_MIDIMT32 "\020"
-#define GUIO_MIDIGM "\021"
+#define GUIO_MIDIPCSPK "\007"
+#define GUIO_MIDICMS "\010"
+#define GUIO_MIDIPCJR "\011"
+#define GUIO_MIDIADLIB "\012"
+#define GUIO_MIDIC64 "\013"
+#define GUIO_MIDIAMIGA "\014"
+#define GUIO_MIDIAPPLEIIGS "\015"
+#define GUIO_MIDITOWNS "\016"
+#define GUIO_MIDIPC98 "\017"
+#define GUIO_MIDIMT32 "\020"
+#define GUIO_MIDIGM "\021"
-#define GUIO_NOASPECT "\022"
+#define GUIO_NOASPECT "\022"
-#define GUIO_RENDERHERCGREEN "\030"
-#define GUIO_RENDERHERCAMBER "\031"
-#define GUIO_RENDERCGA "\032"
-#define GUIO_RENDEREGA "\033"
-#define GUIO_RENDERVGA "\034"
-#define GUIO_RENDERAMIGA "\035"
-#define GUIO_RENDERFMTOWNS "\036"
-#define GUIO_RENDERPC9821 "\037"
-#define GUIO_RENDERPC9801 "\040"
+#define GUIO_RENDERHERCGREEN "\030"
+#define GUIO_RENDERHERCAMBER "\031"
+#define GUIO_RENDERCGA "\032"
+#define GUIO_RENDEREGA "\033"
+#define GUIO_RENDERVGA "\034"
+#define GUIO_RENDERAMIGA "\035"
+#define GUIO_RENDERFMTOWNS "\036"
+#define GUIO_RENDERPC9821 "\037"
+#define GUIO_RENDERPC9801 "\040"
+#define GUIO_RENDERAPPLE2GS "\041"
+#define GUIO_RENDERATARIST "\042"
+#define GUIO_RENDERMACINTOSH "\043"
// Special GUIO flags for the AdvancedDetector's caching of game specific
// options.
-#define GUIO_GAMEOPTIONS1 "\041"
-#define GUIO_GAMEOPTIONS2 "\042"
-#define GUIO_GAMEOPTIONS3 "\043"
-#define GUIO_GAMEOPTIONS4 "\044"
-#define GUIO_GAMEOPTIONS5 "\045"
-#define GUIO_GAMEOPTIONS6 "\046"
-#define GUIO_GAMEOPTIONS7 "\047"
+#define GUIO_GAMEOPTIONS1 "\050"
+#define GUIO_GAMEOPTIONS2 "\051"
+#define GUIO_GAMEOPTIONS3 "\052"
+#define GUIO_GAMEOPTIONS4 "\053"
+#define GUIO_GAMEOPTIONS5 "\054"
+#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/rational.h b/common/rational.h
index 55fb361774..89caaf25b4 100644
--- a/common/rational.h
+++ b/common/rational.h
@@ -84,6 +84,8 @@ public:
int getNumerator() const { return _num; }
int getDenominator() const { return _denom; }
+ bool isOne() const { return _num == _denom; }
+
void debugPrint(int debuglevel = 0, const char *caption = "Rational:") const;
private:
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/rendermode.cpp b/common/rendermode.cpp
index 6115666399..e07cac4b4e 100644
--- a/common/rendermode.cpp
+++ b/common/rendermode.cpp
@@ -38,9 +38,12 @@ const RenderModeDescription g_renderModes[] = {
{ "ega", "EGA", kRenderEGA },
{ "vga", "VGA", kRenderVGA },
{ "amiga", "Amiga", kRenderAmiga },
- { "fmtowns", "FM-Towns", kRenderFMTowns },
- { "pc9821", "PC-9821 (256 Colors)", kRenderPC9821 },
- { "pc9801", "PC-9801 (16 Colors)", kRenderPC9801 },
+ { "fmtowns", "FM-TOWNS", kRenderFMTowns },
+ { "pc9821", _s("PC-9821 (256 Colors)"), kRenderPC9821 },
+ { "pc9801", _s("PC-9801 (16 Colors)"), kRenderPC9801 },
+ { "2gs", "Apple IIgs", kRenderApple2GS },
+ { "atari", "Atari ST", kRenderAtariST },
+ { "macintosh", "Macintosh", kRenderMacintosh },
{0, 0, kRenderDefault}
};
@@ -53,15 +56,18 @@ struct RenderGUIOMapping {
// could be used to indicate "any" mode when passed to renderMode2GUIO (if
// we wanted to merge allRenderModesGUIOs back into)
static const RenderGUIOMapping s_renderGUIOMapping[] = {
- { kRenderHercG, GUIO_RENDERHERCGREEN },
- { kRenderHercA, GUIO_RENDERHERCAMBER },
- { kRenderCGA, GUIO_RENDERCGA },
- { kRenderEGA, GUIO_RENDEREGA },
- { kRenderVGA, GUIO_RENDERVGA },
- { kRenderAmiga, GUIO_RENDERAMIGA },
- { kRenderFMTowns, GUIO_RENDERFMTOWNS },
- { kRenderPC9821, GUIO_RENDERPC9821 },
- { kRenderPC9801, GUIO_RENDERPC9801 }
+ { kRenderHercG, GUIO_RENDERHERCGREEN },
+ { kRenderHercA, GUIO_RENDERHERCAMBER },
+ { kRenderCGA, GUIO_RENDERCGA },
+ { kRenderEGA, GUIO_RENDEREGA },
+ { kRenderVGA, GUIO_RENDERVGA },
+ { kRenderAmiga, GUIO_RENDERAMIGA },
+ { kRenderFMTowns, GUIO_RENDERFMTOWNS },
+ { kRenderPC9821, GUIO_RENDERPC9821 },
+ { kRenderPC9801, GUIO_RENDERPC9801 },
+ { kRenderApple2GS, GUIO_RENDERAPPLE2GS },
+ { kRenderAtariST, GUIO_RENDERATARIST },
+ { kRenderMacintosh, GUIO_RENDERMACINTOSH }
};
DECLARE_TRANSLATION_ADDITIONAL_CONTEXT("Hercules Green", "lowres")
diff --git a/common/rendermode.h b/common/rendermode.h
index 59fa860c6c..ae1a7bc790 100644
--- a/common/rendermode.h
+++ b/common/rendermode.h
@@ -45,7 +45,10 @@ enum RenderMode {
kRenderAmiga = 6,
kRenderFMTowns = 7,
kRenderPC9821 = 8,
- kRenderPC9801 = 9
+ kRenderPC9801 = 9,
+ kRenderApple2GS = 10,
+ kRenderAtariST = 11,
+ kRenderMacintosh = 12
};
struct RenderModeDescription {
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 b8cf7678a4..3513ee2d7d 100644
--- a/common/scummsys.h
+++ b/common/scummsys.h
@@ -23,8 +23,8 @@
#ifndef COMMON_SCUMMSYS_H
#define COMMON_SCUMMSYS_H
-#ifndef __has_feature // Optional of course.
- #define __has_feature(x) 0 // Compatibility with non-clang compilers.
+#ifndef __has_feature // Optional of course.
+ #define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif
// This is a convenience macro to test whether the compiler used is a GCC
@@ -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,11 +372,11 @@
#endif
#ifndef STRINGBUFLEN
- #if defined(__N64__) || defined(__DS__)
- #define STRINGBUFLEN 256
- #else
- #define STRINGBUFLEN 1024
- #endif
+ #if defined(__N64__) || defined(__DS__) || defined(__3DS__)
+ #define STRINGBUFLEN 256
+ #else
+ #define STRINGBUFLEN 1024
+ #endif
#endif
#ifndef MAXPATHLEN
diff --git a/common/str.cpp b/common/str.cpp
index faf84d722f..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;
@@ -751,6 +798,13 @@ bool matchString(const char *str, const char *pat, bool ignoreCase, bool pathMod
return true;
break;
+ case '#':
+ if (!isDigit(*str))
+ return false;
+ pat++;
+ str++;
+ break;
+
default:
if ((!ignoreCase && *pat != *str) ||
(ignoreCase && tolower(*pat) != tolower(*str))) {
diff --git a/common/str.h b/common/str.h
index dede87a005..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
@@ -158,6 +169,7 @@ public:
* Token meaning:
* "*": any character, any amount of times.
* "?": any character, only once.
+ * "#": any decimal digit, only once.
*
* Example strings/patterns:
* String: monkey.s01 Pattern: monkey.s?? => true
@@ -165,6 +177,8 @@ public:
* String: monkey.s99 Pattern: monkey.s?1 => false
* String: monkey.s101 Pattern: monkey.s* => true
* String: monkey.s99 Pattern: monkey.s*1 => false
+ * String: monkey.s01 Pattern: monkey.s## => true
+ * String: monkey.s01 Pattern: monkey.### => false
*
* @param pat Glob pattern.
* @param ignoreCase Whether to ignore the case when doing pattern match
@@ -180,6 +194,7 @@ public:
inline uint size() const { return _size; }
inline bool empty() const { return (_size == 0); }
+ char firstChar() const { return (_size > 0) ? _str[0] : 0; }
char lastChar() const { return (_size > 0) ? _str[_size - 1] : 0; }
char operator[](int idx) const {
@@ -218,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,
@@ -234,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
@@ -329,6 +367,7 @@ String normalizePath(const String &path, const char sep);
* Token meaning:
* "*": any character, any amount of times.
* "?": any character, only once.
+ * "#": any decimal digit, only once.
*
* Example strings/patterns:
* String: monkey.s01 Pattern: monkey.s?? => true
@@ -336,6 +375,8 @@ String normalizePath(const String &path, const char sep);
* String: monkey.s99 Pattern: monkey.s?1 => false
* String: monkey.s101 Pattern: monkey.s* => true
* String: monkey.s99 Pattern: monkey.s*1 => false
+ * String: monkey.s01 Pattern: monkey.s## => true
+ * String: monkey.s01 Pattern: monkey.### => false
*
* @param str Text to be matched against the given pattern.
* @param pat Glob pattern.
diff --git a/common/taskbar.h b/common/taskbar.h
index b4ec673739..f1a9adb2d9 100644
--- a/common/taskbar.h
+++ b/common/taskbar.h
@@ -123,7 +123,7 @@ public:
virtual void addRecent(const String &name, const String &description) {}
/**
- * Notifies the user an error occured through the taskbar icon
+ * Notifies the user an error occurred through the taskbar icon
*
* This will for example show the taskbar icon as red (using progress of 100% and an error state)
* on Windows, and set the launcher icon in the urgent state on Unity
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/common/xmlparser.cpp b/common/xmlparser.cpp
index 67a3d36cec..da4f577e3c 100644
--- a/common/xmlparser.cpp
+++ b/common/xmlparser.cpp
@@ -97,36 +97,38 @@ bool XMLParser::parserError(const String &errStr) {
assert(_stream->pos() == startPosition);
currentPosition = startPosition;
- int keyOpening = 0;
- int keyClosing = 0;
-
- while (currentPosition-- && keyOpening == 0) {
- _stream->seek(-2, SEEK_CUR);
- c = _stream->readByte();
+ Common::String errorMessage = Common::String::format("\n File <%s>, line %d:\n", _fileName.c_str(), lineCount);
- if (c == '<')
- keyOpening = currentPosition - 1;
- else if (c == '>')
- keyClosing = currentPosition;
- }
+ if (startPosition > 1) {
+ int keyOpening = 0;
+ int keyClosing = 0;
- _stream->seek(startPosition, SEEK_SET);
- currentPosition = startPosition;
- while (keyClosing == 0 && c && currentPosition++) {
- c = _stream->readByte();
+ while (currentPosition-- && keyOpening == 0) {
+ _stream->seek(-2, SEEK_CUR);
+ c = _stream->readByte();
- if (c == '>')
- keyClosing = currentPosition;
- }
+ if (c == '<')
+ keyOpening = currentPosition - 1;
+ else if (c == '>')
+ keyClosing = currentPosition;
+ }
- Common::String errorMessage = Common::String::format("\n File <%s>, line %d:\n", _fileName.c_str(), lineCount);
+ _stream->seek(startPosition, SEEK_SET);
+ currentPosition = startPosition;
+ while (keyClosing == 0 && c && currentPosition++) {
+ c = _stream->readByte();
- currentPosition = (keyClosing - keyOpening);
- _stream->seek(keyOpening, SEEK_SET);
+ if (c == '>')
+ keyClosing = currentPosition;
+ }
- while (currentPosition--)
- errorMessage += (char)_stream->readByte();
+ currentPosition = (keyClosing - keyOpening);
+ _stream->seek(keyOpening, SEEK_SET);
+ while (currentPosition--)
+ errorMessage += (char)_stream->readByte();
+ }
+
errorMessage += "\n\nParser error: ";
errorMessage += errStr;
errorMessage += "\n\n";
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 a2f73644cf..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)
@@ -593,7 +597,7 @@ engine_enable() {
parent=`get_subengine_parent ${engine}`
if test `get_engine_build ${parent}` = "no" ; then
set_var _engine_${parent}_build "yes"
- fi
+ fi
fi
if test "$opt" = "static" -o "$opt" = "dynamic" -o "$opt" = "yes" ; then
@@ -805,12 +809,6 @@ get_subengines_build_string() {
}
#
-# Greet user
-#
-echo "Running ScummVM configure..."
-echo "Configure run on" `date` > $TMPLOG
-
-#
# Check any parameters we received
#
# TODO:
@@ -833,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,
- gph, iphone, linuxmoto, maemo, n64, null, openpandora,
- ps2, psp, samsungtv, sdl, webos, wii, wince) [sdl]
+ --backend=BACKEND backend to build (3ds, android, dc, dingux, ds, gcw0,
+ gph, iphone, ios7, linuxmoto, maemo, n64, null, openpandora,
+ ps2, psp, samsungtv, sdl, tizen, webos, wii, wince) [sdl]
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
@@ -861,19 +859,22 @@ 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
dreamcast for Sega Dreamcast
ds for Nintendo DS
gamecube for Nintendo GameCube
gcw0 for GCW Zero
gp2x for GP2X
gp2xwiz for GP2X Wiz
- iphone for Apple iPhone
+ iphone for Apple iPhone (iOS <= 6)
+ ios7 for Apple iPhone / iPad (iOS >= 7)
linupy for Yopy PDA
maemo for Nokia Maemo
motoezx for MotoEZX
@@ -885,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
@@ -895,7 +897,7 @@ Game engines:
--disable-all-engines disable all engines
--enable-engine=<engine name>[,<engine name>...] enable engine(s) listed
--disable-engine=<engine name>[,<engine name>...] disable engine(s) listed
- --enable-engine-static=<engine name>[,<engine name>...]
+ --enable-engine-static=<engine name>[,<engine name>...]
enable engine(s) listed as static builtin (when plugins are enabled)
--enable-engine-dynamic=<engine name>[,<engine name>...]
enable engine(s) listed as dynamic plugin (when plugins are enabled)
@@ -914,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
@@ -928,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)
@@ -952,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]
@@ -971,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)
@@ -1008,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 ;;
@@ -1034,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 ;;
@@ -1057,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 ;;
@@ -1148,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`
@@ -1161,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`
;;
@@ -1222,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`
;;
@@ -1286,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
@@ -1301,10 +1333,37 @@ 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
;;
+raspberrypi)
+ _host_os=linux
+ _host_cpu=arm
+ # This tuple is the one used by the official Rpi toolchain.
+ # It may change in the future.
+ _host_alias=arm-linux-gnueabihf
+ ;;
caanoo)
_host_os=gph-linux
_host_cpu=arm
@@ -1351,6 +1410,11 @@ iphone)
_host_cpu=arm
_host_alias=arm-apple-darwin9
;;
+ios7)
+ _host_os=iphone
+ _host_cpu=arm
+ _host_alias=arm-apple-darwin11
+ ;;
linupy)
_host_os=linux
_host_cpu=arm
@@ -1555,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
@@ -1678,23 +1742,33 @@ LD=$CXX
#
echocheck "compiler version"
-# We first check whether we have an Intel compiler here, since the Intel compiler
-# can also fake itself as an gcc (to ease compatibility with common Linux etc.
-# programs).
+# Some compilers pretend to be gcc to ease compatibility with
+# common Linux etc. programs. We first check for some of these here.
+have_gcc=no
+cc_check_define __GNUC__ && have_gcc=yes
have_icc=no
cc_check_define __INTEL_COMPILER && have_icc=yes
+have_clang=no
+cc_check_define __clang__ && have_clang=yes
if test "$have_icc" = yes; then
add_line_to_config_mk 'HAVE_ICC = 1'
- # Make ICC error our on unknown command line options instead of printing
+ # Make ICC error out on unknown command line options instead of printing
# a warning. This is for example required to make the -Wglobal-destructors
# detection work correctly.
append_var CXXFLAGS "-diag-error 10006,10148"
+
+ # ICC doesn't accept all gcc options, so we disable have_gcc, even if
+ # ICC does have the gcc-compatibility defines.
+ have_gcc=no
fi
-have_gcc=no
-cc_check_define __GNUC__ && have_gcc=yes
+if test "$have_clang" = yes; then
+ add_line_to_config_mk 'HAVE_CLANG = 1'
+
+ # clang does accept all gcc options we use, so we keep have_gcc
+fi
if test "$have_gcc" = yes; then
add_line_to_config_mk 'HAVE_GCC = 1'
@@ -1702,11 +1776,17 @@ if test "$have_gcc" = yes; then
_cxx_minor=`gcc_get_define __GNUC_MINOR__`
cxx_version="`( $CXX -dumpversion ) 2>&1`"
- if test -n "`gcc_get_define __clang__`"; then
- add_line_to_config_mk 'HAVE_CLANG = 1'
- fi
-
- if test "$_cxx_major" -eq 2 && test "$_cxx_minor" -ge 95 || \
+ if test "$have_clang" = yes; then
+ # Clang sets a gcc version number for compatibility.
+ # We keep that as _cxx_minor/_cxx_major for later
+ # compiler version checks.
+
+ # For the version reported in the configure log (cxx_version),
+ # we get the actual clang version.
+ cxx_version=`gcc_get_define __clang_version__`
+ cxx_version="`echo "${cxx_version}" | sed -e 's/"\([^ ]*\) .*/\1/'`"
+ cxx_version="clang $cxx_version, ok"
+ elif test "$_cxx_major" -eq 2 && test "$_cxx_minor" -ge 95 || \
test "$_cxx_major" -gt 2 ; then
cxx_version="$cxx_version, ok"
cxx_verc_fail=no
@@ -1795,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"
@@ -1831,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.
@@ -2039,13 +2119,31 @@ echo_n "Checking host CPU architecture... "
case $_host_cpu in
arm*)
echo "ARM"
- define_in_config_if_yes yes 'USE_ARM_SCALER_ASM'
- define_in_config_if_yes yes 'USE_ARM_SOUND_ASM'
- define_in_config_if_yes yes 'USE_ARM_SMUSH_ASM'
- define_in_config_if_yes yes 'USE_ARM_GFX_ASM'
- # FIXME: The following feature exhibits a bug during the intro scene of Indy 4
- # (on Pandora and iPhone at least)
- #define_in_config_if_yes yes 'USE_ARM_COSTUME_ASM'
+ case $_host_alias in
+ # Apple's as does not support the syntax we use in our ARM
+ # assembly. We simply do not enable it.
+ arm-apple-darwin9)
+ ;;
+ arm-apple-darwin10)
+ ;;
+ arm-apple-darwin11)
+ ;;
+
+ *)
+ define_in_config_if_yes yes 'USE_ARM_SCALER_ASM'
+ # FIXME: The following feature exhibits a bug. It produces distorted
+ # sound since 9003ce517ff9906b0288f9f7c02197fd091d4554. The ARM
+ # assembly will need to be properly adapted to the changes to the C
+ # code in 8f5a7cde2f99de9fef849b0ff688906f05f4643e.
+ # See bug #6957: "AUDIO: ARM ASM sound code causes distorted audio on 32 bit armv6"
+ #define_in_config_if_yes yes 'USE_ARM_SOUND_ASM'
+ define_in_config_if_yes yes 'USE_ARM_SMUSH_ASM'
+ define_in_config_if_yes yes 'USE_ARM_GFX_ASM'
+ # FIXME: The following feature exhibits a bug during the intro scene of Indy 4
+ # (on Pandora and iPhone at least)
+ #define_in_config_if_yes yes 'USE_ARM_COSTUME_ASM'
+ ;;
+ esac
append_var DEFINES "-DARM_TARGET"
;;
@@ -2077,8 +2175,29 @@ 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 "-use-dynld -Wl,--export-dynamic"
+ append_var LDFLAGS "-Wl,--export-dynamic"
append_var LDFLAGS "-L/sdk/local/newlib/lib"
# We have to use 'long' for our 4 byte typedef because AmigaOS already typedefs (u)int32
# as (unsigned) long, and consequently we'd get a compiler error otherwise.
@@ -2229,7 +2348,7 @@ case $_host_os in
LDFLAGS="-L${macport_prefix}/lib $LDFLAGS"
CXXFLAGS="-I${macport_prefix}/include $CXXFLAGS"
-
+
if test -z "$_staticlibpath"; then
_staticlibpath=${macport_prefix}
echo "Set staticlib-prefix to ${_staticlibpath}"
@@ -2291,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__"
@@ -2384,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"
@@ -2406,6 +2540,7 @@ case $_host_os in
;;
ps3)
# Force use of SDL and freetype from the ps3 toolchain
+ _sdlconfig=sdl2-config
_sdlpath="$PS3DEV/portlibs/ppu:$PS3DEV/portlibs/ppu/bin"
_freetypepath="$PS3DEV/portlibs/ppu:$PS3DEV/portlibs/ppu/bin"
@@ -2498,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"
@@ -2511,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)
@@ -2549,7 +2705,7 @@ if test -n "$_host"; then
_mt32emu=no
_optimization_level=-O3
# Disable alsa midi to get the port build on OpenDingux toolchain
- _alsa=no
+ _alsa=no
_vkeybd=yes
_build_hq_scalers=no
_keymapper=no
@@ -2559,6 +2715,33 @@ if test -n "$_host"; then
_seq_midi=no
_port_mk="backends/platform/dingux/dingux.mk"
;;
+ raspberrypi)
+ # This is needed because the official cross compiler doesn't have multiarch enabled
+ # but Raspbian does.
+ # Be careful as it's the linker (LDFLAGS) which must know about sysroot.
+ # These are needed to build against Raspbian's libSDL.
+ append_var LDFLAGS "--sysroot=$RPI_ROOT"
+ append_var LDFLAGS "-B$RPI_ROOT/usr/lib/arm-linux-gnueabihf"
+ append_var LDFLAGS "-Xlinker --rpath-link=$RPI_ROOT/usr/lib/arm-linux-gnueabihf"
+ append_var LDFLAGS "-Xlinker --rpath-link=$RPI_ROOT/lib/arm-linux-gnueabihf"
+ append_var LDFLAGS "-Xlinker --rpath-link=$RPI_ROOT/opt/vc/lib"
+ append_var LDFLAGS "-L$RPI_ROOT/opt/vc/lib"
+ # This is so optional OpenGL ES includes are found.
+ append_var CXXFLAGS "-I$RPI_ROOT/opt/vc/include"
+ _savegame_timestamp=no
+ _eventrec=no
+ _build_scalers=no
+ _build_hq_scalers=no
+ # We prefer SDL2 on the Raspberry Pi: acceleration now depends on it
+ # 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
+ # the Raspberry Pi, so it's enabled by default.
+ # 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"
append_var DEFINES "-DDISABLE_TEXT_CONSOLE"
@@ -2578,7 +2761,11 @@ if test -n "$_host"; then
_build_scalers=no
_mad=yes
_zlib=yes
- add_line_to_config_mk 'ronindir = /usr/local/ronin'
+ if test -z "$RONINDIR"; then
+ add_line_to_config_mk "ronindir := /usr/local/ronin"
+ else
+ add_line_to_config_mk "ronindir := $RONINDIR"
+ fi
_port_mk="backends/platform/dc/dreamcast.mk"
;;
ds)
@@ -2611,22 +2798,22 @@ if test -n "$_host"; then
add_line_to_config_h "/* #define DEBUG_WII_GDB */"
add_line_to_config_h "#define USE_WII_DI"
;;
- gcw0)
- append_var DEFINES "-DDINGUX -DGCW0"
+ gcw0)
+ _sysroot=`$CXX --print-sysroot`
+ _sdlpath=$_sysroot/usr/bin
+ 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)
@@ -2666,6 +2853,13 @@ if test -n "$_host"; then
_seq_midi=no
_timidity=no
;;
+ ios7)
+ append_var DEFINES "-DIPHONE"
+ _backend="ios7"
+ _build_scalers=no
+ _seq_midi=no
+ _timidity=no
+ ;;
m68k-atari-mint)
append_var DEFINES "-DSYSTEM_NOT_SUPPORTING_D_TYPE"
_ranlib=m68k-atari-mint-ranlib
@@ -2679,7 +2873,7 @@ if test -n "$_host"; then
append_var INCLUDES "-I/usr/X11R6/include"
append_var LIBS "-lX11"
append_var LIBS "-L/usr/lib"
-
+
_backend="maemo"
_vkeybd=yes
_keymapper=yes
@@ -2872,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"
@@ -2917,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'
@@ -2959,6 +3159,19 @@ case $_backend in
append_var LIBS "-framework QuartzCore -framework CoreFoundation -framework Foundation"
append_var LIBS "-framework AudioToolbox -framework CoreAudio"
;;
+ ios7)
+ append_var LIBS "-lobjc -framework UIKit -framework CoreGraphics -framework OpenGLES"
+ append_var LIBS "-framework QuartzCore -framework CoreFoundation -framework Foundation"
+ append_var LIBS "-framework AudioToolbox -framework CoreAudio"
+ append_var LDFLAGS "-miphoneos-version-min=7.1 -arch armv7"
+ append_var CFLAGS "-miphoneos-version-min=7.1 -arch armv7"
+ append_var CXXFLAGS "-miphoneos-version-min=7.1 -arch armv7"
+ if test -n "$SDKROOT"; then
+ append_var LDFLAGS "-mlinker-version=134.9 -B/usr/local/bin/arm-apple-darwin11-"
+ append_var CFLAGS "-isysroot $SDKROOT -F$SDKROOT/System/Library/Frameworks"
+ append_var CXXFLAGS "-isysroot $SDKROOT -I$SDKROOT/usr/include/c++/4.2.1 -F$SDKROOT/System/Library/Frameworks"
+ fi
+ ;;
linuxmoto)
append_var DEFINES "-DLINUXMOTO"
;;
@@ -3006,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"
@@ -3054,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
@@ -3067,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`"
@@ -3076,9 +3289,6 @@ case $_backend in
_sdlversion=`$_sdlconfig --version`
case $_sdlversion in
- 1.3.*)
- add_line_to_config_mk "USE_SDL13 = 1"
- ;;
2.0.*)
add_line_to_config_mk "USE_SDL2 = 1"
;;
@@ -3093,7 +3303,7 @@ esac
# Enable 16bit support only for backends which support it
#
case $_backend in
- android | dingux | dc | gph | iphone | 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
@@ -3106,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
@@ -3139,7 +3369,6 @@ case $_backend in
;;
esac
-
#
# Determine whether host is POSIX compliant, or at least POSIX
# compatible enough to support our POSIX code (including dlsym(),
@@ -3153,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 | 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*)
@@ -3419,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'
@@ -3776,48 +4010,130 @@ 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 for libfluidsynth
+# Check is NSDockTilePlugIn protocol is supported
#
-echocheck "libfluidsynth"
-if test "$_fluidsynth" = auto ; then
+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
+#
+echocheck "FluidSynth"
+
+append_var FLUIDSYNTH_LIBS "-lfluidsynth"
+case $_host_os in
+ mingw*)
+ FLUIDSYNTH_STATIC_LIBS="$FLUIDSYNTH_LIBS -lglib-2.0 -lintl -liconv -lws2_32 -lole32 -lshlwapi -lpcre -ldsound -lwinmm"
+ ;;
+
+ darwin*)
+ FLUIDSYNTH_STATIC_LIBS="$FLUIDSYNTH_LIBS -framework Foundation -framework CoreMIDI -framework CoreAudio -lglib-2.0 -lintl -liconv -lreadline"
+ ;;
+
+ iphone)
+ FLUIDSYNTH_STATIC_LIBS="$FLUIDSYNTH_LIBS -framework Foundation -framework CoreMIDI -lglib-2.0 -lintl -liconv"
+ ;;
+
+ *)
+ FLUIDSYNTH_STATIC_LIBS="$FLUIDSYNTH_LIBS -lglib-2.0 -lintl -liconv"
+ ;;
+esac
+
+if test "$_fluidsynth" = auto; then
_fluidsynth=no
cat > $TMPC << EOF
#include <fluidsynth.h>
-int main(void) { return 0; }
+int main(void) { delete_fluid_settings(new_fluid_settings()); return 0; }
EOF
- cc_check $FLUIDSYNTH_CFLAGS $FLUIDSYNTH_LIBS -lfluidsynth && _fluidsynth=yes
+ cc_check_no_clean $FLUIDSYNTH_CFLAGS $FLUIDSYNTH_LIBS && _fluidsynth=yes
+ if test "$_fluidsynth" != yes; then
+ FLUIDSYNTH_LIBS="$FLUIDSYNTH_STATIC_LIBS"
+ cc_check_no_clean $FLUIDSYNTH_CFLAGS $FLUIDSYNTH_LIBS && _fluidsynth=yes
+ fi
+ cc_check_clean
fi
-if test "$_fluidsynth" = yes ; then
- case $_host_os in
- mingw*)
- append_var LIBS "$FLUIDSYNTH_LIBS -lfluidsynth -ldsound -lwinmm"
- ;;
- *)
- append_var LIBS "$FLUIDSYNTH_LIBS -lfluidsynth"
- ;;
- esac
+if test "$_fluidsynth" = yes; then
+ append_var LIBS "$FLUIDSYNTH_LIBS"
append_var INCLUDES "$FLUIDSYNTH_CFLAGS"
fi
define_in_config_if_yes "$_fluidsynth" 'USE_FLUIDSYNTH'
@@ -3949,7 +4265,15 @@ int main(int argc, char *argv[]) {
}
EOF
- cc_check $FREETYPE2_CFLAGS $FREETYPE2_LIBS && _freetype2=yes
+ cc_check_no_clean $FREETYPE2_CFLAGS $FREETYPE2_LIBS && _freetype2=yes
+ # Modern freetype-config scripts accept --static to get all
+ # required flags for static linking. We abuse this to detect
+ # FreeType2 builds which are static themselves.
+ if test "$_freetype2" != "yes"; then
+ FREETYPE2_LIBS=`$_freetypeconfig --prefix="$_freetypepath" --static --libs 2>/dev/null`
+ cc_check_no_clean $FREETYPE2_CFLAGS $FREETYPE2_LIBS && _freetype2=yes
+ fi
+ cc_check_clean
fi
if test "$_freetype2" = "yes"; then
@@ -3972,106 +4296,114 @@ 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
- done
- fi
-fi
-if test "$_opengl" = yes ; then
- # Our simple test case
- cat > $TMPC << EOF
-int main(void) { return 0; }
-EOF
+ 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
+ ;;
- _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
+ tizen)
+ # Tizen always runs in GLES mode
+ _opengl_mode=gles
+ ;;
- if test "$_opengl" = yes ; then
- append_var LIBS "$OPENGL_LIBS"
- append_var INCLUDES "$OPENGL_CFLAGS"
- fi
+ *)
+ _opengl_mode=none
+ ;;
+ esac
fi
-case $_host_os in
- tizen)
- # components live in non-standard locations so just assume sane SDK
- _opengl=yes
- _opengles=yes
+_opengl=yes
+case $_opengl_mode in
+ auto)
+ # This case should never occur but better safe than sorry.
+ echo "no"
+ _opengl=no
;;
-esac
-if test "$_opengles" = "yes" ; then
- echo "yes (OpenGL ES)"
-else
- echo "$_opengl"
-fi
+ none)
+ echo "no"
+ _opengl=no
+ ;;
+
+ any)
+ echo "yes (runtime detection)"
+ add_line_to_config_h "#undef USE_GLES_MODE"
+ ;;
+
+ 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
#
@@ -4286,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
@@ -4299,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
@@ -4325,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
@@ -4556,6 +4900,9 @@ STAGINGPATH=$_stagingpath
WIN32PATH=$_win32path
AMIGAOSPATH=$_amigaospath
STATICLIBPATH=$_staticlibpath
+XCODETOOLSPATH=$_xcodetoolspath
+SPARKLEPATH=$_sparklepath
+SDLCONFIG=$_sdlconfig
ABI := $ABI
diff --git a/devtools/convbdf.cpp b/devtools/convbdf.cpp
index 21c8af8234..59ea5cc4e5 100644
--- a/devtools/convbdf.cpp
+++ b/devtools/convbdf.cpp
@@ -21,7 +21,7 @@
*/
#ifndef __has_feature // Optional of course.
- #define __has_feature(x) 0 // Compatibility with non-clang compilers.
+#define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif
#include <fstream>
@@ -392,7 +392,7 @@ int main(int argc, char *argv[]) {
for (int y = 0; y < box.height; ++y) {
printf("// |");
- unsigned char data;
+ unsigned char data = 0;
for (int x = 0; x < box.width; ++x) {
if (!(x % 8))
data = *bitmap++;
diff --git a/devtools/create_access/amazon_resources.cpp b/devtools/create_access/amazon_resources.cpp
new file mode 100644
index 0000000000..f4b642ffbc
--- /dev/null
+++ b/devtools/create_access/amazon_resources.cpp
@@ -0,0 +1,757 @@
+/* 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 "amazon_resources.h"
+
+namespace Amazon {
+
+const byte MOUSE0[] = {
+ // hotspot x and y, uint16 LE
+ 0, 0, 0, 0,
+ // byte 1: number of skipped pixels
+ // byte 2: number of plotted pixels
+ // then, pixels
+ 0, 2, 6, 1,
+ 0, 3, 6, 6, 1,
+ 0, 3, 6, 6, 1,
+ 0, 4, 6, 6, 6, 1,
+ 0, 4, 6, 6, 6, 1,
+ 0, 5, 6, 6, 6, 6, 1,
+ 0, 5, 6, 6, 6, 6, 1,
+ 0, 6, 6, 6, 6, 6, 6, 1,
+ 0, 6, 6, 6, 6, 6, 6, 1,
+ 0, 7, 6, 6, 6, 6, 6, 6, 1,
+ 0, 6, 6, 6, 6, 6, 6, 1,
+ 0, 5, 6, 6, 6, 6, 1,
+ 2, 3, 6, 6, 1,
+ 3, 3, 6, 6, 1,
+ 3, 3, 6, 6, 1,
+ 4, 2, 6, 1
+};
+
+const byte MOUSE1[] = {
+ // hotspot x and y, uint16 LE
+ 0x07, 0x00, 0x07, 0x00,
+ // byte 1: number of skipped pixels
+ // byte 2: number of plotted pixels
+ // then, pixels
+ 0x06, 0x01, 0x05,
+ 0x04, 0x05, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
+ 0x03, 0x07, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+ 0x02, 0x09, 0xFF, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xFF,
+ 0x01, 0x0B, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+ 0x01, 0x0B, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0xFF,
+ 0x00, 0x0D, 0x05, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00, 0x05,
+ 0x01, 0x0B, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0xFF,
+ 0x01, 0x0B, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+ 0x02, 0x09, 0xFF, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xFF,
+ 0x03, 0x07, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+ 0x04, 0x05, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
+ 0x06, 0x01, 0x05,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00
+};
+
+const byte MOUSE2[] = {
+ // hotspot x and y, uint16 LE
+ 0x08, 0x00, 0x08, 0x00,
+ // byte 1: number of skipped pixels
+ // byte 2: number of plotted pixels
+ // then, pixels
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x07, 0x02, 0x04, 0x05,
+ 0x07, 0x02, 0x04, 0x05,
+ 0x07, 0x02, 0x04, 0x05,
+ 0x07, 0x02, 0x04, 0x05,
+ 0x07, 0x02, 0x04, 0x05,
+ 0x02, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05,
+ 0x07, 0x02, 0x04, 0x05,
+ 0x07, 0x02, 0x04, 0x05,
+ 0x07, 0x02, 0x04, 0x05,
+ 0x07, 0x02, 0x04, 0x05,
+ 0x07, 0x02, 0x04, 0x05,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00
+};
+
+const byte MOUSE3[] = {
+ // hotspot x and y, uint16 LE
+ 0x00, 0x00, 0x00, 0x00,
+ // byte 1: number of skipped pixels
+ // byte 2: number of plotted pixels
+ // then, pixels
+ 0x00, 0x0B, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x00, 0x0C, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x05,
+ 0x00, 0x0C, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x05, 0x05,
+ 0x00, 0x0C, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05,
+ 0x00, 0x0C, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05,
+ 0x00, 0x0C, 0x06, 0x06, 0x06, 0x06, 0x05, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x05,
+ 0x00, 0x0C, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05,
+ 0x00, 0x0C, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05,
+ 0x00, 0x0C, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05,
+ 0x00, 0x0C, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05,
+ 0x00, 0x0C, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05,
+ 0x00, 0x0C, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05,
+ 0x01, 0x0B, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00
+};
+const byte CURSEYE[] = {
+ // hotspot x and y, uint16 LE
+ 0x01, 0x00, 0x08, 0x00,
+ // byte 1: number of skipped pixels
+ // byte 2: number of plotted pixels
+ // then, pixels
+ 0x04, 0x06, 0x0E, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
+ 0x03, 0x09, 0x0E, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x0D, 0x0D,
+ 0x02, 0x0B, 0x0E, 0x01, 0x33, 0x33, 0x01, 0x01, 0x33, 0x34, 0x01, 0x01, 0x0D,
+ 0x01, 0x0D, 0x0E, 0x01, 0x04, 0x34, 0x01, 0x01, 0x01, 0x07, 0x33, 0x04, 0x04, 0x01, 0x0D,
+ 0x00, 0x0F, 0x0E, 0x0E, 0x01, 0x07, 0x33, 0x33, 0x01, 0x01, 0x33, 0x34, 0x07, 0x07, 0x06, 0x01, 0x0E,
+ 0x01, 0x0D, 0x0F, 0x0F, 0x06, 0x07, 0x34, 0x33, 0x33, 0x34, 0x07, 0x07, 0x06, 0x0F, 0x0E,
+ 0x03, 0x09, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0E,
+ 0x01, 0x01, 0x07,
+ 0x00, 0x03, 0x07, 0x01, 0x07,
+ 0x01, 0x01, 0x07,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00
+};
+
+const byte CURSHAND[] = {
+ // hotspot x and y, uint16 LE
+ 0x02, 0x00, 0x03, 0x00,
+ // byte 1: number of skipped pixels
+ // byte 2: number of plotted pixels
+ // then, pixels
+ 0x07, 0x02, 0x17, 0x0E,
+ 0x05, 0x07, 0x0E, 0x12, 0x17, 0x0E, 0x13, 0x17, 0x0E,
+ 0x02, 0x0C, 0x07, 0x00, 0x17, 0x0E, 0x11, 0x0F, 0x0E, 0x11, 0x17, 0x0E, 0x00, 0x17,
+ 0x01, 0x0E, 0x07, 0x01, 0x07, 0x0F, 0x0E, 0x11, 0x17, 0x0E, 0x11, 0x0F, 0x0E, 0x12, 0x17, 0x0E,
+ 0x02, 0x0D, 0x07, 0x00, 0x17, 0x0F, 0x12, 0x0F, 0x0F, 0x11, 0x17, 0x0E, 0x12, 0x0F, 0x0E,
+ 0x04, 0x0B, 0x0F, 0x0E, 0x11, 0x17, 0x0E, 0x12, 0x0F, 0x0F, 0x11, 0x17, 0x0E,
+ 0x04, 0x0B, 0x17, 0x0E, 0x12, 0x17, 0x0E, 0x12, 0x17, 0x0E, 0x11, 0x0F, 0x0E,
+ 0x00, 0x0F, 0x0E, 0x0D, 0x12, 0x00, 0x17, 0x0F, 0x0F, 0x0F, 0x0F, 0x12, 0x0F, 0x0E, 0x12, 0x17, 0x0F,
+ 0x00, 0x0F, 0x0F, 0x17, 0x0D, 0x11, 0x0F, 0x0E, 0x0D, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0E, 0x0D,
+ 0x01, 0x0E, 0x0F, 0x17, 0x0F, 0x0E, 0x0F, 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, 0x0F, 0x0F, 0x0E, 0x0D,
+ 0x02, 0x0D, 0x0F, 0x17, 0x0F, 0x0E, 0x0D, 0x0D, 0x0F, 0x0F, 0x0E, 0x0F, 0x0E, 0x0E, 0x12,
+ 0x03, 0x0C, 0x0F, 0x17, 0x0F, 0x0F, 0x0F, 0x0E, 0x0F, 0x0F, 0x0F, 0x0E, 0x0D, 0x12,
+ 0x04, 0x0A, 0x0F, 0x17, 0x0F, 0x0F, 0x0F, 0x0E, 0x0F, 0x0F, 0x0E, 0x0D,
+ 0x05, 0x09, 0x0F, 0x17, 0x0F, 0x0F, 0x0F, 0x0F, 0x0E, 0x0D, 0x12,
+ 0x06, 0x08, 0x17, 0x0F, 0x0F, 0x0F, 0x0F, 0x0E, 0x0D, 0x12,
+ 0x06, 0x07, 0x17, 0x0F, 0x0F, 0x0F, 0x3D, 0x0E, 0x0D
+};
+
+const byte CURSGET[] = {
+ // hotspot x and y, uint16 LE
+ 0x07, 0x00, 0x0E, 0x00,
+ // byte 1: number of skipped pixels
+ // byte 2: number of plotted pixels
+ // then, pixels
+ 0x0A, 0x05, 0x1C, 0x07, 0x0F, 0x0F, 0x0F,
+ 0x08, 0x08, 0x1C, 0x07, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0C,
+ 0x06, 0x0A, 0x1C, 0x07, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0C,
+ 0x05, 0x0A, 0x07, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0C,
+ 0x03, 0x0C, 0x07, 0x1C, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0C,
+ 0x02, 0x0D, 0x1C, 0x0F, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0C,
+ 0x01, 0x0E, 0x07, 0x0F, 0x0E, 0x0D, 0x0F, 0x0E, 0x0D, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0C,
+ 0x00, 0x0F, 0x1C, 0x0F, 0x0E, 0x0D, 0x0F, 0x0E, 0x0D, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0C,
+ 0x00, 0x0F, 0x1C, 0x0E, 0x0D, 0x0F, 0x0E, 0x0D, 0x0F, 0x0F, 0x0C, 0x0C, 0x0E, 0x0F, 0x0F, 0x0F, 0x0C,
+ 0x00, 0x0E, 0x1C, 0x0D, 0x0F, 0x0E, 0x0D, 0x0F, 0x0F, 0x0C, 0x00, 0x00, 0x0E, 0x0F, 0x0F, 0x0C,
+ 0x00, 0x0E, 0x1C, 0x0E, 0x0F, 0x0D, 0x0F, 0x0F, 0x0C, 0x00, 0x00, 0x0E, 0x1C, 0x0F, 0x0F, 0x0C,
+ 0x00, 0x0D, 0x1C, 0x0D, 0x0F, 0x0D, 0x0F, 0x0C, 0x00, 0x00, 0x00, 0x0E, 0x1C, 0x0F, 0x0C,
+ 0x01, 0x0B, 0x0E, 0x0F, 0x0E, 0x0F, 0x0C, 0x00, 0x00, 0x0E, 0x07, 0x0F, 0x0C,
+ 0x02, 0x09, 0x0E, 0x0D, 0x0F, 0x0C, 0x00, 0x07, 0x0E, 0x0F, 0x0C,
+ 0x03, 0x06, 0x0E, 0x0F, 0x0E, 0x07, 0x01, 0x07,
+ 0x07, 0x01, 0x07
+};
+
+const byte CURSCLIMB[] = {
+ // hotspot x and y, uint16 LE
+ 0x03, 0x00, 0x0E, 0x00,
+ // byte 1: number of skipped pixels
+ // byte 2: number of plotted pixels
+ // then, pixels
+ 0x06, 0x04, 0x01, 0x01, 0x01, 0x01,
+ 0x06, 0x04, 0x0F, 0x0E, 0x01, 0x01,
+ 0x06, 0x04, 0x0F, 0x0E, 0x0D, 0x01,
+ 0x07, 0x02, 0x0F, 0x0D,
+ 0x00, 0x0C, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x13, 0x12, 0x12, 0x12, 0x12, 0x11, 0x11,
+ 0x00, 0x0D, 0x0D, 0x0E, 0x00, 0x00, 0x13, 0x14, 0x13, 0x12, 0x12, 0x12, 0x11, 0x11, 0x0E,
+ 0x01, 0x0C, 0x0D, 0x0D, 0x0D, 0x0E, 0x11, 0x13, 0x13, 0x12, 0x11, 0x11, 0x0E, 0x0D,
+ 0x02, 0x0C, 0x0E, 0x0E, 0x00, 0x00, 0x00, 0x13, 0x12, 0x11, 0x00, 0x00, 0x0E, 0x0D,
+ 0x03, 0x0B, 0x04, 0x04, 0x04, 0x22, 0x21, 0x21, 0x20, 0x00, 0x00, 0x00, 0x0D,
+ 0x02, 0x0D, 0x22, 0x04, 0x20, 0x22, 0x04, 0x21, 0x04, 0x20, 0x00, 0x00, 0x00, 0x0E, 0x0E,
+ 0x03, 0x07, 0x22, 0x21, 0x20, 0x20, 0x22, 0x04, 0x20,
+ 0x04, 0x06, 0x01, 0x01, 0x00, 0x04, 0x22, 0x20,
+ 0x02, 0x09, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x04, 0x20,
+ 0x03, 0x09, 0x07, 0x01, 0x01, 0x00, 0x00, 0x00, 0x22, 0x04, 0x20,
+ 0x02, 0x0B, 0x07, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20,
+ 0x03, 0x0A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01
+};
+
+const byte CURSTALK[] = {
+ // hotspot x and y, uint16 LE
+ 0x02, 0x00, 0x0B, 0x00,
+ // byte 1: number of skipped pixels
+ // byte 2: number of plotted pixels
+ // then, pixels
+ 0x03, 0x08, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x01, 0x0C, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06,
+ 0x00, 0x0E, 0x06, 0x06, 0x06, 0x06, 0x07, 0x06, 0x07, 0x07, 0x06, 0x07, 0x07, 0x06, 0x07, 0x06,
+ 0x00, 0x0F, 0x06, 0x08, 0x08, 0x08, 0x06, 0x08, 0x06, 0x06, 0x08, 0x06, 0x06, 0x08, 0x06, 0x08, 0x06,
+ 0x00, 0x0F, 0x06, 0x06, 0x08, 0x06, 0x08, 0x06, 0x08, 0x06, 0x08, 0x06, 0x06, 0x08, 0x08, 0x06, 0x06,
+ 0x00, 0x0F, 0x06, 0x06, 0x08, 0x06, 0x08, 0x08, 0x08, 0x06, 0x08, 0x06, 0x06, 0x08, 0x06, 0x08, 0x06,
+ 0x01, 0x0E, 0x06, 0x08, 0x06, 0x08, 0x06, 0x08, 0x06, 0x08, 0x08, 0x06, 0x08, 0x06, 0x08, 0x06,
+ 0x02, 0x0C, 0x06, 0x06, 0x06, 0x07, 0x06, 0x07, 0x06, 0x06, 0x07, 0x06, 0x07, 0x06,
+ 0x04, 0x09, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06,
+ 0x07, 0x04, 0x06, 0x07, 0x07, 0x06,
+ 0x02, 0x08, 0x07, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x01, 0x06, 0x07, 0x01, 0x07, 0x06, 0x06, 0x06,
+ 0x02, 0x01, 0x07,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00
+};
+const byte CURSHELP[] = {
+ // hotspot x and y, uint16 LE
+ 0x02, 0x00, 0x0B, 0x00,
+ // byte 1: number of skipped pixels
+ // byte 2: number of plotted pixels
+ // then, pixels
+ 0x04, 0x06, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
+ 0x02, 0x0A, 0x24, 0x24, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x20, 0x20,
+ 0x01, 0x0C, 0x24, 0x22, 0x22, 0x22, 0x20, 0x20, 0x20, 0x22, 0x22, 0x22, 0x22, 0x20,
+ 0x00, 0x0E, 0x24, 0x22, 0x22, 0x22, 0x20, 0x00, 0x00, 0x00, 0x24, 0x22, 0x22, 0x22, 0x22, 0x20,
+ 0x00, 0x0E, 0x24, 0x22, 0x22, 0x22, 0x22, 0x20, 0x00, 0x00, 0x00, 0x24, 0x22, 0x22, 0x22, 0x20,
+ 0x00, 0x0E, 0x24, 0x22, 0x22, 0x22, 0x22, 0x20, 0x00, 0x00, 0x00, 0x24, 0x22, 0x22, 0x22, 0x20,
+ 0x01, 0x0D, 0x24, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x24, 0x22, 0x22, 0x22, 0x22, 0x20,
+ 0x07, 0x06, 0x24, 0x22, 0x22, 0x22, 0x22, 0x20,
+ 0x05, 0x07, 0x24, 0x22, 0x22, 0x22, 0x22, 0x20, 0x20,
+ 0x04, 0x05, 0x24, 0x22, 0x22, 0x22, 0x20,
+ 0x02, 0x07, 0x07, 0x00, 0x24, 0x20, 0x20, 0x20, 0x20,
+ 0x01, 0x03, 0x07, 0x01, 0x07,
+ 0x02, 0x07, 0x07, 0x00, 0x00, 0x24, 0x24, 0x24, 0x24,
+ 0x04, 0x06, 0x24, 0x22, 0x22, 0x22, 0x22, 0x20,
+ 0x04, 0x06, 0x24, 0x22, 0x22, 0x22, 0x22, 0x20,
+ 0x05, 0x04, 0x20, 0x20, 0x20, 0x20
+};
+
+const byte *const CURSORS[AMAZON_NUM_CURSORS] = {
+ MOUSE0, MOUSE1, MOUSE2, MOUSE3, CURSEYE, CURSHAND, CURSGET, CURSCLIMB, CURSTALK, CURSHELP
+};
+const uint CURSOR_SIZES[AMAZON_NUM_CURSORS] = {
+ sizeof(MOUSE0), sizeof(MOUSE1), sizeof(MOUSE2), sizeof(MOUSE3), sizeof(CURSEYE),
+ sizeof(CURSHAND), sizeof(CURSGET), sizeof(CURSCLIMB), sizeof(CURSTALK), sizeof(CURSHELP)
+};
+
+
+const int FONT2_INDEX[] = {
+ 62, 2, 6,
+ 0x0000, 0x0019, 0x0021, 0x002e, 0x0041, 0x005a, 0x0073, 0x008c, 0x0093, 0x009b,
+ 0x00a3, 0x00bc, 0x00d5, 0x00dd, 0x00ea, 0x00f1, 0x00fe, 0x010b, 0x0118, 0x0125,
+ 0x0132, 0x013f, 0x014c, 0x0159, 0x0166, 0x0173, 0x0180, 0x0187, 0x018e, 0x01a7,
+ 0x01b4, 0x01cd, 0x01dc, 0x01f5, 0x0208, 0x0215, 0x0222, 0x022f, 0x023c, 0x0249,
+ 0x025c, 0x0269, 0x0276, 0x0285, 0x0292, 0x029f, 0x02b2, 0x02c5, 0x02d2, 0x02df,
+ 0x02ee, 0x02fb, 0x0308, 0x0315, 0x0322, 0x032f, 0x0342, 0x034f, 0x0362, 0x036f,
+ 0x0388, 0x03a1,
+};
+
+const byte FONT2_DATA[] = {
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0x00, 0xf0, 0x00, 0x06, 0xf3, 0xc0, 0xc3, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x07, 0x1c, 0x00,
+ 0x67, 0x9e, 0xc0, 0x07, 0x1c, 0x00, 0x67, 0x9e, 0xc0, 0x07,
+ 0x1c, 0x00, 0x00, 0x00, 0x00, 0x09, 0x02, 0xc0, 0x00, 0x3f,
+ 0xfc, 0x00, 0xb2, 0xc0, 0x00, 0x3f, 0xfc, 0x00, 0x02, 0xcb,
+ 0x00, 0x3f, 0xfc, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x18, 0x60,
+ 0x70, 0x70, 0x60, 0x1c, 0x00, 0x04, 0x60, 0x18, 0x1c, 0x1c,
+ 0x1c, 0x70, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x30,
+ 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc0,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf0, 0xf0,
+ 0x00, 0x07, 0x00, 0xf0, 0x03, 0xc0, 0x0f, 0x00, 0x3c, 0x00,
+ 0xf0, 0x00, 0x00, 0x00, 0x07, 0x3f, 0xc0, 0x70, 0x70, 0x70,
+ 0x70, 0x70, 0x70, 0x3f, 0xc0, 0x00, 0x00, 0x07, 0x1f, 0x00,
+ 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0xff, 0xf0, 0x00, 0x00,
+ 0x08, 0x2b, 0xf0, 0xb0, 0x2c, 0x00, 0xa0, 0x0a, 0x00, 0xff,
+ 0xfc, 0x00, 0x00, 0x07, 0xff, 0xc0, 0x00, 0x70, 0x03, 0xc0,
+ 0x00, 0x70, 0xff, 0xc0, 0x00, 0x00, 0x07, 0x0b, 0xc0, 0x2d,
+ 0xc0, 0xb1, 0xc0, 0xaa, 0xa0, 0x01, 0xc0, 0x00, 0x00, 0x07,
+ 0xff, 0xf0, 0x70, 0x00, 0x7f, 0xc0, 0x00, 0xb0, 0xbf, 0xc0,
+ 0x00, 0x00, 0x07, 0x2f, 0xc0, 0x70, 0x00, 0x7f, 0xc0, 0x70,
+ 0x70, 0x3f, 0xc0, 0x00, 0x00, 0x08, 0xff, 0xfc, 0x00, 0xb0,
+ 0x02, 0xc0, 0x02, 0xc0, 0x0b, 0x00, 0x00, 0x00, 0x08, 0x2f,
+ 0xf0, 0xb0, 0x1c, 0x2f, 0xf0, 0xb0, 0x1c, 0x2f, 0xf0, 0x00,
+ 0x00, 0x07, 0x3f, 0xc0, 0x70, 0x70, 0x3f, 0xf0, 0x00, 0x70,
+ 0x3f, 0xc0, 0x00, 0x00, 0x03, 0xf0, 0xf0, 0x00, 0xf0, 0xf0,
+ 0x00, 0x03, 0xf0, 0xf0, 0x00, 0xf0, 0x30, 0x00, 0x09, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0xff, 0xc0, 0x00, 0x00,
+ 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0xff, 0x00, 0x03, 0xc0, 0x0f, 0x00, 0x3c, 0x00,
+ 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0a, 0x00, 0x40, 0x00, 0x01, 0xf0, 0x00, 0x07, 0x1c,
+ 0x00, 0x1f, 0xff, 0x00, 0x70, 0x01, 0xc0, 0x00, 0x00, 0x00,
+ 0x08, 0x7f, 0xf0, 0x70, 0x1c, 0x7f, 0xf0, 0x70, 0x1c, 0x6a,
+ 0xb0, 0x00, 0x00, 0x08, 0x2f, 0xfc, 0x70, 0x00, 0x70, 0x00,
+ 0x70, 0x00, 0x2a, 0xa8, 0x00, 0x00, 0x08, 0x7f, 0xf0, 0x70,
+ 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x6a, 0xb0, 0x00, 0x00, 0x07,
+ 0x7f, 0xf0, 0x70, 0x00, 0x7f, 0xc0, 0x70, 0x00, 0x6a, 0xa0,
+ 0x00, 0x00, 0x07, 0x7f, 0xf0, 0x70, 0x00, 0x7f, 0xc0, 0x70,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x09, 0x3f, 0xfc, 0x00, 0x70,
+ 0x00, 0x00, 0x70, 0xff, 0x00, 0x70, 0x1c, 0x00, 0x2a, 0xbc,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x70, 0x1c, 0x70, 0x1c, 0x7f,
+ 0xfc, 0x70, 0x1c, 0x70, 0x1c, 0x00, 0x00, 0x07, 0xff, 0xf0,
+ 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0xaa, 0xa0, 0x00, 0x00,
+ 0x08, 0x0f, 0xfc, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x70,
+ 0x70, 0x2a, 0x40, 0x00, 0x00, 0x08, 0x70, 0x2c, 0x72, 0xc0,
+ 0x7f, 0x00, 0x72, 0xc0, 0x70, 0x28, 0x00, 0x00, 0x07, 0x70,
+ 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x6a, 0xa0, 0x00,
+ 0x00, 0x0a, 0x70, 0x02, 0xc0, 0x7c, 0x09, 0xc0, 0x77, 0x2d,
+ 0xc0, 0x71, 0xb1, 0xc0, 0x60, 0xc1, 0x80, 0x00, 0x00, 0x00,
+ 0x09, 0x70, 0x07, 0x00, 0x77, 0x07, 0x00, 0x71, 0xc7, 0x00,
+ 0x70, 0x77, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x2f, 0xf0, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x2a, 0xa0,
+ 0x00, 0x00, 0x08, 0x7f, 0xf0, 0x70, 0x1c, 0x7f, 0xf0, 0x70,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x08, 0x2f, 0xf0, 0x70, 0x1c,
+ 0x70, 0x1c, 0x71, 0xdc, 0x2a, 0xa0, 0x00, 0x1c, 0x00, 0x00,
+ 0x08, 0x7f, 0xf0, 0x70, 0x1c, 0x7f, 0xc0, 0x70, 0x70, 0x60,
+ 0x18, 0x00, 0x00, 0x07, 0x2f, 0xf0, 0x70, 0x00, 0x2f, 0xc0,
+ 0x00, 0xb0, 0xbf, 0xc0, 0x00, 0x00, 0x07, 0xff, 0xf0, 0x0b,
+ 0x00, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08,
+ 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0xdc, 0x1f, 0x1c,
+ 0x00, 0x00, 0x08, 0xf0, 0x1c, 0xb0, 0x1c, 0x70, 0xb0, 0x72,
+ 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x0b, 0xf0, 0x00, 0xb0, 0xb0,
+ 0x00, 0x70, 0x70, 0xc0, 0x70, 0x72, 0x72, 0xc0, 0x7c, 0x1f,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0xf0, 0x3c, 0x1c, 0xe0, 0x07,
+ 0xc0, 0x1c, 0x70, 0x70, 0x1c, 0x00, 0x00, 0x09, 0x70, 0x07,
+ 0x00, 0x1c, 0x1c, 0x00, 0x07, 0xf0, 0x00, 0x01, 0xc0, 0x00,
+ 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x08, 0xff, 0xfc, 0x00,
+ 0x70, 0x07, 0x00, 0x1c, 0x00, 0xaa, 0xac, 0x00, 0x00, 0x09,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+const int FONT6x6_INDEX[] = {
+ 62, 1, 6,
+ 0x0000, 0x0007, 0x000e, 0x0015, 0x001c, 0x0023, 0x002a, 0x0031, 0x0038, 0x003f,
+ 0x0046, 0x004d, 0x0054, 0x005b, 0x0062, 0x0069, 0x0070, 0x0077, 0x007e, 0x0085,
+ 0x008c, 0x0093, 0x009a, 0x00a1, 0x00a8, 0x00af, 0x00b6, 0x00bd, 0x00c4, 0x00cb,
+ 0x00d2, 0x00d9, 0x00e0, 0x00e7, 0x00ee, 0x00f5, 0x00fc, 0x0103, 0x010a, 0x0111,
+ 0x0118, 0x011f, 0x0126, 0x012d, 0x0134, 0x013b, 0x0142, 0x0149, 0x0150, 0x0157,
+ 0x015e, 0x0165, 0x016c, 0x0173, 0x017a, 0x0181, 0x0188, 0x018f, 0x0196, 0x019d,
+ 0x01a4, 0x01ab,
+};
+
+const byte FONT6x6_DATA[] = {
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x30, 0x30,
+ 0x30, 0x30, 0x00, 0x30, 0x06, 0xd8, 0xd8, 0x90, 0x00, 0x00,
+ 0x00, 0x06, 0x50, 0xf8, 0x50, 0xf8, 0x50, 0x00, 0x06, 0x78,
+ 0xa0, 0x70, 0x28, 0xf0, 0x20, 0x06, 0xc8, 0xd0, 0x20, 0x58,
+ 0x98, 0x00, 0x06, 0x60, 0xd0, 0x60, 0xe8, 0xd0, 0x68, 0x06,
+ 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x06, 0x30, 0x60, 0x60,
+ 0x60, 0x30, 0x00, 0x07, 0x30, 0x18, 0x18, 0x18, 0x30, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, 0x20,
+ 0xf8, 0x20, 0x20, 0x00, 0x06, 0x00, 0x00, 0x00, 0x30, 0x30,
+ 0x60, 0x06, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x06, 0x00,
+ 0x00, 0x00, 0x60, 0x60, 0x00, 0x06, 0x18, 0x30, 0x60, 0xc0,
+ 0x80, 0x00, 0x06, 0x70, 0x98, 0xa8, 0xc8, 0x70, 0x00, 0x06,
+ 0x10, 0x30, 0x10, 0x10, 0x10, 0x00, 0x06, 0xf0, 0x08, 0x70,
+ 0x80, 0xf8, 0x00, 0x06, 0xf0, 0x08, 0x70, 0x08, 0xf0, 0x00,
+ 0x06, 0x30, 0x50, 0x90, 0xf8, 0x10, 0x00, 0x06, 0xf0, 0x80,
+ 0xf0, 0x08, 0xf0, 0x00, 0x06, 0x70, 0x80, 0xf0, 0x88, 0x70,
+ 0x00, 0x06, 0xf8, 0x08, 0x10, 0x20, 0x20, 0x00, 0x06, 0x70,
+ 0x88, 0x70, 0x88, 0x70, 0x00, 0x06, 0x70, 0x88, 0x78, 0x08,
+ 0x70, 0x00, 0x06, 0x60, 0x60, 0x00, 0x60, 0x60, 0x00, 0x06,
+ 0x60, 0x60, 0x00, 0x60, 0x20, 0x40, 0x06, 0x18, 0x30, 0x60,
+ 0x30, 0x18, 0x00, 0x06, 0x00, 0x78, 0x00, 0x78, 0x00, 0x00,
+ 0x06, 0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0x06, 0x70, 0x98,
+ 0x30, 0x30, 0x00, 0x30, 0x06, 0x70, 0x88, 0xb8, 0xb0, 0x80,
+ 0x78, 0x06, 0x70, 0x88, 0xf8, 0x88, 0x88, 0x00, 0x06, 0xf0,
+ 0x88, 0xf0, 0x88, 0xf0, 0x00, 0x06, 0x78, 0x80, 0x80, 0x80,
+ 0x78, 0x00, 0x06, 0xf0, 0x88, 0x88, 0x88, 0xf0, 0x00, 0x06,
+ 0xf8, 0x80, 0xf0, 0x80, 0xf8, 0x00, 0x06, 0xf8, 0x80, 0xf0,
+ 0x80, 0x80, 0x00, 0x06, 0x78, 0x80, 0x98, 0x88, 0x78, 0x00,
+ 0x06, 0x88, 0x88, 0xf8, 0x88, 0x88, 0x00, 0x06, 0x70, 0x20,
+ 0x20, 0x20, 0x70, 0x00, 0x06, 0x08, 0x08, 0x08, 0x88, 0x70,
+ 0x00, 0x06, 0x90, 0xa0, 0xc0, 0xa0, 0x90, 0x00, 0x06, 0x80,
+ 0x80, 0x80, 0x80, 0xf0, 0x00, 0x06, 0x88, 0xd8, 0xa8, 0x88,
+ 0x88, 0x00, 0x06, 0x88, 0xc8, 0xa8, 0x98, 0x88, 0x00, 0x06,
+ 0x70, 0x88, 0x88, 0x88, 0x70, 0x00, 0x06, 0xf0, 0x88, 0xf0,
+ 0x80, 0x80, 0x00, 0x06, 0x70, 0x88, 0x88, 0x88, 0x70, 0x18,
+ 0x06, 0xf0, 0x88, 0xf0, 0xa0, 0x98, 0x00, 0x06, 0x78, 0x80,
+ 0x70, 0x08, 0xf0, 0x00, 0x06, 0xf8, 0x20, 0x20, 0x20, 0x20,
+ 0x00, 0x06, 0x88, 0x88, 0x88, 0x88, 0x78, 0x00, 0x06, 0x88,
+ 0x88, 0x88, 0x50, 0x20, 0x00, 0x06, 0x88, 0x88, 0xa8, 0xd8,
+ 0x88, 0x00, 0x06, 0x88, 0x50, 0x20, 0x50, 0x88, 0x00, 0x06,
+ 0x88, 0x88, 0x50, 0x20, 0x20, 0x00, 0x06, 0xf8, 0x10, 0x20,
+ 0x40, 0xf8, 0x00, 0x06, 0x78, 0x60, 0x60, 0x60, 0x78, 0x00,
+ 0x06, 0xc0, 0x60, 0x30, 0x18, 0x08, 0x00, 0x06, 0x78, 0x18,
+ 0x18, 0x18, 0x78, 0x00, 0x00, 0x52, 0x41, 0x54, 0x00, 0x41,
+ 0x4c, 0x43, 0x4f, 0x48, 0x4f, 0x4c, 0x00, 0x53, 0x41, 0x46,
+ 0x45, 0x20, 0x43, 0x4f, 0x4d, 0x42, 0x49, 0x4e, 0x41, 0x54,
+ 0x49, 0x4f, 0x4e, 0x00, 0x42, 0x45, 0x41, 0x4b, 0x45, 0x52,
+ 0x00, 0x4d, 0x49, 0x43, 0x52, 0x4f, 0x46, 0x49, 0x4c, 0x4d,
+ 0x00, 0x56, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x4b, 0x45, 0x59,
+ 0x00, 0x42, 0x4f, 0x4c, 0x54, 0x20, 0x43, 0x55, 0x54, 0x54,
+ 0x45, 0x52, 0x53, 0x00, 0x42, 0x4c, 0x4f, 0x57, 0x47, 0x55,
+ 0x4e, 0x00, 0x4c, 0x4f, 0x56, 0x45, 0x20, 0x50, 0x4f, 0x54,
+ 0x49, 0x4f, 0x4e, 0x00, 0x4d, 0x4f, 0x4e, 0x45, 0x59, 0x00,
+ 0x44, 0x41, 0x52, 0x54, 0x53, 0x00, 0x54, 0x41, 0x50, 0x45,
+ 0x00, 0x4a, 0x55, 0x4e, 0x47, 0x4c, 0x45, 0x20, 0x50, 0x4f,
+ 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x4d, 0x4f, 0x56, 0x49,
+};
+
+const uint FONT2_INDEX_SIZE = sizeof(FONT2_INDEX) / 2;
+const uint FONT2_DATA_SIZE = sizeof(FONT2_DATA);
+const uint FONT6x6_INDEX_SIZE = sizeof(FONT6x6_INDEX) / 2;
+const uint FONT6x6_DATA_SIZE = sizeof(FONT6x6_DATA);
+
+const char *const ROOM_DESCR[64] = {
+ "Credits", nullptr, nullptr, nullptr, "Outside of Allister Center",
+ "Hall", "Jason's Lab", nullptr, "Allen's Lab", "Outside of the Vault",
+ "Inside the Vault", "Reader", "Jason's Apartment", "Jason's ransacked apartment", "Cutscene 1",
+ "TBD FLYSOUTH", "Cuzco Airport", "TBD INAIR", "Green Monkey Club", "In Plane",
+ "TBD PILFALL", "TBD COCKPIT", "TBD CRASH", "TBD SINKING", "Cutscene Jungle Walk",
+ "TBD TOWN", "TBD HOTEL", "TBD CANTINA", nullptr, "TBD MASSACRE",
+ "TBD TRADE", "TBD BRIDGE", "TBD DOCK", "TBD DRIVER", nullptr,
+ nullptr, "TBD SHORE", "TBD BOAT", "TBD CABIN", "TBD CAPTIVE",
+ nullptr, nullptr, "TBD VILLAGE", nullptr, "TBD TREE",
+ "TBD CANOE", "TBD INTREE", "TBD FALLS", nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, "TBD WATERFALL",
+ "TBD INWATER", nullptr, "Cave Bridge", nullptr, nullptr,
+ nullptr, "Pit with Ants", nullptr, nullptr
+};
+
+
+const byte DEATH_SCREENS_ENG[58] = {
+ 0, 1, 0, 0, 0, 0, 0, 0, 2, 0,
+ 0, 2, 4, 2, 1, 0, 0, 0, 0, 0,
+ 0, 2, 7, 7, 4, 6, 7, 10, 4, 2,
+ 0, 0, 0, 0, 5, 5, 3, 3, 3, 5,
+ 8, 8, 11, 9, 8, 12, 0, 1, 9, 8,
+ 8, 0, 5, 8, 0, 12, 12, 11
+};
+
+const byte DEATH_SCREENS_ENG_DEMO[34] = {
+ 1, 2, 1, 1, 1, 1, 1, 1, 4, 1,
+ 3, 4, 2, 4, 2, 1, 1, 1, 1, 1,
+ 1, 4, 2, 4, 2, 4, 2, 4, 4, 4,
+ 1, 1, 1, 1
+};
+
+const char *const DEATH_TEXT_ENG[58] = {
+ "SAM SALVADOR SPOTS YOU AND LETS YOU HAVE IT.",
+ "WHILE TAKING A MOONLIGHT SWIM YOU DISCOVER THAT PIRANHA REALLY CAN STRIP FLESH TO THE BONE.",
+ "THE GUARD FILLS YOU FULL OF HOLES BEFORE TOSSING YOU TO THE PIRANHA.",
+ "YOU'RE ONLY ABLE TO SWIM HALFWAY ACROSS THE RIVER BEFORE RUNNING OUT OF AIR. "
+ "YOU MAKE SO MUCH NOISE GASPING FOR BREATH THAT SAM EASILY FINDS YOU AND LEAVES "
+ "YOU IN THE RIVER PERMANENTLY.",
+ "SAM SALVADOR NOTICES SOMEONE HAS BEEN PLAYING WITH THE CARGO. "
+ "HE TRACKS YOU DOWN AND LETS YOU HAVE IT.",
+ "THE GUARD COMES AROUND THE CORNER. HE DECIDES THAT THREE LEAD SLUGS WILL "
+ "TEACH YOU TO BE MORE POLITE.",
+ "THE CAPTAIN IS WAITING OUTSIDE THE DOOR.",
+ "THE CAPTAIN'S RANDOM SHOOTING FINALLY FINDS ITS TARGET.",
+ "THE CRATE OUTSIDE THE WINDOW EXPLODES, DESTROYING THE SHIP. "
+ "UNFORTUNATELY, YOU'RE STILL ABOARD.",
+ "THE DOOR WAS NOT BARRED AND THE CAPTAIN WALKS RIGHT IN AND PARTS YOUR HAIR.",
+
+ "",
+ "YOU RUN OUT ON DECK, THEN REALIZE THAT MAYA IS STILL TIED UP. "
+ "AS YOU TURN TO GO BACK THE BOAT BLOWS UP.",
+ "AFTER YOU FAIL TO PROVE YOUR DIVINITY THE NATIVES EAT YOU FOR LUNCH.",
+ "THIS IS THE GENERIC DEATH SCENE",
+ "YOU ONLY MAKE IT HALFWAY ACROSS THE RIVER BEFORE THE PIRANHA STRIKE.",
+ "WITH NOTHING TO PROTECT HIM FROM THE HAIL OF BULLETS ALLEN IS QUICKLY GUNNED DOWN. "
+ "JASON AND MAYA SOON FOLLOW...",
+ "THE COMBINATION OF THE WIND AND GUNFIRE KNOCK THE CORRUGATED IRON OVER, "
+ "LEAVING YOU WITHOUT PROTECTION.",
+ "WITHOUT SUFFICIENT AMMUNITION, ALLEN IS UNABLE TO HOLD OFF THE ATTACKERS FOR LONG. "
+ "THIS RESULTS IN A SERIOUS CASE OF LEAD POISONING. ADDITIONAL AMMUNITION SHOULD "
+ "HAVE BEEN PURCHASED AT THE RIO BLANCO TRADING POST (CHAPTER 6).",
+ "ALLEN IS A MARVELOUS SHOT, BUT HIS AMMUNITION IS NOT UNLIMITED. "
+ "SOON IT IS ALL OVER.",
+ "THE PILOT FEELS YOU ARE TOO CLOSE AND PULLS THE TRIGGER.",
+
+ "THE PILOT SHOOTS YOU IN THE HEART, THEN TOSSES YOUR LIFELESS BODY OUT THE DOOR.",
+ "THE PLANE CRASHES INTO THE JUNGLE CANOPY AT 200 MPH.",
+ "THE CANOE HITS THE ROCKS AND CAPSIZES, AND THE PIRANHA MAKE YOU THEIR LUNCH GUESTS.",
+ "YOU TAKE THE WRONG BRANCH AND ACCIDENTALLY DISCOVER THE FOURTH TALLEST WATERFALL "
+ "IN SOUTH AMERICA.",
+ "YOU TAKE THE WRONG BRANCH AND DISCOVER A VERY HUNGRY TRIBE OF CANNIBALS.",
+ "YOU TAKE THE WRONG BRANCH AND BECOME LOST IN THE WINDING WATERWAYS. "
+ "YOU WANDER UNTIL YOU STARVE TO DEATH.",
+ "YOU TAKE THE WRONG BRANCH AND BECOME TRAPPED IN THE RAPIDS. "
+ "EVENTUALLY YOU AND MAYA ARE CRUSHED BETWEEN THE ROCKS.",
+ "YOU WAIT AROUND FOR SOME TIME, BUT HANS STROHEIM NEVER SPEAKS TO YOU AGAIN. "
+ "FINALLY YOU RETURN HOME KNOWING YOU HAVE FAILED.",
+ "DECIDING THAT YOU THREATEN HIM AND HIS WORK, HANS STROHEIM HAS THE NATIVES "
+ "IN THE VILLAGE KILL YOU.",
+ "YOU DO NOT GET FAR ENOUGH AWAY BEFORE THE DYNAMITE EXPLODES AND YOU ARE BLOWN "
+ "INTO A THOUSAND PIECES.",
+
+ "YOU ARE STANDING SO CLOSE TO THE ENTRANCE WHEN SANCEZ AND HIS MEN BREAK THROUGH "
+ "THE WALL THAT YOU ARE QUICKLY SPOTTED AND SHOT",
+ "THE AMAZON SENTINELS SPOT YOU AND FILL YOU FULL OF ARROWS.",
+ "SAM MAY BE UGLY, BUT HE'S NOT DEAF. HE HEARS ALL THE NOISE YOU ARE MAKING AND "
+ "CANCELS YOUR BOARDING PASS.",
+ "WITH THE BAR OFF THE DOOR THE CAPTAIN WALTZES IN AND BLOWS YOU AWAY",
+ "THE BEAR WANDERS OFF INTO THE WOODS AND DISTURBS THE TWO LOVEBIRDS. "
+ "WHEN THEY COME OUT THEY FIND YOU AND PUT YOU IN THE BIG HOUSE FOR TWENTY YEARS.",
+ "WHEN YOU DO NOT LEAVE THE SECURITY AREA QUICKLY ENOUGH YOU ARE ARRESTED AND CONVICTED "
+ "AS A COMMIE SPY. YOU EMBARK ON A NEW CAREER STAMPING OUT LICENSE PLATES.",
+ "THE HUNGRY BEAR SPOTS YOU AND DECIDES YOU WILL MAKE A NICE APPETIZER.",
+ "YOU DISTURB THE BEAR'S LUNCH AND HE EATS YOU FOR DESSERT.",
+ "AFTER FAILING TO FIND ANY LUNCH AT THE GARBAGE CAN THE BEAR EATS YOU INSTEAD.",
+ "THE SUSPICIOUS LIBRARIAN CALLS SECURITY AND YOU ARE SENT TO JAIL.",
+
+ "YOU PLUMMET 10,000 FEET TO YOUR DEATH.",
+ "EL LOCO FLIES INTO AN INSANE RAGE AND BEATS YOU TO A BLOODY PULP.",
+ "THE WOMAN WALKS OUT THE DOOR AND NEVER RETURNS. YOU SPEND THE REST OF YOUR LIFE "
+ "IN A FUTILE ATTEMPT TO LOCATE ALLEN.",
+ "YOU SLIP OFF THE PLATFORM AND FALL TO YOUR DEATH.",
+ "YOU SLIP OFF THE PLATFORM AND FALL TO YOUR DEATH.",
+ "YOU COME TOO CLOSE TO THE POWERFUL JAWS OF THE ANT AND HE SNIPS YOU IN TWO BEFORE "
+ "DEVOURING YOU.",
+ "B.O.B. HAS A FLAW IN HIS PROGRAMMING THAT DIRECTS HIM TO SHOOT FIRST AND ASK QUESTIONS LATER.",
+ "THE PLANE SINKS AND THE PIRHANA ATTACK BEFORE YOU EVEN GET OUT THE DOOR.",
+ "MAYA FALLS OFF THE END OF THE BROKEN BRIDGE.",
+ "YOUR WEIGHT IS JUST ENOUGH TO CAUSE THE REMAINING SUPPORT CABLE TO SNAP AND YOU "
+ "FALL TO THE BOTTOM OF THE GORGE.",
+
+ "EVEN WITH REPAIRS THE BRIDGE IS NOT STRONG ENOUGH TO HOLD TWO PEOPLE.",
+ "SANCHEZ AND HIS MEN FIND YOU AND HOLD FIRING SQUAD PRACTICE.",
+ "THE TWO GUARDS ARE DISTURBED IN THEIR LOVE NEST AND COME LOOKING FOR ANYONE ACTING SUSPICIOUS. "
+ "THEY FIND YOU AND SEND YOU UP THE RIVER.",
+ "THE PARACHUTE IS NOT LARGE ENOUGH TO SUPPORT YOU, AND YOU HIT THE TREES AT 140 M.P.H.",
+ "SANCHEZ AND HIS MEN FOLLOW YOU ACROSS THE BRIDGE AND CUT YOU DOWN IN A HAIL OF GUNFIRE",
+ "YOU TRIED TO STAB THE ANT BUT HIS SHELL IS TOO DIFFICULT TO PENETRATE. "
+ "YOU NOTICE A SLIGHT CUT IN THE SHELL UNDERNEATH BUT YOU CAN'T GET TO IT "
+ "AND HE SNIPS YOU INTO DELICIOUS MEATY CHUNKS.",
+ "AFTER THE ANT FINISHES SUCKING ALL OF THE SAP OUT OF THE VINE HE TURNS HIS ATTENTION BACK TO YOU "
+ "AND BITES YOUR HEAD OFF.",
+ "THE CANTINA OWNER NOTICES YOU ARE TRYING TO STEAL OBJECTS FROM THE TABLES. "
+ "TWENTY YEARS LATER YOU ARE RELEASED FROM A SOUTH AMERICAN PRISON."
+};
+
+const char *const DEATH_TEXT_ENG_DEMO[34] = {
+ "SAM SALVADOR SPOTS YOU AND LETS YOU HAVE IT.",
+ "WHILE TAKING A MOONLIGHT SWIM YOU DISCOVER THAT PIRANHA REALLY CAN STRIP FLESH TO THE BONE.",
+ "THE GUARD FILLS YOU FULL OF HOLES BEFORE TOSSING YOU TO THE PIRANHA.",
+ "YOU'RE ONLY ABLE TO SWIM HALFWAY ACROSS THE RIVER BEFORE RUNNING OUT OF AIR. YOU MAKE SO MUCH NOISE GASPING FOR BREATH THAT SAM EASILY FINDS YOU AND LEAVES YOU IN THE RIVER PERMANENTLY.",
+ "SAM SALVADOR NOTICES SOMEONE HAS BEEN PLAYING WITH THE CARGO. HE TRACKS YOU DOWN AND LETS YOU HAVE IT.",
+ "THE GUARD COMES AROUND THE CORNER. HE DECIDES THAT THREE LEAD SLUGS WILL TEACH YOU TO BE MORE POLITE.",
+ "THE CAPTAIN IS WAITING OUTSIDE THE DOOR.",
+ "THE CAPTAIN'S RANDOM SHOOTING FINALLY FINDS ITS TARGET.",
+ "THE CRATE OUTSIDE THE WINDOW EXPLODES, DESTROYING THE SHIP. UNFORTUNATELY, YOU'RE STILL ABOARD.",
+ "THE DOOR WAS NOT BARRED AND THE CAPTAIN WALKS RIGHT IN AND PARTS YOUR HAIR.",
+ "",
+ "YOU RUN OUT ON DECK, THEN REALIZE THAT MAYA IS STILL TIED UP. AS YOU TURN TO GO BACK THE BOAT BLOWS UP.",
+ "AFTER YOU FAIL TO PROVE YOUR DIVINITY THE NATIVES EAT YOU FOR LUNCH.",
+ "THIS IS THE GENERIC DEATH SCENE",
+ "YOU ONLY MAKE IT HALFWAY ACROSS THE RIVER BEFORE THE PIRANHA STRIKE.",
+ "WITH NOTHING TO PROTECT HIM FROM THE HAIL OF BULLETS ALLEN IS QUICKLY GUNNED DOWN. JASON AND MAYA SOON FOLLOW...",
+ "THE COMBINATION OF THE WIND AND GUNFIRE KNOCK THE CORRUGATED IRON OVER, LEAVING YOU WITHOUT PROTECTION.",
+ "WITHOUT SUFFICIENT AMMUNITION, ALLEN IS UNABLE TO HOLD OFF THE ATTACKERS FOR LONG. THIS RESULTS IN A SERIOUS CASE OF LEAD POISONING.",
+ "ALLEN IS A MARVELOUS SHOT, BUT HIS AMMUNITION IS NOT UNLIMITED. SOON IT IS ALL OVER.",
+ "THE PILOT FEELS YOU ARE TOO CLOSE AND PULLS THE TRIGGER.",
+ "THE PILOT SHOOTS YOU IN THE HEAD, THEN TOSSES YOUR LIFELESS",
+ "THE PLANE CRASHES INTO THE JUNGLE CANOPY AT 200 MPH.",
+ "THE CANOE HITS THE ROCKS AND CAPSIZES, AND THE PIRANHA MAKE YOU THEIR LUNCH GUESTS.",
+ "YOU ACCIDENTALLY DISCOVER THE FOURTH TALLEST WATERFALL IN SOUTH AMERICA.",
+ "YOU DISCOVER A VERY HUNGRY TRIBE OF CANNIBALS.",
+ "YOU BECOME LOST IN THE WINDING WATERWAYS AND WANDER UNTIL YOU STARVE TO DEATH.",
+ "YOU BECOME TRAPPED IN THE RAPIDS AND ARE CRUSHED BETWEEN THE ROCKS.",
+ "YOU WAIT AROUND FOR SOME TIME, BUT HANS STROHEIM NEVER SPEAKS TO YOU AGAIN. FINALLY YOU RETURN HOME KNOWING YOU HAVE FAILED.",
+ "DECIDING THAT YOU THREATEN HIM AND HIS WORK, HANS STROHEIM HAS THE NATIVES IN THE VILLAGE KILL YOU.",
+ "YOU DO NOT GET FAR ENOUGH AWAY BEFORE THE DYNAMITE EXPLODES AND YOU ARE BLOWN INTO A THOUSAND PIECES.",
+ "STANDING OUT IN THE OPEN YOU ARE EXPOSED TO THE HAIL OF BULLETS FROM SANCHEZ' MEN.",
+ "THE AMAZON SENTINELS SPOT YOU AND FILL YOU FULL OF ARROWS.",
+ "SAM MAY BE UGLY, BUT HE'S NOT DEAF. HE HEARS ALL THE NOISE YOU ARE MAKING AND CANCELS YOUR BOARDING PASS.",
+ "WITH THE BAR OFF THE DOOR THE CAPTAIN WALTZES IN AND BLOWS YOU AWAY"
+};
+
+const char *const INVENTORY_NAMES_ENG[85] = {
+ "RAT", "ALCOHOL", "SAFE COMBINATION", "BEAKER", "MICROFILM",
+ "VAULT KEY", "BOLT CUTTERS", "BLOWGUN", "LOVE POTION", "MONEY",
+ "DARTS", "TAPE", "JUNGLE POTION", "MOVIE", "CABINET KEY",
+ "DISPLAY CASE KEY", "FLITCH'S CAR KEYS", "COAT HANGER",
+ "CROWBAR", "COMPASS", "MAP", "LETTER OPENER", "LETTER",
+ "DECODER", "DIPPED DART", "LOADED BLOWGUN", "CARD", "JERRYCAN",
+ "CIGARETTES", "BIKE PUMP", "PARACHUTE", "PESO", "PEPPERS",
+ "MACHETE", "POISON ROOT", "AMMUNITION", "PADDLE", "FISHING NET",
+ "RAT TRAP", "CHEESE", "LOADED TRAP", "KNIFE", "CHOPPED PEPPERS",
+ "LIGHTER", "LADDER", "SMALL POLE", "JEEP KEY", "CHAIN", "ARROW",
+ "FILLED JERRY CAN", "EXPLOSIVES", "GEIGER COUNTER", "VINE",
+ "GOLD NUGGET", "HOLLOW REED", "AMAZON QUEEN KEYS", "FISHING POLE",
+ "HARPOON", "RAG", "BOTTLE OF RUM", "RAG IN BOTTLE", "MOLOTOV COCKTAIL",
+ "JUNGLE PLANT", "LADLE", "WORM", "FISH", "FIREWORKS", "BAITED POLE",
+ "FILLED LADLE", "EMERALD", "SMALL KEY", "SCROLL", "LIT EXPLOSIVES",
+ "LIGHTER", "BROKEN SPEAR", "SHOE LACES", "TORCH", "LACES AND SPEAR",
+ "KNIFE SPEAR", "GARBAGE CAN", "RAFT", "INFLATED RAFT",
+ "JASON'S CAR KEYS", "PESO BILLS", "PLANK"
+};
+
+const int COMBO_TABLE[85][4] = {
+ { -1, -1, -1, -1 },
+ { 12, 3, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { 24, 25, -1, -1 },
+ { 10, 24, -1, -1 },
+ { -1, -1, -1, -1 },
+ { 8, 24, -1, -1 },
+ { -1, -1, -1, -1 },
+ { 1, 3, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { 7, 25, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { 80, 81, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { 41, 42, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { 39, 40, -1, -1 },
+ { 38, 40, -1, -1 },
+ { -1, -1, -1, -1 },
+ { 32, 42, 77, 78 },
+ { -1, -1, -1, -1 },
+ { 60, 61, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { 73, 72, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { 64, 67, -1, -1 },
+ { -1, -1, -1, -1 },
+ { 59, 60, -1, -1 },
+ { 58, 60, -1, -1 },
+ { 43, 61, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { 56, 67, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { 50, 72, -1, -1 },
+ { 75, 77, -1, -1 },
+ { 74, 77, -1, -1 },
+ { -1, -1, -1, -1 },
+ { 41, 78, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { 29, 81, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 },
+ { -1, -1, -1, -1 }
+};
+
+const char *const NO_HELP_MESSAGE_ENG =
+ "WE ARE UNABLE TO PROVIDE YOU WITH ANY MORE HINTS. YOUR IQ \
+HAS DECREASED SO FAR THAT WE CAN NO LONGER PUT THE HINTS IN TERMS \
+YOU CAN UNDERSTAND.";
+const char *const NO_HINTS_MESSAGE_ENG = "THE HELP SYSTEM HAS BEEN TURNED OFF FOR THIS GAME.";
+const char *const RIVER_HIT1_ENG = "YOU HIT THE ROCKS AND THE CANOE BEGINS TO LEAK.";
+const char *const RIVER_HIT2_ENG = "YOU HIT THE ROCKS AND THE CANOE DEVELOPS SERIOUS LEAKS.";
+const char *const BAR_MESSAGE_ENG = "YOU ARE TOO BUSY TRYING TO KEEP FROM SINKING TO DO THAT";
+const char *const HELPLVLTXT_ENG[3] = { " LEVEL 1 ", " LEVEL 2 ", " LEVEL 3 " };
+
+const char *const IQLABELS_ENG[9] = {
+ "VEGETABLE",
+ "NEANDERTHAL",
+ "LOBOTOMIZED",
+ "DENSE",
+ "AVERAGE",
+ "INTELLIGENT",
+ "MURPHYITE",
+ "BRILLIANT",
+ "GENIUS"
+};
+
+const char *const CANT_GET_THERE_ENG = "YOU CAN'T GET THERE FROM HERE.";
+
+} // End of namespace Amazon
diff --git a/devtools/create_access/amazon_resources.h b/devtools/create_access/amazon_resources.h
new file mode 100644
index 0000000000..aae27ce3ba
--- /dev/null
+++ b/devtools/create_access/amazon_resources.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.
+ *
+ */
+
+#ifndef __AMAZON_RESOURCES_H__
+#define __AMAZON_RESOURCES_H__
+
+#include "common/scummsys.h"
+
+namespace Amazon {
+
+#define AMAZON_NUM_CURSORS 10
+extern const byte *const CURSORS[AMAZON_NUM_CURSORS];
+extern const uint CURSOR_SIZES[AMAZON_NUM_CURSORS];
+
+extern const int FONT2_INDEX[];
+extern const byte FONT2_DATA[];
+extern const int FONT6x6_INDEX[];
+extern const byte FONT6x6_DATA[];
+extern const uint FONT2_INDEX_SIZE;
+extern const uint FONT2_DATA_SIZE;
+extern const uint FONT6x6_INDEX_SIZE;
+extern const uint FONT6x6_DATA_SIZE;
+
+extern const char *const ROOM_DESCR[64];
+extern const char *const DEATH_TEXT_ENG[58];
+extern const char *const DEATH_TEXT_ENG_DEMO[34];
+extern const byte DEATH_SCREENS_ENG[58];
+extern const byte DEATH_SCREENS_ENG_DEMO[34];
+extern const char *const INVENTORY_NAMES_ENG[85];
+extern const int COMBO_TABLE[85][4];
+
+extern const char *const NO_HELP_MESSAGE_ENG;
+extern const char *const NO_HINTS_MESSAGE_ENG;
+extern const char *const RIVER_HIT1_ENG;
+extern const char *const RIVER_HIT2_ENG;
+extern const char *const BAR_MESSAGE_ENG;
+extern const char *const HELPLVLTXT_ENG[3];
+extern const char *const IQLABELS_ENG[9];
+extern const char *const CANT_GET_THERE_ENG;
+
+} // End of namespace Amazon
+
+#endif
diff --git a/devtools/create_access/create_access_dat.cpp b/devtools/create_access/create_access_dat.cpp
new file mode 100644
index 0000000000..a1591ef6e5
--- /dev/null
+++ b/devtools/create_access/create_access_dat.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.
+ *
+ */
+
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
+// HACK to allow building with the SDL backend on MinGW
+// see bug #1800764 "TOOLS: MinGW tools building broken"
+#ifdef main
+#undef main
+#endif // main
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "common/language.h"
+#include "common/rect.h"
+#include "create_access_dat.h"
+#include "amazon_resources.h"
+#include "martian_resources.h"
+
+/**
+ * Format of the access.dat file that will be created:
+ * 4 Bytes - Magic string 'SVMA' to identify valid data file
+ * 2 bytes - Version number
+ * 2 Bytes - Number of different games data in the data file
+ * Series of index entries identifying each game:
+ * 1 byte - Game type: 1 = Amazon, 2 = Martian Memorandum, 3 = Noctropolis
+ * 1 byte - disc type: 0 = Floppy, 1 = CD, 2 = Common data shared across
+ * all variations of the given game
+ * 1 byte - Is Demo: 0 = Full game, 1 = Demo
+ * 1 byte - Language (Common::Language)
+ * 4 bytes - File offset for the data for the game
+ */
+
+File outputFile;
+
+void writeHeader(int numExecutables);
+void writeAmazonCommonData();
+void writeMartianCommonData();
+bool processExecutable(int idx, const char *name);
+
+void NORETURN_PRE error(const char *s, ...) {
+ printf("%s\n", s);
+ exit(1);
+}
+
+int main(int argc, char *argv[]) {
+ const uint NUM_COMMON_ENTRIES = 2;
+
+ if (argc < 3) {
+ printf("Format: %s output_filename executable1 [executable2 ..]\n", argv[0]);
+ exit(0);
+ }
+
+ // Create the new data file for output
+ outputFile.open(argv[1], kFileWriteMode);
+ writeHeader(argc - 2 + NUM_COMMON_ENTRIES);
+
+ // Write out entries containing common data for the games
+ writeAmazonCommonData();
+ writeMartianCommonData();
+
+ // Iterate through processing each specified executable
+ outputFile.seek(0, SEEK_END);
+ for (int idx = 2; idx < argc; ++idx) {
+ if (!processExecutable(idx - 2 + NUM_COMMON_ENTRIES, argv[idx]))
+ break;
+ }
+
+ // Close the output file
+ outputFile.close();
+}
+
+void writeHeader(int numExecutables) {
+ // Write out magic string
+ const char *MAGIC_STR = "SVMA";
+ outputFile.write(MAGIC_STR, 4);
+
+ // Write out version number
+ outputFile.writeWord(VERSION_NUMBER);
+
+ // Write out the number of entries the data file will contain
+ outputFile.writeWord(numExecutables);
+
+ // Write out padding for index entries that will be written
+ outputFile.writeByte(0, 8 * numExecutables);
+}
+
+void writeAmazonCommonData() {
+ // Write out the header entry
+ outputFile.seek(8);
+ outputFile.writeByte(1); // Amazon
+ outputFile.writeByte(2); // Common data
+ outputFile.writeByte(0);
+ outputFile.writeByte(0);
+ outputFile.writeLong(outputFile.size());
+
+ // Write out cursor list
+ outputFile.seek(0, SEEK_END);
+ outputFile.writeWord(AMAZON_NUM_CURSORS);
+
+ for (uint idx = 0; idx < AMAZON_NUM_CURSORS; ++idx) {
+ outputFile.writeWord(Amazon::CURSOR_SIZES[idx]);
+ outputFile.write(Amazon::CURSORS[idx], Amazon::CURSOR_SIZES[idx]);
+ }
+
+ // Write out font data
+ outputFile.writeWord(Amazon::FONT2_INDEX_SIZE);
+ for (uint idx = 0; idx < Amazon::FONT2_INDEX_SIZE; ++idx)
+ outputFile.writeWord(Amazon::FONT2_INDEX[idx]);
+
+ outputFile.writeWord(Amazon::FONT2_DATA_SIZE);
+ outputFile.write(Amazon::FONT2_DATA, Amazon::FONT2_DATA_SIZE);
+
+ outputFile.writeWord(Amazon::FONT6x6_INDEX_SIZE);
+ for (uint idx = 0; idx < Amazon::FONT6x6_INDEX_SIZE; ++idx)
+ outputFile.writeWord(Amazon::FONT6x6_INDEX[idx]);
+
+ outputFile.writeWord(Amazon::FONT6x6_DATA_SIZE);
+ outputFile.write(Amazon::FONT2_DATA, Amazon::FONT6x6_DATA_SIZE);
+}
+
+
+void writeMartianCommonData() {
+ // Write out the header entry
+ outputFile.seek(16);
+ outputFile.writeByte(2); // Martian
+ outputFile.writeByte(2); // Common data
+ outputFile.writeByte(0);
+ outputFile.writeByte(0);
+ outputFile.writeLong(outputFile.size());
+
+ // Write out cursor list
+ outputFile.seek(0, SEEK_END);
+ outputFile.writeByte(MARTIAN_NUM_CURSORS);
+
+ for (uint idx = 0; idx < MARTIAN_NUM_CURSORS; ++idx) {
+ outputFile.writeWord(Martian::CURSOR_SIZES[idx]);
+ outputFile.write(Martian::CURSORS[idx], Martian::CURSOR_SIZES[idx]);
+ }
+}
+
+bool processExecutable(int exeIdx, const char *name) {
+ uint dataSegmentOffset;
+ uint filenamesOffset, numFilenames;
+ uint charsStart, charsEnd;
+ uint roomsStart, roomsEnd, numRooms;
+ uint travelPosOffset;
+ const char *const *roomDescs;
+ const byte *deathScreens;
+ const char *const *deathText;
+ uint numDeaths;
+ uint numItems;
+ const char *const *itemNames;
+ const int *comboTable;
+ byte gameId = 0, discType = 0, demoType = 0;
+ byte language = Common::EN_ANY;
+
+ // Open up the file for access
+ File exeFile;
+ if (!exeFile.open(name)) {
+ printf("Could not open file - %s\n", name);
+ return false;
+ }
+
+ // Total up the first 256 bytes of the executable as a simplified
+ // means of identifying the different executables we support
+ uint fileChecksum = 0;
+ for (int idx = 0; idx < 256; ++idx)
+ fileChecksum += exeFile.readByte();
+
+ switch (fileChecksum) {
+ case 11899:
+ // Amazon English floppy
+ gameId = 1;
+ dataSegmentOffset = 0xC8C0;
+ filenamesOffset = dataSegmentOffset + 0x3628;
+ numFilenames = 100;
+ charsStart = dataSegmentOffset + 0x4234;
+ charsEnd = dataSegmentOffset + 0x49c6;
+ roomsStart = dataSegmentOffset + 0x35a8;
+ roomsEnd = dataSegmentOffset + 0x4234;
+ travelPosOffset = dataSegmentOffset + 0x5ff7;
+ numRooms = 64;
+ roomDescs = &Amazon::ROOM_DESCR[0];
+ deathScreens = Amazon::DEATH_SCREENS_ENG;
+ deathText = &Amazon::DEATH_TEXT_ENG[0];
+ numDeaths = sizeof(Amazon::DEATH_SCREENS_ENG);
+ numItems = 85;
+ itemNames = &Amazon::INVENTORY_NAMES_ENG[0];
+ comboTable = &Amazon::COMBO_TABLE[0][0];
+ break;
+
+ case 12360:
+ // Amazon CD English
+ gameId = 1;
+ discType = 1;
+ dataSegmentOffset = 0xd370;
+ filenamesOffset = dataSegmentOffset + 0x3EA0;
+ numFilenames = 116;
+ charsStart = dataSegmentOffset + 0x4BDC;
+ charsEnd = dataSegmentOffset + 0x5AF4;
+ roomsStart = dataSegmentOffset + 0x3E20;
+ roomsEnd = dataSegmentOffset + 0x4BDC;
+ travelPosOffset = dataSegmentOffset + 0x7125;
+ numRooms = 64;
+ roomDescs = &Amazon::ROOM_DESCR[0];
+ deathScreens = Amazon::DEATH_SCREENS_ENG;
+ deathText = &Amazon::DEATH_TEXT_ENG[0];
+ numDeaths = sizeof(Amazon::DEATH_SCREENS_ENG);
+ numItems = 85;
+ itemNames = &Amazon::INVENTORY_NAMES_ENG[0];
+ comboTable = &Amazon::COMBO_TABLE[0][0];
+ break;
+
+ case 11748:
+ // Amazon English Demo
+ gameId = 1;
+ discType = 0;
+ demoType = 1;
+ dataSegmentOffset = 0xa2a0;
+ filenamesOffset = dataSegmentOffset + 0x242C;
+ numFilenames = 100;
+ charsStart = dataSegmentOffset + 0x2F1A;
+ charsEnd = dataSegmentOffset + 0x34FB;
+ roomsStart = dataSegmentOffset + 0x23AC;
+ roomsEnd = dataSegmentOffset + 0x2F1A;
+ travelPosOffset = dataSegmentOffset + 0x494E;
+ numRooms = 64;
+ roomDescs = &Amazon::ROOM_DESCR[0];
+ deathScreens = Amazon::DEATH_SCREENS_ENG;
+ deathText = &Amazon::DEATH_TEXT_ENG[0];
+ numDeaths = sizeof(Amazon::DEATH_SCREENS_ENG);
+ numItems = 85;
+ itemNames = &Amazon::INVENTORY_NAMES_ENG[0];
+ comboTable = &Amazon::COMBO_TABLE[0][0];
+ break;
+
+ case 1224:
+ // Martian Memorandum English packed
+ printf("Martian Memorandum provided that's packed with EXEPACK.\n");
+ printf("It needs to be first unpacked before it can be used with this tool.\n");
+ return false;
+
+ case 0:
+ // Martian Memorandum English
+ gameId = 2;
+ dataSegmentOffset = 0x8d78;
+ filenamesOffset = dataSegmentOffset + 0x373A;
+ numFilenames = 80;
+ charsStart = dataSegmentOffset + 0x40F2;
+ charsEnd = dataSegmentOffset + 0x46F8;
+ roomsStart = dataSegmentOffset + 0x36DA;
+ roomsEnd = dataSegmentOffset + 0x40F2;
+ travelPosOffset = dataSegmentOffset + 0x58E9;
+ numRooms = 48;
+ roomDescs = &Martian::ROOM_DESCR[0];
+ deathScreens = Martian::DEATH_SCREENS_ENG;
+ deathText = &Martian::DEATH_TEXT_ENG[0];
+ numDeaths = sizeof(Martian::DEATH_SCREENS_ENG);
+ numItems = 85;
+ itemNames = &Martian::INVENTORY_NAMES_ENG[0];
+ comboTable = nullptr;
+ break;
+
+ default:
+ printf("Unknown game executable specified - %s\n", name);
+ exeFile.close();
+ return false;
+ }
+
+ // Write out header entry
+ uint outputOffset = outputFile.size();
+ outputFile.seek(8 + exeIdx * 8);
+ outputFile.writeByte(gameId);
+ outputFile.writeByte(discType);
+ outputFile.writeByte(demoType);
+ outputFile.writeByte(language);
+ outputFile.writeLong(outputOffset);
+ outputFile.seek(0, SEEK_END);
+
+ // Write out list of AP filenames
+ outputFile.writeWord(numFilenames);
+ for (uint idx = 0; idx < numFilenames; ++idx) {
+ exeFile.seek(filenamesOffset + idx * 2);
+ uint nameOffset = exeFile.readWord();
+
+ exeFile.seek(dataSegmentOffset + nameOffset);
+ outputFile.writeString(exeFile);
+ }
+
+ // Write out the character list
+ exeFile.seek(charsStart);
+ Common::Array<uint> charOffsets;
+ charOffsets.push_back(exeFile.readWord());
+ assert((dataSegmentOffset + charOffsets[0] - exeFile.pos()) < 512);
+
+ while (exeFile.pos() < (dataSegmentOffset + charOffsets[0]))
+ charOffsets.push_back(exeFile.readWord());
+
+ outputFile.writeWord(charOffsets.size());
+ charOffsets.push_back(charsEnd);
+ for (uint idx = 0; idx < charOffsets.size() - 1; ++idx) {
+ if (charOffsets[idx] == 0) {
+ outputFile.writeWord(0);
+ } else {
+ uint nextOffset = 0xffff;
+ for (uint idx2 = 0; idx2 < charOffsets.size(); ++idx2) {
+ if (charOffsets[idx2] && charOffsets[idx2] > charOffsets[idx] && charOffsets[idx2] < nextOffset)
+ nextOffset = charOffsets[idx2];
+ }
+ uint size = nextOffset - charOffsets[idx];
+
+ exeFile.seek(dataSegmentOffset + charOffsets[idx]);
+ outputFile.writeWord(size);
+ outputFile.write(exeFile, size);
+ }
+ }
+
+ // Write out the room data
+ Common::Array<uint> roomOffsets;
+ Common::Array<Common::Point> travelPos;
+
+ exeFile.seek(roomsStart);
+ for (uint idx = 0; idx < numRooms; ++idx)
+ roomOffsets.push_back(exeFile.readWord());
+ roomOffsets.push_back(roomsEnd);
+
+ exeFile.seek(travelPosOffset);
+ for (uint idx = 0; idx < numRooms; ++idx) {
+ int16 xp = (int16)exeFile.readWord();
+ int16 yp = (int16)exeFile.readWord();
+ travelPos.push_back(Common::Point(xp, yp));
+ }
+
+ outputFile.writeWord(numRooms);
+ for (uint idx = 0; idx < numRooms; ++idx) {
+ uint dataSize = 0;
+
+ if (roomOffsets[idx] == 0) {
+ dataSize = 0;
+ } else {
+ // Find the offset of the next higher entry that's non-zero
+ uint offset = 0;
+ for (uint idx2 = idx + 1; !offset; ++idx2)
+ offset = roomOffsets[idx2];
+ dataSize = offset - roomOffsets[idx];
+ exeFile.seek(dataSegmentOffset + roomOffsets[idx]);
+ }
+
+ // Write out the room description (used only by the debugger)
+ outputFile.writeString(roomDescs[idx]);
+
+ // Write out travel position
+ outputFile.writeWord((uint16)travelPos[idx].x);
+ outputFile.writeWord((uint16)travelPos[idx].y);
+
+ // Write out the data for the room
+ outputFile.writeWord(dataSize);
+ if (dataSize > 0)
+ outputFile.write(exeFile, dataSize);
+ }
+
+ // Write out the deaths list
+ outputFile.writeWord(numDeaths);
+ for (uint idx = 0; idx < numDeaths; ++idx) {
+ // Write out the screen number and text
+ outputFile.writeByte(deathScreens[idx]);
+ outputFile.writeString(deathText[idx]);
+ }
+
+ // Write out inventory data
+ outputFile.writeWord(numItems);
+ for (uint idx = 0; idx < numItems; ++idx) {
+ outputFile.writeString(itemNames[idx]);
+
+ if (comboTable == nullptr) {
+ for (uint cIdx = 0; cIdx < 4; ++cIdx)
+ outputFile.writeWord(0);
+ } else {
+ for (uint cIdx = 0; cIdx < 4; ++cIdx, ++comboTable)
+ outputFile.writeWord((uint16)*comboTable);
+ }
+ }
+
+ // Write out game specific strings and other data
+ if (gameId == 1) {
+ // Write out miscellaneous strings
+ outputFile.writeString(Amazon::NO_HELP_MESSAGE_ENG);
+ outputFile.writeString(Amazon::NO_HINTS_MESSAGE_ENG);
+ outputFile.writeString(Amazon::RIVER_HIT1_ENG);
+ outputFile.writeString(Amazon::RIVER_HIT2_ENG);
+ outputFile.writeString(Amazon::BAR_MESSAGE_ENG);
+
+ for (int idx = 0; idx < 3; ++idx)
+ outputFile.writeString(Amazon::HELPLVLTXT_ENG[idx]);
+ for (int idx = 0; idx < 9; ++idx)
+ outputFile.writeString(Amazon::IQLABELS_ENG[idx]);
+
+ outputFile.writeString(Amazon::CANT_GET_THERE_ENG);
+ }
+
+ // Do final padding to the next paragraph boundary
+ if ((outputFile.size() % 16) != 0)
+ outputFile.writeByte(0, 16 - (outputFile.size() % 16));
+
+ // Close the executable and signal that it was processed successfully
+ exeFile.close();
+ return true;
+}
diff --git a/devtools/create_access/create_access_dat.h b/devtools/create_access/create_access_dat.h
new file mode 100644
index 0000000000..4976edec46
--- /dev/null
+++ b/devtools/create_access/create_access_dat.h
@@ -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.
+ *
+ */
+
+#ifndef __CREATE_ACCESS_DAT_H__
+#define __CREATE_ACCESS_DAT_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "common/scummsys.h"
+#include "common/endian.h"
+#include "common/array.h"
+
+#define VERSION_NUMBER 1
+
+enum AccessMode {
+ kFileReadMode = 1,
+ kFileWriteMode = 2
+};
+
+class File {
+private:
+ FILE *_f;
+ const byte *_memPtr;
+ size_t _offset, _size;
+public:
+ File() : _f(nullptr), _memPtr(nullptr), _offset(0), _size(0) {}
+
+ bool open(const char *filename, AccessMode mode = kFileReadMode) {
+ _memPtr = nullptr;
+ _f = fopen(filename, (mode == kFileReadMode) ? "rb" : "wb+");
+ return (_f != NULL);
+ }
+ bool open(const byte *data, uint size) {
+ close();
+ _memPtr = data;
+ _size = size;
+ return true;
+ }
+
+ void close() {
+ if (_f)
+ fclose(_f);
+ _f = nullptr;
+ _memPtr = nullptr;
+ }
+ int seek(int32 offset, int whence = SEEK_SET) {
+ if (_f)
+ return fseek(_f, offset, whence);
+
+ switch (whence) {
+ case SEEK_SET:
+ _offset = offset;
+ break;
+ case SEEK_CUR:
+ _offset += offset;
+ break;
+ case SEEK_END:
+ _offset = _size + offset;
+ break;
+ default:
+ break;
+ }
+
+ return _offset;
+ }
+ void skip(int32 offset) {
+ if (_f)
+ fseek(_f, offset, SEEK_CUR);
+ else
+ _offset += offset;
+ }
+ long read(void *buffer, size_t len) {
+ if (_f)
+ return fread(buffer, 1, len, _f);
+
+ uint bytesToRead = CLIP(len, (size_t)0, _size - _offset);
+ memcpy(buffer, &_memPtr[_offset], bytesToRead);
+ _offset += bytesToRead;
+ return bytesToRead;
+ }
+ void write(const void *buffer, size_t len) {
+ assert(_f);
+ fwrite(buffer, 1, len, _f);
+ }
+ void write(File &src, size_t len) {
+ for (size_t idx = 0; idx < len; ++idx)
+ writeByte(src.readByte());
+ }
+ byte readByte() {
+ byte v;
+ read(&v, sizeof(byte));
+ return v;
+ }
+ uint16 readWord() {
+ uint16 v;
+ read(&v, sizeof(uint16));
+ return FROM_LE_16(v);
+ }
+ uint32 readLong() {
+ uint32 v;
+ read(&v, sizeof(uint32));
+ return FROM_LE_32(v);
+ }
+ void writeByte(byte v) {
+ write(&v, sizeof(byte));
+ }
+ void writeByte(byte v, int len) {
+ byte *b = new byte[len];
+ memset(b, v, len);
+ write(b, len);
+ delete[] b;
+ }
+ void writeWord(uint16 v) {
+ uint16 vTemp = TO_LE_16(v);
+ write(&vTemp, sizeof(uint16));
+ }
+ void writeLong(uint32 v) {
+ uint32 vTemp = TO_LE_32(v);
+ write(&vTemp, sizeof(uint32));
+ }
+ void writeString(const char *msg) {
+ if (!msg) {
+ writeByte(0);
+ } else {
+ do {
+ writeByte(*msg);
+ } while (*msg++);
+ }
+ }
+ void writeString(File &src) {
+ char c;
+ do {
+ c = src.readByte();
+ writeByte(c);
+ } while (c);
+ }
+ uint32 pos() const {
+ if (_f)
+ return ftell(_f);
+ else
+ return _offset;
+ }
+ uint32 size() const {
+ if (_f) {
+ uint32 currentPos = pos();
+ fseek(_f, 0, SEEK_END);
+ uint32 result = pos();
+ fseek(_f, currentPos, SEEK_SET);
+ return result;
+ } else if (_memPtr) {
+ return _size;
+ } else {
+ return 0;
+ }
+ }
+ bool eof() const {
+ if (_f)
+ return feof(_f) != 0;
+ else if (_memPtr)
+ return _offset >= _size;
+ return false;
+ }
+};
+
+#endif
diff --git a/devtools/create_access/martian_resources.cpp b/devtools/create_access/martian_resources.cpp
new file mode 100644
index 0000000000..381b79a073
--- /dev/null
+++ b/devtools/create_access/martian_resources.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 "martian_resources.h"
+
+namespace Martian {
+
+
+const byte MOUSE0[] = {
+ // hotspot x and y, uint16 LE
+ 0, 0, 0, 0,
+ // byte 1: number of skipped pixels
+ // byte 2: number of plotted pixels
+ // then, pixels
+ 0, 2, 0xF7, 5,
+ 0, 3, 0xF7, 0xF7, 5,
+ 0, 3, 0xF7, 0xF7, 5,
+ 0, 4, 0xF7, 0xF7, 0xF7, 5,
+ 0, 4, 0xF7, 0xF7, 0xF7, 5,
+ 0, 5, 0xF7, 0xF7, 0xF7, 0xF7, 5,
+ 0, 5, 0xF7, 0xF7, 0xF7, 0xF7, 5,
+ 0, 6, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 5,
+ 0, 6, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 5,
+ 0, 7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 5,
+ 0, 6, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 5,
+ 0, 5, 0xF7, 0xF7, 0xF7, 0xF7, 5,
+ 2, 3, 0xF7, 0xF7, 5,
+ 3, 3, 0xF7, 0xF7, 5,
+ 3, 3, 0xF7, 0xF7, 5,
+ 4, 2, 0xF7, 5
+};
+const byte MOUSE1[] = {
+ // hotspot x and y, uint16 LE
+ 7, 0, 7, 0,
+ // byte 1: number of skipped pixels
+ // byte 2: number of plotted pixels
+ // then, pixels
+ 6, 1, 0xF7,
+ 4, 5, 0xFF, 0xFF, 0, 0xFF, 0xFF,
+ 3, 7, 0xFF, 0, 0, 0, 0, 0, 0xFF,
+ 2, 9, 0xFF, 0, 0, 0, 0xF7, 0, 0, 0, 0xFF,
+ 1, 11, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF,
+ 1, 11, 0xFF, 0, 0, 0, 0, 0xF7, 0, 0, 0, 0, 0xFF,
+ 0, 13, 0xF7, 0, 0, 0xF7, 0, 0xF7, 0, 0xF7, 0, 0xF7, 0, 0, 0xF7,
+ 1, 11, 0xFF, 0, 0, 0, 0, 0xF7, 0, 0, 0, 0, 0xFF,
+ 1, 11, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF,
+ 2, 9, 0xFF, 0, 0, 0, 0xF7, 0, 0, 0, 0xFF,
+ 3, 7, 0xFF, 0, 0, 0, 0, 0, 0xFF,
+ 4, 5, 0xFF, 0xFF, 0, 0xFF, 0xFF,
+ 6, 1, 0xF7,
+ 0, 0,
+ 0, 0,
+ 0, 0
+};
+const byte MOUSE2[] = {
+ // hotspot x and y, uint16 LE
+ 8, 0, 8, 0,
+ // byte 1: number of skipped pixels
+ // byte 2: number of plotted pixels
+ // then, pixels
+ 0, 0,
+ 0, 0,
+ 7, 2, 4, 5,
+ 7, 2, 4, 5,
+ 7, 2, 4, 5,
+ 7, 2, 4, 5,
+ 7, 2, 4, 5,
+ 2, 12, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 5,
+ 7, 2, 4, 5,
+ 7, 2, 4, 5,
+ 7, 2, 4, 5,
+ 7, 2, 4, 5,
+ 7, 2, 4, 5,
+ 0, 0,
+ 0, 0,
+ 0, 0
+};
+const byte MOUSE3[] = {
+ // hotspot x and y, uint16 LE
+ 0, 0, 0, 0,
+ // byte 1: number of skipped pixels
+ // byte 2: number of plotted pixels
+ // then, pixels
+ 0, 11, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 0, 12, 6, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 5,
+ 0, 12, 6, 7, 7, 7, 7, 7, 7, 7, 7, 6, 5, 5,
+ 0, 12, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5,
+ 0, 12, 6, 6, 6, 6, 6, 5, 6, 6, 6, 6, 6, 5,
+ 0, 12, 6, 6, 6, 6, 5, 0, 0, 6, 6, 6, 6, 5,
+ 0, 12, 6, 6, 6, 6, 6, 0, 6, 6, 6, 6, 6, 5,
+ 0, 12, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5,
+ 0, 12, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5,
+ 0, 12, 6, 6, 6, 6, 6, 5, 6, 6, 6, 6, 6, 5,
+ 0, 12, 6, 6, 6, 6, 6, 5, 6, 6, 6, 6, 6, 5,
+ 0, 12, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5,
+ 1, 11, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 0, 0,
+ 0, 0,
+ 0, 0
+};
+
+const byte *const CURSORS[MARTIAN_NUM_CURSORS] = {
+ MOUSE0, MOUSE1, MOUSE2, MOUSE3
+};
+const uint CURSOR_SIZES[MARTIAN_NUM_CURSORS] = {
+ sizeof(MOUSE0), sizeof(MOUSE1), sizeof(MOUSE2), sizeof(MOUSE3)
+};
+
+const char *const ROOM_DESCR[48] = {
+ nullptr, "TBD ROOM_TABLE1", "TBD ROOM_TABLE2", "TBD ROOM_TABLE3", "TBD ROOM_TABLE4",
+ "TBD ROOM_TABLE5", "TBD ROOM_TABLE6", "TBD ROOM_TABLE7", "TBD ROOM_TABLE8", "TBD ROOM_TABLE9",
+ nullptr, "TBD ROOM_TABLE11", nullptr, "TBD ROOM_TABLE13", "TBD ROOM_TABLE14",
+ "TBD ROOM_TABLE15", "TBD ROOM_TABLE16", "TBD ROOM_TABLE17", "TBD ROOM_TABLE18", nullptr,
+ nullptr, "TBD ROOM_TABLE21", "TBD ROOM_TABLE22", "TBD ROOM_TABLE23", "TBD ROOM_TABLE24",
+ "TBD ROOM_TABLE25", "TBD ROOM_TABLE26", "TBD ROOM_TABLE27", "TBD ROOM_TABLE28", "TBD ROOM_TABLE29",
+ "TBD ROOM_TABLE30", "TBD ROOM_TABLE31", "TBD ROOM_TABLE32", "TBD ROOM_TABLE33", nullptr,
+ "TBD ROOM_TABLE35", nullptr, "TBD ROOM_TABLE37", "TBD ROOM_TABLE38", "TBD ROOM_TABLE39",
+ nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, "TBD ROOM_TABLE47"
+};
+
+const byte DEATH_SCREENS_ENG[20] = {
+ 5, 5, 3, 3, 7, 4, 6, 2, 2, 2, 1, 5, 3, 5, 2, 8, 5, 3, 8, 5
+};
+
+const char *const DEATH_TEXT_ENG[20] = {
+ "A VICIOUS THUG PULLS OUT HIS GUN AND AIR CONDITIONS YOUR BRAIN.",
+ "BIG DICK COMES BACK AND ANNOUNCES YOUR TIME IS UP. ONE OF HIS BOYS PROCEEDS TO PART YOUR EYEBROWS.",
+ "ALTHOUGH HIS FIRST SHOT MISSED, THE PUNK FINDS YOU AND TURNS YOU INTO A DOUGHNUT.",
+ "THE CREEP SPOTS YOU. HE TURNS AND FIRES HIS WEAPON. IT BURNS A HOLE A BUZZARD CAN FLY THROUGH.",
+ "OBVIOUSLY RICK LOGAN HAS A FEW TRICK UP HIS SLEEVE. A TREMENDOUS WEIGHT HITS YOUR HEAD. YOU MUMBLE; WATCH OUT FOR THAT TREE...",
+ "SLOWLY SINKING IN THE SLIMY OOZE, YOU THINK OF SEVERAL JELLO WRESTLING MATCHES YOU'VE ATTENDED. BUT NO MORE...",
+ "THE PATH SUDDENLY GIVES WAY AND YOU FEEL MANY STAKES TEAR THROUGH YOUR FLESH. HOW DO YOU LIKE YOUR STAKE",
+ "THE SNAKE SINKS ITS FANGS INTO YOU LEG. THE POISON WORKS QUICKLY. THE SNAKE THEN SWALLOWS YOU WHOLE.",
+ "YOU FADE AWAY, GLOWING LIKE A LIGHTBULB.",
+ "YOU TOUCH THE BUBBLING RADIOACTIVE SELTZER. IT IMMEDIATELY CAUSES VITAL ORGANS TO ELONGATE AND EXPLODE. YOU DIE WITH AN ABSURD AND FOOLISH LOOK ON YOUR FACE.",
+ "THE DOGS PRETTY HUNGRY. IT WON'T TAKE HIM LONG TO FINISH SO SIT BACK AND ENJOY IT.",
+ "ROCKY DOESN'T LIKE BEING FOLLOWED. HE DECIDES TO BEAT YOU. WITHIN AND INCH OF YOUR LIFE. UNFORTUNATELY, HE MISJUDGED THE DISTANCE",
+ "YOU STUMBLE INTO DEADLY LASER FIRE.",
+ "THE OUTPOST AND YOUR BODY PARTS ARE BLOWN TO KINGDOM COME.",
+ "YOU REACH THE TOP, BUT YOUR AIR SOON RUNS OUT LEAVING YOU BREATHLESS.",
+ "YOU DIE IN THE FIERY EXPLOSION.",
+ "YOU FALL HUNDREDS OF FEET TO YOUR DEATH.",
+ "YOU WALK ONTO A PRESSURE SENSITIVE SECURITY PAD. A LASER ZEROS IN AND BLOWS A HOLE THE SIZE OF A SUBARU TIRE THROUGH YOU.",
+ "DANGERFIELD'S EXPERIMENT BACKFIRES. IT RELEASES A DEMON FROM HIS SUBCONSCIOUS WHICH DESTROYS THE ENTIRE PLANET.",
+ "ONCE DANGERFIELD GETS OUT OF HIS CHAMBER, HE PULLS OUT A WEAPON AND LETS YOU HAVE IT."
+};
+
+const char *const INVENTORY_NAMES_ENG[55] = {
+ "CAMERA", "LENS", "PHOTOS", "MAIL", "GUN",
+ "CASH", "COMLINK", "AMMO", "LOCKPICK KIT", "EARRING",
+ "RECIEPTS", "PAPER", "LADDER", "BOOTS", "DOCUMENTS",
+ "KNIFE", "DAGGER", "KEYS", "ROCK", "LOG",
+ "SHOVEL", "STONE", "REMOTE CONTROL", "FOOD AND WATER", "DOOR CARD KEY",
+ "FLASHLIGHT", "INTERLOCK KEY", "TOOLS", "REBREATHER", "JET PACK",
+ "ROD", "HCL2", "SAFE CARD KEY", "TUNING FORK", "STONE",
+ "ROSE", "KEY", "NOTE", "ALLEN WRENCH", "HOVER BOARD",
+ "BLUE PRINTS", "LETTER", "MEMORANDUM", "MARKERS", "FILM",
+ "ANDRETTI FILM", "GLASSES", "AMULET", "FACIAL KIT", "CAT FOOD",
+ "MONKEY WRENCH", "BIG DICK CARD", "BRA", "BOLT", nullptr
+};
+
+} // End of namespace Amazon
diff --git a/devtools/create_access/martian_resources.h b/devtools/create_access/martian_resources.h
new file mode 100644
index 0000000000..f80f4c1cf4
--- /dev/null
+++ b/devtools/create_access/martian_resources.h
@@ -0,0 +1,52 @@
+/* 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 __MARTIAN_RESOURCES_H__
+#define __MARTIAN_RESOURCES_H__
+
+#include "common/scummsys.h"
+
+namespace Martian {
+
+#define MARTIAN_NUM_CURSORS 4
+extern const byte *const CURSORS[MARTIAN_NUM_CURSORS];
+extern const uint CURSOR_SIZES[MARTIAN_NUM_CURSORS];
+
+extern const char *const ROOM_DESCR[48];
+
+extern const char *const DEATH_TEXT_ENG[20];
+extern const byte DEATH_SCREENS_ENG[20];
+extern const char *const INVENTORY_NAMES_ENG[55];
+extern const int COMBO_TABLE[85][4];
+
+extern const char *const NO_HELP_MESSAGE_ENG;
+extern const char *const NO_HINTS_MESSAGE_ENG;
+extern const char *const RIVER_HIT1_ENG;
+extern const char *const RIVER_HIT2_ENG;
+extern const char *const BAR_MESSAGE_ENG;
+extern const char *const HELPLVLTXT_ENG[3];
+extern const char *const IQLABELS_ENG[9];
+extern const char *const CANT_GET_THERE_ENG;
+
+} // End of namespace Amazon
+
+#endif
diff --git a/devtools/create_access/module.mk b/devtools/create_access/module.mk
new file mode 100644
index 0000000000..4694ccc7ef
--- /dev/null
+++ b/devtools/create_access/module.mk
@@ -0,0 +1,13 @@
+
+MODULE := devtools/create_access
+
+MODULE_OBJS := \
+ create_access_dat.o \
+ amazon_resources.o \
+ martian_resources.o
+
+# Set the name of the executable
+TOOL_EXECUTABLE := create_access
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/devtools/create_classicmacfonts.sh b/devtools/create_classicmacfonts.sh
new file mode 100755
index 0000000000..517f3f5638
--- /dev/null
+++ b/devtools/create_classicmacfonts.sh
@@ -0,0 +1,119 @@
+#!/bin/bash
+#
+# This script downloads System 7.0.1 image from Apple and extracts fonts
+# from it. Mac only, unfortunately.
+#
+# On Windows you perhaps can perform the extraction manually with use of
+# HFSxplorer: http://www.catacombae.org/hfsexplorer/
+#
+# More information could be found in the vMac documentation: http://www.gryphel.com/c/image/
+#
+# Alternatively you may use vMac instructions for extracting these disk images:
+# http://www.gryphel.com/c/minivmac/recipes/sys7inst/
+#
+# Based on instructions posted at
+# http://apple.stackexchange.com/questions/58243/can-i-get-the-original-mac-font-chicago-on-a-mountain-lion-mac
+
+echo_n() {
+ printf "$@"
+}
+
+if test `uname` != "Darwin"; then
+ echo This script is Mac OS X-only
+ exit
+fi
+
+echo_n "Downloading System 7.0.1 image..."
+if test ! -f System_7.0.1.smi.bin; then
+ curl -s http://download.info.apple.com/Apple_Support_Area/Apple_Software_Updates/English-North_American/Macintosh/System/Older_System/System_7.0.x/System_7.0.1.smi.bin -o System_7.0.1.smi.bin
+fi
+
+if test ! -f System_7.0.1.smi.bin; then
+ echo "Cannot download System_7.0.1.smi.bin"
+ exit
+fi
+
+echo done
+
+echo_n "Mounting System 7.0.1 image..."
+
+macbinary decode System_7.0.1.smi.bin
+hdiutil convert -quiet System\ 7.0.1.smi -format UDRO -o sys7.dmg
+hdiutil attach -quiet sys7.dmg
+
+if test ! -f /Volumes/7.0.1\ \(1440k.images\)/Fonts.image; then
+ echo "Failed to attach sys7.dmg"
+ exit
+fi
+
+echo done
+
+echo_n "Mounting Fonts disk image..."
+
+hdiutil convert -quiet /Volumes/7.0.1\ \(1440k.images\)/Fonts.image -format UDRO -o fonts.dmg
+hdiutil detach -quiet `hdiutil info|grep "/Volumes/7.0.1 (1440k.images)"|cut -f 1`
+hdiutil attach -quiet fonts.dmg
+
+if test ! -f /Volumes/Fonts/Chicago; then
+ echo "Failed to attach fonts.dmg"
+ exit
+fi
+
+echo done
+
+echo_n "Copying fonts..."
+
+for i in Athens Cairo Chicago Courier Geneva Helvetica London "Los Angeles" Monaco "New York" Palatino "San Francisco" Symbol Times Venice
+do
+ echo $i
+ macbinary encode "/Volumes/Fonts/$i" -o "$i.bin" -n
+done
+
+echo ...Done
+
+hdiutil detach -quiet `hdiutil info|grep "/Volumes/Fonts"|cut -f 1`
+
+if test ! -f fondu_src-060102.tgz; then
+ echo_n "Getting fondu_src-060102.tgz..."
+ curl -s http://fondu.sourceforge.net/fondu_src-060102.tgz -o fondu_src-060102.tgz
+ tar xf fondu_src-060102.tgz
+fi
+
+if test ! -d fondu-060102; then
+ echo "Failed to download fondu_src-060102.tgz"
+ exit
+fi
+
+echo done
+
+if test ! -x fondu-060102/fondu; then
+ echo_n "Compiling fondu..."
+ cd fondu-060102
+ ./configure >configure.log 2>&1 && make 2>&1 >make.log
+ cd ..
+fi
+
+if test ! -x fondu-060102/fondu; then
+ echo "Failed to build fondu. See configure.log and make.log"
+ exit
+else
+ rm -f configure.log make.log
+fi
+
+echo done
+
+echo_n "Converting fonts..."
+fondu-060102/fondu -force *.bin
+echo done
+
+zip -9 classicmacfonts *.bdf
+mv classicmacfonts.zip classicmacfonts.dat
+
+echo_n "Cleaning up..."
+rm *.bdf
+rm *.ttf
+rm *.bin
+rm *.dmg
+echo done
+
+ls -l classicmacfonts.dat
diff --git a/devtools/create_kyradat/create_kyradat.cpp b/devtools/create_kyradat/create_kyradat.cpp
index 441f315c8d..294eadf92b 100644
--- a/devtools/create_kyradat/create_kyradat.cpp
+++ b/devtools/create_kyradat/create_kyradat.cpp
@@ -45,7 +45,7 @@
enum {
- kKyraDatVersion = 86
+ 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_kyradat/resources/lok_pc98_japanese.h b/devtools/create_kyradat/resources/lok_pc98_japanese.h
index 0cbc96aeb9..0a70ab945e 100644
--- a/devtools/create_kyradat/resources/lok_pc98_japanese.h
+++ b/devtools/create_kyradat/resources/lok_pc98_japanese.h
@@ -222,10 +222,11 @@ static const char *const k1PoisonGoneStringPC98Japanese[2] = {
static const StringListProvider k1PoisonGoneStringPC98JapaneseProvider = { ARRAYSIZE(k1PoisonGoneStringPC98Japanese), k1PoisonGoneStringPC98Japanese };
-static const char *const k1ThePoisonStringsPC98Japanese[3] = {
+static const char *const k1ThePoisonStringsPC98Japanese[4] = {
"\x93\xC5\x82\xBE\x81""E""\x81""E""\x81""E",
"\x8C\xC4\x8B""z""\x82\xAA\x8F""o""\x97\x88\x82\xC8\x82\xA2\x81""E""\x81""E""\x81""E",
- "\x8B""C""\x95\xAA\x82\xAA\x88\xAB\x82\xA2\x81""E""\x81""E""\x81""E"
+ "\x8B""C""\x95\xAA\x82\xAA\x88\xAB\x82\xA2\x81""E""\x81""E""\x81""E",
+ "\x82\xA0\x82\xCC\x8E\xD6\x82\xCD""\r""\x93\xC5\x8E\xD6\x82\xC9\x82\xBF\x82\xAA\x82\xA2\x82\xC8\x82\xA2\x81""I"
};
static const StringListProvider k1ThePoisonStringsPC98JapaneseProvider = { ARRAYSIZE(k1ThePoisonStringsPC98Japanese), k1ThePoisonStringsPC98Japanese };
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/codeblocks.cpp b/devtools/create_project/codeblocks.cpp
index 442a2b0025..e9dc8bf234 100644
--- a/devtools/create_project/codeblocks.cpp
+++ b/devtools/create_project/codeblocks.cpp
@@ -200,6 +200,11 @@ void CodeBlocksProvider::createProjectFile(const std::string &name, const std::s
}
+void CodeBlocksProvider::addResourceFiles(const BuildSetup &setup, StringList &includeList, StringList &excludeList) {
+ includeList.push_back(setup.srcDir + "/icons/" + setup.projectName + ".ico");
+ includeList.push_back(setup.srcDir + "/dists/" + setup.projectName + ".rc");
+}
+
void CodeBlocksProvider::writeWarnings(const std::string &name, std::ofstream &output) const {
// Global warnings
diff --git a/devtools/create_project/codeblocks.h b/devtools/create_project/codeblocks.h
index f65604d925..5baa21c242 100644
--- a/devtools/create_project/codeblocks.h
+++ b/devtools/create_project/codeblocks.h
@@ -37,6 +37,8 @@ protected:
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);
diff --git a/devtools/create_project/create_project.cpp b/devtools/create_project/create_project.cpp
index 0aba511491..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,19 +351,51 @@ 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) {
+ 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.
+ // This define will help catching up target dependend files, like "browser_osx.mm"
+ // The suffix ("_osx", or "_ios") will be used by the project provider to filter out
+ // 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");
- setup.defines.push_back("MACOSX"); // This will break iOS, but allows OS X to catch up on browser_osx.
+#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");
@@ -374,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);
@@ -630,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"
@@ -684,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.
@@ -929,16 +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" },
- { "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" },
- { "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" },
+ { "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", "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" },
// Feature flags
{ "bink", "USE_BINK", "", true, "Bink video support" },
@@ -947,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...
};
@@ -1050,6 +1113,12 @@ void splitFilename(const std::string &fileName, std::string &name, std::string &
ext = (dot == std::string::npos) ? std::string() : fileName.substr(dot + 1);
}
+std::string basename(const std::string &fileName) {
+ const std::string::size_type slash = fileName.find_last_of('/');
+ if (slash == std::string::npos) return fileName;
+ return fileName.substr(slash + 1);
+}
+
bool producesObjectFile(const std::string &fileName) {
std::string n, ext;
splitFilename(fileName, n, ext);
@@ -1143,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);
@@ -1334,8 +1403,7 @@ void ProjectProvider::createProject(BuildSetup &setup) {
createModuleList(setup.srcDir + "/image", setup.defines, setup.testDirs, in, ex);
// Resource files
- in.push_back(setup.srcDir + "/icons/" + setup.projectName + ".ico");
- in.push_back(setup.srcDir + "/dists/" + setup.projectName + ".rc");
+ addResourceFiles(setup, in, ex);
// Various text files
in.push_back(setup.srcDir + "/AUTHORS");
diff --git a/devtools/create_project/create_project.h b/devtools/create_project/create_project.h
index 459342a67d..1e417d485b 100644
--- a/devtools/create_project/create_project.h
+++ b/devtools/create_project/create_project.h
@@ -23,8 +23,8 @@
#ifndef TOOLS_CREATE_PROJECT_H
#define TOOLS_CREATE_PROJECT_H
-#ifndef __has_feature // Optional of course.
- #define __has_feature(x) 0 // Compatibility with non-clang compilers.
+#ifndef __has_feature // Optional of course.
+#define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif
#include <map>
@@ -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;
}
};
@@ -316,6 +318,17 @@ std::string convertPathToWin(const std::string &path);
void splitFilename(const std::string &fileName, std::string &name, std::string &ext);
/**
+ * Returns the basename of a path.
+ * examples:
+ * a/b/c/d.ext -> d.ext
+ * d.ext -> d.ext
+ *
+ * @param fileName Filename
+ * @return The basename
+ */
+std::string basename(const std::string &fileName);
+
+/**
* Checks whether the given file will produce an object file or not.
*
* @param fileName Name of the file.
@@ -419,6 +432,13 @@ protected:
virtual void createOtherBuildFiles(const BuildSetup &setup) = 0;
/**
+ * Add resources to the project
+ *
+ * @param setup Description of the desired build setup.
+ */
+ virtual void addResourceFiles(const BuildSetup &setup, StringList &includeList, StringList &excludeList) = 0;
+
+ /**
* Create a project file for the specified list of files.
*
* @param name Name of the project file.
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/msvc.cpp b/devtools/create_project/msvc.cpp
index dbfbcc128d..e6b47fe724 100644
--- a/devtools/create_project/msvc.cpp
+++ b/devtools/create_project/msvc.cpp
@@ -130,6 +130,11 @@ void MSVCProvider::createOtherBuildFiles(const BuildSetup &setup) {
createBuildProp(setup, false, true, "LLVM");
}
+void MSVCProvider::addResourceFiles(const BuildSetup &setup, StringList &includeList, StringList &excludeList) {
+ includeList.push_back(setup.srcDir + "/icons/" + setup.projectName + ".ico");
+ includeList.push_back(setup.srcDir + "/dists/" + setup.projectName + ".rc");
+}
+
void MSVCProvider::createGlobalProp(const BuildSetup &setup) {
std::ofstream properties((setup.outputDir + '/' + setup.projectDescription + "_Global" + getPropertiesExtension()).c_str());
if (!properties)
diff --git a/devtools/create_project/msvc.h b/devtools/create_project/msvc.h
index e75e131bd1..178ba8e216 100644
--- a/devtools/create_project/msvc.h
+++ b/devtools/create_project/msvc.h
@@ -39,6 +39,8 @@ protected:
void createOtherBuildFiles(const BuildSetup &setup);
+ void addResourceFiles(const BuildSetup &setup, StringList &includeList, StringList &excludeList);
+
/**
* Create the global project properties.
*
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/scripts/postbuild.cmd b/devtools/create_project/scripts/postbuild.cmd
index fcbd8c534a..31d2a94416 100644
--- a/devtools/create_project/scripts/postbuild.cmd
+++ b/devtools/create_project/scripts/postbuild.cmd
@@ -59,7 +59,7 @@ echo Invalid installer parameter. Should be "0" or "1" (was %~5)!
goto done
:error_script:
-echo An error occured while running the installer script!
+echo An error occurred while running the installer script!
goto done
:done
diff --git a/devtools/create_project/scripts/prebuild.cmd b/devtools/create_project/scripts/prebuild.cmd
index fbab426137..0efaab190c 100644
--- a/devtools/create_project/scripts/prebuild.cmd
+++ b/devtools/create_project/scripts/prebuild.cmd
@@ -27,7 +27,7 @@ echo Invalid target folder (%~2)!
goto done
:error_script:
-echo An error occured while running the revision script!
+echo An error occurred while running the revision script!
:done
exit /B0
diff --git a/devtools/create_project/xcode.cpp b/devtools/create_project/xcode.cpp
index babd530ad7..bfe7f522f0 100644
--- a/devtools/create_project/xcode.cpp
+++ b/devtools/create_project/xcode.cpp
@@ -26,58 +26,65 @@
#include <fstream>
#include <algorithm>
+#ifdef MACOSX
+#include <sstream>
+#include <iomanip>
+#include <CommonCrypto/CommonCrypto.h>
+#endif
+
namespace CreateProjectTool {
#define DEBUG_XCODE_HASH 0
-#ifdef ENABLE_IOS
#define IOS_TARGET 0
#define OSX_TARGET 1
-#define SIM_TARGET 2
-#else
-#define OSX_TARGET 0
-#endif
#define ADD_DEFINE(defines, name) \
defines.push_back(name);
+#define REMOVE_DEFINE(defines, name) \
+ { ValueList::iterator i = std::find(defines.begin(), defines.end(), name); if (i != defines.end()) defines.erase(i); }
+
+#define CONTAINS_DEFINE(defines, name) \
+ (std::find(defines.begin(), defines.end(), name) != defines.end())
+
#define ADD_SETTING(config, key, value) \
- config.settings[key] = Setting(value, "", SettingsNoQuote);
+ config._settings[key] = Setting(value, "", kSettingsNoQuote);
#define ADD_SETTING_ORDER(config, key, value, order) \
- config.settings[key] = Setting(value, "", SettingsNoQuote, 0, order);
+ config.settings[key] = Setting(value, "", kSettingsNoQuote, 0, order);
#define ADD_SETTING_ORDER_NOVALUE(config, key, comment, order) \
- config.settings[key] = Setting("", comment, SettingsNoValue, 0, order);
+ config._settings[key] = Setting("", comment, kSettingsNoValue, 0, order);
#define ADD_SETTING_QUOTE(config, key, value) \
- config.settings[key] = Setting(value);
+ config._settings[key] = Setting(value);
#define ADD_SETTING_QUOTE_VAR(config, key, value) \
- config.settings[key] = Setting(value, "", SettingsQuoteVariable);
+ config._settings[key] = Setting(value, "", kSettingsQuoteVariable);
#define ADD_SETTING_LIST(config, key, values, flags, indent) \
- config.settings[key] = Setting(values, flags, indent);
+ config._settings[key] = Setting(values, flags, indent);
#define REMOVE_SETTING(config, key) \
- config.settings.erase(key);
+ config._settings.erase(key);
#define ADD_BUILD_FILE(id, name, fileRefId, comment) { \
Object *buildFile = new Object(this, id, name, "PBXBuildFile", "PBXBuildFile", comment); \
- buildFile->addProperty("fileRef", fileRefId, name, SettingsNoValue); \
+ buildFile->addProperty("fileRef", fileRefId, name, kSettingsNoValue); \
_buildFile.add(buildFile); \
- _buildFile.flags = SettingsSingleItem; \
+ _buildFile._flags = kSettingsSingleItem; \
}
#define ADD_FILE_REFERENCE(id, name, properties) { \
Object *fileRef = new Object(this, id, name, "PBXFileReference", "PBXFileReference", name); \
- if (!properties.fileEncoding.empty()) fileRef->addProperty("fileEncoding", properties.fileEncoding, "", SettingsNoValue); \
- if (!properties.lastKnownFileType.empty()) fileRef->addProperty("lastKnownFileType", properties.lastKnownFileType, "", SettingsNoValue|SettingsQuoteVariable); \
- if (!properties.fileName.empty()) fileRef->addProperty("name", properties.fileName, "", SettingsNoValue|SettingsQuoteVariable); \
- if (!properties.filePath.empty()) fileRef->addProperty("path", properties.filePath, "", SettingsNoValue|SettingsQuoteVariable); \
- if (!properties.sourceTree.empty()) fileRef->addProperty("sourceTree", properties.sourceTree, "", SettingsNoValue); \
+ if (!properties._fileEncoding.empty()) fileRef->addProperty("fileEncoding", properties._fileEncoding, "", kSettingsNoValue); \
+ if (!properties._lastKnownFileType.empty()) fileRef->addProperty("lastKnownFileType", properties._lastKnownFileType, "", kSettingsNoValue|kSettingsQuoteVariable); \
+ if (!properties._fileName.empty()) fileRef->addProperty("name", properties._fileName, "", kSettingsNoValue|kSettingsQuoteVariable); \
+ if (!properties._filePath.empty()) fileRef->addProperty("path", properties._filePath, "", kSettingsNoValue|kSettingsQuoteVariable); \
+ if (!properties._sourceTree.empty()) fileRef->addProperty("sourceTree", properties._sourceTree, "", kSettingsNoValue); \
_fileReference.add(fileRef); \
- _fileReference.flags = SettingsSingleItem; \
+ _fileReference._flags = kSettingsSingleItem; \
}
bool producesObjectFileOnOSX(const std::string &fileName) {
@@ -92,12 +99,64 @@ bool producesObjectFileOnOSX(const std::string &fileName) {
return false;
}
+bool targetIsIOS(const std::string &targetName) {
+ return targetName.length() > 4 && targetName.substr(targetName.length() - 4) == "-iOS";
+}
+
+bool shouldSkipFileForTarget(const std::string &fileID, const std::string &targetName, const std::string &fileName) {
+ // Rules:
+ // - if the parent directory is "backends/platform/ios7", the file belongs to the iOS target.
+ // - if the parent directory is "/sdl", the file belongs to the OS X target.
+ // - if the file has a suffix, like "_osx", or "_ios", the file belongs to one of the target.
+ // - if the file is an OS X icon file (icns), it belongs to the OS X target.
+ std::string name, ext;
+ splitFilename(fileName, name, ext);
+ if (targetIsIOS(targetName)) {
+ // iOS target: we skip all files with the "_osx" suffix
+ if (name.length() > 4 && name.substr(name.length() - 4) == "_osx") {
+ return true;
+ }
+ // We don't need SDL for the iOS target
+ static const std::string sdl_directory = "/sdl/";
+ static const std::string surfacesdl_directory = "/surfacesdl/";
+ static const std::string doublebufferdl_directory = "/doublebuffersdl/";
+ if (fileID.find(sdl_directory) != std::string::npos
+ || fileID.find(surfacesdl_directory) != std::string::npos
+ || fileID.find(doublebufferdl_directory) != std::string::npos) {
+ return true;
+ }
+ if (ext == "icns") {
+ return true;
+ }
+ }
+ else {
+ // Ugly hack: explicitly remove the browser.cpp file.
+ // The problem is that we have only one project for two different targets,
+ // and the parsing of the "mk" files added this file for both targets...
+ if (fileID.length() > 12 && fileID.substr(fileID.length() - 12) == "/browser.cpp") {
+ return true;
+ }
+ // OS X target: we skip all files with the "_ios" suffix
+ if (name.length() > 4 && name.substr(name.length() - 4) == "_ios") {
+ return true;
+ }
+ // parent directory
+ const std::string directory = fileID.substr(0, fileID.length() - fileName.length());
+ static const std::string iphone_directory = "backends/platform/ios7";
+ if (directory.length() > iphone_directory.length() && directory.substr(directory.length() - iphone_directory.length()) == iphone_directory) {
+ return true;
+ }
+ }
+ return false;
+}
+
XcodeProvider::Group::Group(XcodeProvider *objectParent, const std::string &groupName, const std::string &uniqueName, const std::string &path) : Object(objectParent, uniqueName, groupName, "PBXGroup", "", groupName) {
- addProperty("name", name, "", SettingsNoValue|SettingsQuoteVariable);
- addProperty("sourceTree", "<group>", "", SettingsNoValue|SettingsQuoteVariable);
-
+ bool path_is_absolute = (path.length() > 0 && path.at(0) == '/');
+ addProperty("name", _name, "", kSettingsNoValue | kSettingsQuoteVariable);
+ addProperty("sourceTree", path_is_absolute ? "<absolute>" : "<group>", "", kSettingsNoValue | kSettingsQuoteVariable);
+
if (path != "") {
- addProperty("path", path, "", SettingsNoValue|SettingsQuoteVariable);
+ addProperty("path", path, "", kSettingsNoValue | kSettingsQuoteVariable);
}
_childOrder = 0;
_treeName = uniqueName;
@@ -106,43 +165,43 @@ XcodeProvider::Group::Group(XcodeProvider *objectParent, const std::string &grou
void XcodeProvider::Group::ensureChildExists(const std::string &name) {
std::map<std::string, Group*>::iterator it = _childGroups.find(name);
if (it == _childGroups.end()) {
- Group *child = new Group(parent, name, this->_treeName + '/' + name, name);
+ Group *child = new Group(_parent, name, this->_treeName + '/' + name, name);
_childGroups[name] = child;
addChildGroup(child);
- parent->_groups.add(child);
+ _parent->_groups.add(child);
}
}
void XcodeProvider::Group::addChildInternal(const std::string &id, const std::string &comment) {
- if (properties.find("children") == properties.end()) {
+ if (_properties.find("children") == _properties.end()) {
Property children;
- children.hasOrder = true;
- children.flags = SettingsAsList;
- properties["children"] = children;
+ children._hasOrder = true;
+ children._flags = kSettingsAsList;
+ _properties["children"] = children;
}
- properties["children"].settings[id] = Setting("", comment + " in Sources", SettingsNoValue, 0, _childOrder++);
+ _properties["children"]._settings[id] = Setting("", comment + " in Sources", kSettingsNoValue, 0, _childOrder++);
if (_childOrder == 1) {
// Force children to use () even when there is only 1 child.
// Also this enforces the use of "," after the single item, instead of ; (see writeProperty)
- properties["children"].flags |= SettingsSingleItem;
+ _properties["children"]._flags |= kSettingsSingleItem;
} else {
- properties["children"].flags ^= SettingsSingleItem;
+ _properties["children"]._flags ^= kSettingsSingleItem;
}
}
-void XcodeProvider::Group::addChildGroup(const Group* group) {
- addChildInternal(parent->getHash(group->_treeName), group->_treeName);
+void XcodeProvider::Group::addChildGroup(const Group *group) {
+ addChildInternal(_parent->getHash(group->_treeName), group->_treeName);
}
void XcodeProvider::Group::addChildFile(const std::string &name) {
std::string id = "FileReference_" + _treeName + "/" + name;
- addChildInternal(parent->getHash(id), name);
+ addChildInternal(_parent->getHash(id), name);
FileProperty property = FileProperty(name, name, name, "\"<group>\"");
- parent->addFileReference(id, name, property);
+ _parent->addFileReference(id, name, property);
if (producesObjectFileOnOSX(name)) {
- parent->addBuildFile(_treeName + "/" + name, name, parent->getHash(id), name + " in Sources");
+ _parent->addBuildFile(_treeName + "/" + name, name, _parent->getHash(id), name + " in Sources");
}
}
@@ -151,14 +210,14 @@ void XcodeProvider::Group::addChildByHash(const std::string &hash, const std::st
}
XcodeProvider::Group *XcodeProvider::Group::getChildGroup(const std::string &name) {
- std::map<std::string, Group*>::iterator it = _childGroups.find(name);
+ std::map<std::string, Group *>::iterator it = _childGroups.find(name);
assert(it != _childGroups.end());
return it->second;
}
XcodeProvider::Group *XcodeProvider::touchGroupsForPath(const std::string &path) {
if (_rootSourceGroup == NULL) {
- assert (path == _projectRoot);
+ assert(path == _projectRoot);
_rootSourceGroup = new Group(this, "Sources", path, path);
_groups.add(_rootSourceGroup);
return _rootSourceGroup;
@@ -180,31 +239,31 @@ XcodeProvider::Group *XcodeProvider::touchGroupsForPath(const std::string &path)
void XcodeProvider::addFileReference(const std::string &id, const std::string &name, FileProperty properties) {
Object *fileRef = new Object(this, id, name, "PBXFileReference", "PBXFileReference", name);
- if (!properties.fileEncoding.empty()) fileRef->addProperty("fileEncoding", properties.fileEncoding, "", SettingsNoValue);
- if (!properties.lastKnownFileType.empty()) fileRef->addProperty("lastKnownFileType", properties.lastKnownFileType, "", SettingsNoValue|SettingsQuoteVariable);
- if (!properties.fileName.empty()) fileRef->addProperty("name", properties.fileName, "", SettingsNoValue|SettingsQuoteVariable);
- if (!properties.filePath.empty()) fileRef->addProperty("path", properties.filePath, "", SettingsNoValue|SettingsQuoteVariable);
- if (!properties.sourceTree.empty()) fileRef->addProperty("sourceTree", properties.sourceTree, "", SettingsNoValue);
+ if (!properties._fileEncoding.empty()) fileRef->addProperty("fileEncoding", properties._fileEncoding, "", kSettingsNoValue);
+ if (!properties._lastKnownFileType.empty()) fileRef->addProperty("lastKnownFileType", properties._lastKnownFileType, "", kSettingsNoValue | kSettingsQuoteVariable);
+ if (!properties._fileName.empty()) fileRef->addProperty("name", properties._fileName, "", kSettingsNoValue | kSettingsQuoteVariable);
+ if (!properties._filePath.empty()) fileRef->addProperty("path", properties._filePath, "", kSettingsNoValue | kSettingsQuoteVariable);
+ if (!properties._sourceTree.empty()) fileRef->addProperty("sourceTree", properties._sourceTree, "", kSettingsNoValue);
_fileReference.add(fileRef);
- _fileReference.flags = SettingsSingleItem;
+ _fileReference._flags = kSettingsSingleItem;
}
void XcodeProvider::addProductFileReference(const std::string &id, const std::string &name) {
Object *fileRef = new Object(this, id, name, "PBXFileReference", "PBXFileReference", name);
- fileRef->addProperty("explicitFileType", "compiled.mach-o.executable", "", SettingsNoValue|SettingsQuoteVariable);
- fileRef->addProperty("includeInIndex", "0", "", SettingsNoValue);
- fileRef->addProperty("path", name, "", SettingsNoValue|SettingsQuoteVariable);
- fileRef->addProperty("sourceTree", "BUILT_PRODUCTS_DIR", "", SettingsNoValue);
+ fileRef->addProperty("explicitFileType", "wrapper.application", "", kSettingsNoValue | kSettingsQuoteVariable);
+ fileRef->addProperty("includeInIndex", "0", "", kSettingsNoValue);
+ fileRef->addProperty("path", name, "", kSettingsNoValue | kSettingsQuoteVariable);
+ fileRef->addProperty("sourceTree", "BUILT_PRODUCTS_DIR", "", kSettingsNoValue);
_fileReference.add(fileRef);
- _fileReference.flags = SettingsSingleItem;
+ _fileReference._flags = kSettingsSingleItem;
}
void XcodeProvider::addBuildFile(const std::string &id, const std::string &name, const std::string &fileRefId, const std::string &comment) {
Object *buildFile = new Object(this, id, name, "PBXBuildFile", "PBXBuildFile", comment);
- buildFile->addProperty("fileRef", fileRefId, name, SettingsNoValue);
+ buildFile->addProperty("fileRef", fileRefId, name, kSettingsNoValue);
_buildFile.add(buildFile);
- _buildFile.flags = SettingsSingleItem;
+ _buildFile._flags = kSettingsSingleItem;
}
XcodeProvider::XcodeProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, const int version)
@@ -212,28 +271,36 @@ XcodeProvider::XcodeProvider(StringList &global_warnings, std::map<std::string,
_rootSourceGroup = NULL;
}
+void XcodeProvider::addResourceFiles(const BuildSetup &setup, StringList &includeList, StringList &excludeList) {
+ includeList.push_back(setup.srcDir + "/dists/ios7/Info.plist");
+
+ ValueList &resources = getResourceFiles();
+ for (ValueList::iterator it = resources.begin(); it != resources.end(); ++it) {
+ includeList.push_back(setup.srcDir + "/" + *it);
+ }
+
+ StringList td;
+ createModuleList(setup.srcDir + "/backends/platform/ios7", setup.defines, td, includeList, excludeList);
+}
+
void XcodeProvider::createWorkspace(const BuildSetup &setup) {
// Create project folder
std::string workspace = setup.outputDir + '/' + PROJECT_NAME ".xcodeproj";
createDirectory(workspace);
_projectRoot = setup.srcDir;
touchGroupsForPath(_projectRoot);
-
+
// Setup global objects
setupDefines(setup);
-#ifdef ENABLE_IOS
- _targets.push_back(PROJECT_DESCRIPTION "-iPhone");
-#endif
+ _targets.push_back(PROJECT_DESCRIPTION "-iOS");
_targets.push_back(PROJECT_DESCRIPTION "-OS X");
-#ifdef ENABLE_IOS
- _targets.push_back(PROJECT_DESCRIPTION "-Simulator");
-#endif
setupCopyFilesBuildPhase();
- setupFrameworksBuildPhase();
+ setupFrameworksBuildPhase(setup);
setupNativeTarget();
setupProject();
setupResourcesBuildPhase();
- setupBuildConfiguration();
+ setupBuildConfiguration(setup);
+ setupImageAssetCatalog(setup);
}
// We are done with constructing all the object graph and we got through every project, output the main project file
@@ -274,10 +341,10 @@ void XcodeProvider::ouputMainProjectFile(const BuildSetup &setup) {
// Header
project << "// !$*UTF8*$!\n"
"{\n"
- "\t" << writeSetting("archiveVersion", "1", "", SettingsNoQuote) << ";\n"
+ "\t" << writeSetting("archiveVersion", "1", "", kSettingsNoQuote) << ";\n"
"\tclasses = {\n"
"\t};\n"
- "\t" << writeSetting("objectVersion", "46", "", SettingsNoQuote) << ";\n"
+ "\t" << writeSetting("objectVersion", "46", "", kSettingsNoQuote) << ";\n"
"\tobjects = {\n";
//////////////////////////////////////////////////////////////////////////
@@ -297,7 +364,7 @@ void XcodeProvider::ouputMainProjectFile(const BuildSetup &setup) {
//////////////////////////////////////////////////////////////////////////
// Footer
project << "\t};\n"
- "\t" << writeSetting("rootObject", getHash("PBXProject"), "Project object", SettingsNoQuote) << ";\n"
+ "\t" << writeSetting("rootObject", getHash("PBXProject"), "Project object", kSettingsNoQuote) << ";\n"
"}\n";
}
@@ -333,24 +400,30 @@ void XcodeProvider::setupCopyFilesBuildPhase() {
#define DEF_SYSFRAMEWORK(framework) properties[framework".framework"] = FileProperty("wrapper.framework", framework".framework", "System/Library/Frameworks/" framework ".framework", "SDKROOT"); \
ADD_SETTING_ORDER_NOVALUE(children, getHash(framework".framework"), framework".framework", fwOrder++);
-
-#define DEF_LOCALLIB_STATIC(lib) properties[lib".a"] = FileProperty("archive.ar", lib".a", "/opt/local/lib/" lib ".a", "\"<group>\""); \
+
+#define DEF_SYSTBD(lib) properties[lib".tbd"] = FileProperty("sourcecode.text-based-dylib-definition", lib".tbd", "usr/lib/" lib ".tbd", "SDKROOT"); \
+ ADD_SETTING_ORDER_NOVALUE(children, getHash(lib".tbd"), lib".tbd", fwOrder++);
+
+#define DEF_LOCALLIB_STATIC_PATH(path,lib,absolute) properties[lib".a"] = FileProperty("archive.ar", lib ".a", path, (absolute ? "\"<absolute>\"" : "\"<group>\"")); \
ADD_SETTING_ORDER_NOVALUE(children, getHash(lib".a"), lib".a", fwOrder++);
+#define DEF_LOCALLIB_STATIC(lib) DEF_LOCALLIB_STATIC_PATH("/opt/local/lib/" lib ".a", lib, true)
+
+
/**
* Sets up the frameworks build phase.
*
* (each native target has different build rules)
*/
-void XcodeProvider::setupFrameworksBuildPhase() {
- _frameworksBuildPhase.comment = "PBXFrameworksBuildPhase";
+void XcodeProvider::setupFrameworksBuildPhase(const BuildSetup &setup) {
+ _frameworksBuildPhase._comment = "PBXFrameworksBuildPhase";
// Just use a hardcoded id for the Frameworks-group
Group *frameworksGroup = new Group(this, "Frameworks", "PBXGroup_CustomTemplate_Frameworks_", "");
Property children;
- children.hasOrder = true;
- children.flags = SettingsAsList;
+ children._hasOrder = true;
+ children._flags = kSettingsAsList;
// Setup framework file properties
std::map<std::string, FileProperty> properties;
@@ -362,6 +435,8 @@ void XcodeProvider::setupFrameworksBuildPhase() {
DEF_SYSFRAMEWORK("Carbon");
DEF_SYSFRAMEWORK("Cocoa");
DEF_SYSFRAMEWORK("CoreAudio");
+ DEF_SYSFRAMEWORK("CoreMIDI");
+ DEF_SYSFRAMEWORK("CoreGraphics");
DEF_SYSFRAMEWORK("CoreFoundation");
DEF_SYSFRAMEWORK("CoreMIDI");
DEF_SYSFRAMEWORK("Foundation");
@@ -370,8 +445,7 @@ void XcodeProvider::setupFrameworksBuildPhase() {
DEF_SYSFRAMEWORK("QuartzCore");
DEF_SYSFRAMEWORK("QuickTime");
DEF_SYSFRAMEWORK("UIKit");
- // Optionals:
- DEF_SYSFRAMEWORK("OpenGL");
+ DEF_SYSTBD("libiconv");
// Local libraries
DEF_LOCALLIB_STATIC("libFLAC");
@@ -380,64 +454,105 @@ void XcodeProvider::setupFrameworksBuildPhase() {
DEF_LOCALLIB_STATIC("libfreetype");
// DEF_LOCALLIB_STATIC("libmpeg2");
- frameworksGroup->properties["children"] = children;
+ std::string absoluteOutputDir;
+#ifdef POSIX
+ char *c_path = realpath(setup.outputDir.c_str(), NULL);
+ absoluteOutputDir = c_path;
+ absoluteOutputDir += "/lib";
+ free(c_path);
+#else
+ absoluteOutputDir = "lib";
+#endif
+
+ DEF_LOCALLIB_STATIC_PATH(absoluteOutputDir + "/libFLAC.a", "libFLAC", true);
+ DEF_LOCALLIB_STATIC_PATH(absoluteOutputDir + "/libfreetype.a", "libfreetype", true);
+ DEF_LOCALLIB_STATIC_PATH(absoluteOutputDir + "/libogg.a", "libogg", true);
+ DEF_LOCALLIB_STATIC_PATH(absoluteOutputDir + "/libpng.a", "libpng", true);
+ DEF_LOCALLIB_STATIC_PATH(absoluteOutputDir + "/libvorbis.a", "libvorbis", true);
+ DEF_LOCALLIB_STATIC_PATH(absoluteOutputDir + "/libmad.a", "libmad", true);
+ DEF_LOCALLIB_STATIC_PATH(absoluteOutputDir + "/libfluidsynth.a", "libfluidsynth", true);
+ DEF_LOCALLIB_STATIC_PATH(absoluteOutputDir + "/libglib.a", "libglib", true);
+ DEF_LOCALLIB_STATIC_PATH(absoluteOutputDir + "/libffi.a", "libffi", true);
+
+ frameworksGroup->_properties["children"] = children;
_groups.add(frameworksGroup);
// Force this to be added as a sub-group in the root.
_rootSourceGroup->addChildGroup(frameworksGroup);
- // Declare this here, as it's used across the three targets
+ // Declare this here, as it's used across all the targets
int order = 0;
-#ifdef ENABLE_IOS
+
//////////////////////////////////////////////////////////////////////////
- // iPhone
+ // ScummVM-iOS
Object *framework_iPhone = new Object(this, "PBXFrameworksBuildPhase_" + _targets[IOS_TARGET], "PBXFrameworksBuildPhase", "PBXFrameworksBuildPhase", "", "Frameworks");
- framework_iPhone->addProperty("buildActionMask", "2147483647", "", SettingsNoValue);
- framework_iPhone->addProperty("runOnlyForDeploymentPostprocessing", "0", "", SettingsNoValue);
+ framework_iPhone->addProperty("buildActionMask", "2147483647", "", kSettingsNoValue);
+ framework_iPhone->addProperty("runOnlyForDeploymentPostprocessing", "0", "", kSettingsNoValue);
// List of frameworks
- Property iPhone_files;
- iPhone_files.hasOrder = true;
- iPhone_files.flags = SettingsAsList;
-
- ValueList frameworks_iPhone;
- frameworks_iPhone.push_back("CoreAudio.framework");
- frameworks_iPhone.push_back("CoreFoundation.framework");
- frameworks_iPhone.push_back("Foundation.framework");
- frameworks_iPhone.push_back("UIKit.framework");
- frameworks_iPhone.push_back("AudioToolbox.framework");
- frameworks_iPhone.push_back("QuartzCore.framework");
- frameworks_iPhone.push_back("libmad.a");
- //frameworks_iPhone.push_back("libmpeg2.a");
- frameworks_iPhone.push_back("libFLAC.a");
- frameworks_iPhone.push_back("libvorbisidec.a");
- frameworks_iPhone.push_back("OpenGLES.framework");
-
- for (ValueList::iterator framework = frameworks_iPhone.begin(); framework != frameworks_iPhone.end(); framework++) {
+ Property iOS_files;
+ iOS_files._hasOrder = true;
+ iOS_files._flags = kSettingsAsList;
+
+ ValueList frameworks_iOS;
+ frameworks_iOS.push_back("CoreAudio.framework");
+ frameworks_iOS.push_back("CoreGraphics.framework");
+ frameworks_iOS.push_back("CoreFoundation.framework");
+ frameworks_iOS.push_back("Foundation.framework");
+ frameworks_iOS.push_back("UIKit.framework");
+ frameworks_iOS.push_back("AudioToolbox.framework");
+ frameworks_iOS.push_back("QuartzCore.framework");
+ frameworks_iOS.push_back("OpenGLES.framework");
+
+ if (CONTAINS_DEFINE(setup.defines, "USE_FLAC")) {
+ frameworks_iOS.push_back("libFLAC.a");
+ }
+ if (CONTAINS_DEFINE(setup.defines, "USE_FREETYPE2")) {
+ frameworks_iOS.push_back("libfreetype.a");
+ }
+ if (CONTAINS_DEFINE(setup.defines, "USE_PNG")) {
+ frameworks_iOS.push_back("libpng.a");
+ }
+ if (CONTAINS_DEFINE(setup.defines, "USE_VORBIS")) {
+ frameworks_iOS.push_back("libogg.a");
+ frameworks_iOS.push_back("libvorbis.a");
+ }
+ if (CONTAINS_DEFINE(setup.defines, "USE_MAD")) {
+ frameworks_iOS.push_back("libmad.a");
+ }
+ if (CONTAINS_DEFINE(setup.defines, "USE_FLUIDSYNTH")) {
+ frameworks_iOS.push_back("libfluidsynth.a");
+ frameworks_iOS.push_back("libglib.a");
+ frameworks_iOS.push_back("libffi.a");
+ frameworks_iOS.push_back("CoreMIDI.framework");
+ frameworks_iOS.push_back("libiconv.tbd");
+ }
+
+ for (ValueList::iterator framework = frameworks_iOS.begin(); framework != frameworks_iOS.end(); framework++) {
std::string id = "Frameworks_" + *framework + "_iphone";
std::string comment = *framework + " in Frameworks";
- ADD_SETTING_ORDER_NOVALUE(iPhone_files, getHash(id), comment, order++);
+ ADD_SETTING_ORDER_NOVALUE(iOS_files, getHash(id), comment, order++);
ADD_BUILD_FILE(id, *framework, getHash(*framework), comment);
ADD_FILE_REFERENCE(*framework, *framework, properties[*framework]);
}
- framework_iPhone->properties["files"] = iPhone_files;
+ framework_iPhone->_properties["files"] = iOS_files;
_frameworksBuildPhase.add(framework_iPhone);
-#endif
+
//////////////////////////////////////////////////////////////////////////
// ScummVM-OS X
Object *framework_OSX = new Object(this, "PBXFrameworksBuildPhase_" + _targets[OSX_TARGET], "PBXFrameworksBuildPhase", "PBXFrameworksBuildPhase", "", "Frameworks");
- framework_OSX->addProperty("buildActionMask", "2147483647", "", SettingsNoValue);
- framework_OSX->addProperty("runOnlyForDeploymentPostprocessing", "0", "", SettingsNoValue);
+ framework_OSX->addProperty("buildActionMask", "2147483647", "", kSettingsNoValue);
+ framework_OSX->addProperty("runOnlyForDeploymentPostprocessing", "0", "", kSettingsNoValue);
// List of frameworks
Property osx_files;
- osx_files.hasOrder = true;
- osx_files.flags = SettingsAsList;
+ osx_files._hasOrder = true;
+ osx_files._flags = kSettingsAsList;
ValueList frameworks_osx;
frameworks_osx.push_back("CoreFoundation.framework");
@@ -452,8 +567,6 @@ void XcodeProvider::setupFrameworksBuildPhase() {
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++) {
@@ -465,81 +578,40 @@ void XcodeProvider::setupFrameworksBuildPhase() {
ADD_FILE_REFERENCE(*framework, *framework, properties[*framework]);
}
- framework_OSX->properties["files"] = osx_files;
+ framework_OSX->_properties["files"] = osx_files;
_frameworksBuildPhase.add(framework_OSX);
-#ifdef ENABLE_IOS
- //////////////////////////////////////////////////////////////////////////
- // Simulator
- Object *framework_simulator = new Object(this, "PBXFrameworksBuildPhase_" + _targets[SIM_TARGET], "PBXFrameworksBuildPhase", "PBXFrameworksBuildPhase", "", "Frameworks");
-
- framework_simulator->addProperty("buildActionMask", "2147483647", "", SettingsNoValue);
- framework_simulator->addProperty("runOnlyForDeploymentPostprocessing", "0", "", SettingsNoValue);
-
- // List of frameworks
- Property simulator_files;
- simulator_files.hasOrder = true;
- simulator_files.flags = SettingsAsList;
-
- ValueList frameworks_simulator;
- frameworks_simulator.push_back("CoreAudio.framework");
- frameworks_simulator.push_back("CoreFoundation.framework");
- frameworks_simulator.push_back("Foundation.framework");
- frameworks_simulator.push_back("UIKit.framework");
- frameworks_simulator.push_back("AudioToolbox.framework");
- frameworks_simulator.push_back("QuartzCore.framework");
- frameworks_simulator.push_back("OpenGLES.framework");
-
- order = 0;
- for (ValueList::iterator framework = frameworks_simulator.begin(); framework != frameworks_simulator.end(); framework++) {
- std::string id = "Frameworks_" + *framework + "_simulator";
- std::string comment = *framework + " in Frameworks";
-
- ADD_SETTING_ORDER_NOVALUE(simulator_files, getHash(id), comment, order++);
- ADD_BUILD_FILE(id, *framework, getHash(*framework), comment);
- ADD_FILE_REFERENCE(*framework, *framework, properties[*framework]);
- }
-
- framework_simulator->properties["files"] = simulator_files;
-
- _frameworksBuildPhase.add(framework_simulator);
-#endif
}
void XcodeProvider::setupNativeTarget() {
- _nativeTarget.comment = "PBXNativeTarget";
+ _nativeTarget._comment = "PBXNativeTarget";
// Just use a hardcoded id for the Products-group
Group *productsGroup = new Group(this, "Products", "PBXGroup_CustomTemplate_Products_" , "");
// Output native target section
for (unsigned int i = 0; i < _targets.size(); i++) {
-#ifndef ENABLE_IOS
- if (i != OSX_TARGET) { // TODO: Fix iOS-targets, for now just disable them.
- continue;
- }
-#endif
Object *target = new Object(this, "PBXNativeTarget_" + _targets[i], "PBXNativeTarget", "PBXNativeTarget", "", _targets[i]);
- target->addProperty("buildConfigurationList", getHash("XCConfigurationList_" + _targets[i]), "Build configuration list for PBXNativeTarget \"" + _targets[i] + "\"", SettingsNoValue);
+ target->addProperty("buildConfigurationList", getHash("XCConfigurationList_" + _targets[i]), "Build configuration list for PBXNativeTarget \"" + _targets[i] + "\"", kSettingsNoValue);
Property buildPhases;
- buildPhases.hasOrder = true;
- buildPhases.flags = SettingsAsList;
- buildPhases.settings[getHash("PBXResourcesBuildPhase_" + _targets[i])] = Setting("", "Resources", SettingsNoValue, 0, 0);
- buildPhases.settings[getHash("PBXSourcesBuildPhase_" + _targets[i])] = Setting("", "Sources", SettingsNoValue, 0, 1);
- buildPhases.settings[getHash("PBXFrameworksBuildPhase_" + _targets[i])] = Setting("", "Frameworks", SettingsNoValue, 0, 2);
- target->properties["buildPhases"] = buildPhases;
+ buildPhases._hasOrder = true;
+ buildPhases._flags = kSettingsAsList;
+ buildPhases._settings[getHash("PBXResourcesBuildPhase_" + _targets[i])] = Setting("", "Resources", kSettingsNoValue, 0, 0);
+ buildPhases._settings[getHash("PBXSourcesBuildPhase_" + _targets[i])] = Setting("", "Sources", kSettingsNoValue, 0, 1);
+ buildPhases._settings[getHash("PBXFrameworksBuildPhase_" + _targets[i])] = Setting("", "Frameworks", kSettingsNoValue, 0, 2);
+ target->_properties["buildPhases"] = buildPhases;
- target->addProperty("buildRules", "", "", SettingsNoValue|SettingsAsList);
+ target->addProperty("buildRules", "", "", kSettingsNoValue | kSettingsAsList);
- target->addProperty("dependencies", "", "", SettingsNoValue|SettingsAsList);
+ target->addProperty("dependencies", "", "", kSettingsNoValue | kSettingsAsList);
- target->addProperty("name", _targets[i], "", SettingsNoValue|SettingsQuoteVariable);
- target->addProperty("productName", PROJECT_NAME, "", SettingsNoValue);
+ target->addProperty("name", _targets[i], "", kSettingsNoValue | kSettingsQuoteVariable);
+ target->addProperty("productName", PROJECT_NAME, "", kSettingsNoValue);
addProductFileReference("PBXFileReference_" PROJECT_DESCRIPTION ".app_" + _targets[i], PROJECT_DESCRIPTION ".app");
productsGroup->addChildByHash(getHash("PBXFileReference_" PROJECT_DESCRIPTION ".app_" + _targets[i]), PROJECT_DESCRIPTION ".app");
- target->addProperty("productReference", getHash("PBXFileReference_" PROJECT_DESCRIPTION ".app_" + _targets[i]), PROJECT_DESCRIPTION ".app", SettingsNoValue);
- target->addProperty("productType", "com.apple.product-type.application", "", SettingsNoValue|SettingsQuoteVariable);
+ target->addProperty("productReference", getHash("PBXFileReference_" PROJECT_DESCRIPTION ".app_" + _targets[i]), PROJECT_DESCRIPTION ".app", kSettingsNoValue);
+ target->addProperty("productType", "com.apple.product-type.application", "", kSettingsNoValue | kSettingsQuoteVariable);
_nativeTarget.add(target);
}
@@ -548,225 +620,155 @@ void XcodeProvider::setupNativeTarget() {
}
void XcodeProvider::setupProject() {
- _project.comment = "PBXProject";
+ _project._comment = "PBXProject";
Object *project = new Object(this, "PBXProject", "PBXProject", "PBXProject", "", "Project object");
- project->addProperty("buildConfigurationList", getHash("XCConfigurationList_scummvm"), "Build configuration list for PBXProject \"" PROJECT_NAME "\"", SettingsNoValue);
- project->addProperty("compatibilityVersion", "Xcode 3.2", "", SettingsNoValue|SettingsQuoteVariable);
- project->addProperty("developmentRegion", "English", "", SettingsNoValue);
- project->addProperty("hasScannedForEncodings", "1", "", SettingsNoValue);
+ project->addProperty("buildConfigurationList", getHash("XCConfigurationList_scummvm"), "Build configuration list for PBXProject \"" PROJECT_NAME "\"", kSettingsNoValue);
+ project->addProperty("compatibilityVersion", "Xcode 3.2", "", kSettingsNoValue | kSettingsQuoteVariable);
+ project->addProperty("developmentRegion", "English", "", kSettingsNoValue);
+ project->addProperty("hasScannedForEncodings", "1", "", kSettingsNoValue);
// List of known regions
Property regions;
- regions.flags = SettingsAsList;
+ regions._flags = kSettingsAsList;
ADD_SETTING_ORDER_NOVALUE(regions, "English", "", 0);
ADD_SETTING_ORDER_NOVALUE(regions, "Japanese", "", 1);
ADD_SETTING_ORDER_NOVALUE(regions, "French", "", 2);
ADD_SETTING_ORDER_NOVALUE(regions, "German", "", 3);
- project->properties["knownRegions"] = regions;
+ project->_properties["knownRegions"] = regions;
- project->addProperty("mainGroup", _rootSourceGroup->getHashRef(), "CustomTemplate", SettingsNoValue);
- project->addProperty("projectDirPath", _projectRoot, "", SettingsNoValue|SettingsQuoteVariable);
- project->addProperty("projectRoot", "", "", SettingsNoValue|SettingsQuoteVariable);
+ project->addProperty("mainGroup", _rootSourceGroup->getHashRef(), "CustomTemplate", kSettingsNoValue);
+ project->addProperty("productRefGroup", getHash("PBXGroup_CustomTemplate_Products_"), "" , kSettingsNoValue);
+ project->addProperty("projectDirPath", _projectRoot, "", kSettingsNoValue | kSettingsQuoteVariable);
+ project->addProperty("projectRoot", "", "", kSettingsNoValue | kSettingsQuoteVariable);
// List of targets
Property targets;
- targets.flags = SettingsAsList;
-#ifdef ENABLE_IOS
- targets.settings[getHash("PBXNativeTarget_" + _targets[IOS_TARGET])] = Setting("", _targets[IOS_TARGET], SettingsNoValue, 0, 0);
-#endif
- targets.settings[getHash("PBXNativeTarget_" + _targets[OSX_TARGET])] = Setting("", _targets[OSX_TARGET], SettingsNoValue, 0, 1);
-#ifdef ENABLE_IOS
- targets.settings[getHash("PBXNativeTarget_" + _targets[SIM_TARGET])] = Setting("", _targets[SIM_TARGET], SettingsNoValue, 0, 2);
-#endif
- project->properties["targets"] = targets;
-#ifndef ENABLE_IOS
+ targets._flags = kSettingsAsList;
+ targets._settings[getHash("PBXNativeTarget_" + _targets[IOS_TARGET])] = Setting("", _targets[IOS_TARGET], kSettingsNoValue, 0, 0);
+ targets._settings[getHash("PBXNativeTarget_" + _targets[OSX_TARGET])] = Setting("", _targets[OSX_TARGET], kSettingsNoValue, 0, 1);
+ project->_properties["targets"] = targets;
+
// Force list even when there is only a single target
- project->properties["targets"].flags |= SettingsSingleItem;
-#endif
+ project->_properties["targets"]._flags |= kSettingsSingleItem;
_project.add(project);
}
+XcodeProvider::ValueList& XcodeProvider::getResourceFiles() const {
+ static ValueList files;
+ if (files.empty()) {
+ files.push_back("gui/themes/scummclassic.zip");
+ files.push_back("gui/themes/scummmodern.zip");
+ files.push_back("gui/themes/translations.dat");
+ files.push_back("dists/engine-data/drascula.dat");
+ files.push_back("dists/engine-data/hugo.dat");
+ files.push_back("dists/engine-data/kyra.dat");
+ files.push_back("dists/engine-data/lure.dat");
+ files.push_back("dists/engine-data/mort.dat");
+ files.push_back("dists/engine-data/neverhood.dat");
+ files.push_back("dists/engine-data/queen.tbl");
+ files.push_back("dists/engine-data/sky.cpt");
+ files.push_back("dists/engine-data/teenagent.dat");
+ files.push_back("dists/engine-data/tony.dat");
+ files.push_back("dists/engine-data/toon.dat");
+ files.push_back("dists/engine-data/wintermute.zip");
+ files.push_back("dists/pred.dic");
+ files.push_back("icons/scummvm.icns");
+ }
+ return files;
+}
+
void XcodeProvider::setupResourcesBuildPhase() {
- _resourcesBuildPhase.comment = "PBXResourcesBuildPhase";
+ _resourcesBuildPhase._comment = "PBXResourcesBuildPhase";
- // Setup resource file properties
- std::map<std::string, FileProperty> properties;
- properties["scummclassic.zip"] = FileProperty("archive.zip", "", "scummclassic.zip", "\"<group>\"");
- properties["scummmodern.zip"] = FileProperty("archive.zip", "", "scummmodern.zip", "\"<group>\"");
-
- properties["kyra.dat"] = FileProperty("file", "", "kyra.dat", "\"<group>\"");
- properties["lure.dat"] = FileProperty("file", "", "lure.dat", "\"<group>\"");
- properties["queen.tbl"] = FileProperty("file", "", "queen.tbl", "\"<group>\"");
- properties["sky.cpt"] = FileProperty("file", "", "sky.cpt", "\"<group>\"");
- properties["drascula.dat"] = FileProperty("file", "", "drascula.dat", "\"<group>\"");
- properties["hugo.dat"] = FileProperty("file", "", "hugo.dat", "\"<group>\"");
- properties["teenagent.dat"] = FileProperty("file", "", "teenagent.dat", "\"<group>\"");
- properties["toon.dat"] = FileProperty("file", "", "toon.dat", "\"<group>\"");
-
- properties["Default.png"] = FileProperty("image.png", "", "Default.png", "\"<group>\"");
- properties["icon.png"] = FileProperty("image.png", "", "icon.png", "\"<group>\"");
- properties["icon-72.png"] = FileProperty("image.png", "", "icon-72.png", "\"<group>\"");
- properties["icon4.png"] = FileProperty("image.png", "", "icon4.png", "\"<group>\"");
+ ValueList &files_list = getResourceFiles();
// Same as for containers: a rule for each native target
for (unsigned int i = 0; i < _targets.size(); i++) {
Object *resource = new Object(this, "PBXResourcesBuildPhase_" + _targets[i], "PBXResourcesBuildPhase", "PBXResourcesBuildPhase", "", "Resources");
- resource->addProperty("buildActionMask", "2147483647", "", SettingsNoValue);
+ resource->addProperty("buildActionMask", "2147483647", "", kSettingsNoValue);
// Add default files
Property files;
- files.hasOrder = true;
- files.flags = SettingsAsList;
-
- ValueList files_list;
- files_list.push_back("scummclassic.zip");
- files_list.push_back("scummmodern.zip");
- files_list.push_back("kyra.dat");
- files_list.push_back("lure.dat");
- files_list.push_back("queen.tbl");
- files_list.push_back("sky.cpt");
- files_list.push_back("Default.png");
- files_list.push_back("icon.png");
- files_list.push_back("icon-72.png");
- files_list.push_back("icon4.png");
- files_list.push_back("drascula.dat");
- files_list.push_back("hugo.dat");
- files_list.push_back("teenagent.dat");
- files_list.push_back("toon.dat");
+ files._hasOrder = true;
+ files._flags = kSettingsAsList;
int order = 0;
for (ValueList::iterator file = files_list.begin(); file != files_list.end(); file++) {
- std::string id = "PBXResources_" + *file;
- std::string comment = *file + " in Resources";
-
- ADD_SETTING_ORDER_NOVALUE(files, getHash(id), comment, order++);
- // TODO Fix crash when adding build file for data
- //ADD_BUILD_FILE(id, *file, comment);
- ADD_FILE_REFERENCE(*file, *file, properties[*file]);
- }
-
- // Add custom files depending on the target
- if (_targets[i] == PROJECT_DESCRIPTION "-OS X") {
- files.settings[getHash("PBXResources_" PROJECT_NAME ".icns")] = Setting("", PROJECT_NAME ".icns in Resources", SettingsNoValue, 0, 6);
-
- // Remove 2 iphone icon files
- files.settings.erase(getHash("PBXResources_Default.png"));
- files.settings.erase(getHash("PBXResources_icon.png"));
+ if (shouldSkipFileForTarget(*file, _targets[i], *file)) {
+ continue;
+ }
+ std::string resourceAbsolutePath = _projectRoot + "/" + *file;
+ std::string file_id = "FileReference_" + resourceAbsolutePath;
+ std::string base = basename(*file);
+ std::string comment = base + " in Resources";
+ addBuildFile(resourceAbsolutePath, base, getHash(file_id), comment);
+ ADD_SETTING_ORDER_NOVALUE(files, getHash(resourceAbsolutePath), comment, order++);
}
- resource->properties["files"] = files;
+ resource->_properties["files"] = files;
- resource->addProperty("runOnlyForDeploymentPostprocessing", "0", "", SettingsNoValue);
+ resource->addProperty("runOnlyForDeploymentPostprocessing", "0", "", kSettingsNoValue);
_resourcesBuildPhase.add(resource);
}
}
void XcodeProvider::setupSourcesBuildPhase() {
- _sourcesBuildPhase.comment = "PBXSourcesBuildPhase";
-
- // Setup source file properties
- std::map<std::string, FileProperty> properties;
+ _sourcesBuildPhase._comment = "PBXSourcesBuildPhase";
// Same as for containers: a rule for each native target
for (unsigned int i = 0; i < _targets.size(); i++) {
+ const std::string &targetName = _targets[i];
Object *source = new Object(this, "PBXSourcesBuildPhase_" + _targets[i], "PBXSourcesBuildPhase", "PBXSourcesBuildPhase", "", "Sources");
- source->addProperty("buildActionMask", "2147483647", "", SettingsNoValue);
+ source->addProperty("buildActionMask", "2147483647", "", kSettingsNoValue);
Property files;
- files.hasOrder = true;
- files.flags = SettingsAsList;
+ files._hasOrder = true;
+ files._flags = kSettingsAsList;
int order = 0;
- for (std::vector<Object*>::iterator file = _buildFile.objects.begin(); file !=_buildFile.objects.end(); ++file) {
- if (!producesObjectFileOnOSX((*file)->name)) {
+ for (std::vector<Object *>::iterator file = _buildFile._objects.begin(); file != _buildFile._objects.end(); ++file) {
+ const std::string &fileName = (*file)->_name;
+ if (shouldSkipFileForTarget((*file)->_id, targetName, fileName)) {
+ continue;
+ }
+ if (!producesObjectFileOnOSX(fileName)) {
continue;
}
- std::string comment = (*file)->name + " in Sources";
- ADD_SETTING_ORDER_NOVALUE(files, getHash((*file)->id), comment, order++);
+ std::string comment = fileName + " in Sources";
+ ADD_SETTING_ORDER_NOVALUE(files, getHash((*file)->_id), comment, order++);
}
- source->properties["files"] = files;
+ setupAdditionalSources(targetName, files, order);
- source->addProperty("runOnlyForDeploymentPostprocessing", "0", "", SettingsNoValue);
+ source->_properties["files"] = files;
+
+ source->addProperty("runOnlyForDeploymentPostprocessing", "0", "", kSettingsNoValue);
_sourcesBuildPhase.add(source);
}
}
// Setup all build configurations
-void XcodeProvider::setupBuildConfiguration() {
+void XcodeProvider::setupBuildConfiguration(const BuildSetup &setup) {
- _buildConfiguration.comment = "XCBuildConfiguration";
- _buildConfiguration.flags = SettingsAsList;
+ _buildConfiguration._comment = "XCBuildConfiguration";
+ _buildConfiguration._flags = kSettingsAsList;
- ///****************************************
- // * iPhone
- // ****************************************/
-#ifdef ENABLE_IOS
- // Debug
- Object *iPhone_Debug_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-iPhone_Debug", _targets[IOS_TARGET] /* ScummVM-iPhone */, "XCBuildConfiguration", "PBXNativeTarget", "Debug");
- Property iPhone_Debug;
- ADD_SETTING_QUOTE(iPhone_Debug, "ARCHS", "$(ARCHS_UNIVERSAL_IPHONE_OS)");
- ADD_SETTING_QUOTE(iPhone_Debug, "CODE_SIGN_IDENTITY", "iPhone Developer");
- ADD_SETTING_QUOTE_VAR(iPhone_Debug, "CODE_SIGN_IDENTITY[sdk=iphoneos*]", "iPhone Developer");
- ADD_SETTING(iPhone_Debug, "COMPRESS_PNG_FILES", "NO");
- ADD_SETTING(iPhone_Debug, "COPY_PHASE_STRIP", "NO");
- ADD_SETTING_QUOTE(iPhone_Debug, "DEBUG_INFORMATION_FORMAT", "dwarf-with-dsym");
- ValueList iPhone_FrameworkSearchPaths;
- iPhone_FrameworkSearchPaths.push_back("$(inherited)");
- iPhone_FrameworkSearchPaths.push_back("\"$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"");
- ADD_SETTING_LIST(iPhone_Debug, "FRAMEWORK_SEARCH_PATHS", iPhone_FrameworkSearchPaths, SettingsAsList, 5);
- ADD_SETTING(iPhone_Debug, "GCC_DYNAMIC_NO_PIC", "NO");
- ADD_SETTING(iPhone_Debug, "GCC_ENABLE_CPP_EXCEPTIONS", "NO");
- ADD_SETTING(iPhone_Debug, "GCC_ENABLE_FIX_AND_CONTINUE", "NO");
- ADD_SETTING(iPhone_Debug, "GCC_OPTIMIZATION_LEVEL", "0");
- ADD_SETTING(iPhone_Debug, "GCC_PRECOMPILE_PREFIX_HEADER", "NO");
- ADD_SETTING_QUOTE(iPhone_Debug, "GCC_PREFIX_HEADER", "");
- ADD_SETTING(iPhone_Debug, "GCC_THUMB_SUPPORT", "NO");
- ADD_SETTING(iPhone_Debug, "GCC_UNROLL_LOOPS", "YES");
- ValueList iPhone_HeaderSearchPaths;
- iPhone_HeaderSearchPaths.push_back("$(SRCROOT)/engines/");
- iPhone_HeaderSearchPaths.push_back("$(SRCROOT)");
- iPhone_HeaderSearchPaths.push_back("include/");
- ADD_SETTING_LIST(iPhone_Debug, "HEADER_SEARCH_PATHS", iPhone_HeaderSearchPaths, SettingsAsList|SettingsQuoteVariable, 5);
- ADD_SETTING(iPhone_Debug, "INFOPLIST_FILE", "Info.plist");
- ValueList iPhone_LibPaths;
- iPhone_LibPaths.push_back("$(inherited)");
- iPhone_LibPaths.push_back("\"$(SRCROOT)/lib\"");
- ADD_SETTING_LIST(iPhone_Debug, "LIBRARY_SEARCH_PATHS", iPhone_LibPaths, SettingsAsList, 5);
- ADD_SETTING(iPhone_Debug, "ONLY_ACTIVE_ARCH", "YES");
- ADD_SETTING(iPhone_Debug, "PREBINDING", "NO");
- ADD_SETTING(iPhone_Debug, "PRODUCT_NAME", PROJECT_DESCRIPTION);
- ADD_SETTING_QUOTE(iPhone_Debug, "PROVISIONING_PROFILE", "EF590570-5FAC-4346-9071-D609DE2B28D8");
- ADD_SETTING_QUOTE_VAR(iPhone_Debug, "PROVISIONING_PROFILE[sdk=iphoneos*]", "");
- ADD_SETTING(iPhone_Debug, "SDKROOT", "iphoneos4.0");
- ADD_SETTING_QUOTE(iPhone_Debug, "TARGETED_DEVICE_FAMILY", "1,2");
-
- iPhone_Debug_Object->addProperty("name", "Debug", "", SettingsNoValue);
- iPhone_Debug_Object->properties["buildSettings"] = iPhone_Debug;
-
- // Release
- Object *iPhone_Release_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-iPhone_Release", _targets[IOS_TARGET] /* ScummVM-iPhone */, "XCBuildConfiguration", "PBXNativeTarget", "Release");
- Property iPhone_Release(iPhone_Debug);
- ADD_SETTING(iPhone_Release, "GCC_OPTIMIZATION_LEVEL", "3");
- ADD_SETTING(iPhone_Release, "COPY_PHASE_STRIP", "YES");
- REMOVE_SETTING(iPhone_Release, "GCC_DYNAMIC_NO_PIC");
- ADD_SETTING(iPhone_Release, "WRAPPER_EXTENSION", "app");
-
- iPhone_Release_Object->addProperty("name", "Release", "", SettingsNoValue);
- iPhone_Release_Object->properties["buildSettings"] = iPhone_Release;
-
- _buildConfiguration.add(iPhone_Debug_Object);
- _buildConfiguration.add(iPhone_Release_Object);
+ std::string projectOutputDirectory;
+#ifdef POSIX
+ char *rp = realpath(setup.outputDir.c_str(), NULL);
+ projectOutputDirectory = rp;
+ free(rp);
#endif
+
/****************************************
- * scummvm
+ * ScummVM - Project Level
****************************************/
// Debug
@@ -774,7 +776,6 @@ void XcodeProvider::setupBuildConfiguration() {
Property scummvm_Debug;
ADD_SETTING(scummvm_Debug, "ALWAYS_SEARCH_USER_PATHS", "NO");
ADD_SETTING_QUOTE(scummvm_Debug, "USER_HEADER_SEARCH_PATHS", "$(SRCROOT) $(SRCROOT)/engines");
- ADD_SETTING_QUOTE(scummvm_Debug, "ARCHS", "$(ARCHS_STANDARD_32_BIT)");
ADD_SETTING_QUOTE(scummvm_Debug, "CODE_SIGN_IDENTITY", "Don't Code Sign");
ADD_SETTING_QUOTE_VAR(scummvm_Debug, "CODE_SIGN_IDENTITY[sdk=iphoneos*]", "Don't Code Sign");
ADD_SETTING_QUOTE(scummvm_Debug, "FRAMEWORK_SEARCH_PATHS", "");
@@ -784,10 +785,12 @@ void XcodeProvider::setupBuildConfiguration() {
ADD_SETTING(scummvm_Debug, "GCC_INPUT_FILETYPE", "automatic");
ADD_SETTING(scummvm_Debug, "GCC_OPTIMIZATION_LEVEL", "0");
ValueList scummvm_defines(_defines);
- ADD_DEFINE(scummvm_defines, "IPHONE");
- ADD_DEFINE(scummvm_defines, "XCODE");
- ADD_DEFINE(scummvm_defines, "IPHONE_OFFICIAL");
- ADD_SETTING_LIST(scummvm_Debug, "GCC_PREPROCESSOR_DEFINITIONS", scummvm_defines, SettingsNoQuote|SettingsAsList, 5);
+ REMOVE_DEFINE(scummvm_defines, "MACOSX");
+ REMOVE_DEFINE(scummvm_defines, "IPHONE");
+ REMOVE_DEFINE(scummvm_defines, "IPHONE_IOS7");
+ REMOVE_DEFINE(scummvm_defines, "IPHONE_SANDBOXED");
+ REMOVE_DEFINE(scummvm_defines, "SDL_BACKEND");
+ ADD_SETTING_LIST(scummvm_Debug, "GCC_PREPROCESSOR_DEFINITIONS", scummvm_defines, kSettingsNoQuote | kSettingsAsList, 5);
ADD_SETTING(scummvm_Debug, "GCC_THUMB_SUPPORT", "NO");
ADD_SETTING(scummvm_Debug, "GCC_USE_GCC3_PFE_SUPPORT", "NO");
ADD_SETTING(scummvm_Debug, "GCC_WARN_ABOUT_RETURN_TYPE", "YES");
@@ -796,16 +799,16 @@ void XcodeProvider::setupBuildConfiguration() {
scummvm_HeaderPaths.push_back("include/");
scummvm_HeaderPaths.push_back("$(SRCROOT)/engines/");
scummvm_HeaderPaths.push_back("$(SRCROOT)");
- ADD_SETTING_LIST(scummvm_Debug, "HEADER_SEARCH_PATHS", scummvm_HeaderPaths, SettingsQuoteVariable|SettingsAsList, 5);
+ ADD_SETTING_LIST(scummvm_Debug, "HEADER_SEARCH_PATHS", scummvm_HeaderPaths, kSettingsQuoteVariable | kSettingsAsList, 5);
ADD_SETTING_QUOTE(scummvm_Debug, "LIBRARY_SEARCH_PATHS", "");
ADD_SETTING(scummvm_Debug, "ONLY_ACTIVE_ARCH", "YES");
ADD_SETTING_QUOTE(scummvm_Debug, "OTHER_CFLAGS", "");
ADD_SETTING_QUOTE(scummvm_Debug, "OTHER_LDFLAGS", "-lz");
ADD_SETTING(scummvm_Debug, "PREBINDING", "NO");
- ADD_SETTING(scummvm_Debug, "SDKROOT", "macosx");
+ ADD_SETTING(scummvm_Debug, "ENABLE_TESTABILITY", "YES");
- scummvm_Debug_Object->addProperty("name", "Debug", "", SettingsNoValue);
- scummvm_Debug_Object->properties["buildSettings"] = scummvm_Debug;
+ scummvm_Debug_Object->addProperty("name", "Debug", "", kSettingsNoValue);
+ scummvm_Debug_Object->_properties["buildSettings"] = scummvm_Debug;
// Release
Object *scummvm_Release_Object = new Object(this, "XCBuildConfiguration_" PROJECT_NAME "_Release", PROJECT_NAME, "XCBuildConfiguration", "PBXProject", "Release");
@@ -814,24 +817,100 @@ void XcodeProvider::setupBuildConfiguration() {
REMOVE_SETTING(scummvm_Release, "GCC_WARN_ABOUT_RETURN_TYPE");
REMOVE_SETTING(scummvm_Release, "GCC_WARN_UNUSED_VARIABLE");
REMOVE_SETTING(scummvm_Release, "ONLY_ACTIVE_ARCH");
+ REMOVE_SETTING(scummvm_Release, "ENABLE_TESTABILITY");
- scummvm_Release_Object->addProperty("name", "Release", "", SettingsNoValue);
- scummvm_Release_Object->properties["buildSettings"] = scummvm_Release;
+ scummvm_Release_Object->addProperty("name", "Release", "", kSettingsNoValue);
+ scummvm_Release_Object->_properties["buildSettings"] = scummvm_Release;
_buildConfiguration.add(scummvm_Debug_Object);
_buildConfiguration.add(scummvm_Release_Object);
+ ///****************************************
+ // * ScummVM - iOS Target
+ // ****************************************/
+
+ // Debug
+ Object *iPhone_Debug_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-iPhone_Debug", _targets[IOS_TARGET] /* ScummVM-iPhone */, "XCBuildConfiguration", "PBXNativeTarget", "Debug");
+ Property iPhone_Debug;
+ ADD_SETTING_QUOTE(iPhone_Debug, "CODE_SIGN_IDENTITY", "iPhone Developer");
+ ADD_SETTING_QUOTE_VAR(iPhone_Debug, "CODE_SIGN_IDENTITY[sdk=iphoneos*]", "iPhone Developer");
+ ADD_SETTING(iPhone_Debug, "COMPRESS_PNG_FILES", "NO");
+ ADD_SETTING(iPhone_Debug, "COPY_PHASE_STRIP", "NO");
+ ADD_SETTING_QUOTE(iPhone_Debug, "DEBUG_INFORMATION_FORMAT", "dwarf");
+ ValueList iPhone_FrameworkSearchPaths;
+ iPhone_FrameworkSearchPaths.push_back("$(inherited)");
+ iPhone_FrameworkSearchPaths.push_back("\"$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"");
+ ADD_SETTING_LIST(iPhone_Debug, "FRAMEWORK_SEARCH_PATHS", iPhone_FrameworkSearchPaths, kSettingsAsList, 5);
+ ADD_SETTING(iPhone_Debug, "GCC_DYNAMIC_NO_PIC", "NO");
+ ADD_SETTING(iPhone_Debug, "GCC_ENABLE_CPP_EXCEPTIONS", "NO");
+ ADD_SETTING(iPhone_Debug, "GCC_ENABLE_FIX_AND_CONTINUE", "NO");
+ ADD_SETTING(iPhone_Debug, "GCC_OPTIMIZATION_LEVEL", "0");
+ ADD_SETTING(iPhone_Debug, "GCC_PRECOMPILE_PREFIX_HEADER", "NO");
+ ADD_SETTING(iPhone_Debug, "GCC_WARN_64_TO_32_BIT_CONVERSION", "NO");
+ ADD_SETTING(iPhone_Debug, "WARNING_CFLAGS", "-Wno-multichar");
+ ADD_SETTING_QUOTE(iPhone_Debug, "GCC_PREFIX_HEADER", "");
+ ADD_SETTING(iPhone_Debug, "GCC_THUMB_SUPPORT", "NO");
+ ADD_SETTING(iPhone_Debug, "GCC_UNROLL_LOOPS", "YES");
+ ValueList iPhone_HeaderSearchPaths;
+ iPhone_HeaderSearchPaths.push_back("$(SRCROOT)/engines/");
+ iPhone_HeaderSearchPaths.push_back("$(SRCROOT)");
+ iPhone_HeaderSearchPaths.push_back("\"" + projectOutputDirectory + "\"");
+ iPhone_HeaderSearchPaths.push_back("\"" + projectOutputDirectory + "/include\"");
+ ADD_SETTING_LIST(iPhone_Debug, "HEADER_SEARCH_PATHS", iPhone_HeaderSearchPaths, kSettingsAsList | kSettingsQuoteVariable, 5);
+ ADD_SETTING_QUOTE(iPhone_Debug, "INFOPLIST_FILE", "$(SRCROOT)/dists/ios7/Info.plist");
+ ValueList iPhone_LibPaths;
+ iPhone_LibPaths.push_back("$(inherited)");
+ iPhone_LibPaths.push_back("\"" + projectOutputDirectory + "/lib\"");
+ ADD_SETTING_LIST(iPhone_Debug, "LIBRARY_SEARCH_PATHS", iPhone_LibPaths, kSettingsAsList, 5);
+ ADD_SETTING(iPhone_Debug, "ONLY_ACTIVE_ARCH", "YES");
+ ADD_SETTING(iPhone_Debug, "PREBINDING", "NO");
+ ADD_SETTING(iPhone_Debug, "PRODUCT_NAME", PROJECT_NAME);
+ ADD_SETTING(iPhone_Debug, "PRODUCT_BUNDLE_IDENTIFIER", "\"org.scummvm.${PRODUCT_NAME}\"");
+ ADD_SETTING(iPhone_Debug, "IPHONEOS_DEPLOYMENT_TARGET", "7.1");
+ //ADD_SETTING_QUOTE(iPhone_Debug, "PROVISIONING_PROFILE", "EF590570-5FAC-4346-9071-D609DE2B28D8");
+ ADD_SETTING_QUOTE_VAR(iPhone_Debug, "PROVISIONING_PROFILE[sdk=iphoneos*]", "");
+ ADD_SETTING(iPhone_Debug, "SDKROOT", "iphoneos");
+ ADD_SETTING_QUOTE(iPhone_Debug, "TARGETED_DEVICE_FAMILY", "1,2");
+ ValueList scummvmIOS_defines;
+ ADD_DEFINE(scummvmIOS_defines, "\"$(inherited)\"");
+ ADD_DEFINE(scummvmIOS_defines, "IPHONE");
+ ADD_DEFINE(scummvmIOS_defines, "IPHONE_IOS7");
+ ADD_DEFINE(scummvmIOS_defines, "IPHONE_SANDBOXED");
+ ADD_SETTING_LIST(iPhone_Debug, "GCC_PREPROCESSOR_DEFINITIONS", scummvmIOS_defines, kSettingsNoQuote | kSettingsAsList, 5);
+ ADD_SETTING(iPhone_Debug, "ASSETCATALOG_COMPILER_APPICON_NAME", "AppIcon");
+ ADD_SETTING(iPhone_Debug, "ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME", "LaunchImage");
+
+ iPhone_Debug_Object->addProperty("name", "Debug", "", kSettingsNoValue);
+ iPhone_Debug_Object->_properties["buildSettings"] = iPhone_Debug;
+
+ // Release
+ Object *iPhone_Release_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-iPhone_Release", _targets[IOS_TARGET] /* ScummVM-iPhone */, "XCBuildConfiguration", "PBXNativeTarget", "Release");
+ Property iPhone_Release(iPhone_Debug);
+ ADD_SETTING(iPhone_Release, "GCC_OPTIMIZATION_LEVEL", "3");
+ ADD_SETTING(iPhone_Release, "COPY_PHASE_STRIP", "YES");
+ REMOVE_SETTING(iPhone_Release, "GCC_DYNAMIC_NO_PIC");
+ ADD_SETTING(iPhone_Release, "WRAPPER_EXTENSION", "app");
+ REMOVE_SETTING(iPhone_Release, "DEBUG_INFORMATION_FORMAT");
+ ADD_SETTING_QUOTE(iPhone_Release, "DEBUG_INFORMATION_FORMAT", "dwarf-with-dsym");
+
+ iPhone_Release_Object->addProperty("name", "Release", "", kSettingsNoValue);
+ iPhone_Release_Object->_properties["buildSettings"] = iPhone_Release;
+
+ _buildConfiguration.add(iPhone_Debug_Object);
+ _buildConfiguration.add(iPhone_Release_Object);
+
/****************************************
- * ScummVM-OS X
+ * ScummVM - OS X Target
****************************************/
// Debug
Object *scummvmOSX_Debug_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-OSX_Debug", _targets[OSX_TARGET] /* ScummVM-OS X */, "XCBuildConfiguration", "PBXNativeTarget", "Debug");
Property scummvmOSX_Debug;
- ADD_SETTING_QUOTE(scummvmOSX_Debug, "ARCHS", "$(NATIVE_ARCH)");
+ ADD_SETTING(scummvmOSX_Debug, "COMBINE_HIDPI_IMAGES", "YES");
+ ADD_SETTING(scummvmOSX_Debug, "SDKROOT", "macosx");
ADD_SETTING(scummvmOSX_Debug, "COMPRESS_PNG_FILES", "NO");
ADD_SETTING(scummvmOSX_Debug, "COPY_PHASE_STRIP", "NO");
- ADD_SETTING_QUOTE(scummvmOSX_Debug, "DEBUG_INFORMATION_FORMAT", "dwarf-with-dsym");
+ ADD_SETTING_QUOTE(scummvmOSX_Debug, "DEBUG_INFORMATION_FORMAT", "dwarf");
ADD_SETTING_QUOTE(scummvmOSX_Debug, "FRAMEWORK_SEARCH_PATHS", "");
ADD_SETTING(scummvmOSX_Debug, "GCC_C_LANGUAGE_STANDARD", "c99");
ADD_SETTING(scummvmOSX_Debug, "GCC_ENABLE_CPP_EXCEPTIONS", "NO");
@@ -841,29 +920,33 @@ void XcodeProvider::setupBuildConfiguration() {
ADD_SETTING(scummvmOSX_Debug, "GCC_OPTIMIZATION_LEVEL", "0");
ADD_SETTING(scummvmOSX_Debug, "GCC_PRECOMPILE_PREFIX_HEADER", "NO");
ADD_SETTING_QUOTE(scummvmOSX_Debug, "GCC_PREFIX_HEADER", "");
- ValueList scummvmOSX_defines(_defines);
+ ValueList scummvmOSX_defines;
+ ADD_DEFINE(scummvmOSX_defines, "\"$(inherited)\"");
ADD_DEFINE(scummvmOSX_defines, "SDL_BACKEND");
ADD_DEFINE(scummvmOSX_defines, "MACOSX");
- ADD_SETTING_LIST(scummvmOSX_Debug, "GCC_PREPROCESSOR_DEFINITIONS", scummvmOSX_defines, SettingsNoQuote|SettingsAsList, 5);
+ 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/");
scummvmOSX_HeaderPaths.push_back("$(SRCROOT)/engines/");
scummvmOSX_HeaderPaths.push_back("$(SRCROOT)");
- ADD_SETTING_LIST(scummvmOSX_Debug, "HEADER_SEARCH_PATHS", scummvmOSX_HeaderPaths, SettingsQuoteVariable|SettingsAsList, 5);
+ ADD_SETTING_LIST(scummvmOSX_Debug, "HEADER_SEARCH_PATHS", scummvmOSX_HeaderPaths, kSettingsQuoteVariable | kSettingsAsList, 5);
ADD_SETTING_QUOTE(scummvmOSX_Debug, "INFOPLIST_FILE", "$(SRCROOT)/dists/macosx/Info.plist");
ValueList scummvmOSX_LibPaths;
scummvmOSX_LibPaths.push_back("/sw/lib");
scummvmOSX_LibPaths.push_back("/opt/local/lib");
scummvmOSX_LibPaths.push_back("\"$(inherited)\"");
scummvmOSX_LibPaths.push_back("\"\\\\\\\"$(SRCROOT)/lib\\\\\\\"\""); // mmmh, all those slashes, it's almost Christmas \o/
- ADD_SETTING_LIST(scummvmOSX_Debug, "LIBRARY_SEARCH_PATHS", scummvmOSX_LibPaths, SettingsNoQuote|SettingsAsList, 5);
+ 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");
@@ -873,14 +956,20 @@ void XcodeProvider::setupBuildConfiguration() {
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, SettingsAsList, 5);
+ ADD_SETTING_LIST(scummvmOSX_Debug, "OTHER_LDFLAGS", scummvmOSX_LdFlags, kSettingsAsList, 5);
ADD_SETTING(scummvmOSX_Debug, "PREBINDING", "NO");
- ADD_SETTING(scummvmOSX_Debug, "PRODUCT_NAME", PROJECT_DESCRIPTION);
+ ADD_SETTING(scummvmOSX_Debug, "PRODUCT_NAME", PROJECT_NAME);
- scummvmOSX_Debug_Object->addProperty("name", "Debug", "", SettingsNoValue);
- scummvmOSX_Debug_Object->properties["buildSettings"] = scummvmOSX_Debug;
+ scummvmOSX_Debug_Object->addProperty("name", "Debug", "", kSettingsNoValue);
+ scummvmOSX_Debug_Object->_properties["buildSettings"] = scummvmOSX_Debug;
// Release
Object *scummvmOSX_Release_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-OSX_Release", _targets[OSX_TARGET] /* ScummVM-OS X */, "XCBuildConfiguration", "PBXNativeTarget", "Release");
@@ -889,68 +978,51 @@ void XcodeProvider::setupBuildConfiguration() {
REMOVE_SETTING(scummvmOSX_Release, "GCC_DYNAMIC_NO_PIC");
REMOVE_SETTING(scummvmOSX_Release, "GCC_OPTIMIZATION_LEVEL");
ADD_SETTING(scummvmOSX_Release, "WRAPPER_EXTENSION", "app");
+ REMOVE_SETTING(scummvmOSX_Release, "DEBUG_INFORMATION_FORMAT");
+ ADD_SETTING_QUOTE(scummvmOSX_Release, "DEBUG_INFORMATION_FORMAT", "dwarf-with-dsym");
- scummvmOSX_Release_Object->addProperty("name", "Release", "", SettingsNoValue);
- scummvmOSX_Release_Object->properties["buildSettings"] = scummvmOSX_Release;
+ scummvmOSX_Release_Object->addProperty("name", "Release", "", kSettingsNoValue);
+ scummvmOSX_Release_Object->_properties["buildSettings"] = scummvmOSX_Release;
_buildConfiguration.add(scummvmOSX_Debug_Object);
_buildConfiguration.add(scummvmOSX_Release_Object);
-#ifdef ENABLE_IOS
- /****************************************
- * ScummVM-Simulator
- ****************************************/
-
- // Debug
- Object *scummvmSimulator_Debug_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-Simulator_Debug", _targets[SIM_TARGET] /* ScummVM-Simulator */, "XCBuildConfiguration", "PBXNativeTarget", "Debug");
- Property scummvmSimulator_Debug(iPhone_Debug);
- ADD_SETTING_QUOTE(scummvmSimulator_Debug, "FRAMEWORK_SEARCH_PATHS", "$(inherited)");
- ADD_SETTING_LIST(scummvmSimulator_Debug, "GCC_PREPROCESSOR_DEFINITIONS", scummvm_defines, SettingsNoQuote|SettingsAsList, 5);
- ADD_SETTING(scummvmSimulator_Debug, "SDKROOT", "iphonesimulator3.2");
- ADD_SETTING_QUOTE(scummvmSimulator_Debug, "VALID_ARCHS", "i386 x86_64");
- REMOVE_SETTING(scummvmSimulator_Debug, "TARGETED_DEVICE_FAMILY");
-
- scummvmSimulator_Debug_Object->addProperty("name", "Debug", "", SettingsNoValue);
- scummvmSimulator_Debug_Object->properties["buildSettings"] = scummvmSimulator_Debug;
-
- // Release
- Object *scummvmSimulator_Release_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-Simulator_Release", _targets[SIM_TARGET] /* ScummVM-Simulator */, "XCBuildConfiguration", "PBXNativeTarget", "Release");
- Property scummvmSimulator_Release(scummvmSimulator_Debug);
- ADD_SETTING(scummvmSimulator_Release, "COPY_PHASE_STRIP", "YES");
- ADD_SETTING(scummvmSimulator_Release, "GCC_OPTIMIZATION_LEVEL", "3");
- REMOVE_SETTING(scummvmSimulator_Release, "GCC_DYNAMIC_NO_PIC");
- ADD_SETTING(scummvmSimulator_Release, "WRAPPER_EXTENSION", "app");
-
- scummvmSimulator_Release_Object->addProperty("name", "Release", "", SettingsNoValue);
- scummvmSimulator_Release_Object->properties["buildSettings"] = scummvmSimulator_Release;
-
- _buildConfiguration.add(scummvmSimulator_Debug_Object);
- _buildConfiguration.add(scummvmSimulator_Release_Object);
- //////////////////////////////////////////////////////////////////////////
- // Configuration List
- _configurationList.comment = "XCConfigurationList";
- _configurationList.flags = SettingsAsList;
-#endif
// Warning: This assumes we have all configurations with a Debug & Release pair
- for (std::vector<Object *>::iterator config = _buildConfiguration.objects.begin(); config != _buildConfiguration.objects.end(); config++) {
+ for (std::vector<Object *>::iterator config = _buildConfiguration._objects.begin(); config != _buildConfiguration._objects.end(); config++) {
- Object *configList = new Object(this, "XCConfigurationList_" + (*config)->name, (*config)->name, "XCConfigurationList", "", "Build configuration list for " + (*config)->refType + " \"" + (*config)->name + "\"");
+ Object *configList = new Object(this, "XCConfigurationList_" + (*config)->_name, (*config)->_name, "XCConfigurationList", "", "Build configuration list for " + (*config)->_refType + " \"" + (*config)->_name + "\"");
Property buildConfigs;
- buildConfigs.flags = SettingsAsList;
+ buildConfigs._flags = kSettingsAsList;
- buildConfigs.settings[getHash((*config)->id)] = Setting("", "Debug", SettingsNoValue, 0, 0);
- buildConfigs.settings[getHash((*(++config))->id)] = Setting("", "Release", SettingsNoValue, 0, 1);
+ buildConfigs._settings[getHash((*config)->_id)] = Setting("", "Debug", kSettingsNoValue, 0, 0);
+ buildConfigs._settings[getHash((*(++config))->_id)] = Setting("", "Release", kSettingsNoValue, 0, 1);
- configList->properties["buildConfigurations"] = buildConfigs;
+ configList->_properties["buildConfigurations"] = buildConfigs;
- configList->addProperty("defaultConfigurationIsVisible", "0", "", SettingsNoValue);
- configList->addProperty("defaultConfigurationName", "Release", "", SettingsNoValue);
+ configList->addProperty("defaultConfigurationIsVisible", "0", "", kSettingsNoValue);
+ configList->addProperty("defaultConfigurationName", "Release", "", kSettingsNoValue);
_configurationList.add(configList);
}
}
+void XcodeProvider::setupImageAssetCatalog(const BuildSetup &setup) {
+ const std::string filename = "Images.xcassets";
+ const std::string absoluteCatalogPath = _projectRoot + "/dists/ios7/" + filename;
+ const std::string id = "FileReference_" + absoluteCatalogPath;
+ Group *group = touchGroupsForPath(absoluteCatalogPath);
+ group->addChildFile(filename);
+ addBuildFile(absoluteCatalogPath, filename, getHash(id), "Image Asset Catalog");
+}
+
+void XcodeProvider::setupAdditionalSources(std::string targetName, Property &files, int &order) {
+ if (targetIsIOS(targetName)) {
+ const std::string absoluteCatalogPath = _projectRoot + "/dists/ios7/Images.xcassets";
+ ADD_SETTING_ORDER_NOVALUE(files, getHash(absoluteCatalogPath), "Image Asset Catalog", order++);
+ }
+}
+
//////////////////////////////////////////////////////////////////////////
// Misc
//////////////////////////////////////////////////////////////////////////
@@ -959,15 +1031,18 @@ void XcodeProvider::setupBuildConfiguration() {
void XcodeProvider::setupDefines(const BuildSetup &setup) {
for (StringList::const_iterator i = setup.defines.begin(); i != setup.defines.end(); ++i) {
- if (*i == "HAVE_NASM") // Not supported on Mac (TODO: change how it's handled in main class or add it only in MSVC/CodeBlocks providers?)
+ if (*i == "HAVE_NASM") // Not supported on Mac (TODO: change how it's handled in main class or add it only in MSVC/CodeBlocks providers?)
continue;
ADD_DEFINE(_defines, *i);
}
// Add special defines for Mac support
+ REMOVE_DEFINE(_defines, "MACOSX");
+ REMOVE_DEFINE(_defines, "IPHONE");
+ REMOVE_DEFINE(_defines, "IPHONE_IOS7");
+ REMOVE_DEFINE(_defines, "IPHONE_SANDBOXED");
+ REMOVE_DEFINE(_defines, "SDL_BACKEND");
ADD_DEFINE(_defines, "CONFIG_H");
- ADD_DEFINE(_defines, "SCUMM_NEED_ALIGNMENT");
- ADD_DEFINE(_defines, "SCUMM_LITTLE_ENDIAN");
ADD_DEFINE(_defines, "UNIX");
ADD_DEFINE(_defines, "SCUMMVM");
}
@@ -976,7 +1051,6 @@ void XcodeProvider::setupDefines(const BuildSetup &setup) {
// Object hash
//////////////////////////////////////////////////////////////////////////
-// TODO use md5 to compute a file hash (and fall back to standard key generation if not passed a file)
std::string XcodeProvider::getHash(std::string key) {
#if DEBUG_XCODE_HASH
@@ -988,14 +1062,32 @@ std::string XcodeProvider::getHash(std::string key) {
return hashIterator->second;
// Generate a new key from the file hash and insert it into the dictionary
+#ifdef MACOSX
+ std::string hash = md5(key);
+#else
std::string hash = newHash();
+#endif
+
_hashDictionnary[key] = hash;
return hash;
#endif
}
-bool isSeparator (char s) { return (s == '-'); }
+bool isSeparator(char s) { return (s == '-'); }
+
+#ifdef MACOSX
+std::string XcodeProvider::md5(std::string key) {
+ unsigned char md[CC_MD5_DIGEST_LENGTH];
+ CC_MD5(key.c_str(), (CC_LONG) key.length(), md);
+ std::stringstream stream;
+ stream << std::hex << std::setfill('0') << std::setw(2);
+ for (int i=0; i<CC_MD5_DIGEST_LENGTH; i++) {
+ stream << (unsigned int) md[i];
+ }
+ return stream.str();
+}
+#endif
std::string XcodeProvider::newHash() const {
std::string hash = createUUID();
@@ -1018,10 +1110,10 @@ std::string replace(std::string input, const std::string find, std::string repla
std::string::size_type findLen = find.length();
std::string::size_type replaceLen = replaceStr.length();
- if (findLen == 0 )
+ if (findLen == 0)
return input;
- for (;(pos = input.find(find, pos)) != std::string::npos;) {
+ for (; (pos = input.find(find, pos)) != std::string::npos;) {
input.replace(pos, findLen, replaceStr);
pos += replaceLen;
}
@@ -1032,30 +1124,30 @@ std::string replace(std::string input, const std::string find, std::string repla
std::string XcodeProvider::writeProperty(const std::string &variable, Property &prop, int flags) const {
std::string output;
- output += (flags & SettingsSingleItem ? "" : "\t\t\t") + variable + " = ";
+ output += (flags & kSettingsSingleItem ? "" : "\t\t\t") + variable + " = ";
- if (prop.settings.size() > 1 || (prop.flags & SettingsSingleItem))
- output += (prop.flags & SettingsAsList) ? "(\n" : "{\n";
+ if (prop._settings.size() > 1 || (prop._flags & kSettingsSingleItem))
+ output += (prop._flags & kSettingsAsList) ? "(\n" : "{\n";
OrderedSettingList settings = prop.getOrderedSettingList();
for (OrderedSettingList::const_iterator setting = settings.begin(); setting != settings.end(); ++setting) {
- if (settings.size() > 1 || (prop.flags & SettingsSingleItem))
- output += (flags & SettingsSingleItem ? " " : "\t\t\t\t");
+ if (settings.size() > 1 || (prop._flags & kSettingsSingleItem))
+ output += (flags & kSettingsSingleItem ? " " : "\t\t\t\t");
- output += writeSetting((*setting).first, (*setting).second);
+ output += writeSetting(setting->first, setting->second);
- // The combination of SettingsAsList, and SettingsSingleItem should use "," and not ";" (i.e children
+ // The combination of kSettingsAsList, and kSettingsSingleItem should use "," and not ";" (i.e children
// in PBXGroup, so we special case that case here.
- if ((prop.flags & SettingsAsList) && (prop.settings.size() > 1 || (prop.flags & SettingsSingleItem))) {
- output += (prop.settings.size() > 0) ? ",\n" : "\n";
+ if ((prop._flags & kSettingsAsList) && (prop._settings.size() > 1 || (prop._flags & kSettingsSingleItem))) {
+ output += (prop._settings.size() > 0) ? ",\n" : "\n";
} else {
output += ";";
- output += (flags & SettingsSingleItem ? " " : "\n");
+ output += (flags & kSettingsSingleItem ? " " : "\n");
}
}
- if (prop.settings.size() > 1 || (prop.flags & SettingsSingleItem))
- output += (prop.flags & SettingsAsList) ? "\t\t\t);\n" : "\t\t\t};\n";
+ if (prop._settings.size() > 1 || (prop._flags & kSettingsSingleItem))
+ output += (prop._flags & kSettingsAsList) ? "\t\t\t);\n" : "\t\t\t};\n";
return output;
}
@@ -1068,32 +1160,31 @@ std::string XcodeProvider::writeSetting(const std::string &variable, std::string
// XCode project generator pbuilder_pbx.cpp, writeSettings() (under LGPL 2.1)
std::string XcodeProvider::writeSetting(const std::string &variable, const Setting &setting) const {
std::string output;
- const std::string quote = (setting.flags & SettingsNoQuote) ? "" : "\"";
+ const std::string quote = (setting._flags & kSettingsNoQuote) ? "" : "\"";
const std::string escape_quote = quote.empty() ? "" : "\\" + quote;
std::string newline = "\n";
// Get indent level
- for (int i = 0; i < setting.indent; ++i)
+ for (int i = 0; i < setting._indent; ++i)
newline += "\t";
// Setup variable
- std::string var = (setting.flags & SettingsQuoteVariable) ? "\"" + variable + "\"" : variable;
+ std::string var = (setting._flags & kSettingsQuoteVariable) ? "\"" + variable + "\"" : variable;
// Output a list
- if (setting.flags & SettingsAsList) {
-
- output += var + ((setting.flags & SettingsNoValue) ? "(" : " = (") + newline;
+ if (setting._flags & kSettingsAsList) {
+ output += var + ((setting._flags & kSettingsNoValue) ? "(" : " = (") + newline;
- for (unsigned int i = 0, count = 0; i < setting.entries.size(); ++i) {
+ for (unsigned int i = 0, count = 0; i < setting._entries.size(); ++i) {
- std::string value = setting.entries.at(i).value;
+ std::string value = setting._entries.at(i)._value;
if (!value.empty()) {
if (count++ > 0)
output += "," + newline;
output += quote + replace(value, quote, escape_quote) + quote;
- std::string comment = setting.entries.at(i).comment;
+ std::string comment = setting._entries.at(i)._comment;
if (!comment.empty())
output += " /* " + comment + " */";
}
@@ -1101,24 +1192,24 @@ std::string XcodeProvider::writeSetting(const std::string &variable, const Setti
}
// Add closing ")" on new line
newline.resize(newline.size() - 1);
- output += (setting.flags & SettingsNoValue) ? "\t\t\t)" : "," + newline + ")";
+ output += (setting._flags & kSettingsNoValue) ? "\t\t\t)" : "," + newline + ")";
} else {
output += var;
- output += (setting.flags & SettingsNoValue) ? "" : " = " + quote;
+ output += (setting._flags & kSettingsNoValue) ? "" : " = " + quote;
- for(unsigned int i = 0; i < setting.entries.size(); ++i) {
- std::string value = setting.entries.at(i).value;
- if(i)
+ for (unsigned int i = 0; i < setting._entries.size(); ++i) {
+ std::string value = setting._entries.at(i)._value;
+ if (i)
output += " ";
output += value;
- std::string comment = setting.entries.at(i).comment;
+ std::string comment = setting._entries.at(i)._comment;
if (!comment.empty())
output += " /* " + comment + " */";
}
- output += (setting.flags & SettingsNoValue) ? "" : quote;
+ output += (setting._flags & kSettingsNoValue) ? "" : quote;
}
return output;
}
diff --git a/devtools/create_project/xcode.h b/devtools/create_project/xcode.h
index 2686d14986..d495dd0dfd 100644
--- a/devtools/create_project/xcode.h
+++ b/devtools/create_project/xcode.h
@@ -40,6 +40,8 @@ protected:
void createOtherBuildFiles(const BuildSetup &setup);
+ 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);
@@ -47,24 +49,23 @@ protected:
const StringList &duplicate, const std::string &objPrefix, const std::string &filePrefix);
private:
enum {
- SettingsAsList = 0x01,
- SettingsSingleItem = 0x02,
- SettingsNoQuote = 0x04,
- SettingsQuoteVariable = 0x08,
- SettingsNoValue = 0x10
+ kSettingsAsList = 0x01,
+ kSettingsSingleItem = 0x02,
+ kSettingsNoQuote = 0x04,
+ kSettingsQuoteVariable = 0x08,
+ kSettingsNoValue = 0x10
};
// File properties
struct FileProperty {
- std::string fileEncoding;
- std::string lastKnownFileType;
- std::string fileName;
- std::string filePath;
- std::string sourceTree;
-
- FileProperty(std::string fileType = "", std::string name = "", std::string path = "", std::string source = "") :
- fileEncoding(""), lastKnownFileType(fileType), fileName(name), filePath(path), sourceTree(source)
- {
+ std::string _fileEncoding;
+ std::string _lastKnownFileType;
+ std::string _fileName;
+ std::string _filePath;
+ std::string _sourceTree;
+
+ FileProperty(std::string fileType = "", std::string name = "", std::string path = "", std::string source = "")
+ : _fileEncoding(""), _lastKnownFileType(fileType), _fileName(name), _filePath(path), _sourceTree(source) {
}
};
@@ -73,33 +74,33 @@ private:
typedef std::vector<std::string> ValueList;
struct Entry {
- std::string value;
- std::string comment;
+ std::string _value;
+ std::string _comment;
- Entry(std::string val, std::string cmt) : value(val), comment(cmt) {}
+ Entry(std::string val, std::string cmt) : _value(val), _comment(cmt) {}
};
typedef std::vector<Entry> EntryList;
struct Setting {
- EntryList entries;
- int flags;
- int indent;
- int order;
+ EntryList _entries;
+ int _flags;
+ int _indent;
+ int _order;
- explicit Setting(std::string value = "", std::string comment = "", int flgs = 0, int idt = 0, int ord = -1) : flags(flgs), indent(idt), order(ord) {
- entries.push_back(Entry(value, comment));
+ Setting(std::string value = "", std::string comment = "", int flgs = 0, int idt = 0, int ord = -1) : _flags(flgs), _indent(idt), _order(ord) {
+ _entries.push_back(Entry(value, comment));
}
- explicit Setting(ValueList values, int flgs = 0, int idt = 0, int ord = -1) : flags(flgs), indent(idt), order(ord) {
+ Setting(ValueList values, int flgs = 0, int idt = 0, int ord = -1) : _flags(flgs), _indent(idt), _order(ord) {
for (unsigned int i = 0; i < values.size(); i++)
- entries.push_back(Entry(values[i], ""));
+ _entries.push_back(Entry(values[i], ""));
}
- explicit Setting(EntryList ents, int flgs = 0, int idt = 0, int ord = -1) : entries(ents), flags(flgs), indent(idt), order(ord) {}
+ Setting(EntryList ents, int flgs = 0, int idt = 0, int ord = -1) : _entries(ents), _flags(flgs), _indent(idt), _order(ord) {}
void addEntry(std::string value, std::string comment = "") {
- entries.push_back(Entry(value, comment));
+ _entries.push_back(Entry(value, comment));
}
};
@@ -107,46 +108,36 @@ private:
typedef std::pair<std::string, Setting> SettingPair;
typedef std::vector<SettingPair> OrderedSettingList;
- static bool OrderSortPredicate(const SettingPair& s1, const SettingPair& s2) {
- return s1.second.order < s2.second.order;
+ static bool OrderSortPredicate(const SettingPair &s1, const SettingPair &s2) {
+ return s1.second._order < s2.second._order;
}
struct Property {
public:
- SettingList settings;
- int flags;
- bool hasOrder;
+ SettingList _settings;
+ int _flags;
+ bool _hasOrder;
- Property() : flags(0), hasOrder(false) {}
+ Property() : _flags(0), _hasOrder(false) {}
// Constructs a simple Property
- explicit Property(std::string name, std::string value = "", std::string comment = "", int flgs = 0, int indent = 0, bool order = false) : flags(flgs), hasOrder(order) {
- Setting setting(value, comment, flags, indent);
-
- settings[name] = setting;
- }
-
- Property(std::string name, ValueList values, int flgs = 0, int indent = 0, bool order = false) : flags(flgs), hasOrder(order) {
- Setting setting(values, flags, indent);
-
- settings[name] = setting;
+ Property(std::string name, std::string value = "", std::string comment = "", int flgs = 0, int indent = 0, bool order = false) : _flags(flgs), _hasOrder(order) {
+ _settings[name] = Setting(value, comment, _flags, indent);
}
- // Copy constructor
- Property(const Property &rhs) {
- settings = rhs.settings;
- flags = rhs.flags;
+ Property(std::string name, ValueList values, int flgs = 0, int indent = 0, bool order = false) : _flags(flgs), _hasOrder(order) {
+ _settings[name] = Setting(values, _flags, indent);
}
OrderedSettingList getOrderedSettingList() {
OrderedSettingList list;
// Prepare vector to sort
- for (SettingList::const_iterator setting = settings.begin(); setting != settings.end(); ++setting)
+ for (SettingList::const_iterator setting = _settings.begin(); setting != _settings.end(); ++setting)
list.push_back(SettingPair(setting->first, setting->second));
// Sort vector using setting order
- if (hasOrder)
+ if (_hasOrder)
std::sort(list.begin(), list.end(), OrderSortPredicate);
return list;
@@ -160,48 +151,48 @@ private:
// be overkill since we only have to generate a single project
struct Object {
public:
- std::string id; // Unique identifier for this object
- std::string name; // Name (may not be unique - for ex. configuration entries)
- std::string refType; // Type of object this references (if any)
- std::string comment; // Main comment (empty for no comment)
+ std::string _id; // Unique identifier for this object
+ std::string _name; // Name (may not be unique - for ex. configuration entries)
+ std::string _refType; // Type of object this references (if any)
+ std::string _comment; // Main comment (empty for no comment)
- PropertyList properties; // List of object properties, including output configuration
+ PropertyList _properties; // List of object properties, including output configuration
// Constructs an object and add a default type property
Object(XcodeProvider *objectParent, std::string objectId, std::string objectName, std::string objectType, std::string objectRefType = "", std::string objectComment = "")
- : id(objectId), name(objectName), refType(objectRefType), comment(objectComment), parent(objectParent) {
+ : _id(objectId), _name(objectName), _refType(objectRefType), _comment(objectComment), _parent(objectParent) {
assert(objectParent);
assert(!objectId.empty());
assert(!objectName.empty());
assert(!objectType.empty());
- addProperty("isa", objectType, "", SettingsNoQuote|SettingsNoValue);
+ addProperty("isa", objectType, "", kSettingsNoQuote | kSettingsNoValue);
}
// Add a simple Property with just a name and a value
void addProperty(std::string propName, std::string propValue, std::string propComment = "", int propFlags = 0, int propIndent = 0) {
- properties[propName] = Property(propValue, "", propComment, propFlags, propIndent);
+ _properties[propName] = Property(propValue, "", propComment, propFlags, propIndent);
}
std::string toString(int flags = 0) {
std::string output;
- output = "\t\t" + parent->getHash(id) + (comment.empty() ? "" : " /* " + comment + " */") + " = {";
+ output = "\t\t" + _parent->getHash(_id) + (_comment.empty() ? "" : " /* " + _comment + " */") + " = {";
- if (flags & SettingsAsList)
+ if (flags & kSettingsAsList)
output += "\n";
// Special case: always output the isa property first
- output += parent->writeProperty("isa", properties["isa"], flags);
+ output += _parent->writeProperty("isa", _properties["isa"], flags);
// Write each property
- for (PropertyList::iterator property = properties.begin(); property != properties.end(); ++property) {
- if ((*property).first == "isa")
+ for (PropertyList::iterator property = _properties.begin(); property != _properties.end(); ++property) {
+ if (property->first == "isa")
continue;
- output += parent->writeProperty((*property).first, (*property).second, flags);
+ output += _parent->writeProperty(property->first, property->second, flags);
}
- if (flags & SettingsAsList)
+ if (flags & kSettingsAsList)
output += "\t\t";
output += "};\n";
@@ -209,50 +200,59 @@ private:
return output;
}
- // Slight hack, to allow Group access to parent.
+ // Slight hack, to allow Group access to parent.
protected:
- XcodeProvider *parent;
+ XcodeProvider *_parent;
private:
// Returns the type property (should always be the first in the properties map)
std::string getType() {
- assert(!properties.empty());
- assert(!properties["isa"].settings.empty());
+ assert(!_properties.empty());
+ assert(!_properties["isa"]._settings.empty());
- SettingList::iterator it = properties["isa"].settings.begin();
+ SettingList::iterator it = _properties["isa"]._settings.begin();
- return (*it).first;
+ return it->first;
}
};
struct ObjectList {
private:
- std::map<std::string, bool> objectMap;
+ std::map<std::string, bool> _objectMap;
public:
- std::vector<Object *> objects;
- std::string comment;
- int flags;
+ std::vector<Object *> _objects;
+ std::string _comment;
+ int _flags;
void add(Object *obj) {
- std::map<std::string, bool>::iterator it = objectMap.find(obj->id);
- if (it != objectMap.end() && it->second == true)
+ std::map<std::string, bool>::iterator it = _objectMap.find(obj->_id);
+ if (it != _objectMap.end() && it->second == true)
return;
- objects.push_back(obj);
- objectMap[obj->id] = true;
+ _objects.push_back(obj);
+ _objectMap[obj->_id] = true;
+ }
+
+ Object *find(std::string id) {
+ for (std::vector<Object *>::iterator it = _objects.begin(); it != _objects.end(); ++it) {
+ if ((*it)->_id == id) {
+ return *it;
+ }
+ }
+ return NULL;
}
std::string toString() {
std::string output;
- if (!comment.empty())
- output = "\n/* Begin " + comment + " section */\n";
+ if (!_comment.empty())
+ output = "\n/* Begin " + _comment + " section */\n";
- for (std::vector<Object *>::iterator object = objects.begin(); object != objects.end(); ++object)
- output += (*object)->toString(flags);
+ for (std::vector<Object *>::iterator object = _objects.begin(); object != _objects.end(); ++object)
+ output += (*object)->toString(_flags);
- if (!comment.empty())
- output += "/* End " + comment + " section */\n";
+ if (!_comment.empty())
+ output += "/* End " + _comment + " section */\n";
return output;
}
@@ -271,10 +271,10 @@ private:
void addChildFile(const std::string &name);
void addChildByHash(const std::string &hash, const std::string &name);
// Should be passed the hash for the entry
- void addChildGroup(const Group* group);
+ void addChildGroup(const Group *group);
void ensureChildExists(const std::string &name);
Group *getChildGroup(const std::string &name);
- std::string getHashRef() const { return parent->getHash(id); }
+ std::string getHashRef() const { return _parent->getHash(_id); }
};
// The path used by the root-source group
@@ -312,18 +312,26 @@ private:
// Setup objects
void setupCopyFilesBuildPhase();
- void setupFrameworksBuildPhase();
+ void setupFrameworksBuildPhase(const BuildSetup &setup);
void setupNativeTarget();
void setupProject();
void setupResourcesBuildPhase();
void setupSourcesBuildPhase();
- void setupBuildConfiguration();
+ void setupBuildConfiguration(const BuildSetup &setup);
+ void setupImageAssetCatalog(const BuildSetup &setup);
+ void setupAdditionalSources(std::string targetName, Property &files, int &order);
// Misc
void setupDefines(const BuildSetup &setup); // Setup the list of defines to be used on build configurations
+ // Retrieve information
+ ValueList& getResourceFiles() const;
+
// Hash generation
std::string getHash(std::string key);
+#ifdef MACOSX
+ std::string md5(std::string key);
+#endif
std::string newHash() const;
// Output
diff --git a/devtools/create_project/xcode/create_project.xcodeproj/project.pbxproj b/devtools/create_project/xcode/create_project.xcodeproj/project.pbxproj
index f13bcf6969..4f06a5e469 100644
--- a/devtools/create_project/xcode/create_project.xcodeproj/project.pbxproj
+++ b/devtools/create_project/xcode/create_project.xcodeproj/project.pbxproj
@@ -140,6 +140,9 @@
/* Begin PBXProject section */
F9A66C1E1396D36100CEE494 /* Project object */ = {
isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0720;
+ };
buildConfigurationList = F9A66C211396D36100CEE494 /* Build configuration list for PBXProject "create_project" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
@@ -177,12 +180,14 @@
F9A66C2E1396D36100CEE494 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_OPTIMIZATION_LEVEL = 0;
- GCC_PREPROCESSOR_DEFINITIONS = DEBUG;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ POSIX,
+ MACOSX,
+ );
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
- GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
@@ -195,9 +200,11 @@
F9A66C2F1396D36100CEE494 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ POSIX,
+ MACOSX,
+ );
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
@@ -213,6 +220,10 @@
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ DEBUG,
+ );
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
@@ -224,6 +235,7 @@
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
diff --git a/devtools/create_translations/create_translations.h b/devtools/create_translations/create_translations.h
index 34a79913ac..e87e3923c3 100644
--- a/devtools/create_translations/create_translations.h
+++ b/devtools/create_translations/create_translations.h
@@ -26,10 +26,10 @@
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
-typedef signed short int16;
+typedef signed short int16;
-#ifndef __has_feature // Optional of course.
- #define __has_feature(x) 0 // Compatibility with non-clang compilers.
+#ifndef __has_feature // Optional of course.
+#define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif
#endif /* CREATE_TRANSLATIONS_H */
diff --git a/devtools/credits.pl b/devtools/credits.pl
index 41c2d4f162..9cc5ad4227 100755
--- a/devtools/credits.pl
+++ b/devtools/credits.pl
@@ -287,7 +287,7 @@ sub begin_section {
# headlines...
my $ascii_title = html_entities_to_ascii($title);
$title = html_entities_to_cpp($title);
- if ($ascii_title ne $title) {
+ if ($ascii_title ne $title) {
print '"A1""'.$ascii_title.'",' . "\n";
}
print '"C1""'.$title.'",' . "\n";
@@ -295,7 +295,7 @@ sub begin_section {
} else {
my $ascii_title = html_entities_to_ascii($title);
$title = html_entities_to_cpp($title);
- if ($ascii_title ne $title) {
+ if ($ascii_title ne $title) {
print '"A1""'.$ascii_title.'",' . "\n";
}
print '"C1""'.$title.'",' . "\n";
@@ -428,7 +428,7 @@ sub add_person {
if (length $desc > 0) {
my $ascii_desc = html_entities_to_ascii($desc);
$desc = html_entities_to_cpp($desc);
- if ($ascii_desc ne $desc) {
+ if ($ascii_desc ne $desc) {
print '"A2""'.$ascii_desc.'",' . "\n";
}
print '"C2""'.$desc.'",' . "\n";
@@ -536,10 +536,11 @@ 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", "");
- add_person("Walter van Niftrik", "waltervn", "(retired)");
+ add_person("Walter van Niftrik", "waltervn", "");
add_person("Kari Salminen", "Buddha^", "");
add_person("Eugene Sandulenko", "sev", "");
add_person("David Symonds", "dsymonds", "(retired)");
@@ -552,17 +553,26 @@ begin_credits("Credits");
add_person("Oliver Kiehl", "olki", "(retired)");
add_person("Ludvig Strigeus", "ludde", "(retired)");
end_section();
-
+
+ begin_section("Access");
+ add_person("Arnaud Boutonn&eacute;", "Strangerke", "");
+ add_person("Paul Gilbert", "dreammaster", "");
+ end_section();
+
begin_section("Avalanche");
add_person("Peter Bozs&oacute;", "uruk", "");
add_person("Arnaud Boutonn&eacute;", "Strangerke", "");
end_section();
+ begin_section("BBVS");
+ add_person("Benjamin Haisch", "john_doe", "");
+ end_section();
+
begin_section("CGE");
add_person("Arnaud Boutonn&eacute;", "Strangerke", "");
add_person("Paul Gilbert", "dreammaster", "");
end_section();
-
+
begin_section("CGE2");
add_person("Peter Bozs&oacute;", "uruk", "");
add_person("Arnaud Boutonn&eacute;", "Strangerke", "");
@@ -594,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");
@@ -604,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", "");
@@ -637,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();
@@ -659,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", "");
@@ -681,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");
@@ -704,12 +720,17 @@ begin_credits("Credits");
add_person("Max Horn", "Fingolfin", "(retired)");
add_person("Filippos Karapetis", "[md5]", "");
add_person("Martin Kiewitz", "m_kiewitz", "");
- add_person("Walter van Niftrik", "waltervn", "(retired)");
+ add_person("Walter van Niftrik", "waltervn", "");
add_person("Willem Jan Palenstijn", "wjp", "");
add_person("Jordi Vilalta Prat", "jvprat", "");
add_person("Lars Skovlund", "lskovlun", "");
end_section();
+ begin_section("Sherlock");
+ add_person("Paul Gilbert", "dreammaster", "");
+ add_person("Martin Kiewitz", "m_kiewitz", "");
+ end_section();
+
begin_section("Sky");
add_person("Robert G&ouml;ffringmann", "lavosspawn", "(retired)");
add_person("Oliver Kiehl", "olki", "(retired)");
@@ -788,7 +809,7 @@ begin_credits("Credits");
add_person("Einar Johan T. S&oslash;m&aring;en", "somaen", "");
add_person("Tobia Tesan", "t0by", "");
end_section();
-
+
begin_section("Z-Vision");
add_person("Adrian Astley", "RichieSams", "");
add_person("Filippos Karapetis", "[md5]", "");
@@ -802,18 +823,24 @@ 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");
add_person("Marcus Comstedt", "", "");
end_section();
+ begin_section("GCW0");
+ add_person("Eugene Sandulenko", "", "");
+ end_section();
+
begin_section("GPH Devices (GP2X, GP2XWiz &amp; Caanoo)");
add_person("John Willis", "DJWillis", "");
end_section();
- begin_section("iPhone");
+ begin_section("iPhone / iPad");
add_person("Oystein Eftevaag", "vinterstum", "");
+ add_person("Vincent B&eacute;nony", "bSr43", "");
end_section();
begin_section("LinuxMoto");
@@ -825,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();
@@ -877,6 +908,10 @@ begin_credits("Credits");
add_person("Andre Heider", "dhewg", "");
end_section();
+ begin_section("Raspberry Pi");
+ add_person("Manuel Alfayate", "vanfanel", "");
+ end_section();
+
end_section();
begin_section("Other subsystems");
@@ -929,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();
@@ -983,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");
@@ -1286,6 +1322,15 @@ begin_credits("Credits");
"Bob Bell, Michel Kripalani, Tommy Yune, from Presto Studios for ".
"providing the source code of The Journeyman Project: Pegasus Prime.");
+ add_paragraph(
+ "Electronic Arts IP Preservation Team, particularly Stefan Serbicki, and Vasyl Tsvirkunov of ".
+ "Electronic Arts for providing the source code of the two Lost Files of Sherlock Holmes games. ".
+ "James M. Ferguson and Barry Duncan for their tenacious efforts to recover the sources.");
+
+ add_paragraph(
+ "The mindFactory team for writing Broken Sword 2.5, a splendid fan-made sequel, and for sharing ".
+ "the source code with us.");
+
end_section();
end_credits();
diff --git a/devtools/dist-scummvm.sh b/devtools/dist-scummvm.sh
index ac411c55a3..56e6b4e05e 100755
--- a/devtools/dist-scummvm.sh
+++ b/devtools/dist-scummvm.sh
@@ -4,6 +4,7 @@
#
# Largely based on dist-fink.sh, Copyright (c) 2001 Christoph Pfisterer.
# Modified to use Subversion instead of CVS by Max Horn in 2007.
+# Modified to use git by Eugene Sandulenko in 2015.
#
# ScummVM is the legal property of its developers, whose names
# are too numerous to list here. Please refer to the COPYRIGHT
@@ -26,25 +27,44 @@
### configuration
-svnroot='https://scummvm.svn.sourceforge.net/svnroot/scummvm'
+scummvmrepo='https://github.com/scummvm/scummvm.git'
+toolsrepo='https://github.com/scummvm/scummvm-tools.git'
### init
if [ $# -lt 2 ]; then
- echo "Usage: $0 <module> <version-number> [<temporary-directory> [<tag>]]"
+ echo "Usage: $0 <scummvm | scummvm-tools> <version-number> [<temporary-directory> [<tag>]]"
exit 1
fi
+echo_n() {
+ printf "$@"
+}
+
module=$1
version=$2
tmpdir=${3:-/tmp}
tag=$4
if [ -z "$tag" ]; then
- tag=release-`echo $version | sed 's/\./-/g'`
+ tag="v$version"
fi
fullname="$module-$version"
-echo "packaging $module release $version, SVN tag $tag"
+# Check modules
+case $module in
+scummvm)
+ gitrepo=$scummvmrepo
+;;
+scummvm-tools)
+ gitrepo=$toolsrepo
+;;
+*)
+ echo "Unknown module $module. Only scummvm or scummvm-tools are supported"
+ exit 1
+esac
+
+
+echo "packaging $module release $version, GIT tag $tag"
### setup temp directory
@@ -54,25 +74,39 @@ umask 022
if [ -d $fullname ]; then
echo "There is a left-over directory in $tmpdir."
- echo "Remove $fullname, then try again."
+ echo "Remove $tmpdir/$fullname, then try again."
exit 1
fi
-### check code out from SVN
-# TODO: Add support for making tarballs from trunk / branches?
+### check code out from GIT
-echo "Exporting module $module, tag $tag from SVN:"
-svn export "$svnroot/$module/tags/$tag" $fullname
+echo "Cloning module $module from GIT:"
+git clone $gitrepo $fullname
if [ ! -d $fullname ]; then
- echo "SVN export failed, directory $fullname doesn't exist!"
+ echo "GIT clone failed, directory $fullname doesn't exist!"
exit 1
fi
+cd $tmpdir/$fullname
+
+echo_n "Checking out tag $tag..."
+if git checkout $tag --quiet 2>/dev/null; then
+ echo done
+else
+ echo "checking out tag $tag failed."
+ exit 1
+fi
+
+cd $tmpdir
+
+echo "Cleaning up .git directory"
+rm -rf $fullname/.git
+
### roll the tarball
-echo "Creating tarball $fullname.tar:"
+echo "Creating tarball $fullname.tar..."
rm -f $fullname.tar $fullname.tar.gz
-tar -cvf $fullname.tar $fullname
+tar -cf $fullname.tar $fullname
echo "Compressing (using gzip) tarball $fullname.tar.gz..."
gzip -c9 $fullname.tar > $fullname.tar.gz
@@ -88,8 +122,15 @@ if [ ! -f $fullname.tar.bz2 ]; then
exit 1
fi
+echo "Compressing (using xz) tarball $fullname.tar.xz..."
+xz -c9 $fullname.tar > $fullname.tar.xz
+if [ ! -f $fullname.tar.xz ]; then
+ echo "Packaging to xz failed, $fullname.tar.xz doesn't exist!"
+ # But do not exit
+fi
+
echo "Zipping $fullname.zip..."
-zip -r9 $fullname.zip $fullname
+zip -r9 $fullname.zip $fullname >/dev/null
if [ ! -f $fullname.zip ]; then
echo "Packaging failed, $fullname.zip doesn't exist!"
exit 1
@@ -99,6 +140,7 @@ fi
### finish up
echo "Done:"
-ls -l $fullname.tar.gz $fullname.tar.bz2 $fullname.zip
+ls -l $fullname.tar.gz $fullname.tar.bz2 $fullname.tar.xz $fullname.zip
+md5sum $fullname.tar.gz $fullname.tar.bz2 $fullname.tar.xz $fullname.zip
exit 0
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 ffde276a3d..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
@@ -81,13 +82,15 @@ maniac Maniac Mansion
183d7464902d40d00800e8ee1f04117c 1988 de DOS V2 V2 - Fingolfin
87f6e8037b7cc996e13474b491a7a98e -1 it DOS V2 V2 from DOTT Andrea Petrucci
0d1b69471605201ef2fa9cec1f5f02d2 -1 es DOS V2 V2 - abnog, Andrea Petrucci
+ f0d294891b813d3dcc525b89bc318815 1988 ru DOS V2 V2 - sev
40564ec47da48a67787d1f9bd043902a 1988 en DOS V2 Demo V2 Demo non-interactive Fingolfin
+ 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
@@ -95,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
@@ -106,8 +109,9 @@ zak Zak McKracken and the Alien Mindbenders
d06fbe28818fef7bfc45c2cdf0c0849d -1 de DOS V2 V2 from 5.25\" floppies Nicolas Sauz&egrave;de, Andrea Petrucci
1900e501a52fbf55bde6e4196f6d2aa6 -1 it DOS V2 V2 - Andrea Petrucci
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
@@ -117,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
@@ -127,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
@@ -140,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
@@ -152,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
@@ -164,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
@@ -184,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
@@ -207,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
@@ -222,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
@@ -233,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
@@ -252,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
@@ -265,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
@@ -292,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
@@ -335,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
@@ -355,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
@@ -369,6 +375,7 @@ dig The Dig
aad201302286c1cfee92321cd406e427 811008 en Windows Steam Steam Steam Version Ben Castricum, Filippos Karapetis
d93cc8be628ed5d3b3a29188fc7105d3 1061296 en Mac Steam Steam Steam Version Filippos Karapetis
d62047a6729349ab36f7ee065bf26509 -1 ru All - - - sev
+ ebdd2fbc995a321605375dc57766db79 16304 ru All - With Subtitles - sev
35a2d3040fa512f8232d9e443319d84d 659335495 en Mac - - Mac bundle Fingolfin
21a6592322f92550f144f68a8a4e685e -1 fr Mac - - Mac bundle kaminari
@@ -377,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
@@ -492,8 +499,9 @@ freddi Freddi Fish 1: The Case of the Missing Kelp Seeds
5ebb57234b2fe5c5dff641e00184ad81 -1 fr Windows HE 73 - - gist974
cf8ef3a1fb483c5c4b1c584d1167b2c4 -1 de Windows HE 73 - - Oncer
1f2e62b5a9c50589fc342285a6bb3a27 -1 he Windows HE 73 - - e_orz
+ 64a22be96d679018696e5c8d3ca8b71d 26375 jp Windows HE 73 - - sev
507bb360688dc4180fdf0d7597352a69 26402 se Windows HE 73 - - Sven Arvidsson
- df047cc4792150f601290357566d36a6 -1 us All HE 90 Updated - khalek
+ df047cc4792150f601290357566d36a6 -1 en All HE 90 Updated - khalek
e44ea295a3f8fe4f41983080dab1e9ce -1 fr Mac HE 90 Updated - ThierryFR
746e88c172a5b7a1ae89ac0ee3ee681a -1 ru Windows HE 90 Updated - sev
a197a87ae77f3b3333f09a7a2c448fe2 -1 en Windows HE 99 Updated - Jonathan
@@ -522,9 +530,9 @@ freddi2 Freddi Fish 2: The Case of the Haunted Schoolhouse
5057fb0e99e5aa29df1836329232f101 -1 All Windows HE 80 - - sev
ac62d50e39492ee3738b4e83a5ac780f -1 nl Windows HE 80 - - joostp
151071053a1d0021198216713939521d -1 en Windows HE 80 - - vampir_raziel
- 51305e929e330e24a75a0351c8f9975e -1 us All HE 99 Updated - Kirben
+ 51305e929e330e24a75a0351c8f9975e -1 en All HE 99 Updated - Kirben
9c0ee9c252785e9fca0143e42ac4b256 -1 de Windows HE 99 Updated - George Kormendi
- 8ee63cafb1fe9d62aa0d5a23117e70e7 -1 us All HE 100 Updated - Kirben
+ 8ee63cafb1fe9d62aa0d5a23117e70e7 -1 en All HE 100 Updated - Kirben
e41de1c2a15abbcdbf9977e2d7e8a340 -1 ru Windows HE 100 Updated - sev
c20848f53c2d48bfacdc840993843765 -1 nl All HE 80 Demo - DarthBo
@@ -532,7 +540,7 @@ freddi2 Freddi Fish 2: The Case of the Haunted Schoolhouse
d37c55388294b66e53e7ced3af88fa68 -1 en All HE 100 Updated Demo - khalek
freddi3 Freddi Fish 3: The Case of the Stolen Conch Shell
- 8368f552b1e3eba559f8d559bcc4cadb -1 All All - - - Kirben, sev
+ 8368f552b1e3eba559f8d559bcc4cadb 55959 All All - - - Kirben, sev (US and ???)
0cccfa5223099a60e76cfcca57a1a141 -1 nl All - - - adutchguy, daniel9
008e76ec3ae58d0add637ea7aa299a2c -1 fr Mac - - - ThierryFR
898ce8eb1234a955ef75e87141902bb3 -1 ru Windows - - - sev
@@ -550,7 +558,7 @@ freddi3 Freddi Fish 3: The Case of the Stolen Conch Shell
d73c851b942af44deb9b6d5f416a0972 -1 he Windows HE 99 Demo - Ori Avtalion
freddi4 Freddi Fish 4: The Case of the Hogfish Rustlers of Briny Gulch
- 4f580a021eee026f3b4589e17d130d78 -1 All All - - - Kirben, sev
+ 4f580a021eee026f3b4589e17d130d78 44190 All All - - - Kirben, sev (US and ???)
14d48c95b43ddeb983254cf6c43851f1 -1 nl All - - - adutchguy, daniel9
3b832f4a90740bf22e9b8ed42ca0128c -1 gb All HE 99 - - Reckless
d74122362a77ec24525fdd50297dfd82 -1 fr Mac - - - ThierryFR
@@ -580,7 +588,7 @@ freddi4 Freddi Fish 4: The Case of the Hogfish Rustlers of Briny Gulch
47e041521d35c7a801bb1c010d84da9d -1 it Windows HE 99 Demo - Kirben
freddicove Freddi Fish 5: The Case of the Creature of Coral Cove
- 590e6546aacd0d374b7f3a4f53013ab1 -1 All All - - - cyx
+ 590e6546aacd0d374b7f3a4f53013ab1 41165 All All - - - cyx (US and ???)
21abe302e1b1e2b66d6f5c12e241ebfd -1 ru Windows unenc Unencrypted - sev
b8955d7d23b4972229060d1592489fef -1 nl All HE 100 - - adutchguy, daniel9
8f345db2f3f5a25ed6305001957e6f72 41182 nl All HE 100 - - Ben Castricum
@@ -650,12 +658,12 @@ moonbase Moonbase Commander
ef71a322b6530ac45b1a070f7c0795f7 -1 en Windows Demo Demo - Kirben
pajama Pajama Sam 1: No Need to Hide When It's Dark Outside
- 672dec94b82f7f0877ebb5b5cf7f4bc1 -1 us All - - - khalek
+ 672dec94b82f7f0877ebb5b5cf7f4bc1 -1 en All - - - khalek
1d7a2e1ddcade791e2de0cfceac86725 -1 fr All - - - gist974, ThierryFR
4fa6870d9bc8c313b65d54b1da5a1891 -1 nl All - - - joostp
a095e33061606d231ff37dca4c64c8ac -1 de All HE 99 - - Joachim Eberhard
898eaa21f79cf8d4f08db856244689ff 66505 en Windows HE 99 Updated - Joachim Eberhard
- 37aed3f91c1ef959e0bd265f9b13781f -1 us All HE 100 Updated - Kirben
+ 37aed3f91c1ef959e0bd265f9b13781f 66599 en All HE 100 Updated - Kirben
4aa93cb30e485b728504ba3a693f12bf -1 ru Windows HE 100 - - sev
782393c5934ecd0b536eaf5fd541bd26 -1 en Windows HE 101 Updated - Jonathan
c225bec1b6c0798a2b8c89ac226dc793 -1 en Wii HE 101 - - sanguinehearts
@@ -759,20 +767,20 @@ 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
puttcircus Putt-Putt Joins the Circus
ecc4340c2b801f5af8da4e00c0e432d9 -1 nl All - - - daniel9
- ab0693e9324cfcf498fdcbb12acf8bb4 -1 en All - - - sev
+ ab0693e9324cfcf498fdcbb12acf8bb4 36655 us All - - - sev
7bad72e332a59f9fcc1d437f4edad32a -1 ru All - - - sev
db74136c20557eca6ed3411bff39f7a1 -1 gb Windows - - - Reckless
d0ad929def3e9cfe39dea55bd12098d4 -1 fr Windows - - - gist974
febf4a983ea5faea1c9dd6c710ebb09c -1 de Windows - - - andy482
c8253da0f4626d2236b5291b99e33408 -1 he Windows HE 99 - - Matan Bareket
- a7cacad9c40c4dc9e1812abf6c8af9d5 -1 en All - Demo - Kirben, sev
+ a7cacad9c40c4dc9e1812abf6c8af9d5 -1 us All - Demo - Kirben, sev
1387d16aa620dc1c2d1fd87f8a9e7a09 -1 fr Windows - Demo - Mevi
3af61c5edf8e15b43dbafd285b2e9777 -1 he Windows - Demo - Ori Avtalion
@@ -787,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
@@ -799,7 +807,7 @@ puttzoo Putt-Putt Saves the Zoo
9781422e4288dbc090720e4563168ba7 -1 fr Windows - - - gist974
0f9d3317910ac7a9f449243118884ada 42070 de Windows - - - George Kormendi
92e7727e67f5cd979d8a1070e4eb8cb3 -1 en All HE 98.5 Updated - cyx
- 3a3e592b074f595489f7f11e150c398d -1 us Windows HE 99 Updated - Adrian
+ 3a3e592b074f595489f7f11e150c398d -1 en Windows HE 99 Updated - Adrian
c5cc7cba02a2fbd539c4439e775b0536 43470 de Windows HE 99 Updated - Lightkey
5c9cecbd2952ccec14c9ecebf5822a34 -1 en iOS HE 100 - - clone2727
7b4ee071eecadc2d8cd0c3509110825c -1 en Windows HE 100 Remastered - Kirben
@@ -815,7 +823,7 @@ puttzoo Putt-Putt Saves the Zoo
PuttTime Putt-Putt Travels Through Time
fcb78ebecab2757264c590890c319cc5 -1 nl All HE 85 - - adutchguy, daniel9
- 63fdcdc95cdeea00060883aed38e5504 -1 en All HE 85 - - iziku
+ 63fdcdc95cdeea00060883aed38e5504 62582 us All HE 85 - - iziku
db21a6e338fe3b70c2723b6530865bf2 -1 fr All HE 85 - - gist974, ThierryFR
84e3c23a49ded8a6f9197735c8eb3de7 -1 de Windows HE 85 - - oncer
2108d83dcf09f8adb4bc524669c8cf51 -1 us All HE 99 Updated - Kirben
@@ -829,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
@@ -840,9 +848,9 @@ balloon Putt-Putt and Pep's Balloon-O-Rama
bab0fb81dcb12b8930c5d850b8f2a7de 12800 de Windows HE 80 - - George Kormendi
145bd3373574feb668cc2eea2ec6cf86 -1 ru Windows HE 80 - - sev
27b2ef1653089fe5b897d9cc89ce784f -1 ru Windows HE 80 - - George Kormendi
- 2232b0b9411575b1f9961713ebc9de61 -1 nl Windows HE 80 - - Ben Castricum
- a22af0ad0e3126d19d22707b0267a37d -1 nl Windows HE 80 - - Ben Castricum
- a56a05c6b865b9956639f8c51269e5ab -1 nl Mac HE 80 - - Ben Castricum
+ 2232b0b9411575b1f9961713ebc9de61 12800 nl Windows HE 80 - - Ben Castricum
+ a22af0ad0e3126d19d22707b0267a37d 12800 nl Windows HE 80 - - Ben Castricum
+ a56a05c6b865b9956639f8c51269e5ab 12800 nl Mac HE 80 - - Ben Castricum
d7b247c26bf1f01f8f7daf142be84de3 -1 en Windows HE 99 Updated - iziku
8e3241ddd6c8dadf64305e8740d45e13 -1 en All HE 100 Updated - Kirben
@@ -854,55 +862,55 @@ 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
spyfox SPY Fox 1: Dry Cereal
- 6bf70eee5de3d24d2403e0dd3d267e8a 49221 All Windows - - - khalek
+ 6bf70eee5de3d24d2403e0dd3d267e8a 49221 All Windows - - - khalek (US and ???)
100b4c8403ad6a83d4bf7dbf83e44dc4 -1 fr Windows - - - gist974
9bda5fee51d2fda5253d02c642016bf4 -1 nl All HE 98.5 - - daniel9, joostp
- 58436e634f4fae1d9973591c2ffa1fcb -1 en All HE 99 Updated - Joachim Eberhard
+ 58436e634f4fae1d9973591c2ffa1fcb -1 en All HE 99 Updated - Joachim Eberhard (GB or US?)
a28135a7ade38cc0208b04507c46efd1 -1 de All HE 99 - - nachbarnebenan
ee785fe2569bc9965526e774f7ab86f1 -1 fr Mac HE 99 - - ThierryFR
76b66b43e593ad4d2f1dfb5cc8f19700 -1 nl Windows HE 99 - - sugarcube
72ac6bc980d5101c2142189d746bd62f -1 ru Windows HE 99 - - sev
3de99ef0523f8ca7958faa3afccd035a -1 us All HE 100 Updated - Kirben
- 23394c8d29cc63c61313959431a12476 -1 en Windows HE 100 Updated - Jonathan
- 50b831f11b8c4b83784cf81f4dcc69ea -1 en Wii HE 101 - - sanguinehearts
- 15878e3bee2e1e759184abee98589eaa -1 en iOS HE 100 - - clone2727
+ 23394c8d29cc63c61313959431a12476 -1 en Windows HE 100 Updated - Jonathan (GB or US?)
+ 50b831f11b8c4b83784cf81f4dcc69ea -1 en Wii HE 101 - - sanguinehearts (GB or US?)
+ 15878e3bee2e1e759184abee98589eaa -1 en iOS HE 100 - - clone2727 (GB or US?)
- 53e94115b55dd51d4b8ff0871aa1df1e 20103 en All - Demo - khalek, sev
- fbdd947d21e8f5bac6d6f7a316af1c5a 15693 en All - Demo - sev
+ 53e94115b55dd51d4b8ff0871aa1df1e 20103 us All - Demo - khalek, sev
+ fbdd947d21e8f5bac6d6f7a316af1c5a 15693 us All - Demo - sev
ba888e6831517597859e91aa173f945c -1 fr All - Demo - Kirben
73b8197e236da4bf49adc99fe8f5fa1b -1 de All - Demo - Joachim Eberhard
4edbf9d03550f7ba01e7f34d69b678dd -1 nl All HE 98.5 Demo - Kirben
- f2ec78e50bdc63b70044e9758be10914 -1 nl Mac HE 98.5 Demo - Ben Castricum
- 9d4ab3e0e1d1ebc6ba8a6a4c470ed184 -1 en All HE 100 Demo - khalek
+ f2ec78e50bdc63b70044e9758be10914 20141 nl Mac HE 98.5 Demo - Ben Castricum
+ 9d4ab3e0e1d1ebc6ba8a6a4c470ed184 15943 us All HE 100 Demo - khalek
spyfox2 SPY Fox 2: Some Assembly Required
- f79e60c17cca601e411f1f75e8ee9b5a 51286 All All - - - Kirben
+ f79e60c17cca601e411f1f75e8ee9b5a 51286 All All - - - Kirben (US and ???)
90e2f0af4f779629695c6394a65bb702 -1 fr All - - - gist974, ThierryFR
bc4700bc0e12879f6d25d14d6be6cfdd -1 de All - - - Joachim Eberhard
3785fd25f7e02b5782bfc5072d8f77c8 -1 it All - - - Saleck
cea91e3dd47f2518ea418e41611aa77f -1 ru All - - - sev
- 9fd66fb3b04703bd50da4356e4202558 51295 en Mac - - - pix_climber
+ 9fd66fb3b04703bd50da4356e4202558 51295 en Mac - - - pix_climber (GB or US?)
71fe97c3108678cf604f14abe342341b 51286 nl All - - - adutchguy
1c792d28376d45e145cb916bca0400a2 -1 nl All - Demo - joostp
7222f260253f325c21fcfa68b5bfab67 -1 us All - Demo - Kirben
732845548b1d6c2da572cb6a1bf81b07 -1 de All - Demo - Joachim Eberhard
- e62056ba675ad65d8854ab3c5ad4b3c0 14689 en Windows - Mini Game - Trekky
+ e62056ba675ad65d8854ab3c5ad4b3c0 14689 gb Windows - Mini Game - Trekky
22c7432dc97a821fcfccd480e93e3911 14689 nl Windows - Mini Game - Ben Castricum
6b10c9977cad9de503642059359792b1 14689 fr Windows - Mini Game - Ben Castricum
9684c161258d68e0d464d6cab7024b9c 14689 it Windows - Mini Game - Ben Castricum
@@ -917,9 +925,9 @@ 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 en All - Demo - Kirben
+ ebd0b2c8a387f18887282afe6cad894a 15317 us All - Demo - Kirben
a99c39ba65b6086be28aef576da69595 -1 fr Windows - Demo - Mevi
65563295c3a06493351870f20a1630cf 5235008 All All HE CUP Preview - sev
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 b313846ab3..3b5f892c3f 100755
--- a/devtools/update-version.pl
+++ b/devtools/update-version.pl
@@ -37,12 +37,13 @@ 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
dists/win32/scummvm.nsi
dists/wii/meta.xml
dists/android/AndroidManifest.xml
- dists/android/plugin-manifest.xml
dists/openpandora/PXML.xml
dists/openpandora/README-OPENPANDORA
dists/openpandora/README-PND.txt
diff --git a/dists/amiga/RM2AG.rx b/dists/amiga/RM2AG.rx
new file mode 100644
index 0000000000..6ee56bb645
--- /dev/null
+++ b/dists/amiga/RM2AG.rx
@@ -0,0 +1,170 @@
+/*
+README to .guide converter $Ver: 0.13 (29.01.2016)
+
+This script converts the pure ASCII-text based README file of ScummVM to a
+basic Amiga guide file.
+
+More AmigaGuide features being added in the process if feasible.
+*/
+
+PARSE ARG readme_txt
+
+/* Check if the given file is really the readme */
+/* If a given filename has spaces in it's name, AmigaDOS/AmigaCLI will add extra quotation marks
+to secure a sane working path. We get rid of them to make AREXX find the file */
+readme_txt=COMPRESS(readme_txt,'"')
+OPEN(check_readme,readme_txt,'R')
+IF READCH(check_readme,14) = 'ScummVM README' THEN
+ CLOSE(check_readme)
+ELSE DO
+ SAY "Not the README file. Aborting!"
+ CLOSE(readme_read)
+ EXIT 0
+END
+
+/* If it's the proper file, lets start converting */
+
+OPEN(readme_read,readme_txt,'R')
+OPEN(guide_write,'README.guide','W')
+
+/* Prepare the Amiga guide file, add the intro and fixed text */
+
+WRITELN(guide_write,'@DATABASE ScummVM README.guide')
+WRITELN(guide_write,'@WORDWRAP')
+WRITELN(guide_write,'@NODE "main" "ScummVM README Guide"')
+WRITELN(guide_write,' ')
+WRITELN(guide_write,'@{b}')
+WRITELN(guide_write,READLN(readme_read))
+WRITELN(guide_write,'@{ub}')
+
+/* Creating the main link nodes */
+
+x=1
+
+DO WHILE EOF(readme_read) = 0
+ /* Read in the line */
+ working_line=READLN(readme_read)
+
+ /* Checking if the sub links have been reached and leave the loop, if met */
+ IF POS('°1.0°',working_line) = 1 & x > 1 THEN
+ LEAVE
+ ENDIF
+ /* If no chapter has been found, simply write the line */
+ IF POS('°',working_line) = 0 THEN
+ WRITELN(guide_write,working_line)
+ ENDIF
+
+ /* Fix the empty chapters - two chapters (1.0 and 7.8) are empty and consist of only the headlines.
+ We add them to the following chapter and link both of them to the empty one */
+
+ /* If chapter 1.1 is found add a link node to 1.0 (as chapter 1.0 is empty) */
+ IF POS(' * °1.1°',working_line) = 1 THEN DO
+ /* Get rid of the markers so the following loops doesn't process them again */
+ working_line=COMPRESS(working_line,'*°')
+ WRITELN(guide_write,' @{" 1.1 " Link "1.0"} 'working_line)
+ END
+
+ /* If chapter 7.8.1 is found add a link node to 7.8 (as chapter 7.8 is empty) */
+ IF POS(' * * °7.8.1°',working_line) = 1 THEN DO
+ /* Get rid of the markers so the following loops doesn't process them again */
+ working_line=COMPRESS(working_line,'*°')
+ WRITELN(guide_write,' @{" 7.8.1 " Link "7.8"} 'working_line)
+ END
+
+ /* If a single number main chapter is found 1.0 upto 9.0), prepare and write the link node */
+ IF POS('.0',working_line) = 3 THEN DO
+ WRITELN(guide_write,' ')
+ WRITELN(guide_write,' @{" 'SUBSTR(working_line,POS('°',working_line)+1,LASTPOS('°',working_line)-POS('°',working_line)-1) '" Link "'SUBSTR(working_line,POS('°',working_line)+1,LASTPOS('°',working_line)-POS('°',working_line)-1)'"} 'COMPRESS(working_line,'*°'))
+ /* Get rid of the markers so the following loops doesn't process them again */
+ working_line=COMPRESS(working_line,'*°')
+ x=x+1
+ END
+
+ /* If a double number main chapter is found (10.0 ff), prepare and write the link node */
+ IF POS('.0',working_line) = 4 THEN DO
+ WRITELN(guide_write,' ')
+ WRITELN(guide_write,' @{" 'SUBSTR(working_line,POS('°',working_line)+1,LASTPOS('°',working_line)-POS('°',working_line)-1) '" Link "'SUBSTR(working_line,POS('°',working_line)+1,LASTPOS('°',working_line)-POS('°',working_line)-1)'"} 'COMPRESS(working_line,'*°'))
+ /* Get rid of the markers so the following loops doesn't process them again */
+ working_line=COMPRESS(working_line,'*°')
+ END
+
+ /* If a level one sub chapter is found (i.e. 1.1), prepare and write the link node */
+ IF POS(' * °',working_line) = 1 THEN DO
+ WRITELN(guide_write,' @{" 'SUBSTR(working_line,POS('°',working_line)+1,LASTPOS('°',working_line)-POS('°',working_line)-1) '" Link "'SUBSTR(working_line,POS('°',working_line)+1,LASTPOS('°',working_line)-POS('°',working_line)-1)'"} 'COMPRESS(working_line,'*°'))
+ /* Get rid of the markers so the following loops doesn't process them again */
+ working_line=COMPRESS(working_line,'*°')
+ END
+
+ /* If a level two sub chapter is found (i.e. 1.1.1), prepare and write the link node */
+ IF POS(' * * °',working_line) = 1 THEN DO
+ WRITELN(guide_write,' @{" 'SUBSTR(working_line,POS('°',working_line)+1,LASTPOS('°',working_line)-POS('°',working_line)-1) '" Link "'SUBSTR(working_line,POS('°',working_line)+1,LASTPOS('°',working_line)-POS('°',working_line)-1)'"} 'COMPRESS(working_line,'*°'))
+ /* Get rid of the markers so the following loops doesn't process them again */
+ working_line=COMPRESS(working_line,'*°')
+ END
+END
+
+/* Finish the TOC, hardcoded due the outro text getting read in last, but needs to be read/written after the TOC creation */
+WRITELN(guide_write,'------------------------------------------------------------------------')
+WRITELN(guide_write,'Good Luck and Happy Adventuring!')
+WRITELN(guide_write,'The ScummVM team.')
+WRITELN(guide_write,'@{"http://www.scummvm.org/" System "URLOpen http://www.scummvm.org/"}')
+WRITELN(guide_write,'------------------------------------------------------------------------')
+
+/* Creating the sub links nodes */
+
+DO WHILE EOF(readme_read) = 0
+ /* If no chapter has been found, simply write the line */
+ IF POS('°',working_line) = 0 THEN
+ WRITELN(guide_write,working_line)
+ ENDIF
+
+ /* Fix the empty chapters - two chapters (1.0 and 7.8) are empty and consist of only the Headlines.
+ We don't close the NODE, rather add the following chapter to the former empty one */
+
+ /* If chapter 1.1 is found don't close the NODE, just write the line */
+ IF POS('°1.1°',working_line) = 1 THEN DO
+ /* Get rid of the markers so the following loops doesn't process them again */
+ working_line=COMPRESS(working_line,'°')
+ WRITELN(guide_write,working_line)
+ END
+ /* If chapter 7.8.1 is found don't close the NODE, just write the line */
+ IF POS('°7.8.1°',working_line) = 1 THEN DO
+ /* Get rid of the markers so the following loops doesn't process them again */
+ working_line=COMPRESS(working_line,'°')
+ WRITELN(guide_write,working_line)
+ END
+
+ IF POS('°',working_line) > 0 THEN DO
+ /* Check for link references inside the text and create link nodes for them */
+ IF POS('section °',working_line) > 0 THEN DO
+ working_line=SUBSTR(working_line,1,POS('°',working_line)-1)'@{"'SUBSTR(working_line,POS('°',working_line)+1,LASTPOS('°',working_line)-POS('°',working_line)-1)'" Link "'SUBSTR(working_line,POS('°',working_line)+1,LASTPOS('°',working_line)-POS('°',working_line)-1)'"}'SUBSTR(working_line,LASTPOS('°',working_line)+1)
+ /* Get rid of the markers so the following loops doesn't process them again */
+ WRITELN(guide_write,COMPRESS(working_line,'°'))
+ END
+ ELSE DO
+ /* If a chapter has been found, prepare and write the link */
+ WRITELN(guide_write,'@ENDNODE')
+ WRITELN(guide_write,'@NODE "'SUBSTR(working_line,POS('°',working_line)+1,LASTPOS('°',working_line)-POS('°',working_line)-1)'" "'COMPRESS(working_line,'°')'"')
+ WRITELN(guide_write,' ')
+ /* Get rid of the markers so the following loops doesn't process them again */
+ WRITELN(guide_write,COMPRESS(working_line,'°'))
+ END
+ END
+
+ /* Read in the line at the end of the second loop, as the first line to work with was already read in on the end of the first loop */
+ working_line=READLN(readme_read)
+
+ /* If the outtro text is found, leave the loop and prepare for closing */
+ IF POS('------------------------------------------------------------------------',working_line) > 0 THEN
+ LEAVE
+ ENDIF
+END
+
+WRITELN(guide_write,'@ENDNODE')
+
+/* Closing the guide and cleaning up */
+WRITELN(guide_write,'@ENDNODE')
+
+CLOSE(readme_read)
+CLOSE(guide_write)
+EXIT 0 \ No newline at end of file
diff --git a/dists/amiga/convertRM.sed b/dists/amiga/convertRM.sed
new file mode 100644
index 0000000000..47b6707001
--- /dev/null
+++ b/dists/amiga/convertRM.sed
@@ -0,0 +1,17 @@
+# $VER: READMEconverter.sed 1.04 (22.12.2015) © Eugene "sev" Sandulenko
+# Additions by Raziel
+#
+# Preprocessing the README file and adding some landmarks for easier parsing
+# and for converting it to an AmigaGuide Hypertext file later.
+#
+s/http:\/\/[#?=&a-zA-Z0-9_.\/\-]*/@{"&" System "URLOpen &"}/ # Convert all URLs to AmigaGuide format
+s/https:\/\/[#?=&a-zA-Z0-9_.\/\-]*/@{"&" System "URLOpen &"}/ # Convert all secure URLs to AmigaGuide format
+s/[0-9][0-9]*\.[0-9][0-9]*/°&°/ # Convert all chapter numbers to °x°...
+s/°\([0-9][0-9]*\.[0-9][0-9]*\)°\(\.[0-9]\)/°\1\2°/ # ...and all three-digit chapter numbers...
+s/°\([01]\.[0-9][0-9]*\.[0-9][0-9]*\)°/\1/ # ...and restore mentioned version numbers like 1.0.0 and 0.7.0.
+s/of °0\.0°/of 0.0/ # "Fluidsynth's gain setting of 0.0" is not a chapter reference.
+s/through °10\.0°/through 10.0/ # "through 10.0" is not a chapter reference.
+s/ttf-°2\.00.1°/ttf-2.00.1/ # This part of an url link is not a chapter reference.
+s/patch °1\.2°/patch 1.2/ # "Zork patch 1.2" is not a chapter reference.
+s/Mac OS X °10\.2.8°/Mac OS X 10.2.8/ # "Mac OS X 10.2.8" is not a chapter reference.
+s/Mac_OS_X_°10\.2.8°/Mac_OS_X_10.2.8/ # "Mac_OS_X_10.2.8" is not a chapter reference. \ No newline at end of file
diff --git a/dists/android/AndroidManifest.xml b/dists/android/AndroidManifest.xml
index ba1046e85c..c091039266 100644
--- a/dists/android/AndroidManifest.xml
+++ b/dists/android/AndroidManifest.xml
@@ -4,7 +4,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.scummvm.scummvm"
android:versionCode="@ANDROID_VERSIONCODE@"
- android:versionName="1.8.0git"
+ android:versionName="1.9.0git"
android:sharedUserId="org.scummvm.scummvm">
<!-- This version works on Android 1.5 (SDK 3) and newer, but we
@@ -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/debian/copyright b/dists/debian/copyright
index 734ec77039..06705fd6bc 100644
--- a/dists/debian/copyright
+++ b/dists/debian/copyright
@@ -7,7 +7,7 @@ It was downloaded from <http://www.scummvm.org/>.
Upstream Authors: see `/usr/share/doc/scummvm/AUTHORS'.
-ScummVM is Copyright © 2002-2015 The ScummVM Team
+ScummVM is Copyright © 2002-2016 The ScummVM Team
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
diff --git a/dists/engine-data/README b/dists/engine-data/README
index e87f04c65b..06939dba42 100644
--- a/dists/engine-data/README
+++ b/dists/engine-data/README
@@ -1,6 +1,9 @@
engine-data README
-------------------------------------------------------------------------------
+access.dat
+TODO
+
drascula.dat
TODO
diff --git a/dists/engine-data/access.dat b/dists/engine-data/access.dat
new file mode 100644
index 0000000000..e90903816f
--- /dev/null
+++ b/dists/engine-data/access.dat
Binary files differ
diff --git a/dists/engine-data/kyra.dat b/dists/engine-data/kyra.dat
index 3ad01b868f..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/engine-data/testbed-audiocd-files/TESTBED b/dists/engine-data/testbed-audiocd-files/TESTBED
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/dists/engine-data/testbed-audiocd-files/TESTBED
diff --git a/dists/gcw0/default.gcw0.desktop b/dists/gcw0/default.gcw0.desktop
index 46bd2be092..9bbb8d5b59 100644
--- a/dists/gcw0/default.gcw0.desktop
+++ b/dists/gcw0/default.gcw0.desktop
@@ -11,6 +11,7 @@ Exec=scummvm.sh
Icon=scummvm
Terminal=false
Type=Application
-Categories=games
+Categories=games;
StartupNotify=false
-X-OD-Manual=README
+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/gph/README-GPH b/dists/gph/README-GPH
index 1c5e6d2898..bcf8bcc278 100644
--- a/dists/gph/README-GPH
+++ b/dists/gph/README-GPH
@@ -1,4 +1,4 @@
-ScummVM 1.8.0git - GPH DEVICE SPECIFIC README
+ScummVM 1.9.0git - GPH DEVICE SPECIFIC README
------------------------------------------------------------------------
diff --git a/dists/gph/scummvm.ini b/dists/gph/scummvm.ini
index 1c57a3cf08..7915f0ce55 100644
--- a/dists/gph/scummvm.ini
+++ b/dists/gph/scummvm.ini
@@ -1,5 +1,5 @@
[info]
-name="ScummVM 1.8.0git"
+name="ScummVM 1.9.0git"
path="/scummvm/scummvm.gpe"
icon="/scummvm/scummvm.png"
title="/scummvm/scummvmb.png"
diff --git a/dists/ios7/Images.xcassets/AppIcon.appiconset/Contents.json b/dists/ios7/Images.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000000..c37df59806
--- /dev/null
+++ b/dists/ios7/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,86 @@
+{
+ "images" : [
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "icon4-29@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "icon4-29@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "icon4-40@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "icon4-40@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "icon4-60@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "icon4-60@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "ipad",
+ "filename" : "icon4-29.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "ipad",
+ "filename" : "icon4-29@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "ipad",
+ "filename" : "icon4-40.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "ipad",
+ "filename" : "icon4-40@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "76x76",
+ "idiom" : "ipad",
+ "filename" : "icon4-76.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "76x76",
+ "idiom" : "ipad",
+ "filename" : "icon4-76@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "83.5x83.5",
+ "idiom" : "ipad",
+ "filename" : "icon4-83.5@2x.png",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29.png b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29.png
new file mode 100644
index 0000000000..9b89d07046
--- /dev/null
+++ b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29.png
Binary files differ
diff --git a/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29@2x.png b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29@2x.png
new file mode 100644
index 0000000000..0de0984ed7
--- /dev/null
+++ b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29@2x.png
Binary files differ
diff --git a/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29@3x.png b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29@3x.png
new file mode 100644
index 0000000000..db6089dcf6
--- /dev/null
+++ b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29@3x.png
Binary files differ
diff --git a/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40.png b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40.png
new file mode 100644
index 0000000000..9a7575b404
--- /dev/null
+++ b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40.png
Binary files differ
diff --git a/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40@2x.png b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40@2x.png
new file mode 100644
index 0000000000..5cd982d0e1
--- /dev/null
+++ b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40@2x.png
Binary files differ
diff --git a/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40@3x.png b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40@3x.png
new file mode 100644
index 0000000000..22580b0ac6
--- /dev/null
+++ b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40@3x.png
Binary files differ
diff --git a/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-60@2x.png b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-60@2x.png
new file mode 100644
index 0000000000..22580b0ac6
--- /dev/null
+++ b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-60@2x.png
Binary files differ
diff --git a/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-60@3x.png b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-60@3x.png
new file mode 100644
index 0000000000..c5f39976bb
--- /dev/null
+++ b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-60@3x.png
Binary files differ
diff --git a/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-76.png b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-76.png
new file mode 100644
index 0000000000..0609594553
--- /dev/null
+++ b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-76.png
Binary files differ
diff --git a/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-76@2x.png b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-76@2x.png
new file mode 100644
index 0000000000..7bc1ae1de1
--- /dev/null
+++ b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-76@2x.png
Binary files differ
diff --git a/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-83.5@2x.png b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-83.5@2x.png
new file mode 100644
index 0000000000..acaf12f435
--- /dev/null
+++ b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-83.5@2x.png
Binary files differ
diff --git a/dists/ios7/Images.xcassets/Contents.json b/dists/ios7/Images.xcassets/Contents.json
new file mode 100644
index 0000000000..da4a164c91
--- /dev/null
+++ b/dists/ios7/Images.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/dists/ios7/Images.xcassets/LaunchImage.launchimage/Contents.json b/dists/ios7/Images.xcassets/LaunchImage.launchimage/Contents.json
new file mode 100644
index 0000000000..40e3b1e3dd
--- /dev/null
+++ b/dists/ios7/Images.xcassets/LaunchImage.launchimage/Contents.json
@@ -0,0 +1,150 @@
+{
+ "images" : [
+ {
+ "extent" : "full-screen",
+ "idiom" : "iphone",
+ "subtype" : "736h",
+ "filename" : "ScummVM-splash-1242x2208.png",
+ "minimum-system-version" : "8.0",
+ "orientation" : "portrait",
+ "scale" : "3x"
+ },
+ {
+ "extent" : "full-screen",
+ "idiom" : "iphone",
+ "subtype" : "736h",
+ "filename" : "ScummVM-splash-2208x1242.png",
+ "minimum-system-version" : "8.0",
+ "orientation" : "landscape",
+ "scale" : "3x"
+ },
+ {
+ "extent" : "full-screen",
+ "idiom" : "iphone",
+ "subtype" : "667h",
+ "filename" : "ScummVM-splash-750x1334.png",
+ "minimum-system-version" : "8.0",
+ "orientation" : "portrait",
+ "scale" : "2x"
+ },
+ {
+ "orientation" : "portrait",
+ "idiom" : "iphone",
+ "extent" : "full-screen",
+ "minimum-system-version" : "7.0",
+ "scale" : "2x"
+ },
+ {
+ "extent" : "full-screen",
+ "idiom" : "iphone",
+ "subtype" : "retina4",
+ "filename" : "ScummVM-splash-640x1136-1.png",
+ "minimum-system-version" : "7.0",
+ "orientation" : "portrait",
+ "scale" : "2x"
+ },
+ {
+ "orientation" : "portrait",
+ "idiom" : "ipad",
+ "filename" : "ScummVM-splash-768x1024.png",
+ "extent" : "full-screen",
+ "minimum-system-version" : "7.0",
+ "scale" : "1x"
+ },
+ {
+ "orientation" : "landscape",
+ "idiom" : "ipad",
+ "filename" : "ScummVM-splash-1024x768.png",
+ "extent" : "full-screen",
+ "minimum-system-version" : "7.0",
+ "scale" : "1x"
+ },
+ {
+ "orientation" : "portrait",
+ "idiom" : "ipad",
+ "filename" : "ScummVM-splash-1536x2048.png",
+ "extent" : "full-screen",
+ "minimum-system-version" : "7.0",
+ "scale" : "2x"
+ },
+ {
+ "orientation" : "landscape",
+ "idiom" : "ipad",
+ "filename" : "ScummVM-splash-2048x1536.png",
+ "extent" : "full-screen",
+ "minimum-system-version" : "7.0",
+ "scale" : "2x"
+ },
+ {
+ "orientation" : "portrait",
+ "idiom" : "iphone",
+ "extent" : "full-screen",
+ "scale" : "1x"
+ },
+ {
+ "orientation" : "portrait",
+ "idiom" : "iphone",
+ "extent" : "full-screen",
+ "scale" : "2x"
+ },
+ {
+ "orientation" : "portrait",
+ "idiom" : "iphone",
+ "extent" : "full-screen",
+ "subtype" : "retina4",
+ "scale" : "2x"
+ },
+ {
+ "orientation" : "portrait",
+ "idiom" : "ipad",
+ "extent" : "to-status-bar",
+ "scale" : "1x"
+ },
+ {
+ "orientation" : "portrait",
+ "idiom" : "ipad",
+ "extent" : "full-screen",
+ "scale" : "1x"
+ },
+ {
+ "orientation" : "landscape",
+ "idiom" : "ipad",
+ "extent" : "to-status-bar",
+ "scale" : "1x"
+ },
+ {
+ "orientation" : "landscape",
+ "idiom" : "ipad",
+ "extent" : "full-screen",
+ "scale" : "1x"
+ },
+ {
+ "orientation" : "portrait",
+ "idiom" : "ipad",
+ "extent" : "to-status-bar",
+ "scale" : "2x"
+ },
+ {
+ "orientation" : "portrait",
+ "idiom" : "ipad",
+ "extent" : "full-screen",
+ "scale" : "2x"
+ },
+ {
+ "orientation" : "landscape",
+ "idiom" : "ipad",
+ "extent" : "to-status-bar",
+ "scale" : "2x"
+ },
+ {
+ "orientation" : "landscape",
+ "idiom" : "ipad",
+ "extent" : "full-screen",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-1024x768.png b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-1024x768.png
new file mode 100644
index 0000000000..5c2367e13e
--- /dev/null
+++ b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-1024x768.png
Binary files differ
diff --git a/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-1242x2208.png b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-1242x2208.png
new file mode 100644
index 0000000000..f88f48d507
--- /dev/null
+++ b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-1242x2208.png
Binary files differ
diff --git a/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-1536x2048.png b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-1536x2048.png
new file mode 100644
index 0000000000..ca9a2c173a
--- /dev/null
+++ b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-1536x2048.png
Binary files differ
diff --git a/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-2048x1536.png b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-2048x1536.png
new file mode 100644
index 0000000000..85e661aa31
--- /dev/null
+++ b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-2048x1536.png
Binary files differ
diff --git a/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-2208x1242.png b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-2208x1242.png
new file mode 100644
index 0000000000..e013a1e605
--- /dev/null
+++ b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-2208x1242.png
Binary files differ
diff --git a/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-640x1136-1.png b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-640x1136-1.png
new file mode 100644
index 0000000000..a67691a088
--- /dev/null
+++ b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-640x1136-1.png
Binary files differ
diff --git a/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-750x1334.png b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-750x1334.png
new file mode 100644
index 0000000000..e73234263c
--- /dev/null
+++ b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-750x1334.png
Binary files differ
diff --git a/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-768x1024.png b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-768x1024.png
new file mode 100644
index 0000000000..ce16a2a2a7
--- /dev/null
+++ b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-768x1024.png
Binary files differ
diff --git a/dists/ios7/Info.plist b/dists/ios7/Info.plist
new file mode 100644
index 0000000000..ceef7e7d36
--- /dev/null
+++ b/dists/ios7/Info.plist
@@ -0,0 +1,57 @@
+<?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>en</string>
+ <key>CFBundleExecutable</key>
+ <string>ScummVM</string>
+ <key>CFBundleIcons</key>
+ <dict/>
+ <key>CFBundleIcons~ipad</key>
+ <dict/>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>ScummVM</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.9.0git</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.9.0git</string>
+ <key>UIApplicationExitsOnSuspend</key>
+ <false/>
+ <key>UIDeviceFamily</key>
+ <array>
+ <integer>1</integer>
+ <integer>2</integer>
+ </array>
+ <key>UIFileSharingEnabled</key>
+ <true/>
+ <key>UILaunchImages</key>
+ <array/>
+ <key>UIPrerenderedIcon</key>
+ <true/>
+ <key>UIRequiresFullScreen</key>
+ <true/>
+ <key>UIStatusBarHidden</key>
+ <true/>
+ <key>UISupportedInterfaceOrientations</key>
+ <array>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ <string>UIInterfaceOrientationPortrait</string>
+ </array>
+ <key>UISupportedInterfaceOrientations~ipad</key>
+ <array>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ <string>UIInterfaceOrientationPortrait</string>
+ </array>
+</dict>
+</plist>
diff --git a/dists/ios7/Info.plist.in b/dists/ios7/Info.plist.in
new file mode 100644
index 0000000000..447677ebd9
--- /dev/null
+++ b/dists/ios7/Info.plist.in
@@ -0,0 +1,57 @@
+<?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>en</string>
+ <key>CFBundleExecutable</key>
+ <string>ScummVM</string>
+ <key>CFBundleIcons</key>
+ <dict/>
+ <key>CFBundleIcons~ipad</key>
+ <dict/>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>ScummVM</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>@VERSION@</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>@VERSION@</string>
+ <key>UIApplicationExitsOnSuspend</key>
+ <false/>
+ <key>UIDeviceFamily</key>
+ <array>
+ <integer>1</integer>
+ <integer>2</integer>
+ </array>
+ <key>UIFileSharingEnabled</key>
+ <true/>
+ <key>UILaunchImages</key>
+ <array/>
+ <key>UIPrerenderedIcon</key>
+ <true/>
+ <key>UIRequiresFullScreen</key>
+ <true/>
+ <key>UIStatusBarHidden</key>
+ <true/>
+ <key>UISupportedInterfaceOrientations</key>
+ <array>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ <string>UIInterfaceOrientationPortrait</string>
+ </array>
+ <key>UISupportedInterfaceOrientations~ipad</key>
+ <array>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ <string>UIInterfaceOrientationPortrait</string>
+ </array>
+</dict>
+</plist>
diff --git a/dists/iphone/Info.plist b/dists/iphone/Info.plist
index d630801504..fe13f57d75 100644
--- a/dists/iphone/Info.plist
+++ b/dists/iphone/Info.plist
@@ -15,11 +15,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
- <string>1.8.0git</string>
+ <string>1.9.0git</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
- <string>1.8.0git</string>
+ <string>1.9.0git</string>
<key>CFBundleIconFile</key>
<string>icon.png</string>
<key>CFBundleIconFiles</key>
diff --git a/dists/irix/scummvm.spec b/dists/irix/scummvm.spec
index 973f7aefae..fce7f8a466 100644
--- a/dists/irix/scummvm.spec
+++ b/dists/irix/scummvm.spec
@@ -1,5 +1,5 @@
product scummvm
- id "ScummVM 1.8.0git"
+ id "ScummVM 1.9.0git"
image sw
id "software"
version 18
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 fffb18056e..ce05e079df 100644
--- a/dists/macosx/Info.plist
+++ b/dists/macosx/Info.plist
@@ -4,18 +4,35 @@
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
+ <key>CFBundleDisplayName</key>
+ <string>ScummVM</string>
+ <key>CFBundleExecutable</key>
+ <string>scummvm</string>
+ <key>CFBundleGetInfoString</key>
+ <string>1.9.0git, Copyright 2001-2016 The ScummVM Team</string>
+ <key>CFBundleIconFile</key>
+ <string>scummvm.icns</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
<key>CFBundleLocalizations</key>
<array>
<string>en</string>
+ <string>be</string>
<string>ca</string>
<string>cs</string>
<string>da</string>
<string>de</string>
<string>es</string>
+ <string>eu</string>
+ <string>fi</string>
<string>fr</string>
+ <string>gl</string>
<string>hu</string>
<string>it</string>
<string>nb</string>
+ <string>nl</string>
<string>nn</string>
<string>pl</string>
<string>pt</string>
@@ -23,32 +40,22 @@
<string>se</string>
<string>uk</string>
</array>
- <key>CFBundleDisplayName</key>
- <string>ScummVM</string>
- <key>CFBundleExecutable</key>
- <string>scummvm</string>
- <key>CFBundleGetInfoString</key>
- <string>1.8.0git, Copyright 2001-2015 The ScummVM Team</string>
- <key>CFBundleIconFile</key>
- <string>scummvm.icns</string>
- <key>CFBundleIdentifier</key>
- <string>org.scummvm.scummvm</string>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
<key>CFBundleName</key>
<string>ScummVM</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
- <string>1.8.0git</string>
+ <string>1.9.0git</string>
<key>CFBundleVersion</key>
- <string>1.8.0git</string>
+ <string>1.9.0git</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>Copyright 2001-2016 The ScummVM Team</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
- <key>NSHumanReadableCopyright</key>
- <string>Copyright 2001-2015 The ScummVM Team</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 7e91984f39..c5f54fe3f0 100644
--- a/dists/macosx/Info.plist.in
+++ b/dists/macosx/Info.plist.in
@@ -4,18 +4,35 @@
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
+ <key>CFBundleDisplayName</key>
+ <string>ScummVM</string>
+ <key>CFBundleExecutable</key>
+ <string>scummvm</string>
+ <key>CFBundleGetInfoString</key>
+ <string>@VERSION@, Copyright 2001-2016 The ScummVM Team</string>
+ <key>CFBundleIconFile</key>
+ <string>scummvm.icns</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
<key>CFBundleLocalizations</key>
<array>
<string>en</string>
+ <string>be</string>
<string>ca</string>
<string>cs</string>
<string>da</string>
<string>de</string>
<string>es</string>
+ <string>eu</string>
+ <string>fi</string>
<string>fr</string>
+ <string>gl</string>
<string>hu</string>
<string>it</string>
<string>nb</string>
+ <string>nl</string>
<string>nn</string>
<string>pl</string>
<string>pt</string>
@@ -23,18 +40,6 @@
<string>se</string>
<string>uk</string>
</array>
- <key>CFBundleDisplayName</key>
- <string>ScummVM</string>
- <key>CFBundleExecutable</key>
- <string>scummvm</string>
- <key>CFBundleGetInfoString</key>
- <string>@VERSION@, Copyright 2001-2015 The ScummVM Team</string>
- <key>CFBundleIconFile</key>
- <string>scummvm.icns</string>
- <key>CFBundleIdentifier</key>
- <string>org.scummvm.scummvm</string>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
<key>CFBundleName</key>
<string>ScummVM</string>
<key>CFBundlePackageType</key>
@@ -43,12 +48,14 @@
<string>@VERSION@</string>
<key>CFBundleVersion</key>
<string>@VERSION@</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>Copyright 2001-2016 The ScummVM Team</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
- <key>NSHumanReadableCopyright</key>
- <string>Copyright 2001-2015 The ScummVM Team</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/msvc14/create_msvc14.bat b/dists/msvc14/create_msvc14.bat
index 7082ac9680..4a16c43c45 100644
--- a/dists/msvc14/create_msvc14.bat
+++ b/dists/msvc14/create_msvc14.bat
@@ -55,14 +55,14 @@ goto done
echo.
echo Creating project files with all engines enabled (stable and unstable)
echo.
-create_project ..\.. --enable-all-engines --msvc --msvc-version 14 --build-events
+create_project ..\.. --enable-all-engines --disable-fluidsynth --msvc --msvc-version 14 --build-events
goto done
:stable
echo.
echo Creating normal project files, with only the stable engines enabled
echo.
-create_project ..\.. --msvc --msvc-version 14
+create_project ..\.. --disable-fluidsynth --msvc --msvc-version 14
goto done
:tools
diff --git a/dists/openpandora/PXML.xml b/dists/openpandora/PXML.xml
index 877a7fd6b4..d74acdf64b 100644
--- a/dists/openpandora/PXML.xml
+++ b/dists/openpandora/PXML.xml
@@ -4,11 +4,11 @@
<package id="scummvm.djwillis.0001">
<author name="DJWillis" website="http://www.scummvm.org/"/>
<!-- version type can be alpha, beta or release, set to release in branch -->
- <version major="1" minor="8" release="0" build="1" type="release"/>
+ <version major="1" minor="9" release="0" build="1" type="release"/>
<!-- Both title and titles are needed -->
- <title lang="en_US">ScummVM 1.8.0git</title>
+ <title lang="en_US">ScummVM 1.9.0git</title>
<titles>
- <title lang="en_US">ScummVM 1.8.0git</title>
+ <title lang="en_US">ScummVM 1.9.0git</title>
</titles>
<descriptions>
<description lang="en_US">
@@ -25,7 +25,7 @@
<exec command="./runscummvm.sh"/>
<author name="DJWillis" website="http://www.scummvm.org/"/>
<!-- version type can be alpha, beta or release, set to release in branch -->
- <version major="1" minor="8" release="0" build="1" type="release"/>
+ <version major="1" minor="9" release="0" build="1" type="release"/>
<!-- Both title and titles are needed -->
<title lang="en_US">ScummVM</title>
<titles>
diff --git a/dists/openpandora/README-OPENPANDORA b/dists/openpandora/README-OPENPANDORA
index 70cff11858..decb295207 100644
--- a/dists/openpandora/README-OPENPANDORA
+++ b/dists/openpandora/README-OPENPANDORA
@@ -1,4 +1,4 @@
-ScummVM 1.8.0git - OPENPANDORA SPECIFIC README
+ScummVM 1.9.0git - OPENPANDORA SPECIFIC README
------------------------------------------------------------------------
Please refer to the:
diff --git a/dists/openpandora/README-PND.txt b/dists/openpandora/README-PND.txt
index 9012c9116b..164d6ac91b 100644
--- a/dists/openpandora/README-PND.txt
+++ b/dists/openpandora/README-PND.txt
@@ -1,4 +1,4 @@
-ScummVM 1.8.0git - OPENPANDORA README - HOW TO INSTALL
+ScummVM 1.9.0git - OPENPANDORA README - HOW TO INSTALL
------------------------------------------------------------------------
Please refer to the:
diff --git a/dists/openpandora/index.html b/dists/openpandora/index.html
index e664623bf8..392b38c678 100644
--- a/dists/openpandora/index.html
+++ b/dists/openpandora/index.html
@@ -5,7 +5,7 @@
</h3>
<h4>
- <p>ScummVM 1.8.0git: OpenPandora Specific Documentation</p>
+ <p>ScummVM 1.9.0git: OpenPandora Specific Documentation</p>
</h4>
<A href="docs/README-OPENPANDORA">ScummVM OpenPandora README</a><br/>
@@ -13,7 +13,7 @@
<A href="http://wiki.scummvm.org/index.php/OpenPandora">ScummVM OpenPandora WiKi</a><br/>
<h4>
- <p>ScummVM 1.8.0git: General Documentation</p>
+ <p>ScummVM 1.9.0git: General Documentation</p>
</h4>
<A href="http://www.scummvm.org/">ScummVM website</a><br/>
diff --git a/dists/openpandora/pnd_make.sh b/dists/openpandora/pnd_make.sh
index 0c03e8154d..a24beaf5d4 100755
--- a/dists/openpandora/pnd_make.sh
+++ b/dists/openpandora/pnd_make.sh
@@ -41,9 +41,16 @@ 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.
- color=${2:-$black} # Defaults to black, if not specified.
- echo -e "$color$message"
- tput sgr0 # Reset to normal.
+
+ # 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 -T"$TERM" sgr0 # Reset to normal.
+ else
+ echo "$message"
+ fi
return
}
diff --git a/dists/ps3/readme-ps3.md b/dists/ps3/readme-ps3.md
index 2fb393b4fb..8290f87066 100644
--- a/dists/ps3/readme-ps3.md
+++ b/dists/ps3/readme-ps3.md
@@ -36,12 +36,12 @@ Unauthorized distribution of an installable package with non freeware games incl
Building from source
====================
-This port of ScummVM to the PS3 is based on SDL. It uses the open source SDK PSL1GHT.
+This port of ScummVM to the PS3 is based on SDL2. It uses the open source SDK PSL1GHT.
The dependencies needed to build it are :
- The toolchain from https://github.com/ps3dev/ps3toolchain
-- SDL from https://github.com/zeldin/SDL_PSL1GHT
+- SDL from https://bitbucket.org/bgK/sdl_psl1ght
- ScummVM from https://github.com/scummvm/scummvm
Once all the dependencies are correctly setup, an installable package can be obtained from source by issuing the following command :
diff --git a/dists/redhat/scummvm-tools.spec b/dists/redhat/scummvm-tools.spec
index 74e86089f1..cedcf141da 100644
--- a/dists/redhat/scummvm-tools.spec
+++ b/dists/redhat/scummvm-tools.spec
@@ -7,7 +7,7 @@
# Prologue information
#------------------------------------------------------------------------------
Name : scummvm-tools
-Version : 1.8.0git
+Version : 1.9.0git
Release : 1
Summary : ScummVM-related tools
Group : Interpreters
diff --git a/dists/redhat/scummvm.spec b/dists/redhat/scummvm.spec
index 18eb020cdc..d764372599 100644
--- a/dists/redhat/scummvm.spec
+++ b/dists/redhat/scummvm.spec
@@ -7,7 +7,7 @@
# Prologue information
#------------------------------------------------------------------------------
Name : scummvm
-Version : 1.8.0git
+Version : 1.9.0git
Release : 1
Summary : Graphic adventure game interpreter
Group : Interpreters
@@ -80,6 +80,8 @@ install -m644 -D dists/engine-data/tony.dat %{buildroot}%{_datadir}/scummvm/tony
install -m644 -D dists/engine-data/toon.dat %{buildroot}%{_datadir}/scummvm/toon.dat
install -m644 -D dists/engine-data/wintermute.zip %{buildroot}%{_datadir}/scummvm/wintermute.zip
install -m644 -D dists/engine-data/neverhood.dat %{buildroot}%{_datadir}/scummvm/neverhood.dat
+install -m644 -D dists/engine-data/mort.dat %{buildroot}%{_datadir}/scummvm/mort.dat
+install -m644 -D dists/engine-data/access.dat %{buildroot}%{_datadir}/scummvm/access.dat
desktop-file-install --vendor scummvm --dir=%{buildroot}/%{_datadir}/applications dists/scummvm.desktop
%clean
@@ -122,6 +124,8 @@ fi
%{_datadir}/scummvm/toon.dat
%{_datadir}/scummvm/wintermute.zip
%{_datadir}/scummvm/neverhood.dat
+%{_datadir}/scummvm/mort.dat
+%{_datadir}/scummvm/access.dat
%{_mandir}/man6/scummvm.6*
#------------------------------------------------------------------------------
diff --git a/dists/redhat/scummvm.spec.in b/dists/redhat/scummvm.spec.in
index 6429e74128..b8694793b8 100644
--- a/dists/redhat/scummvm.spec.in
+++ b/dists/redhat/scummvm.spec.in
@@ -80,6 +80,8 @@ install -m644 -D dists/engine-data/tony.dat %{buildroot}%{_datadir}/scummvm/tony
install -m644 -D dists/engine-data/toon.dat %{buildroot}%{_datadir}/scummvm/toon.dat
install -m644 -D dists/engine-data/wintermute.zip %{buildroot}%{_datadir}/scummvm/wintermute.zip
install -m644 -D dists/engine-data/neverhood.dat %{buildroot}%{_datadir}/scummvm/neverhood.dat
+install -m644 -D dists/engine-data/mort.dat %{buildroot}%{_datadir}/scummvm/mort.dat
+install -m644 -D dists/engine-data/access.dat %{buildroot}%{_datadir}/scummvm/access.dat
desktop-file-install --vendor scummvm --dir=%{buildroot}/%{_datadir}/applications dists/scummvm.desktop
%clean
@@ -122,6 +124,8 @@ fi
%{_datadir}/scummvm/toon.dat
%{_datadir}/scummvm/wintermute.zip
%{_datadir}/scummvm/neverhood.dat
+%{_datadir}/scummvm/mort.dat
+%{_datadir}/scummvm/access.dat
%{_mandir}/man6/scummvm.6*
#------------------------------------------------------------------------------
diff --git a/dists/samsungtv/README-SamsungTV b/dists/samsungtv/README-SamsungTV
index 26ded6c7e6..7c171747dc 100644
--- a/dists/samsungtv/README-SamsungTV
+++ b/dists/samsungtv/README-SamsungTV
@@ -3,7 +3,7 @@ Notes:
- Should works on 2009 B series TVs (Full HD): LExxBE65x, LExxBE75x, PSxxB65x, UExxB7xxx, UExxB8xxx, PSxxB85x, LAxxB65x, LAxxB75x, UNxxB7xxx, UAxxB8xxx
- To allow use mouse and keyboard you need load extension first: "SamyGO Mouse And Keyboard"
Download from SamyGO project and run from Content Library:
- http://sourceforge.net/projects/samygo/files/SamyGO%20Kernel%20Modules/SamyGO%20Mouse%20and%20Keyboard%20Modules%20v0.01.zip/download
+ http://download.samygo.tv/B%20Series/Content%20Library%20Applications/SamyGO%20Mouse%20and%20Keyboard%20Modules%20v0.01.zip
- Buttons on remote controler: EXIT, SOURCE, P+, P-, TV, POWER, CONTENT - cause immediately exit from ScummVM
- Config file is in /mtd_rwarea/.scummvmrc
- Saves are stored in '/mtd_wiselink/scummvm savegames' directory
diff --git a/dists/scummvm.rc b/dists/scummvm.rc
index 2028a5bfd3..873feaa419 100644
--- a/dists/scummvm.rc
+++ b/dists/scummvm.rc
@@ -20,6 +20,9 @@ scummmodern.zip FILE "gui/themes/scummmodern.zip"
translations.dat FILE "gui/themes/translations.dat"
#endif
+#if ENABLE_ACCESS == STATIC_PLUGIN
+access.dat FILE "dists/engine-data/access.dat"
+#endif
#if ENABLE_DRASCULA == STATIC_PLUGIN
drascula.dat FILE "dists/engine-data/drascula.dat"
#endif
@@ -61,8 +64,8 @@ pred.dic FILE "dists/pred.dic"
#endif
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,8,0,0
- PRODUCTVERSION 1,8,0,0
+ FILEVERSION 1,9,0,0
+ PRODUCTVERSION 1,9,0,0
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
@@ -78,14 +81,15 @@ 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.8.0git\0"
+ VALUE "FileVersion", "1.9.0git\0"
VALUE "InternalName", "scummvm\0"
- VALUE "LegalCopyright", "Copyright © 2001-2015 The ScummVM Team\0"
+ VALUE "LegalCopyright", "Copyright © 2001-2016 The ScummVM Team\0"
VALUE "LegalTrademarks", "'SCUMM', and all SCUMM games are a TM of LucasArts. Simon The Sorcerer is a TM of AdventureSoft. Beneath a Steel Sky and Broken Sword are a TM of Revolution. Flight of the Amazon Queen is a TM of John Passfield and Steve Stamatiadis. \0"
VALUE "OriginalFilename", "scummvm.exe\0"
VALUE "ProductName", "ScummVM\0"
- VALUE "ProductVersion", "1.8.0git\0"
+ VALUE "ProductVersion", "1.9.0git\0"
END
END
diff --git a/dists/scummvm.rc.in b/dists/scummvm.rc.in
index 3a619334d5..2e0a5ff745 100644
--- a/dists/scummvm.rc.in
+++ b/dists/scummvm.rc.in
@@ -20,6 +20,9 @@ scummmodern.zip FILE "gui/themes/scummmodern.zip"
translations.dat FILE "gui/themes/translations.dat"
#endif
+#if ENABLE_ACCESS == STATIC_PLUGIN
+access.dat FILE "dists/engine-data/access.dat"
+#endif
#if ENABLE_DRASCULA == STATIC_PLUGIN
drascula.dat FILE "dists/engine-data/drascula.dat"
#endif
@@ -78,10 +81,11 @@ 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"
- VALUE "LegalCopyright", "Copyright © 2001-2015 The ScummVM Team\0"
+ VALUE "LegalCopyright", "Copyright © 2001-2016 The ScummVM Team\0"
VALUE "LegalTrademarks", "'SCUMM', and all SCUMM games are a TM of LucasArts. Simon The Sorcerer is a TM of AdventureSoft. Beneath a Steel Sky and Broken Sword are a TM of Revolution. Flight of the Amazon Queen is a TM of John Passfield and Steve Stamatiadis. \0"
VALUE "OriginalFilename", "scummvm.exe\0"
VALUE "ProductName", "ScummVM\0"
diff --git a/dists/scummvm_logo.bmp b/dists/scummvm_logo.bmp
new file mode 100644
index 0000000000..8217019be4
--- /dev/null
+++ b/dists/scummvm_logo.bmp
Binary files differ
diff --git a/dists/slackware/scummvm.SlackBuild b/dists/slackware/scummvm.SlackBuild
index b1e1fe2c77..00da93f316 100755
--- a/dists/slackware/scummvm.SlackBuild
+++ b/dists/slackware/scummvm.SlackBuild
@@ -9,7 +9,7 @@ if [ "$TMP" = "" ]; then
fi
PKG=$TMP/package-scummvm
-VERSION=1.8.0git
+VERSION=1.9.0git
ARCH=i486
BUILD=1
diff --git a/dists/wii/meta.xml b/dists/wii/meta.xml
index 2dbd8da7fd..24fabb5dd2 100644
--- a/dists/wii/meta.xml
+++ b/dists/wii/meta.xml
@@ -2,7 +2,7 @@
<app version="1">
<name>ScummVM</name>
<coder>The ScummVM Team</coder>
- <version>1.8.0git@REVISION@</version>
+ <version>1.9.0git@REVISION@</version>
<release_date>@TIMESTAMP@</release_date>
<short_description>Point &amp; Click Adventures</short_description>
<long_description>ScummVM is a program which allows you to run certain classic graphical point-and-click adventure games, provided you already have their data files. The clever part about this: ScummVM just replaces the executables shipped with the games, allowing you to play them on systems for which they were never designed!
diff --git a/dists/win32/ScummVM.iss b/dists/win32/ScummVM.iss
index 5afb407177..817cc5aeef 100644
--- a/dists/win32/ScummVM.iss
+++ b/dists/win32/ScummVM.iss
@@ -53,7 +53,6 @@ Name: {group}\Copyright; Filename: {app}\COPYRIGHT.txt; WorkingDir: {app}; Comme
Name: {group}\News; Filename: {app}\NEWS.txt; WorkingDir: {app}; Comment: NEWS; Flags: createonlyiffileexists; Languages: not de
Name: {group}\Neues; Filename: {app}\Neues.txt; WorkingDir: {app}; Comment: Neues; Flags: createonlyiffileexists; Languages: de
;QUICKSTART
-Name: {group}\QuickStart; Filename: {app}\QUICKSTART.txt; WorkingDir: {app}; Comment: QUICKSTART; Flags: createonlyiffileexists; Languages: not (de or es or fr or it or nb or se)
Name: {group}\Schnellstart; Filename: {app}\Schnellstart.txt; WorkingDir: {app}; Comment: Schnellstart; Flags: createonlyiffileexists; Languages: de
Name: {group}\InicioRapido; Filename: {app}\InicioRapido.txt; WorkingDir: {app}; Comment: InicioRapido; Flags: createonlyiffileexists; Languages: es
Name: {group}\DemarrageRapide; Filename: {app}\DemarrageRapide.txt; WorkingDir: {app}; Comment: DemarrageRapide; Flags: createonlyiffileexists; Languages: fr
@@ -93,7 +92,6 @@ Source: COPYRIGHT.txt; DestDir: {app}; Flags: ignoreversion
Source: NEWS.txt; DestDir: {app}; Flags: ignoreversion; Languages: not de
Source: doc/de/Neues.txt; DestDir: {app}; Flags: ignoreversion; Languages: de
;QUICKSTART
-Source: doc/QUICKSTART.txt; DestDir: {app}; Flags: ignoreversion isreadme; Languages: not (de or es or fr or it or nb or se)
Source: doc/de/Schnellstart.txt; DestDir: {app}; Flags: ignoreversion isreadme; Languages: de
Source: doc/es/InicioRapido.txt; DestDir: {app}; Flags: ignoreversion isreadme; Languages: es
Source: doc/fr/DemarrageRapide.txt; DestDir: {app}; Flags: ignoreversion isreadme; Languages: fr
@@ -107,7 +105,7 @@ Source: doc/de/Liesmich.txt; DestDir: {app}; Flags: ignoreversion isreadme; Lang
Source: doc/se/LasMig.txt; DestDir: {app}; Flags: ignoreversion isreadme; Languages: se
Source: README-SDL.txt; DestDir: {app}; Flags: ignoreversion
Source: scummvm.exe; DestDir: {app}; Flags: ignoreversion
-Source: SDL.dll; DestDir: {app}
+Source: SDL.dll; DestDir: {app}; Flags: replacesameversion
;Mirgration script for saved games in Windows NT4 onwards
Source: migration.bat; DestDir: {app}; Flags: ignoreversion; MinVersion: 0, 1
Source: migration.txt; DestDir: {app}; Flags: ignoreversion; MinVersion: 0, 1
diff --git a/dists/win32/migration.bat b/dists/win32/migration.bat
index e1b27a1fb3..0ab38653f6 100644
--- a/dists/win32/migration.bat
+++ b/dists/win32/migration.bat
@@ -4,7 +4,7 @@
:: This script will copy any saved games located in the
:: old default location, to the new default location.
::
-:: (c) 2012-2014 ScummVM Team
+:: (c) 2012-2016 ScummVM Team
::
@echo off
diff --git a/dists/win32/scummvm.nsi b/dists/win32/scummvm.nsi
index a7e891acc2..d0aadd6ac2 100644
--- a/dists/win32/scummvm.nsi
+++ b/dists/win32/scummvm.nsi
@@ -72,11 +72,11 @@ Name ScummVM
# General Symbol Definitions
#########################################################################################
!define REGKEY "Software\$(^Name)\$(^Name)"
-!define VERSION "1.8.0git"
+!define VERSION "1.9.0git"
!define COMPANY "ScummVM Team"
!define URL "http://scummvm.org/"
!define DESCRIPTION "ScummVM Installer. Look! A three headed monkey (TM)!"
-!define COPYRIGHT "Copyright © 2001-2015 The ScummVM Team"
+!define COPYRIGHT "Copyright © 2001-2016 The ScummVM Team"
#########################################################################################
# Installer configuration
@@ -92,7 +92,7 @@ XPStyle on
#TargetMinimalOS 5.0 ; Minimal version of windows for installer: Windows 2000 or more recent
; (will build unicode installer with NSIS 2.50+)
-VIProductVersion 1.8.0.0
+VIProductVersion 1.9.0.0
VIAddVersionKey ProductName $(^Name)
VIAddVersionKey ProductVersion "${VERSION}"
VIAddVersionKey CompanyName "${COMPANY}"
diff --git a/dists/win32/scummvm.nsi.in b/dists/win32/scummvm.nsi.in
index 7a156fb7b4..79e1a9d581 100644
--- a/dists/win32/scummvm.nsi.in
+++ b/dists/win32/scummvm.nsi.in
@@ -76,7 +76,7 @@ Name ScummVM
!define COMPANY "ScummVM Team"
!define URL "http://scummvm.org/"
!define DESCRIPTION "ScummVM Installer. Look! A three headed monkey (TM)!"
-!define COPYRIGHT "Copyright © 2001-2015 The ScummVM Team"
+!define COPYRIGHT "Copyright © 2001-2016 The ScummVM Team"
#########################################################################################
# Installer configuration
diff --git a/doc/cz/PrectiMe b/doc/cz/PrectiMe
index 2baf145cd9..030ddac916 100644
--- a/doc/cz/PrectiMe
+++ b/doc/cz/PrectiMe
@@ -1,8 +1,8 @@
-PŘEČTIMĚ ScummVM
+\rPŘEČTIMĚ ScummVM
------------------------------------------------------------------------
Pro více informací, seznamy kompatibility, podrobnosti o dotacích, nejnovější verze,
-novinky o vývoji a další, prosím navštivte domovskou stránku ScummVM na: http://www.scummvm.org/
+novinky o vývoji a další, prosím navštivte domovskou stránku ScummVM na: <http://www.scummvm.org/>
Obsah:
@@ -10,31 +10,40 @@ Obsah:
1.0) Úvod
* 1.1 O ScummVM
* 1.2 Rychlý návod
+ * 1.3 NejÄastÄ›jší otázky
2.0) Kontakt
* 2.1 Hlášení chyb
3.0) Podporované hry
* 3.1 Ochrana proti kopírování
- * 3.2 Poznámky ke hře Day of the Tentacle
- * 3.3 Poznámky ke hrám Commodore64
- * 3.4 Poznámky k Maniac Mansion NES
- * 3.5 Poznámky ke hrám Macintosh
- * 3.6 Poznámky ke hrám Multi-CD
- * 3.7 Poznámky k The Curse of Monkey Island
- * 3.8 Poznámky ke hrám Broken Sword
- * 3.9 Poznámky k Beneath a Steel Sky
+ * 3.2 Datové soubory
+ * 3.3 Poznámky ke hrám Multi-CD
+ * 3.4 Známé problémy
+ * 3.5 Poznámky k Beneath a Steel Sky
+ * 3.6 Poznámky ke hrám Broken Sword
+ * * 3.6.1 Broken Sword
+ * * 3.6.2 Broken Sword II
+ * * 3.6.3 Videa z her Broken Sword
+ * * 3.6.4 Videa her Broken Sword ve zpětném pohledu
+ * 3.7 Poznámky k Day of the Tentacle
+ * 3.8 Poznámky k Discworld II
+ * 3.9 Poznámky k DraÄí Historie
* 3.10 Poznámky k Flight of the Amazon Queen
* 3.11 Poznámky ke Gobliiins
* 3.12 Poznámky k Inherit the Earth: Quest for the Orb
- * 3.13 Poznámky k Simon the Sorcerer
- * 3.14 Poznámky k The Feeble Files
- * 3.15 Poznámky k The Legend of Kyrandia
- * 3.16 Poznámky k Předvídavému Vstupnímu Dialogu her Sierra AGI
- * 3.17 Poznámky k Mickey's Space Adventure
- * 3.18 Poznámky k Winnie the Pooh
- * 3.19 Poznámky k Troll's Tale
- * 3.20 Poznámky k DraÄí Historie
- * 3.21 Titulky a hlasy souběžně v hrách Sierra SCI
- * 3.22 Známé problémy
+ * 3.13 Poznámky k Maniac Mansion na Apple II/NES
+ * 3.14 Poznámky k Mickey's Space Adventure
+ * 3.15 Poznámky k Nippon Safes Inc. na Amiga
+ * 3.16 Poznámky k Simon the Sorcerer
+ * 3.17 Poznámky k The Curse of Monkey Island
+ * 3.18 Poznámky k The Feeble Files
+ * 3.19 Poznámky k The Legend of Kyrandia
+ * 3.20 Poznámky k Troll's Tale
+ * 3.21 Poznámky k Winnie the Pooh
+ * 3.22 Poznámky k Předvídavému Vstupnímu Dialogu her Sierra AGI
+ * 3.23 Titulky a hlasy souběžně v hrách Sierra SCI
+ * 3.24 Poznámky k hrám Zork
+ * 3.25 Poznámky ke hrám Commodore64
+ * 3.26 Poznámky ke hrám Macintosh
4.0) Podporované platformy
5.0) Spuštění ScummVM
* 5.1 Možnosti příkazového řádku
@@ -52,7 +61,21 @@ Obsah:
* 7.3 Emulace MT-32
* 7.4 Emulace MIDI
* 7.5 Přirozená podpora MIDI
+ * * 7.5.1 Použití voleb MIDI pro přizpůsobení výstupu přirozeného MIDI
* 7.6 Podpora nativního UNIX, ALSA a sekvenceru dmedia
+ * * 7.6.1 Sekvencer ALSA [POUZE UNIX]
+ * * 7.6.2 Sekvencer dmedia IRIX [POUZE UNIX]
+ * 7.7 Podpora MIDI serveru TiMidity++
+ * 7.8 Použití komprimovaných zvukových souborů (MP3, Ogg Vorbis, Flac)
+ * * 7.8.1 Použití souborů MP3 pro zvuky z CD
+ * * 7.8.2 Použití souborů Ogg Vorbis pro zvuky z CD
+ * * 7.8.3 Použití souborů Flac pro zvuky z CD
+ * * 7.8.4 Komprimování MONSTER.SOU pomocí MP3
+ * * 7.8.5 Komprimování MONSTER.SOU pomocí Ogg Vorbis
+ * * 7.8.6 Komprimování MONSTER.SOU pomocí Flac
+ * * 7.8.7 Komprimování hudby/zvuků/hlasů v hrách AGOS
+ * * 7.8.8 Komprimování hlasů/hudby v Broken Sword
+ * * 7.8.9 Komprimování hlasů/hudby v Broken Sword II
* 7.7 Podpora MIDI serveru TiMidity++
* 7.8 Použití komprimovaných zvukových souborů (MP3, Ogg Vorbis, Flac)
* 7.9 Výstupní vzorkovací kmitoÄet
@@ -60,6 +83,7 @@ Obsah:
* 8.1 Rozpoznávaná klíÄová slova nastavení
* 8.2 Vlastní herní volby, které mohou být přepínány pomoci grafického rozhraní
9.0) Sestavení
+10.0) Poděkování
1.0) Úvod:
@@ -104,16 +128,21 @@ V budoucnu byste mÄ›li být schopni pÅ™eskoÄit na krok 5, pokud nechcete pÅ™id
Rada: Pokud chcete pÅ™idat více her najednou, zkuste stisknout a držet klávesu shift pÅ™edtím, než kliknete na 'PÅ™idat hru' – tlaÄítko se zmÄ›ní na 'Hromadné PÅ™idání' a pokud ho stisknÄ›te, jste znovu požádáni o zvolení složky, ale tentokrát ScummVM prohledá vÅ¡echny podsložky pro podporované hry.
+1.3) NejÄastÄ›jší otázky
+---- ------------------
+Na <http://www.scummvm.org/faq/> jsme pro Vás pÅ™ipravili seznam nejÄastÄ›jších otázek a jejich odpovÄ›dí.
+
+
2.0) Kontakt:
---- --------
-Nejjednodušším způsobem, jak kontaktovat tým ScummVM je předložením hlášení o chybě (viz oddíl 2.1) nebo použitím našich fór na http://forums.scummvm.org .
+Nejjednodušším způsobem, jak kontaktovat tým ScummVM je předložením hlášení o chybě (viz oddíl 2.1) nebo použitím našich fór na <http://forums.scummvm.org>.
Můžete se také pÅ™ipojit a odesílat a e-maily na korespondenÄní seznam scummvm-devel, nebo si s námi popovídejte na IRC (#scummvm na irc.freenode.net) Nežádejte nás, prosím, o podporu nefungující hry – nejdříve si pÅ™eÄtÄ›te nejÄastÄ›jší otázky na naší stránce
2.1) Hlášení chyb:
---- -------------
Abyste mohli nahlásit chybu, nejdříve si, prosíme, vytvoÅ™te si úÄet na SourceForge a kliknÄ›te na odkaz "Bug Tracker" na naší stránce. UjistÄ›te se, prosím, že se chyba dá znovu zjistit a stále se objevuje v nejnovÄ›jší verzi git/denního sestavení. Také na naší stránce zkontrolujte seznam známých problémů (níže) a seznam kompatibility pro tuto hru, abyste se ujistili, že problém již není znám:
- http://www.scummvm.org/compatibility
+ <http://www.scummvm.org/compatibility>
Prosíme, nenahlaÅ¡ujte chyby ve hrách, které nejsou v seznamu v sekci 'Supported Games' nebo seznamu kompatibility uvedeny jako dokonÄitelné. My –víme-, že tyto hry mají chyby.
@@ -131,13 +160,18 @@ Nakonec prosíme, abyste každou chybu nahlaÅ¡ovali samostatnÄ›; neohlaÅ¡ujte nÄ
3.0) Podporované hry:
---- ----------------
-V tuto chvíli je o následujících hrách známo, že fungují a měly by být hratelné až dokonce:
+V tuto chvíli je o následujících hrách známo, že fungují a měly by být hratelné až dokonce.
+Podrobnější seznam kompatibility podporovaných her můžete nalézt na adrese:
+
+ <http://www.scummvm.org/compatibility/>)
+
-Hry SCUMM od LucasArts:
+Hry od LucasArts (SCUMM):
Maniac Mansion [maniac]
Zak McKracken and the Alien Mindbenders [zak]
Indiana Jones and the Last Crusade [indy3]
Loom [loom]
+ Passport to Adventure [pass]
The Secret of Monkey Island [monkey]
Monkey Island 2: LeChuck's Revenge [monkey2]
Indiana Jones and the Fate of Atlantis [atlantis]
@@ -147,32 +181,16 @@ Hry SCUMM od LucasArts:
The Dig [dig]
The Curse of Monkey Island [comi]
-Hry AGI a před AGI od Sierra:
- The Black Cauldron [bc]
- Gold Rush! [goldrush]
- King's Quest I [kq1]
- King's Quest II [kq2]
- King's Quest III [kq3]
- King's Quest IV [kq4]
- Leisure Suit Larry in the Land of the
- Lounge Lizards [lsl1]
- Mixed-Up Mother Goose [mixedup]
- Manhunter 1: New York [mh1]
- Manhunter 2: San Francisco [mh2]
- Police Quest I: In Pursuit of the Death
- Angel [pq1]
- Space Quest I: The Sarien Encounter [sq1]
- Space Quest II: Vohaul's Revenge [sq2]
- Fanmade Games [agi-fanmade]
- Mickey's Space Adventure [mickey]
- Troll's Tale [troll]
- Winnie the Pooh in the Hundred Acre Wood [winnie]
+Hry od Activision (MADE):
+ Leather Goddesses of Phobos 2 [lgop2]
+ The Manhole [manhole]
+ Return to Zork [rtz]
+ Rodney's Funscreen [rodney]
-Hry AGOS od Adventuresoft/Horrorsoft:
+Hry od Adventuresoft/Horrorsoft (AGOS):
Elvira - Mistress of the Dark [elvira1]
Elvira II - The Jaws of Cerberus [elvira2]
Personal Nightmare [pn]
- Waxworks [waxworks]
Simon the Sorcerer 1 [simon1]
Simon the Sorcerer 2 [simon2]
Simon the Sorcerer's Puzzle Pack
@@ -184,16 +202,9 @@ Hry AGOS od Adventuresoft/Horrorsoft:
Simon the Sorcerer's Puzzle Pack
- Swampy Adventures [swampy]
The Feeble Files [feeble]
-
-Hry Composer od Animation Magic:
- Darby the Dragon [darby]
- Gregory and the Hot Air Balloon [gregory]
- Magic Tales: Liam Finds a Story [liam]
- The Princess and the Crab [princess]
- Sleeping Cub's Test of Courage [sleepingcub]
+ Waxworks [waxworks]
-Hry GOB od Coktel Vision:
- Bambou le sauveur de la jungle [bambou]
+Hry od Coktel Vision (GOB):
Bargon Attack [bargon]
Fascination [fascination]
Geisha [geisha]
@@ -202,80 +213,40 @@ Hry GOB od Coktel Vision:
Goblins 3 [gob3]
Lost in Time [lostintime]
Once Upon A Time: Little Red Riding Hood [littlered]
+ Playtoons: Bambou le sauveur de la jungle [bambou]
The Bizarre Adventures of Woodruff
and the Schnibble [woodruff]
Urban Runner [urban]
Ween: The Prophecy [ween]
-
-Hry Living Books:
- Aesop's Fables: The Tortoise and the Hare [tortoise]
- Arthur's Birthday [arthurbday]
- Arthur's Teacher Trouble [arthur]
- Dr. Seuss's ABC [seussabc]
- Green Eggs and Ham [greeneggs]
- Harry and the Haunted House [harryhh]
- Just Grandma and Me [grandma]
- Little Monster at School [lilmonster]
- Ruff's Bone [ruff]
- Sheila Rae, the Brave [sheila]
- Stellaluna [stellaluna]
- The Berenstain Bears Get in a Fight [bearfight]
- The Berenstain Bears in the Dark [beardark]
- The New Kid on the Block [newkid]
-Hry MADE od Activision:
- Leather Goddesses of Phobos 2 [lgop2]
- Return to Zork [rtz]
- Rodney's Funscreen [rodney]
- The Manhole [manhole]
-
-Další hry:
- 3 Skulls of the Toltecs [toltecs]
- Blue Force [blueforce]
+Hry od Revolution Software (Různé):
Beneath a Steel Sky [sky]
Broken Sword: The Shadow of the Templars [sword1]
Broken Sword II: The Smoking Mirror [sword2]
- Bud Tucker in Double Trouble [tucker]
- Cruise for a Corpse [cruise]
- Discworld [dw]
- Discworld 2: Missing Presumed ...!? [dw2]
- Dragon History [draci]
- Drascula: The Vampire Strikes Back [drascula]
- DreamWeb [dreamweb]
- Eye of the Beholder [eob]
- Eye of the Beholder II: The Legend of
- Darkmoon [eob2]
- Flight of the Amazon Queen [queen]
- Future Wars [fw]
- Hopkins FBI [hopkins]
- Hugo's House of Horrors [hugo1]
- Hugo 2: Whodunit? [hugo2]
- Hugo 3: Jungle of Doom [hugo3]
- I Have No Mouth, and I Must Scream [ihnm]
- Inherit the Earth: Quest for the Orb [ite]
- Nippon Safes Inc. [nippon]
- Lands of Lore: The Throne of Chaos [lol]
Lure of the Temptress [lure]
- Mortville Manor [mortevielle]
- Nippon Safes Inc. [nippon]
- Ringworld: Revenge Of The Patriarch [ringworld]
- Return to Ringworld [ringworld2]
- Sfinx [sfinx]
- Soltys [soltys]
- TeenAgent [teenagent]
- The Journeyman Project: Pegasus Prime [pegasus]
- The Legend of Kyrandia [kyra1]
- The Legend of Kyrandia: The Hand of Fate [kyra2]
- The Legend of Kyrandia: Malcolm's Revenge [kyra3]
- The 7th Guest [t7g]
- The Neverhood [neverhood]
- Tony Tough and the Night of Roasted Moths [tony]
- Toonstruck [toon]
- Touche: The Adventures of the Fifth
- Musketeer [touche]
- Voyeur [voyeur]
-
-Hry SCI od Sierra Entertainment:
+
+Hry od Sierra (AGI a před AGI):
+ The Black Cauldron [bc]
+ Gold Rush! [goldrush]
+ King's Quest I [kq1]
+ King's Quest II [kq2]
+ King's Quest III [kq3]
+ King's Quest IV [kq4]
+ Leisure Suit Larry in the Land of the
+ Lounge Lizards [lsl1]
+ Mixed-Up Mother Goose [mixedup]
+ Manhunter 1: New York [mh1]
+ Manhunter 2: San Francisco [mh2]
+ Police Quest I: In Pursuit of the Death
+ Angel [pq1]
+ Space Quest I: The Sarien Encounter [sq1]
+ Space Quest II: Vohaul's Revenge [sq2]
+ Hry od fanoušků [agi-fanmade]
+ Mickey's Space Adventure [mickey]
+ Troll's Tale [troll]
+ Winnie the Pooh in the Hundred Acre Wood [winnie]
+
+Hry od Sierra Entertainment (SCI):
Castle of Dr. Brain [castlebrain]
Codename: ICEMAN [iceman]
Conquests of Camelot [camelot]
@@ -316,19 +287,64 @@ Hry SCI od Sierra Entertainment:
Space Quest V [sq5]
The Island of Dr. Brain [islandbrain]
-Hry Wintermute:
+Další hry:
+ 3 Skulls of the Toltecs [toltecs]
+ Amazon: Guardians of Eden [access]
+ Beavis and Butt-head in Virtual Stupidity [bbvs]
+ Blue Force [blueforce]
+ Broken Sword: The Return of the Templars [sword25]
+ Bud Tucker in Double Trouble [tucker]
Chivalry is Not Dead [chivalry]
-
-Hry ZVISION od Activision:
- Zork Nemesis: The Forbidden Lands [znemesis]
+ Cruise for a Corpse [cruise]
+ DreamWeb [dreamweb]
+ Discworld [dw]
+ Discworld 2: Missing Presumed ...!? [dw2]
+ Dragon History [draci]
+ Drascula: The Vampire Strikes Back [drascula]
+ Eye of the Beholder [eob]
+ Eye of the Beholder II: The Legend of
+ Darkmoon [eob2]
+ Flight of the Amazon Queen [queen]
+ Future Wars [fw]
+ Hopkins FBI [hopkins]
+ Hugo's House of Horrors [hugo1]
+ Hugo 2: Whodunit? [hugo2]
+ Hugo 3: Jungle of Doom [hugo3]
+ I Have No Mouth, and I Must Scream [ihnm]
+ Inherit the Earth: Quest for the Orb [ite]
+ Lands of Lore: The Throne of Chaos [lol]
+ Mortville Manor [mortevielle]
+ Nippon Safes Inc. [nippon]
+ Rex Nebular and the Cosmic Gender Bender [nebular]
+ Ringworld: Revenge Of The Patriarch [ringworld]
+ Return to Ringworld [ringworld2]
+ Sfinx [sfinx]
+ Soltys [soltys]
+ The Journeyman Project: Pegasus Prime [pegasus]
+ The Legend of Kyrandia [kyra1]
+ The Legend of Kyrandia: The Hand of Fate [kyra2]
+ The Legend of Kyrandia: Malcolm's Revenge [kyra3]
+ The Lost Files of Sherlock Holmes: The Case
+ of the Serrated Scalpel [scalpel]
+ The Lost Files of Sherlock Holmes: The Case
+ of the Rose Tattoo [rosetattoo]
+ The Neverhood [neverhood]
+ The 7th Guest [t7g]
+ TeenAgent [teenagent]
+ Toonstruck [toon]
+ Tony Tough and the Night of Roasted Moths [tony]
+ Touche: The Adventures of the Fifth
+ Musketeer [touche]
+ Voyeur [voyeur]
Zork: Grand Inquisitor [zgi]
+ Zork Nemesis: The Forbidden Lands [znemesis]
-Hry SCUMM od Humongous Entertainment:
+Hry od Humongous Entertainment (SCUMM):
Backyard Baseball [baseball]
Backyard Baseball 2001 [baseball2001]
Backyard Baseball 2003 [baseball2003]
Backyard Football [football]
- Backyard Football 2002 [football2002]
+ Backyard Football 2002 [football2002]
Bear Stormin' [brstorm]
Big Thinkers First Grade [thinker1]
Big Thinkers Kindergarten [thinkerk]
@@ -354,7 +370,7 @@ Hry SCUMM od Humongous Entertainment:
Let's Explore the Airport with Buzzy [airport]
Let's Explore the Farm with Buzzy [farm]
Let's Explore the Jungle with Buzzy [jungle]
- Pajama Sam: Games to Play on Any Day [pjgames]
+ Pajama Sam: Games to Play on Any Day [pjgames]
Pajama Sam 1: No Need to Hide When It's
Dark Outside [pajama]
Pajama Sam 2: Thunder and Lightning
@@ -363,12 +379,12 @@ Hry SCUMM od Humongous Entertainment:
From Your Head to Your Feet [pajama3]
Pajama Sam's Lost & Found [lost]
Pajama Sam's Sock Works [socks]
- Putt-Putt Joins the Parade [puttputt]
+ Putt-Putt Enters the Race [puttrace]
Putt-Putt Goes to the Moon [puttmoon]
+ Putt-Putt Joins the Circus [puttcircus]
+ Putt-Putt Joins the Parade [puttputt]
Putt-Putt Saves the Zoo [puttzoo]
Putt-Putt Travels Through Time [putttime]
- Putt-Putt Enters the Race [puttrace]
- Putt-Putt Joins the Circus [puttcircus]
Putt-Putt and Pep's Balloon-O-Rama [balloon]
Putt-Putt and Pep's Dog on a Stick [dog]
Putt-Putt & Fatty Bear's Activity Pack [activity]
@@ -387,6 +403,29 @@ Pokud chcete mít nejnovÄ›jší zprávy o kompatibilitách her, navÅ¡tivte naÅ¡Ã
Backyard Soccer 2004 [soccer2004]
Blue's Treasure Hunt [BluesTreasureHunt]
+Hry Composer od Animation Magic:
+ Darby the Dragon [darby]
+ Gregory and the Hot Air Balloon [gregory]
+ Magic Tales: Liam Finds a Story [liam]
+ The Princess and the Crab [princess]
+ Sleeping Cub's Test of Courage [sleepingcub]
+
+Hry Living Books:
+ Aesop's Fables: The Tortoise and the Hare [tortoise]
+ Arthur's Birthday [arthurbday]
+ Arthur's Teacher Trouble [arthur]
+ Dr. Seuss's ABC [seussabc]
+ Green Eggs and Ham [greeneggs]
+ Harry and the Haunted House [harryhh]
+ Just Grandma and Me [grandma]
+ Little Monster at School [lilmonster]
+ Ruff's Bone [ruff]
+ Sheila Rae, the Brave [sheila]
+ Stellaluna [stellaluna]
+ The Berenstain Bears Get in a Fight [bearfight]
+ The Berenstain Bears in the Dark [beardark]
+ The New Kid on the Block [newkid]
+
Následující hry jsou odvozeny od jádra SCUMM, ale ScummVM je nepodporuje (zatím):
Moonbase Commander
@@ -422,95 +461,122 @@ ScummVM přeskakuje ochranu v následujících hrách:
* Waxworks
* Zak McKracken and the Alien Mindbenders
-3.2) Poznámky ke hře Day of the Tentacle:
------------------------------------------
-Na jednom místÄ› ve hÅ™e narazíte na poÄítaÄ umožňující si zahrát původní
-Maniac Mansion jako bonus. ScummVM toto podporuje, ale je třeba
-upozornit na pár věcí:
+3.2) Datové soubory
+---- --------------
+Pro přehledný seznam požadovaných datových souborů u podporovaných her navštivte:
-ScummVM prohledá váš soubor s nastavením hledajíc hru nacházející se
-v podsložce 'Maniac' ve složce hry Day of the Tentacle. Pokud jste
-zkopírovali datové soubory z CD verze, tato struktura by již měla být
-vytvořena, navíc ale budete muset hru přidat také do ScummVM.
+<http://wiki.scummvm.org/index.php/Datafiles>
-Pro návrat do Day of the Tentacle, stisknÄ›te F5 a zvolte "Návrat do spouÅ¡tÄ›Äe".
-Teoreticky toto znamená, že je možné spustit jakoukoli hru jako bonus.
-Vskutku tomu tak je. Existuje "tajná" volba nastavení, "easter_egg", která
-mÄ›ní ID spouÅ¡tÄ›né hry. BuÄte ale opatrní, protože ne vÅ¡echny hry podporují
-návrat do spouÅ¡tÄ›Äe, a nedoporuÄuje se nastavovat spuÅ¡tÄ›ní samotné hry Day
-of the Tentacle jako bonus.
-
-3.3) Poznámky ke hrám Commodore64:
----- -----------------------------
-Jak Maniac Mansion tak Zak McKracken mohou být spuštěny, ale Maniac Mansion není ještě hratelný. Jednoduše pojmenujte disky D64 jako
-"maniac1.d64" a "maniac2.d64" nebo "zak1.d64" a "zak2.d64", pak by měl ScummVM automaticky hru zjistit, pokud ho odkážete na správnou složku.
+3.3) Poznámky ke hrám Multi-CD:
+---- --------------------------
+ObecnÄ› ScummVM moc dobÅ™e nefunguje s hrami na Multi-CD. To je proto, že ScummVM pÅ™edpokládá, že vÅ¡echno o hÅ™e může být nalezeno v jedné složce. I když ScummVM má schopnost požádat uživatele, aby vymÄ›nil CD, původní spouÅ¡tÄ›Ä souboru vÄ›tÅ¡inou nainstaluje malé množství souborů na pevný disk. Pokud tyto soubory nelze najít na vÅ¡ech CD, ScummVM bude mít potíže.
-Nebo můžete použít 'extract_mm_c64' z balíÄku nástrojů pro extrahování datových souborů. Pak ale ScummVM hru řádnÄ› automaticky nezjistí ScummVM, a musíte se ujistit, že platforma je nastavena na Commodore64. DoporuÄujeme použít mnohem jednodušší postup popsaný v pÅ™edchozím odstavci.
+Naštěstí může ScummVM hry bez problémů spouštět přímo z pevného disku, pokud vytvoříte složku se správnou kombinací souborů. Většinou, když se soubor objeví na více, než jednom CD můžete vybrat jeden z nich.
-3.4) Poznámky ke Maniac Mansion NES:
----- -------------------------
-Podporované verze jsou Britská angliÄtina (E), FrancouzÅ¡tina (F), NÄ›mÄina (G), ItalÅ¡tina (I), Å védÅ¡tina (SW) a Americká angliÄtina (U). ScummVM pro spuÅ¡tÄ›ní vyžaduje pouze Äást PRG a ne celý ROM.
+3.4) Známé Problémy:
+---- ---------------
+Toto vydání má následující známé problémy. Není tÅ™eba je ohlaÅ¡ovat, i když záplaty pro jejich opravu jsou vítány. Pokud objevíte chybu, která není zde v seznamu, ani není v seznamu kompatibility na internetové stránce, prohlédnÄ›te si, prosím, Äást o hlášení chyb.
-Abyste mohli hru spustit, musíte vyjmout prvních 16 bajtů z ROM, s kterým pracujete. Jakýkoli hex editor bude fungovat, pokud můžete kopírovat/vkládat. Poté. Co ROM otevÅ™ete pomocí hex editoru, zkopírujte vÅ¡echno z druhého řádku (17. bajt) na konec. Poté, co toto provedete, vložte ho do nového hex souboru. Pojmenujte ho "Maniac Mansion (XX).prg" kde XX znamená verzi, se kterou pracujete (E, F, G, I, SW, nebo U). KoneÄná velikost by mÄ›la být pÅ™esnÄ› 262144 bajtů.
+ Hry CD Audio:
+ - Při hraní her, které používají CD Audio (hry FM-TOWNS, Loom CD, atd) může u uživatelů Microsoft Windows 2000/XP docházet k náhodným pádům. To je díky dlouhotrvající chybě Windows, která má za následek poškozené soubory
+ pÅ™i Ätení z CD. Abyste se tomuto vyhnuli, zkopírujte, prosím, soubory na pevný disk
-Pokud hru pÅ™idáváte ruÄnÄ›, ujistÄ›te se, že platforma je nastavena na NES.
+ Verze FM-TOWNS:
+ - Verze Kandži vyžaduje ROM písma FM-TOWNS
-Nejběžnější chyby, které zabraňují spuštění hry:
+ Loom:
+ - Vypnutí titulků pomocí souboru nastavení je nevypne spolehlivě, protože skripty Loom je znovu automaticky zapnou
+ - Podpora MIDI ve verzi EGA vyžaduje aktualizaci Roland LucasArts
+ - Verze Kandži na PC-Engine vyžaduje rom systémové karty
- * Špatný soubor
- * ROM byl extrahován pomocí nástrojů z verze 0.7.0
- * Snažíte se do ScummVM vkládat CELà ROM a ne jenom PRG Äást.
+ The Secret of Monkey Island:
+ - Podpora MIDI ve verzi EGA vyžaduje aktualizaci Roland LucasArts
-Je také možno extrahovat oddÄ›lené soubory LFL z PRG Äásti. Pro toto použijte nástroj 'extract_mm_nes' z balíÄku nástrojů.
+ Beneath a Steel Sky:
+ - Verze pro Amiga nejsou podporovány
+ - Demoverze z diskety nejsou podporovány
+ - Není chyba: Ve verzi na CD chybí v jistých dialozích Å™eÄ, to je normální.
+ Elvira - Mistress of the Dark:
+ - Ve verzi pro Atari ST nefunguje hudba
-3.5) 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.
+ Elvira II - The Jaws of Cerberus:
+ - Ve verzi pro Atari ST nefunguje hudba
+ - Ve verzi pro PC nefungují zvukové efekty
+ - Ve verzi pro Atari ST jsou problémy s paletou
-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).
+ Inherit the Earth: Quest for the Orb:
+ - Verze pro Amiga nejsou podporovány
-V balíÄku nástrojů také poskytujeme nástroj nazvaný 'extract_scumm_mac', který extrahuje data z tÄ›chto datových souborů, ale toto není ani potÅ™eba, ani doporuÄeno.
+ Lure of the Temptress:
+ - Žádná podpora Roland MT-32
+ - Podpora zvuku není dokonÄena a nezní jako v původní hÅ™e
-Pro další informace o kopírování herních souborů Macintosh na Váš pevný disk si prohlédněte:
+ Simon the Sorcerer 1:
+ - V anglických a německých verzích na CD nejsou titulky dostupné, protože jim většina titulků chybí.
- http://wiki.scummvm.org/index.php/HOWTO-Mac_Games
+ Simon the Sorcerer 2:
+ - Kombinace Å™eÄi a titulků Äasto způsobí, že Å™eÄ je pÅ™eruÅ¡ena brzo, toto je omezení původní hry.
+ - Ve verzích pro Amiga a Macintosh je podporován pouze výchozí jazyk datových souborů (angliÄtina).
+ Simon the Sorcerer's Puzzle Pack:
+ - Žádná podpora pro zobrazování, zadávání, ukládání, Äi naÄítání nejvyšších skóre.
+ - Žádná podpora pro zobrazování názvů položek, když na ně najedete myší ve Swampy Adventures.
-3.6) Poznámky ke hrám Multi-CD:
----- --------------------------
-ObecnÄ› ScummVM moc dobÅ™e nefunguje s hrami na Multi-CD. To je proto, že ScummVM pÅ™edpokládá, že vÅ¡echno o hÅ™e může být nalezeno v jedné složce. I když ScummVM má schopnost požádat uživatele, aby vymÄ›nil CD, původní spouÅ¡tÄ›Ä souboru vÄ›tÅ¡inou nainstaluje malé množství souborů na pevný disk. Pokud tyto soubory nelze najít na vÅ¡ech CD, ScummVM bude mít potíže.
+ The Feeble Files:
+ - Titulky jsou Äasto nedokonÄené. V původní hÅ™e byly vždy zakázány.
-Naštěstí může ScummVM hry bez problémů spouštět přímo z pevného disku, pokud vytvoříte složku se správnou kombinací souborů. Většinou, když se soubor objeví na více, než jednom CD můžete vybrat jeden z nich.
+ The Legend of Kyrandia:
+ - Ve verzích na disketě pro Mac není žádná hudba ani zvukové efekty.
+ - CD Macintosh používá zahrnutou hudbu a zvukové efekty z DOS.
+ Hry Humongous Entertainment:
+ - Pouze původní rozhraní pro uložení a naÄtení mohou být použity.
+ - Žádná podpora pro hru více hráÄů nebo tisknutí obrázků
-3.7) Poznámky k The Curse of Monkey Island:
----- --------------------------------------
-Pro tuto hru budete potřebovat soubory comi.la0, comi.la1 a comi.la2.
-Soubor comi.la0 můžete nalézt na všech CD hry, ale protože jsou stejné, můžete použít kterýkoli z nich.
-Dále potřebujete vytvořit podsložku "resource" obsahující všechny soubory z –obou- podsložek "resource" na dvou CD. Některé soubory se objevují na obou CD, ale znovu jsou stejné.
+3.5) Poznámky k Beneath a Steel Sky:
+---- -------------------------------
+Od ScummVM 0.8.0 potÅ™ebujete dodateÄný soubor 'SKY.CPT', abyste mohli Beneath a Steel Sky spustit.
+Tento soubor je dostupný na stránce 'Downloads' domovské stránky ScummVM.
+Můžete ho umístit buÄ do složky obsahující ostatní datové soubory (SKY.DNR, SKY.DSK), na VaÅ¡i dodateÄnou cestu, nebo do složky. Kde se nachází spouÅ¡tÄ›cí soubor ScummVM.
-3.8) Poznámky ke hrám Broken Sword:
+
+3.6) Poznámky ke hrám Broken Sword:
---- ------------------------------
Pokyny pro hry Broken Sword jsou pro verze od Sold-Out Software, kde každá hra je na dvou CD, protože tyto verze byly nejdostupnÄ›jší v dobÄ›, kdy je ScummVM zaÄal podporovat. Doufáme, že jsou dostateÄnÄ› obecné pro použití i v jiných vydáních her.
-3.8.1) Videa z her Broken Sword:
+3.6.1) Broken Sword:
+------ -------------
+Pro tuto hru budete potřebovat všechny soubory ze seskupení složek na obou CD. Pro verze Windows a Macintosh budete také potřebovat soubory speech.clu ze složek speech, ale protože soubory nejsou stejné, budete je muset přejmenovat na speech1.clu a speech2.clu z CD 1 a 2 v tomto pořadí. Verze na PlayStation vyžaduje speech.tab, speech.dat, speech.lis, a speech.inf.
+
+Dále verze pro Windows a Macintosh vyžadují podsložku music se vÅ¡emi soubory z podsložek music na obou CD. NÄ›které z tÄ›chto souborů se objevují na obou CD, ale v tÄ›chto případech jsou buÄ stejné, nebo, v jednom případÄ›, je téměř stejný, že to nemá žádný význam. Verze pro PlayStation vyžaduje tunes.dat a tunes.tab.
+
+
+3.6.2) Broken Sword II:
+------ ----------------
+Pro tuto hru budete potřebovat všechny soubory ze seskupení složek na obou CD. (Abych pravdu řekl, pár z nich nemusí být nezbytně nutné, ale ty, o kterých nemám jistotu, jsou velmi malé.)
+Je také třeba přejmenovat soubory speech.clu a music.clu na speech1.clu, speech2.clu, music1.clu a music2.clu, aby ScummVM mohl zjistit, které jsou z CD 1 a které z CD 2. Všechny ostatní soubory, které jsou umístěny v seskupení složek, jsou stejné. Použijte kterékoli soubory chcete.
+
+Kromě toho budete potřebovat soubory cd.inf a, případně, startup.inf ze složky sword2 na CD 1.
+
+
+3.6.3) Videa z her Broken Sword:
------ -------------------------
Videa pro hry Broken Sword mají v sobÄ› trochu historie (viz další oddíl, pokud jste zvÄ›daví), ale obecnÄ› jediné, co potÅ™ebujete udÄ›lat, je zkopírovat soubory .SMK ze složek "SMACKS" nebo "SMACKSHI" na CD do stejné složky jako ostatní datové soubory hry. (Broken Sword má také složku "SMACKSLO" se stejnými videi, ale ty jsou nižší kvality.) Můžete je umístit do podsložky s názvem "video", pokud Vám to pÅ™ijde hezÄí.
Ve verzích pro PlayStation, můžete původní videa vypsat z disku. Každý soubor, který má příponu "STR", byste mÄ›li vypsat jako *Äist* sektory z disku (vÅ¡ech 2352 bajtů na sektor). Můžete také míst toho použít pÅ™eformátovaná videa, která jsou zmínÄ›na níže, ale to nebude fungovat pro vÅ¡echny videa v Broken Sword II. Pro více informací si prohlédnÄ›te:
- http://wiki.scummvm.org/index.php/HOWTO-PlayStation_Videos
+ <http://wiki.scummvm.org/index.php/HOWTO-PlayStation_Videos>
Některá vydání hry, a také verze pro PlayStation, Smacker videa nemají. Revolution Software nám laskavě dovolilo poskytovat přeformátovaná videa ke stažení na naší stránce:
- http://www.scummvm.org/downloads.php
+ <http://www.scummvm.org/downloads.php>
Tato videa jsou poskytována ve formátu DXA se zvukem ve formátu FLAC. Jejich kvalita se rovná originálu díky použití bezztrátové komprese. Zobrazení těchto videí vyžaduje, aby verze ScummVM byla sestavena s podporou FLAC i zlib.
@@ -519,7 +585,7 @@ Pro systémy, které jsou příliš pomalé, aby zvládli dekódovat formát FLA
Pro Broken Sword také poskytujeme přídavek pro titulky. JednoduÅ¡e ho rozbalte a následujte pokyny v souboru readme.txt. BalíÄek v souÄasnosti nefunguje ve videích na PlayStation. (Broken Sword II již titulky má; není tÅ™eba další práce pro jejich pÅ™idání.)
-3.8.2) Videa her Broken Sword ve zpětném pohledu:
+3.6.4) Videa her Broken Sword ve zpětném pohledu:
------ ------------------------------------------
Původní vydání her Broken Sword používalo formát Smackerâ„¢ od RAD Game Tools. Protože spoleÄnost RAD nebyla ochotna nám otevřít starší zastaralé verze tohoto formátu a požádala, abychom neprovádÄ›li jeho zpÄ›tnou analýzu, museli jsme nalézt jiné Å™eÅ¡ení.
@@ -531,64 +597,125 @@ Ve ScummVM 0.6.0 jsme používali MPEG, což zajistilo rozumný kompromis mezi v
Nakonec na zaÄátku roku 2006 byl formát Smacker zpÄ›tnÄ› analyzován pro projekt FFmpeg. Díky jejich tvrdé práci ScummVM 1.0.0 nyní podporuje původní videa. Zároveň byla ukonÄena podpora MPEG. Z technického hlediska je toto dobÅ™e, protože pÅ™ehrávání videí MPEG bylo velmi složité a stejnÄ› nevypadaly tak dobÅ™e jako verze ve formátu DXA a Smacker.
-3.8.3) Broken Sword:
------- -------------
-Pro tuto hru budete potřebovat všechny soubory ze seskupení složek na obou CD. Pro verze Windows a Macintosh budete také potřebovat soubory speech.clu ze složek speech, ale protože soubory nejsou stejné, budete je muset přejmenovat na speech1.clu a speech2.clu z CD 1 a 2 v tomto pořadí. Verze na PlayStation vyžaduje speech.tab, speech.dat, speech.lis, a speech.inf.
+3.7) Poznámky k Day of the Tentacle:
+---- -------------------------------
+
+Na jednom místÄ› ve hÅ™e narazíte na poÄítaÄ umožňující si zahrát původní Maniac Mansion jako bonus. ScummVM toto podporuje, ale je tÅ™eba upozornit na pár vÄ›cí:
-Dále verze pro Windows a Macintosh vyžadují podsložku music se vÅ¡emi soubory z podsložek music na obou CD. NÄ›které z tÄ›chto souborů se objevují na obou CD, ale v tÄ›chto případech jsou buÄ stejné, nebo, v jednom případÄ›, je téměř stejný, že to nemá žádný význam. Verze pro PlayStation vYžaduje tunes.dat a tunes.tab.
+ScummVM prohledá váš soubor s nastavením hledajíc hru nacházející se v podsložce 'Maniac' ve složce hry Day of the Tentacle. Pokud jste zkopírovali datové soubory z CD verze, tato struktura by již měla být
+vytvořena, navíc ale budete muset hru přidat také do ScummVM.
+Pro návrat do Day of the Tentacle, stisknÄ›te F5 a zvolte "Návrat do spouÅ¡tÄ›Äe".
-3.8.4) Broken Sword II:
------- ----------------
-Pro tuto hru budete potřebovat všechny soubory ze seskupení složek na obou CD. (Abych pravdu řekl, pár z nich nemusí být nezbytně nutné, ale ty, o kterých nemám jistotu, jsou velmi malé.)
-Je také třeba přejmenovat soubory speech.clu a music.clu na speech1.clu,
-speech2.clu, music1.clu a music2.clu, aby ScummVM mohl zjistit, které jsou z CD 1 a které z CD 2. Všechny ostatní soubory, které jsou umístěny v seskupení složek, jsou stejné. Použijte kterékoli soubory chcete.
+Teoreticky toto znamená, že je možné spustit jakoukoli hru jako bonus. Vskutku tomu tak je. Existuje "tajná" volba nastavení, "easter_egg", která mÄ›ní ID spouÅ¡tÄ›né hry. BuÄte ale opatrní, protože ne vÅ¡echny hry podporují
+návrat do spouÅ¡tÄ›Äe, a nedoporuÄuje se nastavovat spuÅ¡tÄ›ní samotné hry Day of the Tentacle jako bonus.
-Kromě toho budete potřebovat soubory cd.inf a, případně, startup.inf ze složky sword2 na CD 1.
+3.8) Poznámky k Discworld II:
+---- ------------------------
-3.9) Poznámky k Beneath a Steel Sky:
----- -------------------------------
-Od ScummVM 0.8.0 potÅ™ebujete dodateÄný soubor 'SKY.CPT', abyste mohli Beneath a Steel Sky spustit.
+Pro tuto hru potřebujete všechny soubory z podsložky DW2 na obou CD.
+Dále je třeba zkopírovat soubor SAMPLE.BNK.
-Tento soubor je dostupný na stránce 'Downloads' domovské stránky ScummVM.
-Můžete ho umístit buÄ do složky obsahující ostatní datové soubory (SKY.DNR, SKY.DSK), na VaÅ¡i dodateÄnou cestu, nebo do složky. Kde se nachází spouÅ¡tÄ›cí soubor ScummVM.
+Je třeba přejmenovat soubory ENGLISH.SMP, ENGLISH.IDX a ENGLISH.TXT na CD1 na ENGLISH1.SMP, ENGLISH1.IDX a ENGLISH1.txt.
+To samé provést se soubory z CD2 a přejmenovat je na ENGLISH2.SMP, ENGLISH2.IDX a ENGLISH2.TXT.
+
+
+3.9) Poznámky k DraÄí Historie:
+---- --------------------------
+Existují 4 jazykové varianty této hry: Äeská, anglická, polská a nÄ›mecká. Každá je umístÄ›na v oddÄ›leném archivu. Jediná oficiální verze je Äeská, a anglická, polská a nÄ›mecká byly vždycky nedokonÄené práce a nikdy nebyly oficiálnÄ› vydány. I když texty byly zcela pÅ™eloženy, je známo, že nÄ›které z nich obsahují pÅ™eklepy.
+
+Pro tuto hru existuje nepovinný Äeský dabing. Z důvodu velikosti si ho můžete dodateÄnÄ› stáhnout a pak ho rozbalit do adresáře hry. Můžete také Äeský dabing poslouchat se vÅ¡emi jazykovými varianty hry, zatímco Ätete titulky.
+
+Všechny herní soubory a návody můžou být staženy z:
+
+<http://www.ucw.cz/draci-historie/index-en.html>
3.10) Poznámky k Flight of the Amazon Queen:
----- --------------------------------------
-Abyste mohli použít tu verzi, která není volně šiřitelná
-(z původního CD), musíte mít soubor 'queen.tbl'
-(dostupný ze stránky 'Downloads' naší domovské stránky) a umístit ho buÄ do složky obsahující soubor hry 'queen.1', na VaÅ¡i dodateÄnou cestu, nebo do složky. Kde se nachází spouÅ¡tÄ›cí soubor ScummVM.
+----- --------------------------------------
+Abyste mohli použít tu verzi, která není volnÄ› Å¡iÅ™itelná (z původního CD), musíte mít soubor 'queen.tbl' (dostupný ze stránky 'Downloads' naší domovské stránky) a umístit ho buÄ do složky obsahující soubor hry 'queen.1',
+na VaÅ¡i dodateÄnou cestu, nebo do složky. Kde se nachází spouÅ¡tÄ›cí soubor ScummVM.
Také můžete použít nástroj 'compress_queen' z balíÄku nástrojů pro 'znovu sestavení' VaÅ¡eho datového souboru FOTAQ pro zahrnutí tabulky pro tuto konkrétní verzi, Äímž odstraníte závislost na soubor 'queen.tbl' pÅ™i spuÅ¡tÄ›ní. Tento nástroj Vám také umožňuje komprimovat Å™eÄ a zvukové efekty do formátu MP3, OGG nebo FLAC.
3.11) Poznámky ke Gobliiins:
----- ----------------------
-CD verze série Gobliiins obsahuje jednu velkou zvukovou stopu, kterou potÅ™ebujete vyjmout (viz oddíl o použití komprimovaných zvukových souborů) a zkopírovat ji do herní složky, pokud chcete ve hÅ™e hudbu, aniž byste museli CD mít stále v jednotce. V této stopÄ› jsou také Å™eÄ a její hlasitost se tedy také mÄ›ní podle hlasitosti hudby.
+CD verze série Gobliiins obsahuje jednu velkou zvukovou stopu, kterou je tÅ™eba vyjmout (viz oddíl o použití komprimovaných zvukových souborů) a zkopírovat ji do herní složky, pokud chcete ve hÅ™e hudbu, aniž byste museli CD mít stále v jednotce. V této stopÄ› je také Å™eÄ a její hlasitost se tedy také mÄ›ní podle hlasitosti hudby.
3.12) Poznámky k Inherit the Earth: Quest for the Orb:
----- ------------------------------------------------
Abyste mohli spustit verzi pro Mac OS X od Wyrmkeep musíte data zkopírovat z CD na Váš pevný disk. Pokud používáte PC, pak se podívejte na:
- http://wiki.scummvm.org/index.php/HOWTO-Mac_Games
+ <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
Ve staré verzi pro Mac OS 9 potřebujete soubory zkopírovat ve formátu MacBinary, protože by měli obsahovat jak zdrojové, tak datové vidlice. Zkopírujte všechny soubory 'ITE *'.
-3.13) Poznámky k Simon the Sorcerer 1 a 2:
+3.13) Poznámky ke Maniac Mansion na Apple II/NES:
+----- -------------------------------------------
+Apple II:
+Je třeba přejmenovat obraz disku 1 na maniac1.dsk
+Je třeba přejmenovat obraz disku 2 na maniac2.dsk
+
+NES:
+Podporované verze jsou Britská angliÄtina (E), FrancouzÅ¡tina (F), NÄ›mÄina (G), ItalÅ¡tina (I), Å védÅ¡tina (SW) a Americká angliÄtina (U). ScummVM pro spuÅ¡tÄ›ní vyžaduje pouze Äást PRG a ne celý ROM.
+
+Abyste mohli hru spustit, musíte vyjmout prvních 16 bajtů z ROM, s kterým pracujete. Jakýkoli hex editor bude fungovat, pokud můžete kopírovat/vkládat. Poté. Co ROM otevÅ™ete pomocí hex editoru, zkopírujte vÅ¡echno z druhého řádku (17. bajt) na konec. Poté, co toto provedete, vložte ho do nového hex souboru. Pojmenujte ho "Maniac Mansion (XX).prg" kde XX znamená verzi, se kterou pracujete (E, F, G, I, SW, nebo U). KoneÄná velikost by mÄ›la být pÅ™esnÄ› 262144 bajtů.
+
+Pokud hru pÅ™idáváte ruÄnÄ›, ujistÄ›te se, že platforma je nastavena na NES.
+
+Nejběžnější chyby, které zabraňují spuštění hry:
+
+ * Špatný soubor
+ * ROM byl extrahován pomocí nástrojů z verze 0.7.0
+ * Snažíte se do ScummVM vkládat CELà ROM a ne jenom PRG Äást.
+
+Je také možno extrahovat oddÄ›lené soubory LFL z PRG Äásti. Pro toto použijte nástroj 'extract_mm_nes' z balíÄku nástrojů.
+
+
+3.14) Poznámky k Mickey's Space Adventure:
+----- ------------------------------------
+Abyste mohli Mickey's Space Adventure hrát ve ScummVM, potÅ™ebujete spolu s datovými soubory hry také původní spouÅ¡tÄ›Ä (mickey.exe).
+
+Pro tuto hru ve ScummVM, existuje rozšířená podpora myÅ¡i, i když v původní hÅ™e takováto podpora nebyla. Položky menu mohou být vybrány pomocí myÅ¡i a je také možné se myší pÅ™esunout do jiných míst. Když se kurzor myÅ¡i nachází na okraji obrazovky, zÄervená, pokud je možné jít v tomto smÄ›ru. HrÃ¡Ä pak může jednoduÅ¡e kliknout na okraje herní obrazovky pro zmÄ›nu místa, podobnÄ› jako mnoho adventur, což je jednodušší a přímoÄaÅ™ejší než pohyb pomocí menu.
+
+
+3.15) Nippon Safes Inc. Amiga notes:
+----- ------------------------------
+Pro tuto hru potřebujete disk0, soubory global.table a pointer a it (en, fr, ge pro mezinárodní verzi).
+
+Dále je třeba přejmenovat obraz disku 2 na disk1, obraz disku 3 na disk2, obraz disku 4 na disk3 a obraz disku 5 na disk4.
+
+
+3.16) Poznámky k Simon the Sorcerer 1 a 2:
----- ------------------------------------
Pokud máte dvojitou verzi Simon the Sorcerer 1 nebo 2 na CD, verzi pro Windows naleznete v hlavní složce na CD a verzi pro DOS ve složce DOS na CD.
-3.14) Poznámky k The Feeble Files:
+3.17) Poznámky k The Curse of Monkey Island:
+----- --------------------------------------
+Pro tuto hru budete potřebovat soubory comi.la0, comi.la1 a comi.la2.
+Soubor comi.la0 můžete nalézt na všech CD hry, ale protože jsou stejné, můžete použít kterýkoli z nich.
+
+Dále potřebujete vytvořit podsložku "resource" obsahující všechny soubory z –obou- podsložek "resource" na dvou CD. Některé soubory se objevují na obou CD, ale znovu jsou stejné.
+
+
+3.18) Poznámky k The Feeble Files:
----- ----------------------------
+Amiga/Macintosh:
+Musíte nainstalovat malý balíÄek videí, které chybí v obou tÄ›chto verzích této hry. Jmenuje se "The Feeble Files - Omni TV and epilogue cutscenes for the Amiga and Macintosh versions"
+a lze ho získat zde:
+
+ <http://www.scummvm.org/games/#feeble>
+
+Windows:
Pokud máte verzi pro Windows, je třeba si uvědomit pár věcí.
Mnoho souborů, které hra vyžaduje, je uloženo v souboru InstallShield s názvem data1.cab, který ScummVM nemůže rozbalit. Budete muset použít původní instalátor, nebo i5comp pro rozbalení obsahu tohoto souboru. Nástroj pro dekomprimaci i5comp může být nalezen při hledání na internetu.
@@ -599,7 +726,7 @@ Přejmenovat voices.wav na CD2 na voices2.wav
Přejmenovat voices.wav na CD3 na voices3.wav
Přejmenovat voices.wav na CD4 na voices4.wav
-3.15) Poznámky k The Legend of Kyrandia:
+3.19) Poznámky k The Legend of Kyrandia:
----- ----------------------------------
Abyste mohli spustit The Legend of Kyrandia ve ScummVM potřebujete soubor 'kyra.dat'.
Soubor by mÄ›l být vždycky souÄástí oficiálních balíÄků ScummVM. V případÄ›, že ScummVM
@@ -607,7 +734,20 @@ nahlásí, že soubor chybí, můžete ho najít na stránce ScummVM v sekci 'Do
Nezapomeňte, že souÄasná verze ScummVM pro Windows by mÄ›la soubor obsahovat ve spouÅ¡tÄ›Äi a tudíž ho
musíte mít pouze, když ScummVM soubor nemůže nalézt.
-3.16) Poznámky k Předvídavému Vstupnímu Dialogu her Sierra AGI:
+
+3.20) Poznámky k Troll's Tale:
+----- ------------------------
+Původní hra vycházela na zaváděcím disku PC, proto je nutné vypsat obsah tohoto disku jako obraz disku a přejmenovat ho na "troll.img", abyste tuho hru mohli hrát ve ScummVM.
+
+
+3.21) Winnie the Pooh notes:
+----- ----------------------
+Je možné importovat uložené hry z původní hry do ScummVM.
+
+Pro tuto hru ve ScummVM, existuje rozšířená podpora myÅ¡i, i když v původní hÅ™e takováto podpora nebyla. Položky menu mohou být vybrány pomocí myÅ¡i a je také možné se myší pÅ™esunout do jiných míst. Když se kurzor myÅ¡i nachází na okraji obrazovky, zÄervená, pokud je možné jít v tomto smÄ›ru. HrÃ¡Ä pak může jednoduÅ¡e kliknout na okraje herní obrazovky pro zmÄ›nu místa, podobnÄ› jako mnoho adventur, což je jednodušší a přímoÄaÅ™ejší než pohyb pomocí menu.
+
+
+3.22) Poznámky k Předvídavému Vstupnímu Dialogu her Sierra AGI:
----- ---------------------------------------------------------
Předvídavý Vstupní Dialog je pomůcka ScummVM pro spouštění her používající jádro AGI (který je znám, že vyžaduje vstup z příkazové řádky) na zařízeních s omezenou podporou klávesnice. V těchto situacích, kdy zadávání pomocí emulované klávesnice je dosti únavné, můžou být příkazy rychle a snadno zadány pomocí Předvídavého Vstupního Dialogu.
@@ -615,48 +755,19 @@ Abyste zapnuli předvídavý vstup v hrách AGI, potřebujete zkopírovat soubor
Pokud je slovník zjiÅ¡tÄ›n, je PÅ™edvídavý Vstupní Dialog zobrazen buÄ pÅ™i kliknutí na oblast příkazového řádku (kdykoliv je požadován vstup klávesnice, i v rámeÄcích dialogových oken), nebo v nÄ›kterých verzích pro jiné systémy stisknutím urÄené klávesové zkratky.
-PÅ™edvídavý Vstupní Dialog pracuje ve tÅ™ech režimech, které jsou pÅ™epínány tlaÄítkem (*)Pre/123/Abc. Hlavní vstupní metodou je pÅ™edvídavý režim
-(Pre), který připomíná "rychlé zadávání" v mobilních telefonech.
+PÅ™edvídavý Vstupní Dialog pracuje ve tÅ™ech režimech, které jsou pÅ™epínány tlaÄítkem (*)Pre/123/Abc. Hlavní vstupní metodou je pÅ™edvídavý režim
+(Pre), který připomíná "rychlé zadávání" v mobilních telefonech.
Abeceda je rozdÄ›lena do 9 sad, které pÅ™irozenÄ› odpovídají 9 klávesám Äíselné klávesnice (0 je mezera). Pro psaní slova zmáÄknÄ›te jednou Äíslo sady, která obsahuje písmeno slova, které chcete napsat, pak pokraÄujete k dalšímu. Například, pokud chcete napsat příkaz 'look', mÄ›li byste zmáÄknout 5665. Jak postupnÄ› píšete Äíselný kód zamýšleného slova, je slovník prohledáván pro známá slova, která se shodují s Vaším vstupem až do tohoto bodu. Jak maÄkáte více kláves, slovník se pÅ™iblíží ke správnému slovu. To je důvod, proÄ vypsané slovo se může náhle zmÄ›nit mezi stisky kláves. NÄ›kdy se ale vyskytnou případy, kdy více než jedno slovo má stejné Äíselné zastoupení. Například slova 'quit' a 'suit' odpovídají stejným Äíslům, a to 7848. V tÄ›chto případech se rozsvítí tlaÄítko další
(#). Jeho stisknutím můžete procházet seznam slov, která sdílejí stejný kód a nakonec pÅ™ijmout to správné stisknutím (0)mezera nebo tlaÄítka Ok.
Druhou vstupní metodou (123) je Äíselný vstup: Každou klávesu, kterou stisknÄ›te, je doslova zadána jako Äíslo.
-
+
TÅ™etí vstupní metodou (Abc) je vstupní režim Alfa/opakovaného stisknutí tlaÄítka. Tento režim je urÄen pro zadávání textu bez pomoci od slovníku pÅ™edvídavého režimu (Pre). Text je zadáván po jednotlivých písmenech. Pro každé písmeno nejdříve stisknÄ›te Äíslo sady, které obsahuje písmeno, které chcete, pak použijte tlaÄítko další (#) pro procházení písmeny a opakujte s dalším Äíslem. Například, pro zadání slova 'look' musíte stisknout následující: 5##6##6##5#
Dialogové okno je plnÄ› použitelné pomocí myÅ¡i, ale v nÄ›kterých verzích ScummVM pro jiné platformy, je použití dialogu pohodlnÄ›jší pomocí Äíselné klávesnice. NÄ›která tlaÄítka dialogu mohou být také používána pomocí Å¡ipkových kláves a enter.
-3.17) Poznámky k Mickey's Space Adventure:
------ ------------------------------------
-Abyste mohli Mickey's Space Adventure hrát ve ScummVM, potÅ™ebujete spolu s datovými soubory hry také původní spouÅ¡tÄ›Ä (mickey.exe).
-
-Pro tuto hru ve ScummVM, existuje rozšířená podpora myÅ¡i, i když v původní hÅ™e takováto podpora nebyla. Položky menu mohou být vybrány pomocí myÅ¡i a je také možné se myší pÅ™esunout do jiných míst. Když se kurzor myÅ¡i nachází na okraji obrazovky, zÄervená, pokud je možné jít v tomto smÄ›ru. HrÃ¡Ä pak může jednoduÅ¡e kliknout na okraje herní obrazovky pro zmÄ›nu místa, podobnÄ› jako mnoho adventur, což je jednodušší a přímoÄaÅ™ejší než pohyb pomocí menu.
-
-
-3.18) Winnie the Pooh notes:
------ ----------------------
-Je možné importovat uložené hry z původní hry do ScummVM.
-
-Pro tuto hru ve ScummVM, existuje rozšířená podpora myÅ¡i, i když v původní hÅ™e takováto podpora nebyla. Položky menu mohou být vybrány pomocí myÅ¡i a je také možné se myší pÅ™esunout do jiných míst. Když se kurzor myÅ¡i nachází na okraji obrazovky, zÄervená, pokud je možné jít v tomto smÄ›ru. HrÃ¡Ä pak může jednoduÅ¡e kliknout na okraje herní obrazovky pro zmÄ›nu místa, podobnÄ› jako mnoho adventur, což je jednodušší a přímoÄaÅ™ejší než pohyb pomocí menu.
-
-
-3.19) Poznámky k Troll's Tale:
------ ------------------------
-Původní hra vycházela na zaváděcím disku PC, proto je nutné vypsat obsah tohoto disku jako obraz disku a přejmenovat ho na "troll.img", abyste tuho hru mohli hrát ve ScummVM.
-
-
-3.20) Poznámky k DraÄí Historie:
------ --------------------------
-Existují 4 jazykové varianty této hry: Äeská, anglická, polská a
-nÄ›mecká. Každá je umístÄ›na v oddÄ›leném archivu. Jediná oficiální verze je Äeská, a anglická, polská a nÄ›mecká byly vždycky nedokonÄené práce a nikdy nebyly oficiálnÄ› vydány. I když texty byly zcela pÅ™eloženy, je známo, že nÄ›které z nich obsahují pÅ™eklepy.
-
-Pro tuto hru existuje nepovinný Äeský dabing. Z důvodu velikosti si ho můžete dodateÄnÄ› stáhnout a pak ho rozbalit do adresáře hry. Můžete také Äeský dabing poslouchat se vÅ¡emi jazykovými varianty hry, zatímco Ätete titulky.
-
-Všechny herní soubory a návody můžou být staženy z
-http://www.ucw.cz/draci-historie/index-en.html
-
-3.21) Titulky a hlasy souběžně v hrách Sierra SCI:
+3.23) Titulky a hlasy souběžně v hrách Sierra SCI:
----- --------------------------------------------
UrÄité CD verze her Sierra SCI mají textová i hlasová data.
Některé z nich mají volbu pro přepínání mezi nimi, ale existují případy
@@ -674,7 +785,7 @@ Hry na CD, kde zvuk i titulky lze zobrazit souÄasnÄ›:
Space Quest 4 CD
EcoQuest 1 CD:
- Hlas i text lze zapnout pomocí volby "Mode" v okně nastavení,
+ Hlas i text lze zapnout pomocí volby "Mode" v okně nastavení,
nebo přes nastavení zvuku ScummVM.
Freddy Pharkas CD:
@@ -684,84 +795,136 @@ Freddy Pharkas CD:
King's Quest 6 CD
Hlas i text lze zapnout pomocí volby "Mode" v okně nastavení (kde je ve
- ScummVM pÅ™idána dodateÄná volba "Dual"), nebo pomocí nastavení
+ ScummVM pÅ™idána dodateÄná volba "Dual"), nebo pomocí nastavení
zvuku ve ScummVM.
Laura Bow 2 CD
Hlas i text lze zapnout pomocí volby "Mode" v okně nastavení (kde je ve
- ScummVM pÅ™idána dodateÄná volba "Dual"), nebo pomocí nastavení
+ ScummVM pÅ™idána dodateÄná volba "Dual"), nebo pomocí nastavení
zvuku ve ScummVM.
Leisure Suit Larry 6 CD
Ve hÅ™e lze povolit buÄ hlas, nebo hlas a text. Neexistuje možnost pro
- povolení textu. Pouze nastavení zvuku ve ScummVM lze použít pro
+ povolení textu. Pouze nastavení zvuku ve ScummVM lze použít pro
zobrazení jen titulků.
Space Quest 4 CD:
Hlas a text lze povolit pomocí tlaÄítka "Display Mode" v
nastavení hry, nebo pomocí nastavení zvuku ve ScummVM.
-
-
-3.22) Známé Problémy:
------ ---------------
-Toto vydání má následující známé problémy. Není tÅ™eba je ohlaÅ¡ovat, i když záplaty pro jejich opravu jsou vítány. Pokud objevíte chybu, která není zde v seznamu, ani není v seznamu kompatibility na internetové stránce, prohlédnÄ›te si, prosím, Äást o hlášení chyb.
-
- Hry CD Audio:
- - Při hraní her, které používají CD Audio (hry FM-TOWNS, Loom CD, atd) může u uživatelů Microsoft Windows 2000/XP docházet k náhodným pádům. To je díky dlouhotrvající chybě Windows, která má za následek poškozené soubory
- pÅ™i Ätení z CD. Abyste se tomuto vyhnuli, zkopírujte, prosím, soubory na pevný disk
-
- Verze FM-TOWNS:
- - Verze Kandži vyžaduje ROM písma FM-TOWNS
- Loom:
- - Vypnutí titulků pomocí souboru nastavení je nevypne spolehlivě, protože skripty Loom je znovu automaticky zapnou
- - Podpora MIDI ve verzi EGA vyžaduje aktualizaci Roland LucasArts
- - Verze Kandži na PC-Engine vyžaduje rom systémové karty
- The Secret of Monkey Island:
- - Podpora MIDI ve verzi EGA vyžaduje aktualizaci Roland LucasArts
-
- Beneath a Steel Sky:
- - Verze pro Amiga nejsou podporovány
- - Demoverze z diskety nejsou podporovány
- - Není chyba: Ve verzi na CD chybí v jistých dialozích Å™eÄ, to je normální.
-
- Elvira - Mistress of the Dark
- - Ve verzi pro Atari ST nefunguje hudba
-
- Elvira II - The Jaws of Cerberus
- - Ve verzi pro Atari ST nefunguje hudba
- - Ve verzi pro PC nefungují zvukové efekty
- - Ve verzi pro Atari ST jsou problémy s paletou
+3.24) Poznámky ke hrám Zork:
+----- ----------------------
+Pro spuÅ¡tÄ›ní podporovaných her Zork (Zork Nemesis: The Forbidden Lands a Zork: Grand Inquisitor) musíte zkopírovat nÄ›která (dodateÄná) data do odpovídajících umístÄ›ní.
+
+Zork Nemesis: The Forbidden Lands
+
+VÅ¡echny verze
+
+StáhnÄ›te si balíÄek písem Liberation(tm)
+<https://fedorahosted.org/releases/l/i/liberation-fonts/liberation-fonts-ttf-2.00.1.tar.gz>
+a rozbalte vÅ¡echny soubory ttf do vaší dodateÄné složky ScummVM.
+Nebo si stáhnÄ›te balíÄek GNU FreeFont TTF
+<https://ftp.gnu.org/gnu/freefont/freefont-ttf.zip> a umístÄ›te vÅ¡echny soubory ttf z adresáře sfd do dodateÄné složky ScummVM, i když je tÅ™eba říci, že v souÄasné dobÄ›
+mají některá tato písma potíže při vykreslování.
+Stáhněte si opravu pro titulky
+<http://www.thezorklibrary.com/installguides/znpatch.zip> a rozbalte adresář addon přímo do kořenového adresáře hry
+
+Verze z GoG
+
+Použijte instalátor GoG, žádných dalších kroků není třeba
+
+Verze z CD
+
+Zkopírujte následující z adresáře nemesis na CD1 do kořenového adresáře hry:
+Adresář znemmx
+Adresář znemscr
+nemesis.str
+Z CD1 zkopírujte adresář zassets do kořenového adresáře hry
+Z CD2 zkopírujte adresář zassets do koÅ™enového adresáře hry a nahraÄte vÅ¡echny soubory
+Z CD3 zkopírujte adresář zassets do koÅ™enového adresáře hry a nahraÄte vÅ¡echny soubory
+
+Verze z DVD
+
+Zkopírujte následující z adresáře nemesis do kořenového adresáře hry:
+Adresář znemmx
+Adresář znemscr
+nemesis.str
+Poznámka: Je třeba také přesunout cursor.zfs z adresáře zassets/global do adresáře znemscr
+Zkopírujte adresář disc2 do kořenového adresáře hry
+Zkopírujte adresář disc3 do kořenového adresáře hry
+Zkopírujte adresář zassets do kořenového adresáře hry
+
+
+Zork: Grand Inquisitor
+
+VÅ¡echny verze
+
+StáhnÄ›te si balíÄek písem Liberation(tm)
+<https://fedorahosted.org/releases/l/i/liberation-fonts/liberation-fonts-ttf-2.00.1.tar.gz>
+a rozbalte vÅ¡echny soubory ttf do vaší dodateÄné složky ScummVM.
+Nebo si stáhnÄ›te balíÄek GNU FreeFont TTF
+<https://ftp.gnu.org/gnu/freefont/freefont-ttf.zip> a umístÄ›te vÅ¡echny soubory ttf z adresáře sfd do dodateÄné složky ScummVM, i když je tÅ™eba říci, že v souÄasné dobÄ›
+mají některá tato písma potíže při vykreslování.
+
+Verze z GoG
+
+Použijte instalátor GoG, žádných dalších kroků není třeba
+
+Verze z CD
+
+Zkopírujte následující z adresáře zgi na CD1 do kořenového adresáře hry:
+Adresář zgi_mx
+cursor.zfs
+death.zfs
+inquis.str
+inquis.zix
+r.svr
+scripts.zfs
+subtitle.zfs
+Z CD1 zkopírujte adresář zassets1 do kořenového adresáře hry
+Z CD2 zkopírujte adresář zassets2 do kořenového adresáře hry
+DoporuÄujeme V8m nainstalovat záplatu 1.2
+<http://www.thezorklibrary.com/installguides/Zpatch.exe>,
+ale je možné že pro to budete muset hru nainstalovat normálním způsobem, protože záplata má vlastní instalátor.
+
+Verze z DVD
+
+Zkopírujte následující z adresáře zgi_e do kořenového adresáře hry:
+Adresář addon (oprava hry 1.2)
+Adresář zgi_mx
+cursor.zfs
+death.zfs
+inquis.str
+inquis.zix
+r.svr
+scripts.zfs
+subtitle.zfs
+Zkopírujte adresář eng_mpeg (video soubory MPEG2 ve vysokém rozlišení) do kořenového adresáře hry
+Zkopírujte adresář zassetsc do kořenového adresáře hry
+Zkopírujte adresář zassetse do kořenového adresáře hry
+
+
+3.25) Poznámky ke hrám Commodore64:
+----- -----------------------------
+Jak Maniac Mansion tak Zak McKracken mohou být spuštěny, ale Maniac Mansion není ještě hratelný. Jednoduše pojmenujte disky D64 jako
+"maniac1.d64" a "maniac2.d64" nebo "zak1.d64" a "zak2.d64", pak by měl ScummVM automaticky hru zjistit, pokud ho odkážete na správnou složku.
- Inherit the Earth: Quest for the Orb
- - Verze pro Amiga nejsou podporovány
+Nebo můžete použít 'extract_mm_c64' z balíÄku nástrojů pro extrahování datových souborů. Pak ale ScummVM hru řádnÄ› automaticky nezjistí ScummVM, a musíte se ujistit, že platforma je nastavena na Commodore64. DoporuÄujeme použít mnohem jednodušší postup popsaný v pÅ™edchozím odstavci.
- Lure of the Temptress
- - Žádná podpora Roland MT-32
- - Podpora zvuku není dokonÄena a nezní jako v původní hÅ™e
- Simon the Sorcerer 1:
- - V anglických a německých verzích na CD nejsou titulky dostupné, protože jim většina titulků chybí.
+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 "HFSExplorer" pro Windows a "hfsutils" pro Linux a ostatní Unixové operaÄní systémy.
- Simon the Sorcerer 2:
- - Kombinace Å™eÄi a titulků Äasto způsobí, že Å™eÄ je pÅ™eruÅ¡ena brzo, toto je omezení původní hry.
- - Ve verzích pro Amiga a Macintosh je podporován pouze výchozí jazyk datových souborů (angliÄtina).
+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).
- Simon the Sorcerer's Puzzle Pack:
- - Žádná podpora pro zobrazování, zadávání, ukládání, Äi naÄítání nejvyšších skóre.
- - Žádná podpora pro zobrazování názvů položek, když na ně najedete myší ve Swampy Adventures.
+V balíÄku nástrojů také poskytujeme nástroj nazvaný 'extract_scumm_mac', který extrahuje data z tÄ›chto datových souborů, ale toto není ani potÅ™eba, ani doporuÄeno.
- The Feeble Files:
- - Titulky jsou Äasto nedokonÄené. V původní hÅ™e byly vždy zakázány.
+Pro další informace o kopírování herních souborů Macintosh na Váš pevný disk si prohlédněte:
- The Legend of Kyrandia:
- - Ve verzích na disketě pro Mac není žádná hudba ani zvukové efekty.
- - CD Macintosh používá zahrnutou hudbu a zvukové efekty z DOS.
+ <http://wiki.scummvm.org/index.php/HOWTO-Mac_Games>
- Hry Humongous Entertainment:
- - Pouze původní rozhraní pro uložení a naÄtení mohou být použity.
- - Žádná podpora pro hru více hráÄů nebo tisknutí obrázků
4.0) Podporované Platformy:
---- ----------------------
@@ -772,7 +935,8 @@ Podporované platformy zahrnují (mimo jiné):
UNIX (Linux, Solaris, IRIX, *BSD, ...)
Windows
- Windows CE a Windows Mobile (vÄetnÄ› Smartphonů a PocketPCs)
+ Windows CE
+ Windows Mobile (vÄetnÄ› Smartphonů a PocketPCs)
Mac OS X
AmigaOS
Android
@@ -793,7 +957,7 @@ Podporované platformy zahrnují (mimo jiné):
Verze pro Dreamcast nepodporuje The Curse of Monkey Island, ani The Dig. Verze pro Nintendo DS nepodporuje Full Throttle, The Dig, nebo The Curse of Monkey Island.
Pro další omezení v závislosti na platformě se, prosím, podívejte na naší Wiki:
- http://wiki.scummvm.org/index.php/Platforms
+ <http://wiki.scummvm.org/index.php/Platforms>
Ve verzi pro Macintosh je stisknutí pravého tlaÄítka myÅ¡i emulováno pomocí Cmd-kliknutí (to je, že stisknete tlaÄítko myÅ¡i pÅ™i držení klávesy
Command/Apple/Vrtule).
@@ -833,7 +997,7 @@ ScummVM může také hru spustit přímo pomocí argumentů příkazové řádky
-g, --gfx-mode=REŽIM Vybere režim obrazu (viz také Äást 5.3)
--gui-theme=VZHLED Vybere vzhled rozhraní (výchozí, moderní, klasický)
--themepath=CESTA Cesta kde jsou vzhledy rozhraní uloženy
- --list-themes Zobrazí seznam všech použitelných vzhledů
+ --list-themes Zobrazí seznam všech použitelných vzhledů
-e, --music-driver=REŽIM Vybere ovladaÄ hudby (viz také Äást 7.0)
--list-audio-devices Zobrazí seznam všech dostupných zvukových zařízení
-q, --language=JAZYK Vybere jazyk hry (viz také Äást 5.2)
@@ -858,7 +1022,10 @@ ScummVM může také hru spustit přímo pomocí argumentů příkazové řádky
--output-rate=FREKVENCE Výstupní vzorkovací kmitoÄet v Hz (napÅ™. 22050)
--opl-driver=OVLADAČ Vybere emulátor AdLib (OPL) (db, mame)
--aspect-ratio Povolí korekci poměru stran
- --render-mode=REŽIM Povolí dodateÄné režimy vykreslení (cga, ega, hercGreen, hercAmber, amiga)
+ --render-mode=REŽIM Povolí dodateÄné režimy vykreslení (hercGreen, hercAmber,
+ cga, ega, vga, amiga, fmtowns, pc9821, pc9801, 2gs,
+ atari, macintosh)
+
--alt-intro Použije alternativní intro pro CD verze Beneath a Steel Sky a Flight of the Amazon Queen
--copy-protection Povolí ochranu proti kopírování v hrách, když ji ScummVM standardně zakazuje.
--talkspeed=ÄŒÃSLO Nastaví zdržení mluvení v hrách SCUMM, nebo rychlost mluvení v jiných hrách (výchozí: 60)
@@ -1018,12 +1185,12 @@ ScummVM podporuje různé zkratky ve hře. Liší se mezi různými hrami SCUMM
Ctrl-F5 - Zobrazí Globální Menu
Cmd-q - UkonÄit (Mac OS X)
Ctrl-q - UkonÄit (další unixy vÄetnÄ› Linux)
- Ctrl-z NEBO Alt-x - UkonÄit (další platformy)
+ Ctrl-z - UkonÄit (další platformy)
Ctrl-u - Zeslabí všechny zvuky
Ctrl-m - Přepínat zachycení myši
Ctrl-Alt 1-8 - Přepínat mezi grafickými filtry
Ctrl-Alt + a - - Zvětšit/Zmenšit faktor zvětšení
- Ctrl-Alt a - Přepínat korekci poměru stran. Většina her používá rozlišení 320x200 pixelů, což může na většině novějších monitorů vypadat splácle. Korekce poměru stran obraz roztáhne, aby místo toho použil
+ Ctrl-Alt a - Přepínat korekci poměru stran. Většina her používá rozlišení 320x200 pixelů, což může na většině novějších monitorů vypadat splácle. Korekce poměru stran obraz roztáhne, aby místo toho použil
320x240, nebo jeho násobky
Alt-Enter - Přepíná celou obrazovku/do okna
Alt-s - Vytvořit snímek obrazovky (pouze jádro SDL)
@@ -1032,6 +1199,7 @@ ScummVM podporuje různé zkratky ve hře. Liší se mezi různými hrami SCUMM
prostÅ™edního tlaÄítka nebo koleÄka myÅ¡i.
SCUMM:
+ Alt-x - UkonÄit
Ctrl 0-9 a Alt 0-9 - Nahrát a uložit stav hry
Ctrl-d - Spustit ladění
Ctrl-f - Zapnout rychlý režim
@@ -1058,12 +1226,12 @@ ScummVM podporuje různé zkratky ve hře. Liší se mezi různými hrami SCUMM
TeÄka (.) - PÅ™eskoÄí souÄasný řádek textu
Broken Sword:
- F5 nebo Escape - Zobrazí rámeÄek pro uložení/naÄtení
+ F5 nebo Escape - Zobrazí rámeÄek pro uložení/naÄtení
Broken Sword II:
Ctrl-d - Spustit ladění
Ctrl-f - Zapnout rychlý režim
- p - Pozastavení
+ p - Pozastavení
DraÄí Historie:
F5 - Zobrazí Globální Menu
@@ -1084,7 +1252,7 @@ ScummVM podporuje různé zkratky ve hře. Liší se mezi různými hrami SCUMM
Escape - PÅ™eskoÄí video
Mezerník - PÅ™eskoÄí souÄasný řádek textu
- Future Wars
+ Future Wars:
F1 - Prozkoumat
F2 - Vzít
F3 - Inventář
@@ -1095,7 +1263,7 @@ ScummVM podporuje různé zkratky ve hře. Liší se mezi různými hrami SCUMM
F10 - Menu "Použít"
Escape - Zobrazit menu příkazů
- Nippon Safes
+ Nippon Safes:
Ctrl-d - Spustit ladění
l - NaÄíst hru
s - Uložit hru
@@ -1115,21 +1283,21 @@ ScummVM podporuje různé zkratky ve hře. Liší se mezi různými hrami SCUMM
t - PÅ™epínat mezi Å™eÄí a kombinací Å™eÄi a titulků [Simon the Sorcerer 1 CD (jiné než angliÄtina a nÄ›mÄina) a Simon the Sorcerer 2 CD (vÅ¡echny jazyky)]
v - PÅ™epínat mezi titulky a kombinací Å™eÄi a titulků [Pouze Simon the Sorcerer 2 CD]
- Simon the Sorcerer's Puzzle Pack
+ Simon the Sorcerer's Puzzle Pack:
Ctrl-d - Spustit ladění
Ctrl-f - Zapnout rychlý režim
F12 - Zapnout/vypnout režim rychle rychlosti ve Swampy Adventures
- a + - Hlasitost hudby, snížit/zvýšit
m - Hudba vypnout/zapnout
s - Zvukové efekty zapnout/vypnout
- Pause - Pozastavení
+ Pause - Pozastavení
- The Feeble Files
+ The Feeble Files:
Ctrl-d - Spustit ladění
Ctrl-f - Zapnout rychlý režim
F7 - Vyměnit postavy
F9 - Zapnout/vypnout jména hitboxů
- s - Zvukové efekty zapnout/vypnout
+ s - Zvukové efekty zapnout/vypnout
Pause - Pozastavení
t - PÅ™epínat mezi Å™eÄí a kombinací Å™eÄi a titulků
v - PÅ™epínat mezi titulky a kombinací Å™eÄi a titulků
@@ -1143,16 +1311,16 @@ ScummVM podporuje různé zkratky ve hře. Liší se mezi různými hrami SCUMM
F5 - Zobrazí Globální Menu
Touche: The Adventures of the Fifth Musketeer:
- Ctrl-f - Zapnout rychlý režim
+ Ctrl-f - Zapnout rychlý režim
F5 - Zobrazit možnosti
F9 - Zapnout režim rychlé chůze
- F10 - Vypnout režim rychlé chůze
+ F10 - Vypnout režim rychlé chůze
Escape - UkonÄit
Mezerník - PÅ™eskoÄí souÄasný řádek textu
t - PÅ™epnout mezi 'Pouze ŘeÄ',
'ŘeÄ a Text' a 'Pouze Text'
-
- Zork: Grand Inquisitor
+
+ Zork: Grand Inquisitor:
Ctrl-s - Uložit
Ctrl-r - NaÄíst
Ctrl-q - UkonÄit
@@ -1165,7 +1333,7 @@ ScummVM podporuje různé zkratky ve hře. Liší se mezi různými hrami SCUMM
F9 - Vyjmout minci (musíte mít měšec)
Space - PÅ™eskoÄit videa
- Zork Nemesis: The Forbidden Lands
+ Zork Nemesis: The Forbidden Lands:
Ctrl-s - Uložit
Ctrl-r - NaÄíst
Ctrl-q - UkonÄit
@@ -1182,18 +1350,24 @@ Poznámka pro uživatele WinCE: Kvůli omezenému vstupu z klávesnice ve vÄ›tÅ
Uložené hry jsou na nÄ›kterých platformách standardnÄ› umístÄ›ny do souÄasné složky a v jiných do pÅ™ednastavené složky. To můžete urÄit v souboru s nastavením pomocí parametru savepath. Podívejte se na vzorový soubor s nastavením dále v tomto souboru.
Platformy, které v souÄasnosti mají jiné výchozí složky jsou:
- Mac OS X:
+ Mac OS X:
$HOME/Documents/ScummVM Savegames/
-
+
Jiné unixy:
- $HOME/.scummvm/
-
+ Řídíme se specifikacemi základního adresáře XDG. To znamená, že nastavení lze nalézt v:
+ $XDG_DATA_HOME/scummvm/saves/
+
+ Pokud XDG_DATA_HOME není nastaven nebo je prázdný, bude, podle pravidel specifikace, použito '~/.local/share' jako hodnota pro XDG_DATA_HOME.
+
+ Pokud byla ve vašem systému nainstalována dřívější verze ScummVM, bude ponecháno původní výchozí umístění '~/.scummvm'.
+ Program toto zjistí nalezením složky '~/.scummvm'´ v cestě.
+
Windows Vista/7:
\Users\užjméno\AppData\Roaming\ScummVM\Saved games\
-
+
Windows 2000/XP:
\Documents and Settings\užjméno\Application Data\ScummVM\Saved games\
-
+
Windows NT4:
<windir>\Profiles\užjméno\Application Data\ScummVM\Saved games\
@@ -1203,7 +1377,7 @@ povolením zobrazení skrytých složek v Průzkumníku Windows.
Poznámka pro uživatele Windows NT4/2000/XP/Vista/7: Výchozí umístění uložených her
bylo ve ScummVM 1.5.0 změněno. Dávkový soubor přesunu může být použit pro zkopírování
-uložených her ze starého výchozího umístění do nového.
+uložených her ze starého výchozího umístění do nového.
6.1) 6.1 Automatické ukládání:
---- -------------------------
@@ -1465,7 +1639,7 @@ do VaÅ¡eho souboru s nastavením v Äásti [scummvm], nebo nastavením SCUMMVM_P
7.7) Použití MIDI serveru TiMidity++:
---- --------------------------------
-Pokud na Vašem systému chybí jakýkoliv sekvencer MIDI, ale přesto chcete lepší kvalitu MIDI, než kterou může nabídnout standardní emulace AdLib, můžete zkusit MIDI server TiMidity++. Prohlédněte si http://timidity.sourceforge.net/ pro stažení a pokyny k instalaci.
+Pokud na Vašem systému chybí jakýkoliv sekvencer MIDI, ale přesto chcete lepší kvalitu MIDI, než kterou může nabídnout standardní emulace AdLib, můžete zkusit MIDI server TiMidity++. Prohlédněte si <http://timidity.sourceforge.net/> pro stažení a pokyny k instalaci.
Nejdříve musíte spustit daemona:
@@ -1475,7 +1649,7 @@ Nyní můžete spustit ScummVM a zkusit vybrat TiMidity jako výstup pro hudbu.
"Äíslo zařízení" použitím promÄ›nné "SCUMMVM_MIDIPORT".
-7.8) Použití komprimovaných zvukových souborů
+7.8) Použití komprimovaných zvukových souborů
---- ----------------------------------------
7.8.0) Použití souborů MP3 pro CD audio:
@@ -1625,7 +1799,12 @@ StandardnÄ› je soubor s nastavením uložen a naÄítán:
Pokud ve Windows nainstalována dřívější verze ScummVM bude ponecháno dřívější umístění '<složkawin>\scummvm.ini'.
Unix:
- ~/.scummvmrc
+ Řídíme se specifikacemi základního adresáře XDG. To znamená, že naše nastavení lze nalézt v:
+ $XDG_CONFIG_HOME/scummvm/scummvm.ini
+
+ Pokud XDG_CONFIG_HOME není nastaven nebo je prázdný, bude, podle pravidel specifikace, použito '~/.config' jako hodnota pro XDG_CONFIG_HOME.
+
+ Pokud byla ve vašem systému nainstalována dřívější verze ScummVM, bude ponecháno původní výchozí umístění '~/.scummvmrc'.
Mac OS X:
~/Library/Preferences/ScummVM Preferences
@@ -1672,7 +1851,7 @@ Vzorový soubor s nastavením vypadá takto:
music_driver=windows
8.1) Rozpoznávaná klíÄová slova nastavení
----- ------------------------------------
+---- ------------------------------------
Jsou rozpoznávána následující klíÄová slova:
path řetězec Cesta, kde jsou umístěny datové soubory hry
@@ -1689,7 +1868,8 @@ Jsou rozpoznávána následující klíÄová slova:
talkspeed Äíslo ZpoždÄ›ní textu v hrách SCUMM, nebo rychlost textu v jiných hrách.
fullscreen boolean Režim celé obrazovky
aspect_ratio boolean Povolit korekci poměru stran
- gfx_mode řetězec Grafický režim (normální, 2x, 3x, 2xsai, super2xsai, supereagle, advmame2x, advmame3x,hq2x, hq3x, tv2x, dotmatrix)
+ gfx_mode řetězec Grafický režim (normální, 2x, 3x, 2xsai, super2xsai, supereagle, advmame2x, advmame3x, hq2x, hq3x, tv2x, dotmatrix, opengl_linear, opengl_nearest)
+
confirm_exit boolean Zeptat se uživatele na potvrzení pÅ™ed ukonÄením (pouze jádro SDL).
console boolean Povolit okno konzole (výchozí: zapnuto) (pouze Windows).
cdrom Äíslo Číslo jednotky CD-ROM, kterou použít pro zvuk. Pokud je záporné, k pokusu o přístup k CD-ROM nedojde.
@@ -1727,7 +1907,7 @@ Hry Sierra používající jádro SCI přidávají následující nestandardní
use_cdaudio boolean Použít zvuky na CD místo ve hře, pokud je dostupné
windows_cursors boolean Použít kurzory Windows (menší a Äernobílé) místo kurzorů z DOS (King's Quest 6)
silver_cursors boolean Použít alternativní sadu stříbrných kurzorů místo standardních zlatých (Space Quest 4)
-
+
Broken Sword II pÅ™idává následující nestandardní klíÄová slova:
gfx_details Äíslo Nastavení grafických detailů (0-3)
@@ -1740,13 +1920,13 @@ Flight of the Amazon Queen pÅ™idává následující nestandardní klíÄová sl
music_mute boolean Pokud true, hudba je ztlumena
sfx_mute boolean Pokud true, zvukové efekty jsou ztlumeny
-
+
Hopkins FBI pÅ™idává následující nestandardní klíÄové slovo:
enable_gore boolean Pokud true, povolí některé nepovinné krvavé scény ve hře
Jones in the Fast Lane pÅ™idává následující nestandardní klíÄové slovo:
- music_mute boolean Pokud true, je použito CD audio místo zvuků ve hře
+ music_mute boolean Pokud true, je použito CD audio místo zvuků ve hře
King's Quest VI Windows pÅ™idává následující nestandardní klíÄové slovo:
@@ -1758,14 +1938,14 @@ Lands of Lore: The Throne of Chaos pÅ™idává následující nestandardní klíÄ
floating_cursors boolean Pokud true, je kurzor zmÄ›nÄ›n na smÄ›rovou Å¡ipku pÅ™i najetí na okraj obrazovky. HrÃ¡Ä pak může kliknout pro pohyb v tomto smÄ›ru.
Space Quest IV CD pÅ™idává následující nestandardní klíÄové slovo:
-
+
silver_cursors boolean Pokud true, je místo původních zlatých kurzorů použita alternativní sada stříbrných
-
+
Simon the Sorcerer 1 a 2 pÅ™idává následující nestandardní klíÄová slova:
music_mute boolean Pokud true, hudba je ztlumena
sfx_mute boolean Pokud true, zvukové efekty jsou ztlumeny
-
+
Soltys pÅ™idává následující nestandardní klíÄové slovo:
enable_color_blind bool Pokud true, jsou původní barvy nahrazeny odstíny šedi
@@ -1777,7 +1957,7 @@ The Legend of Kyrandia: The Hand of Fate přidává následující nestandardní
walkspeed Äíslo Rychlost chůze (3 nebo 5, což znamená
rychle nebo pomalu)
-
+
The Legend of Kyrandia: Malcolm's Revenge pÅ™idává následující nestandardní klíÄová slova:
walkspeed Äíslo Rychlost chůze (3 nebo 5, což znamená
@@ -1785,10 +1965,10 @@ The Legend of Kyrandia: Malcolm's Revenge pÅ™idává následující nestandardnÃ
studio_audience boolean Pokud true, je slyšet potlesk a smích kdykoliv Malcolm provede něco vtipného
skip_support boolean Pokud true, hrÃ¡Ä může pÅ™eskakovat text a scény hry
helium_mode boolean Pokud true, lidé znějí tak, jakoby se nadýchali hélia
-
+
The Neverhood pÅ™idává následující nestandardní klíÄová slova:
- originalsaveload boolean Pokud true, jsou použity původní obrazovky pro
+ originalsaveload boolean Pokud true, jsou použity původní obrazovky pro
naÄítání/ukládání místo obrazovek ScummVM
skiphallofrecordsscenes boolean
Pokud true, umožní hráÄi pÅ™eskoÄit
@@ -1823,10 +2003,8 @@ Zork: Grand Inquisitor pÅ™idává následující nestandardní klíÄové slovo:
mpegmovies boolean Pokud true, jsou použita videa MPEG ve vysokém rozlišení z
DVD verze hry, místo videí AVI v nízkém rozlišení
-8.2) Vlastní herní volby, které mohou být přepínány pomoci grafického
----- ----------------------------------------------------------------
-rozhraní
---------
+8.2) Vlastní herní volby, které mohou být přepínány pomoci grafického rozhraní
+---- -------------------------------------------------------------------------
Mnoho vlastních herních voleb v pÅ™edchozí Äásti může být pÅ™epnuto pÅ™es grafické rozhraní. Pokud je takováto volba pro urÄitou hru dostupná, objeví se karta "Jádro" pÅ™i pÅ™idávání nebo úpravÄ› nastavení této hry.
Pokud vlastní možnosti nejsou zobrazeny, musí být konkrétní hry spuÅ¡tÄ›ny jednou nebo znovu pÅ™idány do seznamu her spouÅ¡tÄ›Äe ScummVM. Toto aktualizuje nastavení každé položky, Äímž umožní zobrazení vlastních voleb.
@@ -1834,73 +2012,124 @@ Pokud vlastní možnosti nejsou zobrazeny, musí být konkrétní hry spuštěny
---- ----------
Pro aktuální přehled o tom, jak ScummVM sestavit pro různé platformy, prohlédněte si, prosím, naší Wiki, zvláště tuto stránku:
- http://wiki.scummvm.org/index.php/Compiling_ScummVM
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM>
Pokud sestavujete ve Windows, Linux nebo Mac OS X, potřebujete SDL-1.2.2
Nebo novÄ›jší (starší verze mohou fungovat, ale nejsou podporovány) a podporovaný kompilátor. VÄ›tÅ¡ina kompilátorů, vÄetnÄ› GCC, mingw a novÄ›jších verzí Microsoft Visual C++ jsou podporovány. Pokud chcete použít stopy CD komprimované do MP3 nebo soubory .SOU, musíte nainstalovat knihovnu MAD; podobnÄ› potÅ™ebujete vhodné knihovny pro komprimovaný zvuk pomocí Ogg Vorbis a FLAC. Pro komprimované uložené stavy je potÅ™eba mít zlib.
-NÄ›které Äásti ScummVM, zvláštÄ› zvÄ›tÅ¡ovaÄe, mají vysoce optimalizované verze napsané v assembleru. Pokud si pÅ™ejete tuto možnost použít, potÅ™ebuje mít nainstalován assembler nasm (viz http://nasm.sf.net). Nezapomeňte, že v souÄasnosti máme pouze verze optimalizované pro x86 MMX, a nebudou sestaveny pro jiné procesory.
-
-Na Win9x/NT/XP můžete urÄit USE_WINDBG a pÅ™ipojit WinDbg pro procházení ladících zpráv (viz http://www.sysinternals.com/ntw2k/freeware/debugview.shtml).
-
- GCC a MinGW32:
- * Zadejte "./configure"
- * Zadejte "make" (nebo "gmake", Äi "gnumake", v závislosti na tom, jak je GNU make ve VaÅ¡em systému nazván) a ScummVM snad bude pro Vás sestaven.
- * Pro další informace si prohlédněte:
- http://wiki.scummvm.org/index.php/Compiling_ScummVM/GCC
- Äi
- http://wiki.scummvm.org/index.php/Compiling_ScummVM/MinGW
-
- Microsoft Visual C++ 9 a novější:
- * PÅ™eÄtÄ›te si, jak vytvoÅ™it soubory projektu v odpovídající",
- složce "dists\msvc".
- * Otevřete výsledný soubor projektu.
- * Zadejte cestu k potÅ™ebným knihovnám a hlsiÄkovým souborům v
- Tools|Options|Projects and Solutions|VC++ Directories".
- * TeÄ by program mÄ›l být úspěšnÄ› sestaven.
- * Pro další informace si prohlédněte:
- http://wiki.scummvm.org/index.php/Compiling_ScummVM/Visual_Studio
-
- Windows Mobile:
- * PÅ™eÄtÄ›te si prosím:
- http://wiki.scummvm.org/index.php/Compiling_ScummVM/Windows_CE
-
- Mac OS X:
- * Ujistěte se, že máte nainstalovány nástroje pro vývojáře.
- * BalíÄek SDL pro vývojáře na OS X, který je dostupný na stránce SDL _není_ vhodný. Spíše potÅ™ebujete sestavení v unixovém stylu. Jeden takový způsob, jak ho nainstalovat je pomocí Fink
- (http://fink.sf.net). Také můžete SDL sestavit ruÄnÄ› ze zdrojového kódu pomocí systému sestavení pro unix (configure a make).
- * Ve složce ScummVM zadejte "./configure".
- * Nyní můžete zadat 'make' pro vytvoÅ™ení spouÅ¡tÄ›Äe příkazového řádku.
- * Abyste získali verzi, kterou můžete spustit z Finder, zadejte 'make bundle' což vytvoří ScummVM.app (toto se pokusí zjistit kde máte nainstalovány statické knihovny, což by mělo fungovat ve většině případů, pokud ne, musíte jejich cestu zadat pomocí --with-staticlib-prefix= při konfiguraci - například "./configure --with-staticlib-prefix=/Uživatelé/bla" pokud jsou knihovny umístěny v /Uživatelé/bla/lib.
- * Pro další informace si prohlédněte:
- http://wiki.scummvm.org/index.php/Compiling_ScummVM/MacOS_X_Crosscompiling
-
- AmigaOS 4 (Křížová kompilace pomocí Cygwin):
- * Ujistěte se, že máte nainstalován SDL, můžete také potřebovat
- libogg, libvorbis, libvorbisfile, zlib, libmad.
- * Zadejte ./configure --host=ppc-amigaos
- * Pokud dostanete chybu o sdl-config, použijte parametr --with-sdl-prefix pro nastavení cesty.
- * Zkontrolujte soubor 'config.mk' a pokud je vše v pořádku:
- * Spusťte 'make'.
- * Křížová kompilace pomocí Linux může být také tak lehká.
-
- iPhone:
- * PÅ™eÄtÄ›te si prosím:
- http://wiki.scummvm.org/index.php/Compiling_ScummVM/iPhone
-
- Maemo:
- * Nainstalujte Maemo SDK s rootstrap 4.1.2
- * Nainstalujte libmad, Tremor, FLAC ze zdroje
- * Spusťte 'ln -s backends/platform/maemo/debian'
- * Aktualizujte debian/changelog
- * Spusťte 'sb2 dpkg-buildpackage -b'
+NÄ›které Äásti ScummVM, zvláštÄ› zvÄ›tÅ¡ovaÄe, mají vysoce optimalizované verze napsané v assembleru. Pokud si pÅ™ejete tuto možnost použít, potÅ™ebuje mít nainstalován assembler nasm (viz http://www.nasm.us/). Nezapomeňte, že v souÄasnosti máme pouze verze optimalizované pro x86 MMX, a nebudou sestaveny pro jiné procesory.
+
+Na Win9x/NT/XP můžete urÄit USE_WINDBG a pÅ™ipojit WinDbg pro procházení ladících zpráv (viz <https://technet.microsoft.com/en-us/sysinternals/debugview.aspx)>.
+
+ Windows:
+ * Dev-C++
+ PÅ™eÄtÄ›te si prosím:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/DevCPP>
+ * MinGW
+ PÅ™eÄtÄ›te si prosím:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/MinGW>
+ * Visual Studio (MSVC)
+ PÅ™eÄtÄ›te si prosím:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Visual_Studio>
+ * Windows CE/Mobile
+ PÅ™eÄtÄ›te si prosím:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Windows_CE>
+
+ Linux:
+ * GCC
+ PÅ™eÄtÄ›te si prosím:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/GCC>
+
+ Mac OS X:
+ PÅ™eÄtÄ›te si prosím:
+ <http://wiki.scummvm.org/index.php/Mac_OS_X>
+
+ AmigaOS4:
+ PÅ™eÄtÄ›te si prosím:
+ <http://wiki.scummvm.org/index.php/AmigaOS>
+
+ Apple iPhone:
+ PÅ™eÄtÄ›te si prosím:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/iPhone>
+
+ Atari/FreeMiNT:
+ PÅ™eÄtÄ›te si prosím:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Atari/FreeMiNT>
+
+ Bada/Tizen:
+ PÅ™eÄtÄ›te si prosím:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Bada/Tizen>
+
+ BeOS/ZETA/Haiku:
+ PÅ™eÄtÄ›te si prosím:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/BeOS/ZETA/Haiku>
+
+ Google Android:
+ PÅ™eÄtÄ›te si prosím:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Android>
+
+ HP webOS:
+ PÅ™eÄtÄ›te si prosím:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/WebOS>
+
+ Mac OS:
+ * Mac OS X
+ PÅ™eÄtÄ›te si prosím:
+ <http://wiki.scummvm.org/index.php/Mac_OS_X>
+ * Mac OS X 10.2.8
+ PÅ™eÄtÄ›te si prosím:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Mac_OS_X_10.2.8>
+ * Mac OS X Křížová kompilace
+ PÅ™eÄtÄ›te si prosím:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Mac_OS_X_Crosscompiling>
+
+ Maemo:
+ PÅ™eÄtÄ›te si prosím:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Maemo>
+
+ Nintendo DS:
+ PÅ™eÄtÄ›te si prosím:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Nintendo_DS>
+
+ Nintendo Wii a Gamecube:
+ PÅ™eÄtÄ›te si prosím:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Wii>
+
+ RaspberryPi:
+ PÅ™eÄtÄ›te si prosím:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/RPI>
+
+ Sega Dreamcast:
+ PÅ™eÄtÄ›te si prosím:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Dreamcast>
+
+ Sony Playstation:
+ * Sony PlayStation 2
+ PÅ™eÄtÄ›te si prosím:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/PlayStation_2>
+ * Sony PlayStation 3
+ PÅ™eÄtÄ›te si prosím:
+ <http://wiki.scummvm.org/index.php/PlayStation_3#Building_from_source>
+ * Sony PlayStation Portable
+ PÅ™eÄtÄ›te si prosím:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/PlayStation_Portable>
+
+ Symbian:
+ PÅ™eÄtÄ›te si prosím:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Symbian>
+
+
+10.0) Poděkování
+----- ----------
+Prosím pÅ™eÄtÄ›te si náš rozsáhlý seznam lidí, kterým chceme podÄ›kovat na
+
+<http://www.scummvm.org/credits/>
+
+
+
------------------------------------------------------------------------
Hodně Štěstí a Šťastné Adventurování!
Tým ScummVM.
-http://www.scummvm.org/
+<http://www.scummvm.org/>
------------------------------------------------------------------------
-
-
-
-
diff --git a/doc/de/Liesmich b/doc/de/Liesmich
index a962ae6baa..84eb6b53fd 100644
--- a/doc/de/Liesmich
+++ b/doc/de/Liesmich
@@ -11,40 +11,49 @@ Inhaltsverzeichnis:
1.0) Einführung
* 1.1 Ãœber ScummVM
* 1.2 Schnellstart
+ * 1.3 Häufig gestellte Fragen
2.0) Kontakt
- * 2.1 Fehler berichten
+ * 2.1 Fehler melden
3.0) Unterstützte Spiele
* 3.1 Kopierschutz
- * 3.2 Hinweise zu Day of the Tentacle
- * 3.3 Hinweise zu Commodore-64-Spielen
- * 3.4 Hinweise zu Maniac Mansion (NES)
- * 3.5 Hinweise zu Macintosh-Spielen
- * 3.6 Hinweise zu Spielen auf mehren CDs
- * 3.7 Hinweise zu The Curse of Monkey Island
- * 3.8 Hinweise zu Baphomets Fluch I und II
- * 3.9 Hinweise zu Beneath a Steel Sky
+ * 3.2 Spieldateien
+ * 3.3 Hinweise zu Spielen auf mehreren CDs
+ * 3.4 Bekannte Probleme
+ * 3.5 Hinweise zu Beneath a Steel Sky
+ * 3.6 Hinweise zu Baphomets Fluch I und II
+ * * 3.6.1 Baphomets Fluch
+ * * 3.6.2 Baphomets Fluch II
+ * * 3.6.3 Zwischensequenzen in Baphomets Fluch
+ * * 3.6.4 Zwischensequenzen in Baphomets Fluch (Rückblick)
+ * 3.7 Hinweise zu Day of the Tentacle
+ * 3.8 Hinweise zu Discworld II
+ * 3.9 Hinweise zu DraÄi Historie
* 3.10 Hinweise zu Flight of the Amazon Queen
* 3.11 Hinweise zu Gobliiins
* 3.12 Hinweise zu Inherit the Earth: Quest for the Orb (Macintosh)
- * 3.13 Hinweise zu Simon the Sorcerer 1 und 2
- * 3.14 Hinweise zu Floyd – Es gibt noch Helden
- * 3.15 Hinweise zu The Legend of Kyrandia
- * 3.16 Hinweise zum vorhersagenden Eingabedialog bei Sierras AGI-Spielen
- * 3.17 Hinweise zu Mickey's Space Adventure
- * 3.18 Hinweise zu Winnie the Pooh
- * 3.19 Hinweise zu Troll's Tale
- * 3.20 Hinweise zu DraÄi Historie
- * 3.21 Gleichzeitige Sprachausgabe und Untertitel in Sierra-SCI-Spielen
- * 3.22 Bekannte Probleme
+ * 3.13 Hinweise zu Maniac Mansion (Apple II/NES)
+ * 3.14 Hinweise zu Mickey's Space Adventure
+ * 3.15 Hinweise zu Nippon Safes Inc. (Amiga)
+ * 3.16 Hinweise zu Simon the Sorcerer 1 und 2
+ * 3.17 Hinweise zu The Curse of Monkey Island
+ * 3.18 Hinweise zu Floyd – Es gibt noch Helden
+ * 3.19 Hinweise zu The Legend of Kyrandia
+ * 3.20 Hinweise zu Troll's Tale
+ * 3.21 Hinweise zu Winnie the Pooh
+ * 3.22 Hinweise zum vorhersagenden Eingabedialog in AGI-Spielen von Sierra
+ * 3.23 Gleichzeitige Sprachausgabe und Untertitel in SCI-Spielen von Sierra
+ * 3.24 Hinweise zu den Spielen der Zork-Reihe
+ * 3.25 Hinweise zu Spielen für den Commodore 64
+ * 3.26 Hinweise zu Spielen für den Macintosh
4.0) Unterstützte Plattformen
5.0) ScummVM verwenden
* 5.1 Kommandozeilenoptionen
- * 5.2 Sprachoptionen
+ * 5.2 Globales Menü
* 5.3 Grafikfilter
- * 5.4 Globales Menü
- * 5.5 Tastenkürzel
+ * 5.4 Tastenkürzel
+ * 5.5 Sprachoptionen
6.0) Spielstände
- * 6.1 Automatische Spielstand-Speicherung
+ * 6.1 Automatisches Speichern von Spielständen
* 6.2 Spielstände umwandeln
* 6.3 Spielstände von der Kommandozeile aus anzeigen/laden
7.0) Musik und Sound
@@ -53,14 +62,27 @@ Inhaltsverzeichnis:
* 7.3 MT-32-Emulation
* 7.4 MIDI-Emulation
* 7.5 Native MIDI-Unterstützung
- * 7.6 UNIX-eigene, ALSA- und Dmedia-Sequenzer-Unterstützung
+ * 7.5.1 Native MIDI-Ausgabe mithilfe der MIDI-Optionen anpassen
+ * 7.6 UNIX-eigene, ALSA- und dmedia-Sequenzer-Unterstützung
+ * 7.6.1 ALSA-Sequencer [NUR UNIX]
+ * 7.6.2 IRIX dmedia-Sequencer [NUR UNIX]
* 7.7 TiMidity++-MIDI-Server-Unterstützung
* 7.8 Komprimierte Audio-Dateien verwenden (MP3, Ogg Vorbis, FLAC)
+ * * 7.8.1 MP3-Dateien für CD-Audio verwenden
+ * * 7.8.2 Ogg-Vorbis-Dateien für CD-Audio verwenden
+ * * 7.8.3 FLAC-Dateien für CD-Audio verwenden
+ * * 7.8.4 MONSTER.SOU mit MP3 komprimieren
+ * * 7.8.5 MONSTER.SOU mit Ogg Vorbis komprimieren
+ * * 7.8.6 MONSTER.SOU mit FLAC komprimieren
+ * * 7.8.7 Musik/Effekte/Sprachausgabe in AGOS-Spielen komprimieren
+ * * 7.8.8 Sprachausgabe/Musik in Baphomets Fluch komprimieren
+ * * 7.8.9 Sprachausgabe/Musik in Baphomets Fluch II komprimieren
* 7.9 Ausgabefrequenzen
8.0) Konfigurationsdatei
* 8.1 Verwendbare Konfigurationsschlüsselwörter
- * 8.2 Spielspezifische Optionen bei der grafischen Benutzeroberfläche
-9.0) Kompilierung
+ * 8.2 Spielspezifische Optionen der grafischen Benutzeroberfläche
+9.0) Kompilieren
+10.0) Mitwirkende
1.0) Einführung:
@@ -91,8 +113,8 @@ Fluch I und II, Flight of the Amazon Queen, Gobliiins 1-3, die Adventure-Reihe
The Legend of Kyrandia, viele der SCUMM-Spiele für Kinder von Humongous
Entertainment (einschließlich der Spiele von Fritzi Fisch und Töff-Töff) und
viele mehr. Sie können eine vollständige Liste mit Einzelheiten einsehen, welche
-Auskunft darüber gibt, welche Spiele wie gut unterstützt werden. Gehen Sie
-hierfür auf die Kompatibilitätsseite. ScummVM wird fortlaufend verbessert, also
+Auskunft darüber gibt, welche Spiele wie gut unterstützt werden. Besuchen Sie
+hierfür die Kompatibilitätsseite. ScummVM wird fortlaufend verbessert, also
schauen Sie öfter einmal vorbei.
Unter den Systemen, mit denen Sie diese Spiele spielen können, befinden sich
@@ -154,7 +176,7 @@ und klicken Sie auf „Auswählen“.
4. Ein Dialog sollte erscheinen, der Ihnen ermöglicht, verschiedene
Einstellungen vorzunehmen, sollten Sie dies wünschen (es sollte jedoch in
-Ordnung sein, alles voreingestellt zu belassen). Bestätigen Sie diesen Dialog.
+Ordnung sein, die Voreinstellungen beizubehalten). Bestätigen Sie diesen Dialog.
5. Wählen Sie das Spiel aus der Liste aus, welches Sie spielen möchten, und
klicken Sie auf „Starten“.
@@ -227,11 +249,12 @@ auch daran, dass alle Fehlerberichte in Englisch verfasst sein müssen.
Im Moment gelten folgende Spiele als funktionsfähig und sollten bis zum Ende
spielbar sein:
-SCUMM-Spiele von LucasArts:
+Spiele von LucasArts (SCUMM):
Maniac Mansion [maniac]
Zak McKracken and the Alien Mindbenders [zak]
Indiana Jones and the Last Crusade [indy3]
Loom [loom]
+ Passport to Adventure [pass]
The Secret of Monkey Island [monkey]
Monkey Island 2: LeChuck's Revenge [monkey2]
Indiana Jones and the Fate of Atlantis [atlantis]
@@ -241,32 +264,17 @@ SCUMM-Spiele von LucasArts:
The Dig [dig]
The Curse of Monkey Island [comi]
-AGI- und preAGI-Spiele von Sierra:
- The Black Cauldron [bc]
- Gold Rush! [goldrush]
- King's Quest I [kq1]
- King's Quest II [kq2]
- King's Quest III [kq3]
- King's Quest IV [kq4]
- Leisure Suit Larry in the Land of the
- Lounge Lizards [lsl1]
- Mixed-Up Mother Goose [mixedup]
- Manhunter 1: New York [mh1]
- Manhunter 2: San Francisco [mh2]
- Police Quest I: In Pursuit of the Death
- Angel [pq1]
- Space Quest I: The Sarien Encounter [sq1]
- Space Quest II: Vohaul's Revenge [sq2]
- Von Fans erstellte Spiele [agi-fanmade]
- Mickey's Space Adventure [mickey]
- Troll's Tale [troll]
- Winnie the Pooh in the Hundred Acre Wood [winnie]
+Spiele von Activision (MADE):
+ Leather Goddesses of Phobos 2 [lgop2]
+ Return to Zork [rtz]
+ The Manhole [manhole]
+ Rodney's Funscreen [rodney]
-AGOS-Spiele von Adventuresoft/Horrorsoft:
+Spiele von Adventuresoft/Horrorsoft (AGOS):
Elvira - Mistress of the Dark [elvira1]
Elvira II - The Jaws of Cerberus [elvira2]
+ Floyd - Es gibt noch Helden [feeble]
Personal Nightmare [pn]
- Waxworks [waxworks]
Simon the Sorcerer 1 [simon1]
Simon the Sorcerer 2 [simon2]
Simon the Sorcerer's Game Pack
@@ -277,17 +285,9 @@ AGOS-Spiele von Adventuresoft/Horrorsoft:
- NoPatience [puzzle]
Simon the Sorcerer's Game Pack
- Swampy Adventures [swampy]
- Floyd - Es gibt noch Helden [feeble]
-
-Spiele von Animation Magic:
- Darby der Drache [darby]
- Gregory and the Hot Air Balloon [gregory]
- Magic Tales: Liam Finds a Story [liam]
- The Princess and the Crab [princess]
- Sleeping Cub's Test of Courage [sleepingcub]
+ Waxworks [waxworks]
-GOB-Spiele von Coktel Vision:
- Bambou le sauveur de la jungle [bambou]
+Spiele von Coktel Vision (GOB):
Bargon Attack [bargon]
Fascination [fascination]
Geisha [geisha]
@@ -296,78 +296,39 @@ GOB-Spiele von Coktel Vision:
Goblins 3 [gob3]
Lost in Time [lostintime]
Once Upon A Time: Little Red Riding Hood [littlered]
+ Playtoons: Bambou le sauveur de la jungle [bambou]
Urban Runner [urban]
- Woodruff and the Schnibble of Azimuth [woodruff]
Ween: The Prophecy [ween]
+ Woodruff and the Schnibble of Azimuth [woodruff]
-Living-Books-Spiele von Random House/Brøderbund:
- Aesop's Fables: The Tortoise and the Hare [tortoise]
- Arthur's Birthday [arthurbday]
- Arthur's Teacher Trouble [arthur]
- Dr. Seuss's ABC [seussabc]
- Green Eggs and Ham [greeneggs]
- Harry and the Haunted House [harryhh]
- Just Grandma and Me [grandma]
- Little Monster at School [lilmonster]
- Ruff's Bone [ruff]
- Sheila Rae, the Brave [sheila]
- Stellaluna [stellaluna]
- The Berenstain Bears Get in a Fight [bearfight]
- The Berenstain Bears in the Dark [beardark]
- The New Kid on the Block [newkid]
-
-MADE-Spiele von Activision:
- Leather Goddesses of Phobos 2 [lgop2]
- Return to Zork [rtz]
- Rodney's Funscreen [rodney]
- The Manhole [manhole]
-
-Andere Spiele:
- 3 Skulls of the Toltecs [toltecs]
- Baphomets Fluch [sword1]
- Baphomets Fluch II:
- Die Spiegel der Finsternis [sword2]
+Spiele von Revolution Software:
Beneath a Steel Sky [sky]
- Blue Force [blueforce]
- Cruise for a Corpse [cruise]
- Discworld [dw]
- Discworld 2: Vermutlich vermisst [dw2]
- DraÄi Historie [draci]
- Drascula: The Vampire Strikes Back [drascula]
- DreamWeb [dreamweb]
- Erben der Erde: Die große Suche [ite]
- Eye of the Beholder [eob]
- Eye of the Beholder II: The Legend of
- Darkmoon [eob2]
- Flight of the Amazon Queen [queen]
- Future Wars [fw]
- Hopkins FBI [hopkins]
- Hugo's House of Horrors [hugo1]
- Hugo 2: Whodunit? [hugo2]
- Hugo 3: Jungle Doom [hugo3]
- I Have No Mouth, and I Must Scream [ihnm]
- Lands of Lore: The Throne of Chaos [lol]
+ Baphomets Fluch I [sword1]
+ Baphomets Fluch II [sword2]
Lure of the Temptress [lure]
- Mortville Manor [morteville]
- Nippon Safes Inc. [nippon]
- Ringworld: Revenge of the Patriarch [ringworld]
- Return to Ringworld [ringworld2]
- Sfinx [sfinx]
- Soltys [soltys]
- TeenAgent [teenagent]
- The 7th Guest [t7g]
- The Journeyman Project: Pegasus Prime [pegasus]
- The Legend of Kyrandia [kyra1]
- The Legend of Kyrandia: The Hand of Fate [kyra2]
- The Legend of Kyrandia: Malcolm's Revenge [kyra3]
- The Neverhood [neverhood]
- Tony Tough and the Night of Roasted Moths [tony]
- Toonstruck [toon]
- Touché: Die Abenteuer des fünften
- Musketiers [touche]
- Voyeur [voyeur]
-SCI-Spiele von Sierra Entertainment:
+Spiele von Sierra (AGI und preAGI):
+ The Black Cauldron [bc]
+ Gold Rush! [goldrush]
+ King's Quest I [kq1]
+ King's Quest II [kq2]
+ King's Quest III [kq3]
+ King's Quest IV [kq4]
+ Leisure Suit Larry in the Land of the
+ Lounge Lizards [lsl1]
+ Mixed-Up Mother Goose [mixedup]
+ Manhunter 1: New York [mh1]
+ Manhunter 2: San Francisco [mh2]
+ Police Quest I: In Pursuit of the Death
+ Angel [pq1]
+ Space Quest I: The Sarien Encounter [sq1]
+ Space Quest II: Vohaul's Revenge [sq2]
+ Von Fans erstellte Spiele [agi-fanmade]
+ Mickey's Space Adventure [mickey]
+ Troll's Tale [troll]
+ Winnie the Pooh in the Hundred Acre Wood [winnie]
+
+Spiele von Sierra (SCI):
Codename: ICEMAN [iceman]
Conquests of Camelot [camelot]
Conquests of the Longbow [longbow]
@@ -408,14 +369,60 @@ SCI-Spiele von Sierra Entertainment:
Space Quest V [sq5]
The Island of Dr. Brain [islandbrain]
-Wintermute-Spiel von Deirdra Kiai Productions:
+Andere Spiele:
+ 3 Skulls of the Toltecs [toltecs]
+ Amazon: Guardians of Eden [access]
+ Baphomets Fluch 2.5:
+ Die Rückkehr der Tempelritter [sword25]
+ Beavis and Butt-head in Virtual Stupidity [bbvs]
+ Blue Force [blueforce]
+ Bud Tucker in Double Trouble [tucker]
Chivalry is Not Dead [chivalry]
+ Cruise for a Corpse [cruise]
+ Die ungelösten Fälle von Sherlock Holmes:
+ Das gezackte Skalpell [scalpel]
+ Die ungelösten Fälle von Sherlock Holmes:
+ Die tätowierte Rose [rosetattoo]
+ Discworld [dw]
+ Discworld 2: Vermutlich vermisst [dw2]
+ DraÄi Historie [draci]
+ Drascula: The Vampire Strikes Back [drascula]
+ DreamWeb [dreamweb]
+ Erben der Erde: Die große Suche [ite]
+ Eye of the Beholder [eob]
+ Eye of the Beholder II: The Legend of
+ Darkmoon [eob2]
+ Flight of the Amazon Queen [queen]
+ Future Wars [fw]
+ Hopkins FBI [hopkins]
+ Hugo's House of Horrors [hugo1]
+ Hugo 2: Whodunit? [hugo2]
+ Hugo 3: Jungle Doom [hugo3]
+ I Have No Mouth, and I Must Scream [ihnm]
+ Lands of Lore: The Throne of Chaos [lol]
+ Mortville Manor [morteville]
+ Nippon Safes Inc. [nippon]
+ Rex Nebular and the Cosmic Gender Bender [nebular]
+ Ringworld: Revenge of the Patriarch [ringworld]
+ Return to Ringworld [ringworld2]
+ Sfinx [sfinx]
+ Soltys [soltys]
+ TeenAgent [teenagent]
+ The 7th Guest [t7g]
+ The Journeyman Project: Pegasus Prime [pegasus]
+ The Legend of Kyrandia [kyra1]
+ The Legend of Kyrandia: The Hand of Fate [kyra2]
+ The Legend of Kyrandia: Malcolm's Revenge [kyra3]
+ The Neverhood [neverhood]
+ Tony Tough and the Night of Roasted Moths [tony]
+ Toonstruck [toon]
+ Touché: Die Abenteuer des fünften
+ Musketiers [touche]
+ Voyeur [voyeur]
+ Zork: Der Großinquisitor [zgi]
+ Zork Nemesis: Das verbotene Land [znemesis]
-ZVISION-Spiele von Activision:
- Zork Nemesis: The Forbidden Lands [znemesis]
- Zork: Grand Inquisitor [zgi]
-
-SCUMM-Spiele von Humongous Entertainment:
+Spiele von Humongous Entertainment (SCUMM):
Backyard Baseball [baseball]
Backyard Baseball 2001 [baseball2001]
Backyard Football 2002 [football2002]
@@ -479,6 +486,29 @@ nach.
Backyard Soccer 2004 [soccer2004]
Blue's Treasure Hunt [BluesTreasureHunt]
+Spiele von Animation Magic (Composer):
+ Darby der Drache [darby]
+ Gregory and the Hot Air Balloon [gregory]
+ Magic Tales: Liam Finds a Story [liam]
+ The Princess and the Crab [princess]
+ Sleeping Cub's Test of Courage [sleepingcub]
+
+Living-Books-Spiele von Random House/Brøderbund:
+ Aesop's Fables: The Tortoise and the Hare [tortoise]
+ Arthur's Birthday [arthurbday]
+ Arthur's Teacher Trouble [arthur]
+ Dr. Seuss's ABC [seussabc]
+ Green Eggs and Ham [greeneggs]
+ Harry and the Haunted House [harryhh]
+ Just Grandma and Me [grandma]
+ Little Monster at School [lilmonster]
+ Ruff's Bone [ruff]
+ Sheila Rae, the Brave [sheila]
+ Stellaluna [stellaluna]
+ The Berenstain Bears Get in a Fight [bearfight]
+ The Berenstain Bears in the Dark [beardark]
+ The New Kid on the Block [newkid]
+
Die folgenden Spiele basieren auf der SCUMM-Engine, werden aber (noch) nicht von
ScummVM unterstützt:
@@ -486,10 +516,10 @@ ScummVM unterstützt:
Seien Sie sich bitte bewusst, dass die Engines („Motoren“ der Spiele) Fehler
enthalten können und manche Funktionen möglicherweise fehlen, was es unmöglich
-macht, das Spiel zu Ende zu spielen. Speichern Sie oft und bitte schicken Sie
-englische Fehlerberichte ein (Anweisungen zum Senden von Fehlerberichten finden
-Sie oben), wenn Sie einen solchen Fehler in einem „unterstützten“ Spiel
-vorfinden.
+machen kann, das Spiel zu Ende zu spielen. Speichern Sie oft und bitte schicken
+Sie englischsprachige Fehlerberichte ein (Anweisungen zum Senden von
+Fehlerberichten finden Sie oben), wenn Sie einen solchen Fehler in einem
+„unterstützten“ Spiel vorfinden.
3.1) Kopierschutz:
@@ -531,143 +561,167 @@ ScummVM wird den Kopierschutz in folgenden Spielen überspringen:
* Zak McKracken and the Alien Mindbenders
-3.2) Hinweise zu Day of the Tentacle
----- -------------------------------
-
-An einem bestimmten Punkt im Spiel kommen Sie an einem Computer vorbei, der
-Ihnen erlaubt, das originale Maniac Mansion zu spielen. ScummVM unterstützt
-dies, jedoch gilt Folgendes zu beachten:
-
-ScummVM wird die Konfigurationsdatei nach einem Spiel durchsuchen, welches sich
-im Unterordner "Maniac" innerhalb des "Day of the Tentacle"-Ordners befindet.
-Wenn Sie die Spieldateien von der CD-Version kopiert haben, sollte dies bereits
-der Fall sein, Sie müssen das Spiel jedoch ebenfalls zu ScummVM hinzufügen.
+3.2) Spieldateien:
+---- -------------
+Für eine ausführliche Liste der benötigten Spieldateien für unterstützte Spiele,
+besuchen Sie:
-Um zu Day of the Tentacle zurückzukehren, drücken Sie F5 und wählen Sie „Zurück
-zum Hauptmenü“.
+ http://wiki.scummvm.org/index.php/Datafiles
-Dies bedeutet, dass Sie theoretisch jedes Spiel als Easter Egg verwenden
-könnten. Es gibt eine "geheime" Konfigurationseinstellung namens "easter_egg",
-mit welcher Sie die ID des Spiels, welches als Easter-Egg gestartet werden soll,
-festlegen können. Jedoch erlauben nicht alle Spiele die Rückkehr zum Hauptmenü.
-Es ist nicht empfehlenswert, Day of the Tentacle selbst als Easter-Egg-Spiel
-festzulegen.
+3.3) Hinweise zu Spielen auf mehreren CDs:
+---- -------------------------------------
+Allgemein kann ScummVM nicht sehr gut mit Spielen auf mehreren CDs umgehen. Das
+liegt daran, dass ScummVM annimmt, alles von einem Spiel in einem Verzeichnis
+vorzufinden. Selbst wenn ScummVM einige Fälle berücksichtigt und den Anwender
+dazu auffordert, die CD zu wechseln, so installierten die ursprünglichen
+ausführbaren Dateien des Spiels normalerweise eine kleine Anzahl an Dateien auf
+die Festplatte. Sofern diese Dateien nicht auf allen CDs vorgefunden werden
+können, wird ScummVM Schwierigkeiten haben.
-3.3) Hinweise zu Commodore-64-Spielen:
----- ---------------------------------
-Sowohl Maniac Mansion als auch Zak McKracken laufen, aber Maniac Mansion ist
-noch nicht spielbar. Benennen Sie einfach die D64-Datenträger um in
-„maniac1.d64“ und „maniac2.d64“ und entsprechend „zak1.d64“ und „zak2.d64“, dann
-sollte ScummVM in der Lage sein, das Spiel automatisch zu erkennen, wenn Sie auf
-das richtige Verzeichnis zeigen.
+Glücklicherweise hat ScummVM keine Probleme damit, die Spiele komplett von der
+Festplatte aus laufen zu lassen, wenn Sie ein Verzeichnis mit der richtigen
+Kombination der Dateien erstellen. Wenn eine Datei auf mehr als einer CD
+vorkommt, ist es normalerweise egal, welche Sie in das Verzeichnis
+hineinkopieren.
-Alternativ können Sie „extract_mm_c64“ aus dem Tools-Paket verwenden, um die
-Spieldateien zu extrahieren. Dann wird das Spiel jedoch nicht einwandfrei von
-ScummVM automatisch erkannt und Sie müssen sicherstellen, dass Commodore 64 als
-Plattform eingestellt ist. Wir empfehlen, auf die viel einfachere Methode
-zurückzugreifen, die im vorherigen Absatz beschrieben ist.
+3.4) Bekannte Probleme:
+---- ------------------
+Diese Version hat die unten folgenden bekannten Probleme. Es ist nicht
+notwendig, diese zu melden, jedoch sind Patches, um diese zu beheben,
+willkommen. Wenn Sie einen Fehler entdecken, der weder hier noch auf der
+Kompatibilitätsseite der Website aufgeführt ist, sehen Sie bitte im Abschnitt
+„Fehler melden“ nach, wenn Sie diesen melden möchten.
-3.4) Hinweise zu Maniac Mansion (NES):
----- ---------------------------------
-Unterstützte Versionen sind Deutsch (G) [G=German], Englisch GB (E), Französisch
-(F), Italienisch (I), Schwedisch (SW) und Englisch US (U). ScummVM benötigt nur
-den PRG-Bereich und nicht die gesamte ROM-Datei, um das Spiel laufen zu lassen.
+ Spiele mit Ton von CD:
+ - Bei Spielen, die auf Audio von CD zurückgreifen (FM-TOWNS-Spiele,
+ CD-Version von Loom usw.), ist es möglich, dass Anwender von Microsoft
+ Windows 2000/XP zufällige Abstürze erleben. Das liegt an einem lange
+ bestehenden Windows-Fehler, der dazu führt, dass fehlerhafte Spieldaten
+ von der CD ausgelesen werden. Bitte kopieren Sie die Spieldaten in ein
+ Verzeichnis Ihrer Festplatte, um dies zu vermeiden.
-Damit das Spiel funktioniert, müssen Sie die ersten 16 Bytes aus der ROM-Datei
-entfernen, die Sie verwenden wollen. Das klappt mit jedem Hexeditor, solange Sie
-mit diesem kopieren und einfügen können. Nachdem Sie die ROM-Datei mit dem
-Hexeditor geöffnet haben, kopieren Sie alles von der zweiten Reihe (17. Byte)
-bis zum Ende. Danach fügen Sie den kopierten Inhalt in eine neue Hexdatei ein.
-Speichern Sie die neue Datei unter dem Namen „Maniac Mansion (XX).prg“, wobei XX
-für die Sprachversion steht, die Sie verwenden wollen (G, E, F, I, SW oder U).
-Die Größe der neuen Datei sollte genau 262144 Bytes betragen.
+ FM-TOWNS-Versionen:
+ - Die Kanji-Versionen erfordern die Schriftart-ROM-Datei von FM-TOWNS.
-Wenn Sie das Spiel manuell hinzufügen, stellen Sie sicher, dass die Plattform
-auf NES eingestellt ist.
+ Loom:
+ - Das Abschalten der Untertitel über die Spieleinstellungen funktioniert
+ nicht zuverlässig, da die Loom-Skripte diese wieder einschalten.
+ - MIDI-Unterstützung in der EGA-Version erfordert das Roland-Update von
+ LucasArts.
+ - Die Kanji-Version der PC-Engine erfordert die Systemkarten-ROM-Datei.
-Die häufigsten Fehler, die verhindern, dass das Spiel läuft:
+ The Secret of Monkey Island:
+ - MIDI-Unterstützung in der EGA-Version erfordert das Roland-Update von
+ LucasArts.
- * Fehlerhafte Datei
- * ROM extrahiert mit den Tools der Version 0.7.0
- * Sie versuchen, in ScummVM die VOLLE ROM-DATEI zu laden und nicht nur den
- PRG-Bereich.
+ Beneath a Steel Sky:
+ - Amiga-Versionen werden nicht unterstützt.
+ - Disketten-Demos werden nicht unterstützt.
+ - Kein Fehler: In der CD-Version fehlt in einigen Dialogen Sprachausgabe;
+ das ist normal.
-Es ist auch möglich, die einzelnen LFL-Dateien aus dem PRG-Bereich zu
-extrahieren. Um dies zu tun, verwenden Sie das Dienstprogramm „extract_mm_nes“
-aus dem Tools-Paket.
+ Elvira - Mistress of the Dark
+ - Keine Musik in der Atari-ST-Version
+ Elvira II - The Jaws of Cerberus
+ - Keine Musik in der Atari-ST-Version
+ - Keine Geräusch-Effekte in der PC-Version
+ - Palettenprobleme in der Atari-ST-Version
-3.5) Hinweise zu Macintosh-Spielen:
----- ------------------------------
-Alle auf SCUMM basierenden Adventures von Lucasarts, mit Ausnahme von COMI,
-existieren auch als Versionen für den Macintosh. ScummVM kann die meisten
-(alle?) von diesen verwenden, jedoch ist in manchen Fällen zusätzliche Arbeit
-erforderlich. Zuallererst: Wenn Sie keinen Macintosh dafür verwenden, könnte es
-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
-Linux und andere Betriebssysteme, die Unix ähnlich sind.
+ Inherit the Earth: Quest for the Orb
+ - Amiga-Versionen werden nicht unterstützt.
-Die meisten neueren Spiele für den Macintosh wurden nur mit einer einzigen
-Spieldatei ausgeliefert (beachten Sie, dass in manchen Fällen diese Spieldatei
-unsichtbar gemacht wurde und Sie somit zusätzliche Tools benötigen, um diese zu
-kopieren). ScummVM ist in der Lage, eine solche Spieldatei direkt zu verwenden;
-verweisen Sie ScummVM einfach auf das Verzeichnis, welches diese enthält und es
-sollte klappen (so wie mit jedem anderen unterstützten Spiel).
+ Lure of the Temptress:
+ - Keine Unterstützung für Roland MT32
+ - Sound-Unterstützung ist unvollständig und klingt nicht wie ursprünglich.
-Wir stellen außerdem ein Tool mit dem Namen „extract_scumm_mac“ im Tools-Paket
-zur Verfügung, um die Daten aus diesen Spieldateien zu extrahieren, aber dies
-ist weder erforderlich, noch wird es empfohlen.
+ Simon the Sorcerer 1:
+ - Untertitel sind in den deutschen und englischen CD-Versionen nicht
+ verfügbar, da bei diesen der überwiegende Teil der Untertiteltexte fehlt.
-Für weitere Informationen dazu, wie Sie Macintosh-Spieldateien auf Ihre
-Festplatte kopieren können, lesen Sie:
+ Simon the Sorcerer 2:
+ - Sprache und Untertitel zusammen führen manchmal dazu, dass die
+ Sprachausgabe vorzeitig abgeschnitten wird. Dies ist eine Beschränkung des
+ Originalspiels.
+ - Nur die Standard-Sprache (Englisch) der Spieldaten wird bei den Amiga- und
+ Macintosh-Versionen unterstützt.
- http://wiki.scummvm.org/index.php/HOWTO-Mac_Games
+ Simon the Sorcerer's Game Pack:
+ - Keine Unterstützung für das Anzeigen, Anlegen, Laden oder Speichern von
+ Highscores.
+ - Keine Unterstützung in Swampy Adventures für das Anzeigen von Namen von
+ Gegenständen, wenn man über diese mit der Maus fährt
+ Floyd – Es gibt noch Helden:
+ - Untertitel sind oft unvollständig und nur in Englisch, da sie im
+ Originalspiel immer ausgeschaltet waren.
-3.6) Hinweise zu Spielen auf mehren CDs:
----- -----------------------------------
-Allgemein kann ScummVM nicht sehr gut mit Spielen auf mehreren CDs umgehen. Das
-liegt daran, dass ScummVM annimmt, alles von einem Spiel in einem Verzeichnis
-vorzufinden. Selbst wenn ScummVM einige Fälle berücksichtigt und den Anwender
-dazu auffordert, die CD zu wechseln, so installierten die ursprünglichen
-ausführbaren Dateien des Spiels normalerweise eine kleine Anzahl an Dateien auf
-die Festplatte. Sofern diese Dateien nicht auf allen CDs vorgefunden werden
-können, wird ScummVM Schwierigkeiten haben.
+ The Legend of Kyrandia:
+ - Keine Musik oder Geräusch-Effekte in der Macintosh-Diskettenversion
+ - Die Macintosh-CD-Version verwendet eingebundene DOS-Musik und
+ DOS-Geräusch-Effekte.
-Glücklicherweise hat ScummVM keine Probleme damit, die Spiele komplett von der
-Festplatte aus laufen zu lassen, wenn Sie ein Verzeichnis mit der richtigen
-Kombination der Dateien erstellen. Wenn eine Datei auf mehr als einer CD
-vorkommt, ist es normalerweise egal, welche sie in das Verzeichnis
-hineinkopieren.
+ Spiele von Humongous Entertainment:
+ - Nur die Originaloberfläche kann zum Laden und Speichern verwendet werden.
+ - Keine Unterstützung für den Mehrspielermodus und das Ausdrucken von
+ Bildern
-3.7) Hinweise zu The Curse of Monkey Island:
----- ---------------------------------------
-Für dieses Spiel benötigen Sie die Dateien comi.la0, comi.la1 und comi.la2. Die
-Datei comi.la0 kann auf beiden CDs vorgefunden werden, ist aber auf beiden
-identisch, womit es egal ist, welche der beiden Sie verwenden.
+3.5) Hinweise zu Beneath a Steel Sky:
+---- --------------------------------
+Beginnend mit ScummVM 0.8.0 benötigen Sie die zusätzliche Datei „SKY.CPT“, um
+Beneath a Steel Sky laufen lassen.
-Zusätzlich müssen Sie ein Unterverzeichnis namens „resource“ erstellen, das alle
-Dateien des Unterverzeichnisses „resource“ auf -beiden- CDs beinhaltet. Einige
-dieser Dateien lassen sich auf beiden CDs vorfinden, jedoch sind sie auch in
-diesem Fall identisch.
+Diese Datei ist auf der Seite „Downloads“ der ScummVM-Website verfügbar. Sie
+können sie entweder im Verzeichnis mit den anderen Spieldateien (SKY.DNR,
+SKY.DSK) ablegen, in einem Extrapfad oder im Verzeichnis, in dem sich Ihre
+ausführbare ScummVM-Datei befindet.
-3.8) Hinweise zu Baphomets Fluch I und II:
+3.6) Hinweise zu Baphomets Fluch I und II:
---- -------------------------------------
-Die Anweisungen für die Spiele Baphomets Fluch I und II sind für die
-ausverkauften Software-Versionen, bei welchen sich jedes Spiel auf je zwei CDs
+Die Anweisungen für die Spiele Baphomets Fluch I und II beziehen sich auf die
+Version von Sold-Out Software, bei der sich jedes Spiel auf je zwei CDs
befindet, da diese am leichtesten erhältlich waren, als ScummVM Unterstützung
für diese Spiele erlangte. Wir hoffen, dass sie allgemein ausreichend
ausführlich sind, um für andere Ausgaben genauso hilfreich zu sein.
-3.8.1) Zwischensequenzen von Baphomets Fluch I und II:
+3.6.1) Baphomets Fluch:
+------ ----------------
+Für dieses Spiel benötigen Sie die Dateien aus dem Verzeichnis clusters von
+beiden CDs. Für die Windows- und Macintosh-Versionen benötigen Sie auch die
+Datei speech.clu aus dem Verzeichnis speech von beiden CDs. Da diese jedoch
+nicht identisch sind, müssen Sie diese in speech1.clu und speech2.clu für CD 1
+und 2 entsprechend umbenennen. Die PlayStation-Version erfordert die Dateien
+speech.tab, speech.dat, speech.lis, und speech.inf.
+
+Zusätzlich benötigen die Windows- und Macintosh-Versionen das Unterverzeichnis
+„music“ mit allen Dateien der „music“-Unterverzeichnisse auf beiden CDs. Einige
+dieser Dateien tauchen auf beiden CDs auf, aber in diesen Fällen sind sie
+entweder identisch oder in einem Fall nahezu so identisch, dass es wenig
+Unterschied macht. Die PlayStation-Version erfordert die Dateien tunes.dat und
+tunes.tab.
+
+
+3.6.2) Baphomets Fluch II:
+------ -------------------
+Für dieses Spiel benötigen Sie die Dateien aus dem Verzeichnis clusters von
+beiden CDs. (Ein paar von ihnen sind streng genommen eigentlich nicht notwendig,
+aber diejenigen, über die Unsicherheit besteht, sind alle ziemlich klein.)
+Sie müssen die Dateien speech.clu und music.clu umbenennen, und zwar in
+speech1.clu, speech2.clu, music1.clu und music2.clu, sodass ScummVM weiß, welche
+dieser Dateien von CD 1 und welche von CD 2 sind. Alle anderen Dateien, die in
+beiden „clusters“-Verzeichnissen auftauchen, sind identisch. Verwenden Sie in
+diesen Fällen die Datei, die Sie möchten.
+
+Zusätzlich brauchen Sie die Datei cd.inf und optional die Datei startup.inf aus
+dem Verzeichnis sword2 von CD 1.
+
+
+3.6.3) Zwischensequenzen von Baphomets Fluch I und II:
------ -----------------------------------------------
Die Zwischensequenzen für Baphomets Fluch I und II haben eine kleine Geschichte
(schauen Sie im nächsten Abschnitt, wenn Sie interessiert sind), aber im Großen
@@ -713,7 +767,7 @@ funktioniert momentan nicht bei der Verwendung von PlayStation-Videos.
Arbeit notwendig.)
-3.8.2) Zwischensequenzen von Baphomets Fluch I und II im Rückblick:
+3.6.4) Zwischensequenzen von Baphomets Fluch I und II im Rückblick:
------ ------------------------------------------------------------
Die Originalausgaben von Baphomets Fluch I und II verwendeten das
Smacker™-Format der RAD Game Tools. Da RAD uns nicht die ältere Ur-Version
@@ -739,47 +793,55 @@ Sache, da das Entschlüsseln von MPEG-Filmen mit vielen Schwierigkeiten verbunde
war und diese ohnehin nicht so gut aussahen wie Smacker- und DXA-Versionen.
-3.8.3) Baphomets Fluch:
------- ----------------
-Für dieses Spiel benötigen Sie die Dateien aus dem Verzeichnis clusters von
-beiden CDs. Für die Windows- und Macintosh-Versionen benötigen Sie auch die
-Datei speech.clu aus dem Verzeichnis speech von beiden CDs. Da diese jedoch
-nicht identisch sind, müssen Sie diese in speech1.clu und speech2.clu für CD 1
-und 2 entsprechend umbenennen. Die PlayStation-Version erfordert die Dateien
-speech.tab, speech.dat, speech.lis, und speech.inf.
+3.7) Hinweise zu Day of the Tentacle:
+---- --------------------------------
-Zusätzlich benötigen die Windows- und Macintosh-Versionen das Unterverzeichnis
-„music“ mit allen Dateien der „music“-Unterverzeichnisse auf beiden CDs. Einige
-dieser Dateien tauchen auf beiden CDs auf, aber in diesen Fällen sind sie
-entweder identisch oder in einem Fall nahezu so identisch, dass es wenig
-Unterschied macht. Die PlayStation-Version erfordert die Dateien tunes.dat und
-tunes.tab.
+An einem bestimmten Punkt im Spiel kommen Sie an einem Computer vorbei, der
+Ihnen erlaubt, das originale Maniac Mansion zu spielen. ScummVM unterstützt
+dies, jedoch gilt Folgendes zu beachten:
+ScummVM wird die Konfigurationsdatei nach einem Spiel durchsuchen, welches sich
+im Unterordner "Maniac" innerhalb des "Day of the Tentacle"-Ordners befindet.
+Wenn Sie die Spieldateien von der CD-Version kopiert haben, sollte dies bereits
+der Fall sein, Sie müssen das Spiel jedoch ebenfalls zu ScummVM hinzufügen.
-3.8.4) Baphomets Fluch II:
------- -------------------
-Für dieses Spiel benötigen Sie die Dateien aus dem Verzeichnis clusters von
-beiden CDs. (Ein paar von ihnen sind streng genommen eigentlich nicht notwendig,
-aber diejenigen, über die Unsicherheit besteht, sind alle ziemlich klein.)
-Sie müssen die Dateien speech.clu und music.clu umbenennen, und zwar in
-speech1.clu, speech2.clu, music1.clu und music2.clu, sodass ScummVM weiß, welche
-dieser Dateien von CD 1 und welche von CD 2 sind. Alle anderen Dateien, die in
-beiden „clusters“-Verzeichnissen auftauchen, sind identisch. Verwenden Sie in
-diesen Fällen die Datei, die Sie möchten.
+Um zu Day of the Tentacle zurückzukehren, drücken Sie F5 und wählen Sie „Zurück
+zum Hauptmenü“.
-Zusätzlich brauchen Sie die Datei cd.inf und optional die Datei startup.inf aus
-dem Verzeichnis sword2 von CD 1.
+Dies bedeutet, dass Sie theoretisch jedes Spiel als Easter Egg verwenden
+könnten. Es gibt eine "geheime" Konfigurationseinstellung namens "easter_egg",
+mit welcher Sie die ID des Spiels, welches als Easter-Egg gestartet werden soll,
+festlegen können. Jedoch erlauben nicht alle Spiele die Rückkehr zum Hauptmenü.
+Es ist nicht empfehlenswert, Day of the Tentacle selbst als Easter-Egg-Spiel
+festzulegen.
-3.9) Hinweise zu Beneath a Steel Sky:
----- --------------------------------
-Beginnend mit ScummVM 0.8.0 benötigen Sie die zusätzliche Datei „SKY.CPT“, um
-Beneath a Steel Sky laufen lassen.
+3.8) Hinweise zu Discworld II:
+---- -------------------------
+Für diese Spiel benötigen Sie alle Dateien im Verzeichnis DW2 auf beiden CDs.
+Zusätzlich benötigen Sie die Datei SAMPLE.BNK.
-Diese Datei ist auf der Seite „Downloads“ der ScummVM-Website verfügbar. Sie
-können sie entweder im Verzeichnis mit den anderen Spieldateien (SKY.DNR,
-SKY.DSK) ablegen, in einem Extrapfad oder im Verzeichnis, in dem sich Ihre
-ausführbare ScummVM-Datei befindet.
+Sie müssen ENGISH.SMP, ENGLISH.IDX und ENGLISH.TXT von CD1 zu ENGLISH1.SMP,
+ENGLISH1.IDX und ENGLISH1.TXT umbenennen. Die gleichen Dateien auf CD2 müssen
+in ENGLISH2.SMP, ENGLISH2.IDX und ENGLISH2.TXT umbenannt werden.
+
+
+3.9) Hinweise zu DraÄi Historie:
+---- ---------------------------
+Es gibt vier Sprachvarianten des Spiels: Tschechisch, Deutsch, Englisch und
+Polnisch. Jede von ihnen wird in einem gesonderten Archiv bereitgestellt. Die
+einzige offizielle Version ist die tschechische, während die deutsche, englische
+und polnische immer in Bearbeitung waren und nie offiziell veröffentlicht
+wurden. Obwohl alle Texte vollständig übersetzt sind, ist bekannt, dass einige
+von ihnen Fehler enthalten.
+
+Es existiert optionale tschechische Sprachausgabe für das Spiel. Aus Gründen der
+Bandbreite können Sie diese in einem gesonderten Archiv herunterladen und dann
+im Verzeichnis des Spiels entpacken. Sie können mit allen Sprachvarianten die
+tschechische Sprachausgabe hören, während Sie Untertitel lesen.
+
+Alle Spieldateien und die Komplettlösung können von der folgenden Website
+heruntergeladen werden: http://www.ucw.cz/draci-historie/index-en.html
3.10) Hinweise zu Flight of the Amazon Queen:
@@ -816,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:
@@ -828,15 +890,96 @@ kopieren, da sie sowohl Ressourcen- als auch Datenverzweigungen beinhalten
sollten. Kopieren Sie alle „ITE *“-Dateien.
-3.13) Hinweise zu Simon the Sorcerer 1 und 2:
+3.13) Hinweise zu Maniac Mansion (Aplle II/NES):
+----- ------------------------------------------
+Apple II:
+Sie müssen das Diskettenabbild 1 in maniac1.dsk umbenennen.
+Sie müssen das Diskettenabbild 2 in maniac2.dsk umbenennen.
+
+NES:
+Unterstützte Versionen sind Deutsch (G) [G=German], Englisch GB (E), Französisch
+(F), Italienisch (I), Schwedisch (SW) und Englisch US (U). ScummVM benötigt nur
+den PRG-Bereich und nicht die gesamte ROM-Datei, um das Spiel laufen zu lassen.
+
+Damit das Spiel funktioniert, müssen Sie die ersten 16 Bytes aus der ROM-Datei
+entfernen, die Sie verwenden wollen. Das klappt mit jedem Hexeditor, solange Sie
+mit diesem kopieren und einfügen können. Nachdem Sie die ROM-Datei mit dem
+Hexeditor geöffnet haben, kopieren Sie alles von der zweiten Reihe (17. Byte)
+bis zum Ende. Danach fügen Sie den kopierten Inhalt in eine neue Hexdatei ein.
+Speichern Sie die neue Datei unter dem Namen „Maniac Mansion (XX).prg“, wobei XX
+für die Sprachversion steht, die Sie verwenden wollen (G, E, F, I, SW oder U).
+Die Größe der neuen Datei sollte genau 262144 Bytes betragen.
+
+Wenn Sie das Spiel manuell hinzufügen, stellen Sie sicher, dass die Plattform
+auf NES eingestellt ist.
+
+Die häufigsten Fehler, die verhindern, dass das Spiel läuft:
+
+ * Fehlerhafte Datei
+ * ROM extrahiert mit den Tools der Version 0.7.0
+ * Sie versuchen, in ScummVM die VOLLE ROM-DATEI zu laden und nicht nur den
+ PRG-Bereich.
+
+Es ist auch möglich, die einzelnen LFL-Dateien aus dem PRG-Bereich zu
+extrahieren. Um dies zu tun, verwenden Sie das Dienstprogramm „extract_mm_nes“
+aus dem Tools-Paket.
+
+
+3.14) Hinweise zu Mickey's Space Adventure:
+----- -------------------------------------
+Um Mickey's Space Adventure unter ScummVM laufen zu lassen, benötigen Sie die
+originale EXE-Datei des Spiels (mickey.exe) sowie die Spieldateien.
+
+Für das Spiel gibt es unter ScummVM umfangreiche Mausunterstützung, obwohl es im
+Originalspiel überhaupt keine Mausunterstützung gab. Menüpunkte können mit der
+Maus ausgewählt werden und es ist auch möglich, mittels Maus an andere Orte zu
+wechseln. Wenn die Maus über den Rand des Bildschirms bewegt wird, ändert sich
+die Farbe des Zeigers in Rot, wenn es möglich ist, in diese Richtung zu gehen.
+Der Spieler kann dann einfach auf den Rand des Spielbildschirms klicken, um den
+Ort zu wechseln, ähnlich wie in vielen Adventures, was einfacher und viel
+unkomplizierter ist, als sich mit dem Menü umherzubewegen.
+
+
+3.15) Hinweise zu Nippon Safes Inc. (Amiga):
+----- --------------------------------------
+Für dieses Spiel benötigen Sie die Dateien
+disk0, global.table, pointer und it (en, fr, ge für die internationale Version).
+
+Zusätzlich müssen Sie das Diskettenabbild 2 in disk1, Abbild 3 in disk2,
+Abbild 4 in disk3 sowie Abbild 5 in disk4 umbenennen.
+
+
+3.16) Hinweise zu Simon the Sorcerer 1 und 2:
----- ---------------------------------------
Wenn Sie die Doppel-Version von Simon the Sorcerer 1 oder 2 auf CD haben, finden
Sie die Windows-Version im Hauptverzeichnis der CD und die DOS-Version im
DOS-Verzeichnis der CD.
-3.14) Hinweise zu Floyd – Es gibt noch Helden:
+3.17) Hinweise zu The Curse of Monkey Island:
+----- ---------------------------------------
+Für dieses Spiel benötigen Sie die Dateien comi.la0, comi.la1 und comi.la2. Die
+Datei comi.la0 kann auf beiden CDs vorgefunden werden, ist aber auf beiden
+identisch, womit es egal ist, welche der beiden Sie verwenden.
+
+Zusätzlich müssen Sie ein Unterverzeichnis namens „resource“ erstellen, das alle
+Dateien des Unterverzeichnisses „resource“ auf -beiden- CDs beinhaltet. Einige
+dieser Dateien lassen sich auf beiden CDs vorfinden, jedoch sind sie auch in
+diesem Fall identisch.
+
+
+3.18) Hinweise zu Floyd – Es gibt noch Helden:
----- ----------------------------------------
+Amiga/Macintosh:
+Sie benötigen ein kleines Paket mit Zwischensequenzen, welche sowohl in der
+Amiga- als auch in der Macintosh-Version fehlen. Es heißt
+„The Feeble Files - Omni TV and epilogue cutscenes for the Amiga and Macintosh
+versions“
+und kann hier heruntergeladen werden:
+
+ http://www.scummvm.org/games/#feeble
+
+Windows:
Wenn Sie die Windows-Version von Floyd – Es gibt noch Helden haben, sind einige
Dinge zu beachten.
@@ -854,7 +997,7 @@ voices.wav von CD3 in voices3.wav
voices.wav von CD4 in voices4.wav
-3.15) Hinweise zu The Legend of Kyrandia:
+3.19) Hinweise zu The Legend of Kyrandia:
----- -----------------------------------
Um The Legend of Kyrandia unter ScummVM laufen zu lassen, benötigen Sie die
Datei „kyra.dat“. Die Datei sollte immer in offiziellen ScummVM-Paketen
@@ -865,7 +1008,29 @@ eingebettet sein sollte. Also müssen Sie sich nur diese besorgen, wenn sich
ScummVM darüber beschwert, dass diese Datei fehlt.
-3.16) Hinweise zum vorhersagenden Eingabedialog bei Sierras AGI-Spielen:
+3.20) Hinweise zu Troll's Tale:
+----- -------------------------
+Das Originalspiel wurde auf einer PC-Boot-Diskette ausgeliefert, weshalb es
+notwendig ist, die Inhalte dieser Diskette in einer Abbild-Datei auszugeben und
+diese „troll.img“ zu nennen, um das Spiel unter ScummVM spielen zu können.
+
+
+3.21) Hinweise zu Winnie the Pooh:
+----- ----------------------------
+Es ist möglich, Spielstände vom Original-Interpreter des Spiels in ScummVM zu
+importieren.
+
+Für das Spiel gibt es unter ScummVM umfangreiche Mausunterstützung, obwohl es im
+Originalspiel überhaupt keine Mausunterstützung gab. Menüpunkte können mit der
+Maus ausgewählt werden und es ist auch möglich, mittels Maus an andere Orte zu
+wechseln. Wenn die Maus über den Rand des Bildschirms bewegt wird, ändert sich
+die Farbe des Zeigers in Rot, wenn es möglich ist, in diese Richtung zu gehen.
+Der Spieler kann dann einfach auf den Rand des Spielbildschirms klicken, um den
+Ort zu wechseln, ähnlich wie in vielen Adventures, was einfacher und viel
+unkomplizierter ist, als sich mit dem Menü umherzubewegen.
+
+
+3.22) Hinweise zum vorhersagenden Eingabedialog bei Sierras AGI-Spielen:
----- ------------------------------------------------------------------
Der vorhersagende Eingabedialog ist ein ScummVM-Hilfsmittel, um die englischen
Spiele der AGI-Engine (die offensichtlich Kommandozeilen-Eingabe erfordern) auf
@@ -924,62 +1089,7 @@ Ziffernblock zugewiesen wurde. Ebenso können die Schaltflächen mittels der
Pfeiltasten und der Eingabetaste gesteuert werden.
-3.17) Hinweise zu Mickey's Space Adventure:
------ -------------------------------------
-Um Mickey's Space Adventure unter ScummVM laufen zu lassen, benötigen Sie die
-originale EXE-Datei des Spiels (mickey.exe) sowie die Spieldateien.
-
-Für das Spiel gibt es unter ScummVM umfangreiche Mausunterstützung, obwohl es im
-Originalspiel überhaupt keine Mausunterstützung gab. Menüpunkte können mit der
-Maus ausgewählt werden und es ist auch möglich, mittels Maus an andere Orte zu
-wechseln. Wenn die Maus über den Rand des Bildschirms bewegt wird, ändert sich
-die Farbe des Zeigers in Rot, wenn es möglich ist, in diese Richtung zu gehen.
-Der Spieler kann dann einfach auf den Rand des Spielbildschirms klicken, um den
-Ort zu wechseln, ähnlich wie in vielen Adventures, was einfacher und viel
-unkomplizierter ist, als sich mit dem Menü umherzubewegen.
-
-
-3.18) Hinweise zu Winnie the Pooh:
------ ----------------------------
-Es ist möglich, Spielstände vom Original-Interpreter des Spiels in ScummVM zu
-importieren.
-
-Für das Spiel gibt es unter ScummVM umfangreiche Mausunterstützung, obwohl es im
-Originalspiel überhaupt keine Mausunterstützung gab. Menüpunkte können mit der
-Maus ausgewählt werden und es ist auch möglich, mittels Maus an andere Orte zu
-wechseln. Wenn die Maus über den Rand des Bildschirms bewegt wird, ändert sich
-die Farbe des Zeigers in Rot, wenn es möglich ist, in diese Richtung zu gehen.
-Der Spieler kann dann einfach auf den Rand des Spielbildschirms klicken, um den
-Ort zu wechseln, ähnlich wie in vielen Adventures, was einfacher und viel
-unkomplizierter ist, als sich mit dem Menü umherzubewegen.
-
-
-3.19) Hinweise zu Troll's Tale:
------ -------------------------
-Das Originalspiel wurde auf einer PC-Boot-Diskette ausgeliefert, weshalb es
-notwendig ist, die Inhalte dieser Diskette in einer Abbild-Datei auszugeben und
-diese „troll.img“ zu nennen, um das Spiel unter ScummVM spielen zu können.
-
-
-3.20) Hinweise zu DraÄi Historie:
------ ---------------------------
-Es gibt vier Sprachvarianten des Spiels: Tschechisch, Deutsch, Englisch und
-Polnisch. Jede von ihnen wird in einem gesonderten Archiv bereitgestellt. Die
-einzige offizielle Version ist die tschechische, während die deutsche, englische
-und polnische immer in Bearbeitung waren und nie offiziell veröffentlicht
-wurden. Obwohl alle Texte vollständig übersetzt sind, ist bekannt, dass einige
-von ihnen Fehler enthalten.
-
-Es existiert optionale tschechische Sprachausgabe für das Spiel. Aus Gründen der
-Bandbreite können Sie diese in einem gesonderten Archiv herunterladen und dann
-im Verzeichnis des Spiels entpacken. Sie können mit allen Sprachvarianten die
-tschechische Sprachausgabe hören, während Sie Untertitel lesen.
-
-Alle Spieldateien und die Komplettlösung können von der folgenden Website
-heruntergeladen werden: http://www.ucw.cz/draci-historie/index-en.html
-
-
-3.21) Gleichzeitige Sprachausgabe und Untertitel in Sierra-SCI-Spielen:
+3.23) Gleichzeitige Sprachausgabe und Untertitel in Sierra-SCI-Spielen:
----- -----------------------------------------------------------------
Bestimmte CD-Versionen von Sierra-SCI-Spielen boten sowohl Sprachausgabe als
auch Untertitel an. Bei einigen gab es die Möglichkeit, zwischen beidem hin- und
@@ -1032,83 +1142,162 @@ Space Quest 4 CD:
deaktiviert und aktiviert werden.
-3.22) Bekannte Probleme:
------ ------------------
-Diese veröffentlichte Version hat die unten folgenden bekannten Probleme. Es ist
-nicht notwendig, diese zu berichten, jedoch sind Patches, um diese zu beheben,
-willkommen. Wenn Sie einen Fehler entdecken, der weder hier noch auf der
-Kompatibilitätsseite der Website aufgeführt ist, sehen Sie bitte im Abschnitt
-„Fehler berichten“ nach, wenn Sie ihn melden möchten.
-
- Spiele mit Ton von CD:
- - Bei Spielen, die auf Audio von CD zurückgreifen (FM-TOWNS-Spiele,
- Loom-CD-Version usw.), ist es möglich, dass Anwender von Microsoft Windows
- 2000/XP zufällige Abstürze erleben. Das liegt an einem lange bestehenden
- Windows-Fehler, der dazu führt, dass fehlerhafte Spieldaten von der CD
- ausgelesen werden. Bitte kopieren Sie die Spieldaten in ein Verzeichnis
- Ihrer Festplatte, um dies zu vermeiden.
-
- FM-TOWNS-Versionen:
- - Die Kanji-Versionen erfordern die Schriftart-ROM-Datei von FM-TOWNS.
-
- Loom:
- - Das Abschalten der Untertitel über die Spieleinstellungen funktioniert
- nicht zuverlässig, da die Loom-Skripte diese wieder einschalten.
- - MIDI-Unterstützung in der EGA-Version erfordert das Roland-Update von
- LucasArts.
- - Die Kanji-Version der PC-Engine erfordert die Systemkarten-ROM-Datei.
-
- The Secret of Monkey Island:
- - MIDI-Unterstützung in der EGA-Version erfordert das Roland-Update von
- LucasArts.
-
- Beneath a Steel Sky:
- - Amiga-Versionen werden nicht unterstützt.
- - Disketten-Demos werden nicht unterstützt.
- - Kein Fehler: In der CD-Version fehlt in einigen Dialogen Sprachausgabe;
- das ist normal.
-
- Elvira - Mistress of the Dark
- - Keine Musik in der Atari-ST-Version
+3.24) Hinweise zu den Spielen der Zork-Reihe:
+----- ---------------------------------------
+Um die unterstützen Zork-Spiele (Zork Nemesis: Das verbotene Land und
+Zork: Der Großinquisitor) spielen zu können, müssen Sie einige zusätzliche
+Dateien zu ihren entsprechenden Zielen kopieren.
+
+Zork Nemesis: Das verbotene Land
+
+Alle Versionen
+
+Laden Sie das Liberation(tm)-Schriftartenpaket unter
+https://fedorahosted.org/releases/l/i/liberation-fonts/liberation-fonts-ttf-
+2.00.1.tar.gz
+herunter und entpacken Sie alle ttf-Dateien in ScummVMs Extras-Pfad. Alternativ
+können Sie auch das GNU FreeFont TTF-Paket unter
+https://ftp.gnu.org/gnu/freefont/freefont-ttf.zip
+herunterladen und alle ttf-Dateien aus dem sfd-Verzeichnis in ScummVMs Extras-
+Pfad kopieren. Diese Schriftarten können Probleme bei der Textdarstellung
+verursachen. Laden Sie den Untertitel-Patch unter
+http://www.thezorklibrary.com/installguides/znpatch.zip
+herunter und entpacken Sie das Verzeichnis "addon" in das Hauptverzeichnis des
+Spiels.
+
+GoG-Version
+
+Verwenden Sie das GoG-Installationsprogramm. Keine weiteren Dateien müssen
+kopiert werden.
+
+CD-Version
+
+Kopieren Sie folgende Verzeichnisse und Dateien aus dem Verzeichnis "nemesis"
+auf CD1 in das Hauptverzeichnis des Spiels:
+das Verzeichnis "znemmx"
+das Verzeichnis "znemscr"
+nemesis.str
+Von CD1 kopieren Sie das Verzeichnis "zassets" in das Hauptverzeichnis des
+Spiels.
+Von CD2 kopieren Sie das Verzeichnis "zassets" in das Hauptverzeichnis des
+Spiels und überschreiben Sie alle identischen Dateien.
+Von CD3 kopieren Sie das Verzeichnis "zassets" in das Hauptverzeichnis des
+Spiels und überschreiben Sie alle identischen Dateien.
+
+DVD-Version
+
+Kopieren Sie folgende Verzeichnisse und Dateien aus dem Verzeichnis "nemesis"
+auf CD1 in das Hauptverzeichnis des Spiels:
+Das Verzeichnis "znemmx"
+Das Verzeichnis "znemscr"
+nemesis.str
+Hinweis: Sie müssen auch die Datei cursor.zfs vom Verzeichnis "zassets/global"
+in das Verzeichnis "znemscr" verschieben.
+Kopieren Sie die Verzeichnisse "disc2", "disc3" und "zassets" in das
+Hauptverzeichnis des Spiels.
+
+
+Zork: Der Großinquisitor
+
+Alle Versionen
+
+Laden Sie das Liberation(tm)-Schriftartenpaket unter
+https://fedorahosted.org/releases/l/i/liberation-fonts/liberation-fonts-ttf-
+2.00.1.tar.gz
+herunter und entpacken Sie alle ttf-Dateien in ScummVMs Extras-Pfad.
+Alternativ können Sie auch das GNU FreeFont TTF-Paket unter
+https://ftp.gnu.org/gnu/freefont/freefont-ttf.zip
+herunterladen und alle ttf-Dateien aus dem sfd-Verzeichnis in ScummVMs Extras-
+Pfad kopieren. Diese Schriftarten können Probleme bei der Textdarstellung
+verursachen.
+
+GoG-Version
+
+Verwenden Sie das GoG-Installationsprogramm. Es müssen keine weiteren Dateien
+kopiert werden.
+
+CD-Version:
+
+Kopieren Sie die folgenden Verzeichnisse und Dateien aus dem Verzeichnis "zgi"
+von CD1 in das Hauptverzeichnis des Spiels:
+das Verzeichnis "zgi_mx"
+cursor.zfs
+death.zfs
+inquis.str
+inquis.zix
+r.svr
+scripts.zfs
+subtitle.zfs
+Von CD1 kopieren Sie das Verzeichnis "zassets1" in das Hauptverzeichnis des
+Spiels.
+Von CD2 kopieren Sie das Verzeichnis "zassets2" in das Hauptverzeichnis des
+Spiels.
+Es wird empfohlen, den hier erhältlichen Patch 1.2 anzuwenden:
+http://www.thezorklibrary.com/installguides/Zpatch.exe
+Möglicherweise müssen Sie das Spiel zuvor normal installieren, da der Patch ein
+eigenes Installationsprogramm besitzt.
+
+DVD-Version
+
+Kopieren Sie die folgenden Verzeichnisse und Dateien aus dem Verzeichnis "zgi_e"
+in das Hauptverzeichnis des Spiels:
+das Verzeichnis "addon" (Spiel-Patch 1.2)
+das Verzeichnis zgi_mx
+cursor.zfs
+death.zfs
+inquis.str
+inquis.zix
+r.svr
+scripts.zfs
+subtitle.zfs
+Kopieren Sie das Verzeichnis "eng_mpeg" (hochauflösende MPEG2-Videodateien) in
+das Hauptverzeichnis des Spiels. Kopieren Sie die Verzeichnisse "zassetsc" und
+"zassetse" ebenfalls in das Hauptverzeichnis des Spiels.
+
+
+3.25) Hinweise zu Spielen für den Commodore 64:
+----- -----------------------------------------
+Sowohl Maniac Mansion als auch Zak McKracken laufen, aber Maniac Mansion ist
+noch nicht spielbar. Benennen Sie einfach die D64-Datenträger um in
+„maniac1.d64“ und „maniac2.d64“ und entsprechend „zak1.d64“ und „zak2.d64“, dann
+sollte ScummVM in der Lage sein, das Spiel automatisch zu erkennen, wenn Sie auf
+das richtige Verzeichnis zeigen.
- Elvira II - The Jaws of Cerberus
- - Keine Musik in der Atari-ST-Version
- - Keine Geräusch-Effekte in der PC-Version
- - Palettenprobleme in der Atari-ST-Version
+Alternativ können Sie „extract_mm_c64“ aus dem Tools-Paket verwenden, um die
+Spieldateien zu extrahieren. Dann wird das Spiel jedoch nicht einwandfrei von
+ScummVM automatisch erkannt und Sie müssen sicherstellen, dass Commodore 64 als
+Plattform eingestellt ist. Wir empfehlen, auf die viel einfachere Methode
+zurückzugreifen, die im vorherigen Absatz beschrieben ist.
- Inherit the Earth: Quest for the Orb
- - Amiga-Versionen werden nicht unterstützt.
- Simon the Sorcerer 1:
- - Untertitel sind in den deutschen und englischen CD-Versionen nicht
- verfügbar, da bei diesen der überwiegende Teil der Untertiteltexte fehlt.
-
- Simon the Sorcerer 2:
- - Sprache und Untertitel zusammen führen manchmal dazu, dass die
- Sprachausgabe vorzeitig abgeschnitten wird. Dies ist eine Beschränkung des
- Originalspiels.
- - Nur die Standard-Sprache (Englisch) der Spieldaten wird bei den Amiga- und
- Macintosh-Versionen unterstützt.
+3.26) Hinweise zu Spielen für den Macintosh:
+----- --------------------------------------
+Alle auf SCUMM basierenden Adventures von Lucasarts, mit Ausnahme von COMI,
+existieren auch als Versionen für den Macintosh. ScummVM kann die meisten
+(alle?) von diesen verwenden, jedoch ist in manchen Fällen zusätzliche Arbeit
+erforderlich. Zuallererst: Wenn Sie keinen Macintosh dafür verwenden, könnte es
+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. „HFSExplorer“ für Windows und „hfsutils“ für
+Linux und andere Betriebssysteme, die Unix ähnlich sind.
- Simon the Sorcerer's Game Pack:
- - Keine Unterstützung für das Anzeigen, Anlegen, Laden oder Speichern von
- Highscores.
- - Keine Unterstützung in Swampy Adventures für das Anzeigen von Namen von
- Gegenständen, wenn man über diese mit der Maus fährt
+Die meisten neueren Spiele für den Macintosh wurden nur mit einer einzigen
+Spieldatei ausgeliefert (beachten Sie, dass in manchen Fällen diese Spieldatei
+unsichtbar gemacht wurde und Sie somit zusätzliche Tools benötigen, um diese zu
+kopieren). ScummVM ist in der Lage, eine solche Spieldatei direkt zu verwenden;
+verweisen Sie ScummVM einfach auf das Verzeichnis, welches diese enthält und es
+sollte klappen (so wie mit jedem anderen unterstützten Spiel).
- Floyd – Es gibt noch Helden:
- - Untertitel sind oft unvollständig und nur in Englisch, da sie im
- Originalspiel immer ausgeschaltet waren.
+Wir stellen außerdem ein Tool mit dem Namen „extract_scumm_mac“ im Tools-Paket
+zur Verfügung, um die Daten aus diesen Spieldateien zu extrahieren, aber dies
+ist weder erforderlich, noch wird es empfohlen.
- The Legend of Kyrandia:
- - Keine Musik oder Geräusch-Effekte in der Macintosh-Diskettenversion
- - Die Macintosh-CD-Version verwendet eingebundene DOS-Musik und
- DOS-Geräusch-Effekte.
+Für weitere Informationen dazu, wie Sie Macintosh-Spieldateien auf Ihre
+Festplatte kopieren können, lesen Sie:
- Spiele von Humongous Entertainment:
- - Nur die Originaloberfläche kann zum Laden und Speichern verwendet werden.
- - Keine Unterstützung für den Mehrspielermodus und das Ausdrucken von
- Bildern
+ http://wiki.scummvm.org/index.php/HOWTO-Mac_Games
4.0) Unterstützte Plattformen:
@@ -1252,8 +1441,9 @@ gestartet werden -- siehe nächster Abschnitt.
--output-rate=FREQUENZ Wählt Ausgabefrequenz in Hz (z. B. 22050).
--opl-driver=TREIBER Wählt AdLib-(OPL-)Emulator (db, mame).
--aspect-ratio Aktiviert Seitenverhältniskorrektur.
- --render-mode=MODUS Aktiviert zusätzlichen Render-Modus (cga, ega,
- hercGreen, hercAmber, amiga).
+ --render-mode=MODUS Aktiviert zusätzlichen Render-Modus (hercGreen,
+ hercAmber, cga, ega, vga, amiga, fmtowns, pc9821,
+ pc9801, 2gs, atari, macintosh).
--alt-intro Verwendet alternativen Vorspann in CD-Versionen von
Beneath a Steel Sky und Flight of the Amazon Queen.
@@ -1293,64 +1483,50 @@ Beispiele:
/Pfad/zu/scummvm -f -n -p/cdrom/resource/ ft
-5.2) Sprachoptionen:
----- ---------------
-ScummVM beinhaltet Sprachoptionen für Maniac Mansion, Zak McKracken,
-The Dig, The Curse of Monkey Island, Beneath a Steel Sky und Baphomets Fluch.
-
-Beachten Sie, dass mit Ausnahme von Beneath a Steel Sky, Baphomets Fluch,
-mehrsprachigen Versionen der Goblins-Spiele und Nippon Safes Inc. die Verwendung
-dieser Option nicht die Sprache des Spiels ändert (die normalerweise fest
-programmiert ist), sondern nur dazu verwendet wird, um die passende Schriftart
-zu wählen (z. B. für eine deutsche Version eines Spiels, in der Umlaute
-enthalten sind).
-
-Eine Ausnahme bilden The Dig und The Curse of Monkey Island -- nicht-englische
-Versionen dieser Spiele können auf Englisch eingestellt werden. Dies hat
-allerdings nur Auswirkungen auf die Untertitel; die Sprachausgabe bleibt
-dieselbe.
-
-Maniac Mansion und Zak McKracken
- en - Englisch (Standard)
- de - Deutsch
- fr - Französisch
- it - Italienisch
- es - Spanisch
-
-The Dig
- jp - Japanisch
- zh - Chinesisch
- kr - Koreanisch
+5.2) Globales Menü:
+---- --------------
+Das globale Menü ist ein allgemeines Menü, das in allen Spiel-Engines verfügbar
+ist und mit Strg+F5 aufgerufen werden kann. In diesem Menü befinden sich
+folgende Schaltflächen: „Fortsetzen“, „Optionen“, „Über“, „Zur Spieleliste
+zurück“ und „Beenden“. Wenn Sie „Optionen“ auswählen, wird ein Dialog angezeigt,
+in welchem einfache Audio-Einstellungen, wie beispielsweise Lautstärkepegel,
+festgelegt werden können. Wenn Sie „Zurück zur Spieleliste“ wählen, wird das
+momentane Spiel beendet und das Programm kehrt zur Spieleliste zurück, von der
+aus ein anderes Spiel gestartet werden kann.
-The Curse of Monkey Island
- en - Englisch (Standard)
- de - Deutsch
- fr - Französisch
- it - Italienisch
- pt - Portugiesisch
- es - Spanisch
- jp - Japanisch
- zh - Chinesisch
- kr - Koreanisch
+Hinweis: Das Zurückkehren zur Spieleliste wird nicht von allen Engines
+unterstützt, weshalb die Schaltfläche im globalen Menü deaktiviert wird, wenn
+diese Funktion nicht verfügbar ist.
-Beneath a Steel Sky
- gb - Englisch (Großbritannien) (Standard)
- en - Englisch (USA)
- de - Deutsch
- fr - Französisch
- it - Italienisch
- pt - Portugiesisch
- es - Spanisch
- se - Schwedisch
+Die Engines, die momentan das Zurückkehren zur Spieleliste unterstützen, sind:
-Baphomets Fluch
- en - Englisch (Standard)
- de - Deutsch
- fr - Französisch
- it - Italienisch
- es - Spanisch
- pt - Portugiesisch
- cz - Tschechisch
+ AGI
+ AGOS
+ CINE
+ COMPOSER
+ CRUISE
+ DRACI
+ DRASCULA
+ GOB
+ GROOVIE
+ HUGO
+ KYRA
+ LURE
+ MADE
+ MOHAWK
+ PARALLACTION
+ QUEEN
+ SAGA
+ SCI
+ SCUMM
+ SKY
+ SWORD1
+ SWORD2
+ TEENAGENT
+ TOUCHE
+ TSAGE
+ TUCKER
+ ZVISION
5.3) Grafikfilter:
@@ -1408,53 +1584,7 @@ Auflösung 640x480 verwendet haben (wie beispielsweise The Curse of Monkey Islan
oder Baphomets Fluch), auf 1280x960 und 1920x1440 skaliert.
-5.4) Globales Menü:
----- --------------
-Das globale Menü ist ein allgemeines Menü, das in allen Spiel-Engines verfügbar
-ist und mit Strg+F5 aufgerufen werden kann. In diesem Menü befinden sich
-folgende Schaltflächen: „Fortsetzen“, „Optionen“, „Über“, „Zur Spieleliste
-zurück“ und „Beenden“. Wenn Sie „Optionen“ auswählen, wird ein Dialog angezeigt,
-in welchem einfache Audio-Einstellungen, wie beispielsweise Lautstärkepegel,
-festgelegt werden können. Wenn Sie „Zurück zur Spieleliste“ wählen, wird das
-momentane Spiel beendet und das Programm kehrt zur Spieleliste zurück, von der
-aus ein anderes Spiel gestartet werden kann.
-
-Hinweis: Das Zurückkehren zur Spieleliste wird nicht von allen Engines
-unterstützt, weshalb die Schaltfläche im globalen Menü deaktiviert wird, wenn
-diese Funktion nicht verfügbar ist.
-
-Die Engines, die momentan das Zurückkehren zur Spieleliste unterstützen, sind:
-
- AGI
- AGOS
- CINE
- COMPOSER
- CRUISE
- DRACI
- DRASCULA
- GOB
- GROOVIE
- HUGO
- KYRA
- LURE
- MADE
- MOHAWK
- PARALLACTION
- QUEEN
- SAGA
- SCI
- SCUMM
- SKY
- SWORD1
- SWORD2
- TEENAGENT
- TOUCHE
- TSAGE
- TUCKER
- ZVISION
-
-
-5.5) Tastenkürzel:
+5.4) Tastenkürzel:
---- -------------
ScummVM unterstützt zahlreiche Tastenkürzel in Spielen. Sie unterscheiden sich
zwischen SCUMM-Spielen und anderen Spielen.
@@ -1463,6 +1593,7 @@ zwischen SCUMM-Spielen und anderen Spielen.
Strg+F5 - Zeigt globales Menü.
Cmd+q - Beenden (Mac OS X)
Strg+q - Beenden (andere UNIX-Systeme einschließlich Linux)
+ Alt+F4 - Beenden (Windows)
Strg+z ODER Alt+x - Beenden (andere Plattformen)
Strg+u - Allen Ton abschalten - EIN/AUS
Strg+m - Mausbegrenzung in Fenster EIN/AUS
@@ -1557,10 +1688,6 @@ zwischen SCUMM-Spielen und anderen Spielen.
l - Spiel laden
s - Spiel speichern
- Lure of the Temptress
- - Keine Unterstützung für Roland MT-32
- - Ton-Unterstützung ist nicht vollständig und klingt nicht wie das Original.
-
Simon the Sorcerer 1 und 2:
Strg 0-9 und Alt 0-9 - Lädt und speichert entsprechenden Speicherstand.
Strg+d - Startet den Debugger.
@@ -1622,6 +1749,27 @@ zwischen SCUMM-Spielen und anderen Spielen.
t - Wechselt zwischen „Nur Sprachausgabe“,
„Sprachausgabe und Text“ und „Nur Text“.
+ Zork: Der Großinquisitor:
+ Strg+s - Speichern
+ Strg+r - Laden
+ Strg+q - Beenden
+ Strg+p - Einstellungen
+ F1 - Hilfe
+ F5 - Inventar
+ F6 - Zauberbuch
+ F7 - Punkte
+ F8 - Aktuelles Objekt wegtun / Zauberspruch vergessen
+ F9 - Münze hervorholen (muss Münzentasche haben)
+ Space - Ãœberspringt Zwischensequenzen.
+
+ Zork Nemesis: Das verbotene Land:
+ Strg+s - Speichern
+ Strg+r - Laden
+ Strg+q - Beenden
+ Strg+p - Einstellungen
+ Leertaste - Ãœberspringt Zwischensequenzen.
+
+
Beachten Sie, dass von der Verwendung von Strg+f oder Strg+g abgeraten wird:
Spiele können abstürzen, wenn sie schneller als mit ihrer normalen
Geschwindigkeit laufen, da Skripte aus dem Takt kommen.
@@ -1632,6 +1780,66 @@ Neutastenzuweisung und/oder Konsolenaktionen unterstützt. Näheres ist in der
Datei README-WinCE.txt nachzulesen.
+5.5) Sprachoptionen:
+---- ---------------
+ScummVM beinhaltet Sprachoptionen für Maniac Mansion, Zak McKracken,
+The Dig, The Curse of Monkey Island, Beneath a Steel Sky und Baphomets Fluch.
+
+Beachten Sie, dass mit Ausnahme von Beneath a Steel Sky, Baphomets Fluch,
+mehrsprachigen Versionen der Goblins-Spiele und Nippon Safes Inc. die Verwendung
+dieser Option nicht die Sprache des Spiels ändert (die normalerweise fest
+programmiert ist), sondern nur dazu verwendet wird, um die passende Schriftart
+zu wählen (z. B. für eine deutsche Version eines Spiels, in der Umlaute
+enthalten sind).
+
+Eine Ausnahme bilden The Dig und The Curse of Monkey Island -- nicht-englische
+Versionen dieser Spiele können auf Englisch eingestellt werden. Dies hat
+allerdings nur Auswirkungen auf die Untertitel; die Sprachausgabe bleibt
+dieselbe.
+
+Maniac Mansion und Zak McKracken
+ en - Englisch (Standard)
+ de - Deutsch
+ fr - Französisch
+ it - Italienisch
+ es - Spanisch
+
+The Dig
+ jp - Japanisch
+ zh - Chinesisch
+ kr - Koreanisch
+
+The Curse of Monkey Island
+ en - Englisch (Standard)
+ de - Deutsch
+ fr - Französisch
+ it - Italienisch
+ pt - Portugiesisch
+ es - Spanisch
+ jp - Japanisch
+ zh - Chinesisch
+ kr - Koreanisch
+
+Beneath a Steel Sky
+ gb - Englisch (Großbritannien) (Standard)
+ en - Englisch (USA)
+ de - Deutsch
+ fr - Französisch
+ it - Italienisch
+ pt - Portugiesisch
+ es - Spanisch
+ se - Schwedisch
+
+Baphomets Fluch
+ en - Englisch (Standard)
+ de - Deutsch
+ fr - Französisch
+ it - Italienisch
+ es - Spanisch
+ pt - Portugiesisch
+ cz - Tschechisch
+
+
6.0) Spielstände:
---- ------------
Spielstände werden bei einigen Plattformen standardmäßig im aktuellen
@@ -1643,9 +1851,19 @@ Die folgenden Plattformen haben ein anderes Standard-Verzeichnis:
$HOME/Documents/ScummVM Savegames/
Andere UNIX-Systeme:
- $HOME/.scummvm/
+ Wir befolgen die Spezifikation XDG Base Directory. Dies bedeutet, dass
+ die Spielstände in
+ $XDG_DATA_HOME/scummvm/saves/
+ gespeichert werden.
- Windows Vista/7:
+ Wenn XDG_DATA_HOME nicht definiert oder leer ist, wird ~/.local/share als
+ Wert für XDG_DATA_HOME in Übereinstimmung mit der Spezifikation verwendet.
+
+ Wenn eine frühere Version von ScummVM auf Ihrem System installiert war, wird
+ das ursprüngliche Standard-Verzeichnis „~/.scummvm“ beibehalten. Dies wird
+ daran erkannt, dass der Pfad „~/.scummvm“ vorhanden ist.
+
+ Windows Vista/7/8/10:
\Users\Benutzername\AppData\Roaming\ScummVM\Saved games\
Windows 2000/XP:
@@ -1656,10 +1874,15 @@ Die folgenden Plattformen haben ein anderes Standard-Verzeichnis:
<Windows-Verzeichnis>\Profiles\Benutzername\
Application Data\ScummVM\Saved games\
-Hinweis für Anwender von Windows NT4/2000/XP/Vista/7: Das Standard-Verzeichnis
-für Spielstände wurde bei ScummVM 1.5.0 geändert. Die Stapelverarbeitungsdatei
-migration.bat kann verwendet werden, um die Spielstände vom alten
-Standard-Verzeichnis in das neue zu kopieren.
+Spielstände werden unter Windows NT4/2000/XP/Vista/7/8/10 in einem versteckten
+Verzeichnis gespeichert, auf welches über den Pfad
+„%APPDATA%\ScummVM\Saved Games\“ zugegriffen werden kann. Es wird auch sichtbar,
+wenn die Anzeige versteckter Dateien im Windows Explorer aktiviert wird.
+
+Hinweis für Anwender von Windows NT4/2000/XP/Vista/7/8/10: Das Standard-
+Verzeichnis für Spielstände wurde bei ScummVM 1.5.0 geändert. Die
+Stapelverarbeitungsdatei migration.bat kann verwendet werden, um die Spielstände
+vom alten Standard-Verzeichnis in das neue zu kopieren.
6.1) Automatische Speicherung der Spielstände:
@@ -1673,11 +1896,6 @@ automatischen Spielstände auf Platz 0 abgelegt. Bei der SCUMM-Engine kann diese
Speicherstand über die Tastenkombination Strg+0 oder über das F5-Menü geladen
werden.
-Spielstände werden unter Windows NT4/2000/XP/Vista/7/8/10 in einem versteckten
-Bereich gespeichert, auf den durch Aufruf von „%APPDATA%\ScummVM\Saved Games\“
-zugegriffen werden kann oder indem das Anzeigen versteckter Dateien im Windows
-Explorer aktiviert wird.
-
6.2) Spielstände umwandeln:
---- ----------------------
@@ -1753,6 +1971,7 @@ der Spielstand unter ScummVM befinden soll.
TOUCHE
TSAGE
TUCKER
+ ZVISION
--save-slot/-x:
@@ -1787,6 +2006,7 @@ der Spielstand unter ScummVM befinden soll.
TOUCHE
TSAGE
TUCKER
+ ZVISION
7.0) Musik und Sound:
@@ -2054,7 +2274,7 @@ festlegen.
7.8) Komprimierte Audio-Dateien verwenden
---- ------------------------------------
-7.8.0) MP3-Dateien für Audio von CD verwenden:
+7.8.1) MP3-Dateien für Audio von CD verwenden:
------ ---------------------------------------
Verwenden Sie LAME oder einen anderen MP3-Kodierer, um die CD-Audio-Titel in
Dateien zu extrahieren. Benennen Sie die Dateien in track1.mp3, track2.mp3 usw.
@@ -2065,7 +2285,7 @@ LAME-Befehl in der Kommandozeile geschehen:
lame -t -q 0 -b 96 track1.wav track1.mp3
-7.8.1) Ogg-Vorbis-Dateien für Audio von CD verwenden:
+7.8.2) Ogg-Vorbis-Dateien für Audio von CD verwenden:
------ ----------------------------------------------
Verwenden Sie oggenc oder einen anderen Vorbis-Kodierer, um die CD-Audio-Titel
in Dateien umzuwandeln. Benennen Sie die Dateien in track1.ogg, track2.ogg usw.
@@ -2078,7 +2298,7 @@ gewünschte Qualität zwischen 0 und 10 festlegt:
oggenc -q 5 track1.wav
-7.8.2) FLAC-Dateien für Audio von CD verwenden:
+7.8.3) FLAC-Dateien für Audio von CD verwenden:
------ ----------------------------------------
Verwenden Sie flac oder einen anderen FLAC-Kodierer, um die CD-Audio-Titel in
Dateien umzuwandeln. Benennen Sie die Dateien in track1.flac, track2.flac usw.
@@ -2096,7 +2316,7 @@ Kodieroptionen nur Auswirkungen auf die Kodierzeit und letztendliche Dateigröß
haben.
-7.8.3) MONSTER.SOU mittels MP3 komprimieren:
+7.8.4) MONSTER.SOU mittels MP3 komprimieren:
------ -------------------------------------
Sie benötigen LAME und unser Dienstprogramm „compress_scumm_sou“ aus dem
ScummVM-Tools-Paket, um diese Aufgabe zu verrichten, und ScummVM muss mit
@@ -2109,7 +2329,7 @@ Datei ins Verzeichnis des Spiels. Sie können unbesorgt die Datei monster.sou
hieraus entfernen.
-7.8.4) MONSTER.SOU mittels Ogg Vorbis komprimieren:
+7.8.5) MONSTER.SOU mittels Ogg Vorbis komprimieren:
------ --------------------------------------------
Ähnlich wie oben muss ScummVM mit Ogg-Unterstützung kompiliert sein. Rufen Sie
auf:
@@ -2121,7 +2341,7 @@ Verzeichnis des Spiels kopieren sollten. Die Umwandlung in Ogg kann beträchtlic
länger dauern als bei MP3, also sollten Sie ein gutes Buch zur Hand haben.
-7.8.5) MONSTER.SOU mittels FLAC komprimieren:
+7.8.6) MONSTER.SOU mittels FLAC komprimieren:
------ --------------------------------------
Ähnlich wie oben muss ScummVM mit FLAC-Unterstützung kompiliert sein. Rufen Sie
auf:
@@ -2138,7 +2358,7 @@ auf jeden Fall die Dokumentation des Kodierers, bevor Sie einen anderen Wert
verwenden.
-7.8.6) Musik/Sound/Sprachausgabe in AGOS-Spielen komprimieren:
+7.8.7) Musik/Sound/Sprachausgabe in AGOS-Spielen komprimieren:
------ -------------------------------------------------------
Verwenden Sie unser Dienstprogramm „compress_agos“ aus dem ScummVM-Tools-Paket,
um diese Aufgabe zu verrichten. Sie können zwischen mehreren Zielformaten
@@ -2175,7 +2395,7 @@ Kopieren Sie diese Datei ins Verzeichnis des Spiels. Sie können unbesorgt die
alte Datei hieraus entfernen.
-7.8.7) Sprachausgabe/Musik in Baphomets Fluch komprimieren:
+7.8.8) Sprachausgabe/Musik in Baphomets Fluch komprimieren:
------ ----------------------------------------------------
Das Tool „compress_sword1“ aus dem ScummVM-Tools-Paket kann Musik und
Sprachausgabe des Spiels sowohl in MP3, Ogg Vorbis als auch FLAC kodieren. Die
@@ -2195,7 +2415,7 @@ Rufen Sie „compress_sword1 --help“ auf, um eine komplette Liste der Optionen
angezeigt zu bekommen.
-7.8.8) Sprachausgabe/Musik in Baphomets Fluch II komprimieren:
+7.8.9) Sprachausgabe/Musik in Baphomets Fluch II komprimieren:
------ -------------------------------------------------------
Verwenden Sie unser Dienstprogramm „compress_sword2“ aus dem
ScummVM-Tools-Paket, um diese Aufgabe zu verrichten. Sie können zwischen
@@ -2278,7 +2498,17 @@ Standardmäßig wird die Konfigurationsdatei hier gespeichert und geladen:
der frühere Standard-Ort „<Windows-Verzeichnis>\scummvm.ini“ beibehalten.
Unix:
- ~/.scummvmrc
+ Wir befolgen die Spezifikation XDG Base Directory. Dies bedeutet, dass
+ unsere Konfiguration in
+ $XDG_DATA_HOME/scummvm/scummvm.ini
+ gefunden werden kann.
+
+ Wenn XDG_DATA_HOME nicht definiert oder leer ist, wird ~/.local/share als
+ Wert für XDG_DATA_HOME in Übereinstimmung mit der Spezifikation verwendet.
+
+ Wenn eine frühere Version von ScummVM auf Ihrem System installiert war, wird
+ das ursprüngliche Standard-Verzeichnis „~/.scummvm“ beibehalten. Dies wird
+ daran erkannt, dass der Pfad „~/.scummvm“ vorhanden ist.
Mac OS X:
~/Library/Preferences/ScummVM Preferences
@@ -2554,7 +2784,7 @@ Schlüsselwort:
Geschwindigkeit wiedergegeben, um Probleme bei
der Musik-Synchronität zu vermeiden.
-Zork Nemesis: The Forbidden Lands verfügt zusätzlich über folgende nicht
+Zork Nemesis: Das verbotene Land verfügt zusätzlich über folgende nicht
standardmäßige Schlüsselwörter:
originalsaveload Bool Falls „true“, werden die originalen Menüs zum
@@ -2565,12 +2795,26 @@ standardmäßige Schlüsselwörter:
noanimwhileturning Bool Falls „true“, werden Animationen während des
Drehens im Panorama-Modus deaktiviert.
mpegmovies Bool Falls „true“, werden hochauflösende MPEG-Videos
- der DVD-Version im Spiel verwendet, anstelle der
+ der DVD-Version im Spiel verwendet anstelle der
niedrig auflösenden AVI-Videos.
+Zork: Der Großinquisitor verfügt zusätzlich über folgende nicht standardmäßige
+Schlüsselwörter:
-8.2) Spielspezifische Optionen bei der grafischen Benutzeroberfläche
----- ---------------------------------------------------------------
+ originalsaveload Bool Falls „true“, werden die originalen Menüs zum
+ Speichern und Laden statt der erweiterten
+ von ScummVM verwendet.
+ doublefps Bool Falls „true“, wird die Bildwiederholrate von 30
+ auf 60 Bilder pro Sekunde erhöht.
+ noanimwhileturning Bool Falls „true“, werden Animationen während des
+ Drehens im Panorama-Modus deaktiviert.
+ mpegmovies Bool Falls „true“, werden hochauflösende MPEG-Videos
+ der DVD-Version im Spiel verwendet anstelle der
+ niedrig auflösenden AVI-Videos.
+
+
+8.2) Spielspezifische Optionen bei der grafischen Benutzeroberfläche:
+---- ----------------------------------------------------------------
Viele spielspezifische Optionen, die im vorigen Abschnitt aufgeführt wurden,
können über die grafische Benutzeroberfläche angesprochen werden. Falls eine
spielspezifische Option für ein bestimmtes Spiel verfügbar ist, erscheint ein
@@ -2581,8 +2825,8 @@ Spieleliste hinzugefügt werden. Dadurch wird die Konfiguration von jedem Eintra
aktualisiert, was die spielspezifischen Optionen zum Vorschein bringt.
-9.0) Kompilierung:
----- -------------
+9.0) Kompilieren:
+---- ------------
Für eine aktuelle Übersicht dazu, wie man ScummVM für unterschiedliche
Plattformen kompiliert, schauen Sie bitte in unserem Wiki nach, insbesondere auf
dieser Seite:
@@ -2590,90 +2834,126 @@ dieser Seite:
Wenn Sie für Windows, Linux oder Mac OS X kompilieren, benötigen Sie SDL-1.2.2
oder höher (ältere Versionen funktionieren möglicherweise, haben aber keinen
-Support) und einen unterstützten Kompilierer. Mehrere Kompilierer,
-einschließlich GCC, mingw und neue Versionen von Microsoft Visual C++ werden
-unterstützt. Wenn Sie mit MP3 komprimierte CD-Titel oder .SOU-Dateien verwenden
-möchten, müssen Sie die MAD-Bibliothek installieren; ebenso benötigen Sie die
-geeigneten Bibliotheken für Sound-Dateien, die mit Ogg Vorbis und FLAC
-komprimiert wurden. Für komprimierte Speicherstände ist zlib erforderlich.
+Support) und einen unterstützten Compiler. Mehrere Compiler, einschließlich GCC,
+mingw und neue Versionen von Microsoft Visual C++ werden unterstützt. Wenn Sie
+mit MP3 komprimierte CD-Titel oder .SOU-Dateien verwenden möchten, müssen Sie
+die MAD-Bibliothek installieren; ebenso benötigen Sie die geeigneten
+Bibliotheken für Sound-Dateien, die mit Ogg Vorbis und FLAC komprimiert wurden.
+Für komprimierte Speicherstände ist zlib erforderlich.
Von einigen Teilen in ScummVM, insbesondere Grafikwandlern, gibt es stark
optimierte Versionen, die in Assembler geschrieben sind. Wenn Sie diese
verwenden möchten, müssen Sie den Assembler nasm installieren
(siehe http://nasm.sf.net). Beachten Sie, dass wir momentan nur für x86 MMX
optimierte Versionen haben und diese auf keinem anderen Prozessor kompiliert
-werden.
+werden können.
Bei Win9x/NT/XP können Sie USE_WINDBG definieren und WinDbg anhängen, um
Debug-Nachrichten zu durchsuchen
(siehe http://www.sysinternals.com/ntw2k/freeware/debugview.shtml).
- GCC und MinGW32:
- * Geben Sie „./configure“ ein.
- * Geben Sie „make“ ein (oder „gmake“ bzw. „gnumake“, abhängig davon,
- wie GNU make auf Ihrem System genannt wird) und mit
- etwas Glück wird ScummVM für Sie kompiliert.
- * Weitere Information finden Sie hier:
- http://wiki.scummvm.org/index.php/Compiling_ScummVM/GCC
- entsprechend
- http://wiki.scummvm.org/index.php/Compiling_ScummVM/MinGW
- Microsoft Visual C++ 9 und höher:
- * Lesen Sie nach, wie man die Projektmappendatei im entsprechenden
- „dists\msvc*“-Verzeichnis erstellt.
- * Öffnen Sie die erstellte Projektmappendatei.
- * Geben Sie die Pfade zu den benötigten Bibliotheksdateien
- und Includedateien unter
- „Extras|Optionen|Projekte und Projektmappen|VC++-Verzeichnisse“ ein.
- * Jetzt sollte das Programm erfolgreich kompiliert werden können.
- * Weitere Information finden Sie hier:
+ Windows:
+ * Dev-C++
+ Weiterführende Informationen finden Sie unter:
+ http://wiki.scummvm.org/index.php/Compiling_ScummVM/DevCPP
+ * MinGW
+ Weiterführende Informationen finden Sie unter:
+ http://wiki.scummvm.org/index.php/Compiling_ScummVM/MinGW
+ * Visual Studio (MSVC)
+ Weiterführende Informationen finden Sie unter:
http://wiki.scummvm.org/index.php/Compiling_ScummVM/Visual_Studio
-
- Windows Mobile:
- * Bitte lesen Sie:
+ * Windows CE/Mobile
+ Weiterführende Informationen finden Sie unter:
http://wiki.scummvm.org/index.php/Compiling_ScummVM/Windows_CE
- Mac OS X:
- * Stellen Sie sicher, dass Sie die „Developer“-Tools installiert haben.
- * Das „Developer“-Paket von SDL für OS X, das auf der SDL-Website
- zur Verfügung steht, ist _nicht_ geeignet. Sie benötigen stattdessen eine
- SDL-Zusammenstellung im UNIX-Stil. Eine Möglichkeit, diese zu erhalten,
- ist, SDL über Fink zu installieren (http://fink.sf.net). Alternativ können
- Sie SDL mittels Quellcode manuell kompilieren, indem Sie dessen
- UNIX-Zusammenstellungssystem verwenden (configure && make).
- * Geben Sie „./configure“ im ScummVM-Verzeichnis ein.
- * Sie können nun „make“ eingeben, um eine von der Kommandozeile aus
- aufrufbare Binärdatei zu erstellen.
- * Um eine Version zu erhalten, die Sie vom Finder aus aufrufen können, geben
- Sie „make bundle“ ein, wodurch ScummVM.app erstellt wird (das funktioniert
- nur dann auf Anhieb, wenn Sie SDL in das Verzeichnis /sw installiert haben
- [wie es bei der Verwendung von Fink getan wird].
- Wenn Sie SDL auf andere Weise installiert haben, müssen Sie
- die Datei ports.mk von ScummVM bearbeiten.
- * Weitere Information finden Sie hier:
- http://wiki.scummvm.org/index.php/Compiling_ScummVM/MacOS_X_Crosscompiling
-
- AmigaOS 4 (Cross-Kompilation mit Cygwin):
- * Stellen Sie sicher, dass Sie SDL installiert haben. Sie benötigen
- womöglich auch libogg, libvorbis, libvorbisfile, zlib und libmad.
- * Geben Sie „./configure --host=ppc-amigaos“ ein.
- * Wenn Sie einen Fehler wegen sdl-config erhalten, verwenden Sie den
- Parameter „--with-sdl-prefix“, um den Pfad zu bestimmen.
- * Überprüfen Sie die Datei „config.mk“ und wenn alles in Ordnung
- zu sein scheint:
- * Rufen Sie „make“ auf.
- * Cross-Kompilation mit Linux ist womöglich genauso einfach.
-
- iPhone:
- * Bitte lesen Sie:
+ Linux:
+ * GCC
+ Weiterführende Informationen finden Sie unter:
+ http://wiki.scummvm.org/index.php/Compiling_ScummVM/GCC
+
+ AmigaOS4:
+ Weiterführende Informationen finden Sie unter:
+ http://wiki.scummvm.org/index.php/AmigaOS
+
+ Apple iPhone:
+ Weiterführende Informationen finden Sie unter:
http://wiki.scummvm.org/index.php/Compiling_ScummVM/iPhone
- Maemo:
- * Installieren Sie Maemo SDK mit rootstrap 4.1.2.
- * Installieren Sie libmad, Tremor und FLAC mittels Quellcode.
- * Rufen Sie „ln -s backends/platform/maemo/debian“ auf.
- * Aktualisieren Sie debian/changelog.
- * Rufen Sie „sb2 dpkg-buildpackage -b“ auf.
+ Atari/FreeMiNT:
+ Weiterführende Informationen finden Sie unter:
+ http://wiki.scummvm.org/index.php/Compiling_ScummVM/Atari/FreeMiNT
+
+ Bada/Tizen:
+ Weiterführende Informationen finden Sie unter:
+ http://wiki.scummvm.org/index.php/Compiling_ScummVM/Bada/Tizen
+
+ BeOS/ZETA/Haiku:
+ Weiterführende Informationen finden Sie unter:
+ http://wiki.scummvm.org/index.php/Compiling_ScummVM/BeOS/ZETA/Haiku
+
+ Google Android:
+ Weiterführende Informationen finden Sie unter:
+ http://wiki.scummvm.org/index.php/Compiling_ScummVM/Android
+
+ HP webOS:
+ Weiterführende Informationen finden Sie unter:
+ http://wiki.scummvm.org/index.php/Compiling_ScummVM/WebOS
+
+ Mac OS:
+ * Mac OS X
+ Weiterführende Informationen finden Sie unter:
+ http://wiki.scummvm.org/index.php/Mac_OS_X
+ * Mac OS X 10.2.8
+ Weiterführende Informationen finden Sie unter:
+ http://wiki.scummvm.org/index.php/Compiling_ScummVM/Mac_OS_X_10.2.8
+ * Mac OS X Crosscompiling
+ Weiterführende Informationen finden Sie unter:
+http://wiki.scummvm.org/index.php/Compiling_ScummVM/Mac_OS_X_Crosscompiling
+
+ Maemo:
+ Weiterführende Informationen finden Sie unter:
+ http://wiki.scummvm.org/index.php/Compiling_ScummVM/Maemo
+
+ Nintendo DS:
+ Weiterführende Informationen finden Sie unter:
+ http://wiki.scummvm.org/index.php/Compiling_ScummVM/Nintendo_DS
+
+ Nintendo Wii and Gamecube:
+ Weiterführende Informationen finden Sie unter:
+ http://wiki.scummvm.org/index.php/Compiling_ScummVM/Wii
+
+ RaspberryPi:
+ Weiterführende Informationen finden Sie unter:
+ http://wiki.scummvm.org/index.php/Compiling_ScummVM/RPI
+
+ Sega Dreamcast:
+ Weiterführende Informationen finden Sie unter:
+ http://wiki.scummvm.org/index.php/Compiling_ScummVM/Dreamcast
+
+ Sony Playstation:
+ * Sony PlayStation 2
+ Weiterführende Informationen finden Sie unter:
+ http://wiki.scummvm.org/index.php/Compiling_ScummVM/PlayStation_2
+ * Sony PlayStation 3
+ Weiterführende Informationen finden Sie unter:
+ http://wiki.scummvm.org/index.php/PlayStation_3#Building_from_source
+ * Sony PlayStation Portable
+ Weiterführende Informationen finden Sie unter:
+ http://wiki.scummvm.org/index.php/Compiling_ScummVM/PlayStation_Portable
+
+ Symbian:
+ Weiterführende Informationen finden Sie unter:
+ http://wiki.scummvm.org/index.php/Compiling_ScummVM/Symbian
+
+
+10.0) Mitwirkende
+----- -------
+Eine ausführliche Liste derjenigen, die ScummVM ermöglicht haben, finden Sie
+unter:
+
+ http://www.scummvm.org/credits/
+
------------------------------------------------------------------------
Viel Glück und viel Spaß beim Spielen wünscht
diff --git a/doc/de/Neues b/doc/de/Neues
index 2b67913359..6870accf40 100644
--- a/doc/de/Neues
+++ b/doc/de/Neues
@@ -1,24 +1,171 @@
-Umfangreichere Änderungsaufzeichnungen des neusten experimentellen Codes finden
-Sie auf Englisch unter:
+Umfangreichere Informationen über die Änderungen des aktuellen experimentellen
+Programmcodes finden Sie auf Englisch unter:
https://github.com/scummvm/scummvm/commits/
-1.8.0 (??.??.????)
+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.
- Unterstützung für Sfinx hinzugefügt.
- - Unterstützung für Zork Nemesis: The Forbidden Lands hinzugefügt.
- - Unterstützung für Zork: Grand Inquisitor hinzugefügt.
+ - Unterstützung für Zork Nemesis: Das verbotene Land hinzugefügt.
+ - Unterstützung für Zork: Der Großinquisitor hinzugefügt.
+ - Unterstützung für Die ungelösten Fälle von Sherlock Holmes: Das gezackte
+ Skalpell hinzugefügt.
+ - Unterstützung für Die ungelösten Fälle von Sherlock Holmes: Das Geheimnis
+ der tätowierten Rose hinzugefügt.
+ - Unterstützung für Beavis and Butthead in Virtual Stupidity hinzugefügt.
+ - Unterstützung für Amazon: Guardians of Eden hinzugefügt.
+ - Unterstützung für Baphomets Fluch 2.5: Die Rückkehr der Tempelritter
+ hinzugefügt.
+ - Unterstützung für Labyrinth of Time hinzugefügt.
+
+ Neue Portierungen:
+ - Portierung für den Raspberry Pi hinzugefügt.
+ - Portierung für den GCW Zero (GCW0) hinzugefügt.
Allgemein:
- Code für Munt-MT-32-Emulation auf Version 1.5.0 aktualisiert.
+ 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
+ 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
+ unterstützen weiterhin die vorherigen Speicherorte. Solange diese vorhanden
+ sind, werden wir diese weiter verwenden. Bitte beachten Sie die
+ Liesmich-Datei für weitere Informationen. Speicherorte auf Mac OS X sind
+ von dieser Änderung nicht betroffen.
+
3 Skulls of the Toltecs:
- Unterstützung für AdLib-Musik verbessert.
AGI:
- Es ist nun möglich, die Maus-Unterstützung zu deaktivieren (außer bei
-Amiga-Versionen und Fan-Spielen, die eine Maus benötigen).
- - Fehlerhafte Lautstärke-Dämpfung im PCjr-Sound-Code behoben (Fehler #6858).
+ Amiga-Versionen und Fan-Spielen, die eine Maus benötigen).
+ - Fehlerhafte Lautstärke in PCjr-Spielen korrigiert.
+ - Umfangreiche Änderung im Grafik-Subsystem.
+ - Unterstützung für Übergänge, Schriftarten und Mauszeigern für Apple IIgs,
+ Amiga und Atari (die Systemschriftart Atari ST 8x8 ist nicht in ScummVM
+ enthalten)
+ - Eine PC-Version kann jetzt wie eine Apple IIgs-Version dargestellt werden
+ (inklusive Farbpalette, Cursor, Übergänge und Schriftart). Sie müssen
+ lediglich den gewünschten Darstellungsmodus auswählen.
+ - Apple IIgs-Spiele laufen nicht mehr zu schnell.
+ - Unterstützung für automatisches Speichern / Laden hinzugefügt
+ (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.
AGOS:
- Arpeggio-Effekt in der Musik der Amiga-Version von Elvira 1 repariert.
@@ -26,13 +173,18 @@ Amiga-Versionen und Fan-Spielen, die eine Maus benötigen).
- Verb-Feld in der Amiga-Version von Simon the Sorcerer 1 repariert.
- Accolade AdLib- und MT32-Treiber für folgende Spiele hinzugefügt:
Elvira 1, Elvira 2, Waxworks und Simon the Sorcerer 1 (Demoversion)
+ - AdLib-Ausgabe in Simon the Sorcerer 1 hinzugefügt. Dies verbessert die
+ AdLib-Ausgabe erheblich und erhöht die Originaltreue.
Baphomets Fluch 1:
- - Erkennung der Byte-Reihenfolge der Sprachausgabe auf Big-Endian-Systemen
- für die Macintosh-Version (Fehler #6720) repariert.
- - Absturz beim Neuladen eines Spiels aus dem Hauptmenü heraus, während sich
- das Spiel in der Szene am Bull's Head Hill befindet, behoben
- (Fehler #6728). Dieser Fehler trat womöglich auch in anderen Szenen auf.
+ - 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
+ in anderen Szenen auf.
+
+ CinE:
+ - Unterstützung für Musik in der CD-Version von Future Wars hinzugefügt.
MADE:
- Unterstützung für AdLib-Musik in Return to Zork verbessert.
@@ -43,15 +195,23 @@ Amiga-Versionen und Fan-Spielen, die eine Maus benötigen).
SCI:
- Behandlung der Musik-Priorität extrem verbessert.
- Viele Fehler in den originalen Skripten behoben, die auch bei
- Verwendung des originalen Interpreters auftreten:
- KQ6 (Sprache und Untertitel), LSL5, QfG1 (EGA), QfG (VGA), QfG2, QfG3,
- SQ1, SQ4 (CD)
+ Verwendung des originalen Interpreters auftreten.
+ Folgende Spiele sind davon betroffen:
+ KQ6 (Sprache und Untertitel), LSL5, PQ1, QfG1 (EGA), QfG (VGA),
+ QfG2, QfG3, SQ1, SQ4 (CD)
- Rückkehr aus dem ScummVM-Menü im Spiel sollte nun immer funktionieren.
- Verbesserte Unterstützung für japanische PC-9801-Spiele
+ - Verwende standardmäßig die hochauflösende Version von KQ6
+ (kann in den Spieloptionen umgeschaltet werden)
SCUMM:
+ - Umfangreiche Verbesserung der Textdarstellung in koreanischen Versionen
+ - Originaler Code der Geh-Animation in Maniac Mansion v0-v1 hinzugefügt.
- Es ist nun möglich, Maniac Mansion innerhalb von Day of the
Tentacle zu spielen. Bitte Liesmich-Datei für weitere Details lesen.
+ - Alt+x kann jetzt auf allen Plattformen dazu verwendet werden, SCUMM-Spiele
+ zu beenden.
+ - Lippensynchronisation in neueren Spielen von Humongous Entertainment verbessert.
Tinsel:
- Unterstützung für AdLib-Musik in Discworld 1 verbessert.
diff --git a/engines/access/access.cpp b/engines/access/access.cpp
index 56fa6c7533..6f91bd76dd 100644
--- a/engines/access/access.cpp
+++ b/engines/access/access.cpp
@@ -34,19 +34,24 @@ namespace Access {
AccessEngine::AccessEngine(OSystem *syst, const AccessGameDescription *gameDesc)
: _gameDescription(gameDesc), Engine(syst), _randomSource("Access"),
_useItem(_flags[99]), _startup(_flags[170]), _manScaleOff(_flags[172]) {
+ _aboutBox = nullptr;
_animation = nullptr;
_bubbleBox = nullptr;
_char = nullptr;
_debugger = nullptr;
_events = nullptr;
_files = nullptr;
+ _invBox = nullptr;
_inventory = nullptr;
+ _helpBox = nullptr;
_midi = nullptr;
_player = nullptr;
+ _res = nullptr;
_room = nullptr;
_screen = nullptr;
_scripts = nullptr;
_sound = nullptr;
+ _travelBox = nullptr;
_video = nullptr;
_destIn = nullptr;
@@ -130,6 +135,7 @@ AccessEngine::~AccessEngine() {
delete _inventory;
delete _midi;
delete _player;
+ delete _res;
delete _room;
delete _screen;
delete _scripts;
@@ -204,6 +210,13 @@ void AccessEngine::initialize() {
}
Common::Error AccessEngine::run() {
+ _res = Resources::init(this);
+ Common::String errorMessage;
+ if (!_res->load(errorMessage)) {
+ GUIErrorMessage(errorMessage);
+ return Common::kNoError;
+ }
+
setVGA();
initialize();
@@ -231,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;
@@ -312,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;
@@ -423,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 37b9fec5a5..972dd4c380 100644
--- a/engines/access/access.h
+++ b/engines/access/access.h
@@ -42,6 +42,7 @@
#include "access/font.h"
#include "access/inventory.h"
#include "access/player.h"
+#include "access/resources.h"
#include "access/room.h"
#include "access/screen.h"
#include "access/scripts.h"
@@ -147,6 +148,7 @@ public:
FileManager *_files;
InventoryManager *_inventory;
Player *_player;
+ Resources *_res;
Room *_room;
Screen *_screen;
Scripts *_scripts;
@@ -154,8 +156,8 @@ public:
MusicManager *_midi;
VideoPlayer *_video;
- ASurface *_destIn;
- ASurface *_current;
+ BaseSurface *_destIn;
+ BaseSurface *_current;
ASurface _buffer1;
ASurface _buffer2;
ASurface _vidBuf;
@@ -278,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
@@ -313,6 +315,8 @@ public:
void SPRINTCHR(char c, int fontNum);
void PRINTCHR(Common::String msg, int fontNum);
+
+ bool playMovie(const Common::String &filename, const Common::Point &pos);
};
} // End of namespace Access
diff --git a/engines/access/amazon/amazon_game.cpp b/engines/access/amazon/amazon_game.cpp
index 7a55873d97..8467d8b623 100644
--- a/engines/access/amazon/amazon_game.cpp
+++ b/engines/access/amazon/amazon_game.cpp
@@ -146,27 +146,24 @@ void AmazonEngine::playGame() {
}
void AmazonEngine::setupGame() {
+ Amazon::AmazonResources &res = *((Amazon::AmazonResources *)_res);
+
// Load death list
- if (isDemo()) {
- _deaths.resize(34);
- for (int i = 0; i < 34; ++i) {
- _deaths[i]._screenId = DEATH_SCREENS_DEMO[i];
- _deaths[i]._msg = DEATH_TEXT_DEMO[i];
- }
- } else {
- _deaths.resize(58);
- for (int i = 0; i < 58; ++i) {
- _deaths[i]._screenId = DEATH_SCREENS[i];
- _deaths[i]._msg = DEATH_TEXT[i];
- }
+ _deaths.resize(_res->DEATHS.size());
+
+ for (uint idx = 0; idx < _deaths.size(); ++idx) {
+ _deaths[idx]._screenId = res.DEATHS[idx]._screenId;
+ _deaths[idx]._msg = res.DEATHS[idx]._msg;
}
+
+ // Load the deaths cells
_deaths._cells.resize(13);
for (int i = 0; i < 13; ++i)
_deaths._cells[i] = CellIdent(DEATH_CELLS[i][0], DEATH_CELLS[i][1], DEATH_CELLS[i][2]);
// Miscellaneous
- _fonts._font1.load(FONT6x6_INDEX, FONT6x6_DATA);
- _fonts._font2.load(FONT2_INDEX, FONT2_DATA);
+ _fonts._font1.load(&res.FONT6x6_INDEX[0], &res.FONT6x6_DATA[0]);
+ _fonts._font2.load(&res.FONT2_INDEX[0], &res.FONT2_DATA[0]);
initVariables();
}
@@ -195,8 +192,8 @@ void AmazonEngine::initVariables() {
_timers.push_back(te);
}
- _player->_playerX = _player->_rawPlayer.x = _travelPos[_player->_roomNumber][0];
- _player->_playerY = _player->_rawPlayer.y = _travelPos[_player->_roomNumber][1];
+ _player->_playerX = _player->_rawPlayer.x = _res->ROOMTBL[_player->_roomNumber]._travelPos.x;
+ _player->_playerY = _player->_rawPlayer.y = _res->ROOMTBL[_player->_roomNumber]._travelPos.y;
_room->_selectCommand = -1;
_events->setNormalCursor(CURSOR_CROSSHAIRS);
_mouseMode = 0;
@@ -411,6 +408,7 @@ void AmazonEngine::calcIQ() {
}
void AmazonEngine::helpTitle() {
+ AmazonResources &res = *(AmazonResources *)_res;
int width = _fonts._font2.stringWidth(_bubbleBox->_bubbleTitle);
int posX = 160 - (width / 2);
_fonts._font2._fontColors[0] = 0;
@@ -419,13 +417,13 @@ void AmazonEngine::helpTitle() {
_fonts._font2._fontColors[3] = 35;
_fonts._font2.drawString(_screen, _bubbleBox->_bubbleTitle, Common::Point(posX, 24));
- width = _fonts._font2.stringWidth(HELPLVLTXT[_helpLevel]);
+ width = _fonts._font2.stringWidth(res.HELPLVLTXT[_helpLevel]);
posX = 160 - (width / 2);
_fonts._font2._fontColors[0] = 0;
_fonts._font2._fontColors[1] = 10;
_fonts._font2._fontColors[2] = 11;
_fonts._font2._fontColors[3] = 12;
- _fonts._font2.drawString(_screen, HELPLVLTXT[_helpLevel], Common::Point(posX, 36));
+ _fonts._font2.drawString(_screen, res.HELPLVLTXT[_helpLevel], Common::Point(posX, 36));
Common::String iqText = "IQ: ";
calcIQ();
@@ -441,7 +439,7 @@ void AmazonEngine::helpTitle() {
index /= 20;
iqText += " ";
- iqText += IQLABELS[index];
+ iqText += res.IQLABELS[index];
width = _fonts._font2.stringWidth(iqText);
posX = 160 - (width / 2);
@@ -498,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;
@@ -619,7 +617,12 @@ void AmazonEngine::startChapter(int chapter) {
_establishGroup = 1;
loadEstablish(0x40 + _chapter);
- uint16 msgOffset = READ_LE_UINT16(_establish->data() + ((0x40 + _chapter) * 2) + 2);
+
+ byte *entryOffset = _establish->data() + ((0x40 + _chapter) * 2);
+ if (isCD())
+ entryOffset += 2;
+
+ uint16 msgOffset = READ_LE_UINT16(entryOffset);
_printEnd = 170;
Common::String msg((const char *)_establish->data() + msgOffset);
@@ -642,25 +645,27 @@ void AmazonEngine::startChapter(int chapter) {
_room->init4Quads();
}
- if (chapter == 14) {
- _conversation = 31;
- _char->loadChar(_conversation);
- _events->setCursor(CURSOR_ARROW);
+ if (isCD()) {
+ if (chapter == 14) {
+ _conversation = 31;
+ _char->loadChar(_conversation);
+ _events->setCursor(CURSOR_ARROW);
- _images.clear();
- _oldRects.clear();
- _scripts->_sequence = 0;
- _scripts->searchForSequence();
+ _images.clear();
+ _oldRects.clear();
+ _scripts->_sequence = 0;
+ _scripts->searchForSequence();
- if (_screen->_vesaMode) {
- _converseMode = 1;
- }
- } else if (chapter != 1) {
- _player->_roomNumber = CHAPTER_JUMP[_chapter - 1];
- _room->_function = FN_CLEAR1;
- _converseMode = 0;
+ if (_screen->_vesaMode) {
+ _converseMode = 1;
+ }
+ } else if (chapter != 1) {
+ _player->_roomNumber = CHAPTER_JUMP[_chapter - 1];
+ _room->_function = FN_CLEAR1;
+ _converseMode = 0;
- _scripts->cmdRetPos();
+ _scripts->cmdRetPos();
+ }
}
}
diff --git a/engines/access/amazon/amazon_logic.cpp b/engines/access/amazon/amazon_logic.cpp
index de53da51cd..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();
}
}
@@ -1251,6 +1259,9 @@ Cast::Cast(AmazonEngine *vm) : PannedScene(vm) {
void Cast::doCast(int param1) {
Screen &screen = *_vm->_screen;
+ _vm->_buffer1.create(_vm->_screen->w, _vm->_screen->h);
+ _vm->_buffer2.create(_vm->_screen->w, _vm->_screen->h);
+
screen.setDisplayScan();
_vm->_events->hideCursor();
screen.forceFadeOut();
@@ -1294,8 +1305,8 @@ void Cast::doCast(int param1) {
_pan[i]._pObjXl = _pan[i]._pObjYl = 0;
}
- _pNumObj = 4;
- for (int i = 0; i < _pNumObj; i++) {
+ _pNumObj += 4;
+ for (int i = 0; i < 4; i++) {
_pan[26 + i]._pObject = _vm->_objectsTable[1];
_pan[26 + i]._pImgNum = CAST_END_OBJ1[i][0];
_pan[26 + i]._pObjX = CAST_END_OBJ1[i][1];
@@ -1319,20 +1330,16 @@ void Cast::doCast(int param1) {
_vm->plotList();
_vm->copyBlocks();
- _vm->_events->pollEvents();
+ for (int idx = 0; idx < 5 && !_vm->shouldQuit() &&
+ !_vm->_events->isKeyMousePressed(); ++idx)
+ _vm->_events->pollEventsAndWait();
+
if (_vm->_events->isKeyMousePressed())
break;
if (_yCam < -7550) {
- _vm->_events->_vbCount = 50;
-
- while (!_vm->shouldQuit() && !_vm->_events->isKeyMousePressed() && _vm->_events->_vbCount > 0) {
- _vm->_events->pollEventsAndWait();
- }
-
while (!_vm->shouldQuit() && !_vm->_midi->checkMidiDone())
_vm->_events->pollEventsAndWait();
-
break;
}
}
@@ -1598,7 +1605,7 @@ void River::moveCanoe() {
if (events._leftButton && pt.y >= 140) {
if (pt.x < _vm->_room->_rMouse[8][0]) {
// Disk icon wasn't clicked
- _vm->_scripts->printString(BAR_MESSAGE);
+ _vm->_scripts->printString(AMRES.BAR_MESSAGE);
} else {
// Clicked on the Disc icon. Show the ScummVM menu
_vm->_room->handleCommand(9);
diff --git a/engines/access/amazon/amazon_resources.cpp b/engines/access/amazon/amazon_resources.cpp
index 430aa64f30..7dbe1c9f90 100644
--- a/engines/access/amazon/amazon_resources.cpp
+++ b/engines/access/amazon/amazon_resources.cpp
@@ -27,50 +27,60 @@ namespace Access {
namespace Amazon {
-const char *const FILENAMES[] = {
- "S00.AP", "S01.AP", "S02.AP", "R03.AP", "S04.AP", "S05.AP",
- "S06.AP", "S07.AP", "S08.AP", "S09.AP", "S10.AP", "S11.AP",
- "S12.AP", "S13.AP", "S14.AP", "S15.AP", "S16.AP", "S17.AP",
- "S18.AP", "S19.AP", "S20.AP", "S21.AP", "S22.AP", "S23.AP",
- "S24.AP", "S25.AP", "S26.AP", "S27.AP", "S28.AP", "S29.AP",
- "S30.AP", "S31.AP", "S32.AP", "S33.AP", "S34.AP", "R35.AP",
- "S36.AP", "S37.AP", "S38.AP", "S39.AP", "S40.AP", "C26.AP",
- "S42.AP", "S01.AP", "S44.AP", "S45.AP", "S46.AP", "S47.AP",
- "C36.AP", nullptr, "S50.AP", nullptr, nullptr, "S53.AP",
- "S54.AP", "S55.AP", "C35.AP", "S57.AP", "S58.AP", nullptr,
- nullptr, "S61.AP", nullptr, nullptr, "S64.AP", "C00.AP",
- "C01.AP", "C06.AP", "C07.AP", "C08.AP", "C05.AP", "C09.AP",
- "C12.AP", "C03.AP", "C13.AP", "C15.AP", "C14.AP", "C16.AP",
- "C17.AP", "C19.AP", "C20.AP", "C21.AP", "C22.AP", "C23.AP",
- "C24.AP", "C25.AP", "C29.AP", "C30.AP", "C32.AP", "C33.AP",
- "C34.AP", "CREDITS.AP", "MIDIDRV.AP", "SUMMARY.AP", "DEAD.AP",
- "EST.AP", "CHAPTER.AP", "MIDI.AP", "SOUND.AP", "INV.AP",
- // The following files are only present in the CD version
- "NARATE01.AP", "NARATE02.AP", "NARATE03.AP", "NARATE04.AP",
- "NARATE05.AP", "NARATE06.AP", "NARATE07.AP", "NARATE08.AP",
- "NARATE09.AP", "NARATE10.AP", "NARATE11.AP", "NARATE12.AP",
- "NARATE13.AP", "NARATE14.AP", "S00.AP", "TAG.AP"
-};
-
-const char *const FILENAMES_DEMO[] = {
- "S00.AP", "S01.AP", "S02.AP", "R03.AP", "S04.AP", "S05.AP",
- "S06.AP", "S07.AP", "S08.AP", "S09.AP", "S10.AP", "S11.AP",
- "S12.AP", "S13.AP", "S14.AP", "S15.AP", "S16.AP", "S17.AP",
- "S18.AP", "S19.AP", "S20.AP", "S21.AP", "S22.AP", "S23.AP",
- "S24.AP", "S25.AP", "S26.AP", "S27.AP", "S28.AP", "S29.AP",
- "S30.AP", "S31.AP", "S32.AP", "S33.AP", "S34.AP", "R35.AP",
- "S36.AP", "S37.AP", "S38.AP", "S39.AP", "S40.AP", "TITLE.AP",
- "S42.AP", "S01.AP", "S44.AP", "S45.AP", "S46.AP", "S47.AP",
- nullptr, nullptr, "S50.AP", nullptr, nullptr, "S53.AP",
- "S54.AP", nullptr, nullptr, "S57.AP", nullptr, nullptr,
- nullptr, "S61.AP", nullptr, "C23.AP", "C12.AP", "C00.AP",
- "C01.AP", "C06.AP", "C07.AP", "C08.AP", "C05.AP", "C09.AP",
- "C12.AP", "C03.AP", "C13.AP", "C15.AP", "C14.AP", "C16.AP",
- "C17.AP", "C19.AP", "C20.AP", "C21.AP", "C22.AP", "C23.AP",
- "C24.AP", "C25.AP", "R49.AP", "R49.AP", "R49.AP", "R49.AP",
- "R49.AP", "R49.AP", "R49.AP", "R49.AP", "DEAD.AP", "EST.AP",
- "CHAPTER.AP", "MUSIC.AP", "SOUND.AP", "INV.AP"
-};
+void AmazonResources::load(Common::SeekableReadStream &s) {
+ Resources::load(s);
+ uint count;
+
+ // Load the version specific data
+ NO_HELP_MESSAGE = readString(s);
+ NO_HINTS_MESSAGE = readString(s);
+ RIVER_HIT1 = readString(s);
+ RIVER_HIT2 = readString(s);
+ BAR_MESSAGE = readString(s);
+
+ for (int idx = 0; idx < 3; ++idx)
+ HELPLVLTXT[idx] = readString(s);
+ for (int idx = 0; idx < 9; ++idx)
+ IQLABELS[idx] = readString(s);
+
+ CANT_GET_THERE = readString(s);
+
+ // Get the offset of the general shared data for the game
+ uint entryOffset = findEntry(_vm->getGameID(), 2, 0, (Common::Language)0);
+ s.seek(entryOffset);
+
+ // Read in the cursor list
+ count = s.readUint16LE();
+ CURSORS.resize(count);
+ for (uint idx = 0; idx < count; ++idx) {
+ uint count2 = s.readUint16LE();
+ CURSORS[idx].resize(count2);
+ s.read(&CURSORS[idx][0], count2);
+ }
+
+ // Load font data
+ count = s.readUint16LE();
+ FONT2_INDEX.resize(count);
+ for (uint idx = 0; idx < count; ++idx)
+ FONT2_INDEX[idx] = s.readSint16LE();
+
+ count = s.readUint16LE();
+ FONT2_DATA.resize(count);
+ for (uint idx = 0; idx < count; ++idx)
+ FONT2_DATA[idx] = s.readByte();
+
+ count = s.readUint16LE();
+ FONT6x6_INDEX.resize(count);
+ for (uint idx = 0; idx < count; ++idx)
+ FONT6x6_INDEX[idx] = s.readSint16LE();
+
+ count = s.readUint16LE();
+ FONT6x6_DATA.resize(count);
+ for (uint idx = 0; idx < count; ++idx)
+ FONT6x6_DATA[idx] = s.readByte();
+}
+
+/*------------------------------------------------------------------------*/
const int SIDEOFFR[] = { 5, 5, 5, 5, 5, 5, 5, 5, 0 };
const int SIDEOFFL[] = { 5, 5, 5, 5, 5, 5, 5, 5, 0 };
@@ -85,316 +95,6 @@ const int DIAGOFFULY[] = { 3, 3, 1, 2, 2, 1, 1, 1, 0 };
const int DIAGOFFDLX[] = { 4, 5, 3, 3, 5, 4, 6, 1, 0 };
const int DIAGOFFDLY[] = { 2, 2, 1, 2, 3, 1, 2, 1, 0 };
-const byte MOUSE0[] = {
- // hotspot x and y, uint16 LE
- 0, 0, 0, 0,
- // byte 1: number of skipped pixels
- // byte 2: number of plotted pixels
- // then, pixels
- 0, 2, 6, 1,
- 0, 3, 6, 6, 1,
- 0, 3, 6, 6, 1,
- 0, 4, 6, 6, 6, 1,
- 0, 4, 6, 6, 6, 1,
- 0, 5, 6, 6, 6, 6, 1,
- 0, 5, 6, 6, 6, 6, 1,
- 0, 6, 6, 6, 6, 6, 6, 1,
- 0, 6, 6, 6, 6, 6, 6, 1,
- 0, 7, 6, 6, 6, 6, 6, 6, 1,
- 0, 6, 6, 6, 6, 6, 6, 1,
- 0, 5, 6, 6, 6, 6, 1,
- 2, 3, 6, 6, 1,
- 3, 3, 6, 6, 1,
- 3, 3, 6, 6, 1,
- 4, 2, 6, 1
-};
-
-const byte MOUSE1[] = {
- // hotspot x and y, uint16 LE
- 0x07, 0x00, 0x07, 0x00,
- // byte 1: number of skipped pixels
- // byte 2: number of plotted pixels
- // then, pixels
- 0x06, 0x01, 0x05,
- 0x04, 0x05, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
- 0x03, 0x07, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
- 0x02, 0x09, 0xFF, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xFF,
- 0x01, 0x0B, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
- 0x01, 0x0B, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0xFF,
- 0x00, 0x0D, 0x05, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00, 0x05,
- 0x01, 0x0B, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0xFF,
- 0x01, 0x0B, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
- 0x02, 0x09, 0xFF, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xFF,
- 0x03, 0x07, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
- 0x04, 0x05, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
- 0x06, 0x01, 0x05,
- 0x00, 0x00,
- 0x00, 0x00,
- 0x00, 0x00
-};
-
-const byte MOUSE2[] = {
- // hotspot x and y, uint16 LE
- 0x08, 0x00, 0x08, 0x00,
- // byte 1: number of skipped pixels
- // byte 2: number of plotted pixels
- // then, pixels
- 0x00, 0x00,
- 0x00, 0x00,
- 0x07, 0x02, 0x04, 0x05,
- 0x07, 0x02, 0x04, 0x05,
- 0x07, 0x02, 0x04, 0x05,
- 0x07, 0x02, 0x04, 0x05,
- 0x07, 0x02, 0x04, 0x05,
- 0x02, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05,
- 0x07, 0x02, 0x04, 0x05,
- 0x07, 0x02, 0x04, 0x05,
- 0x07, 0x02, 0x04, 0x05,
- 0x07, 0x02, 0x04, 0x05,
- 0x07, 0x02, 0x04, 0x05,
- 0x00, 0x00,
- 0x00, 0x00,
- 0x00, 0x00
-};
-
-const byte MOUSE3[] = {
- // hotspot x and y, uint16 LE
- 0x00, 0x00, 0x00, 0x00,
- // byte 1: number of skipped pixels
- // byte 2: number of plotted pixels
- // then, pixels
- 0x00, 0x0B, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
- 0x00, 0x0C, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x05,
- 0x00, 0x0C, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x05, 0x05,
- 0x00, 0x0C, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05,
- 0x00, 0x0C, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05,
- 0x00, 0x0C, 0x06, 0x06, 0x06, 0x06, 0x05, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x05,
- 0x00, 0x0C, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05,
- 0x00, 0x0C, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05,
- 0x00, 0x0C, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05,
- 0x00, 0x0C, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05,
- 0x00, 0x0C, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05,
- 0x00, 0x0C, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05,
- 0x01, 0x0B, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
- 0x00, 0x00,
- 0x00, 0x00,
- 0x00, 0x00
-};
-const byte CURSEYE[] = {
- // hotspot x and y, uint16 LE
- 0x01, 0x00, 0x08, 0x00,
- // byte 1: number of skipped pixels
- // byte 2: number of plotted pixels
- // then, pixels
- 0x04, 0x06, 0x0E, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
- 0x03, 0x09, 0x0E, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x0D, 0x0D,
- 0x02, 0x0B, 0x0E, 0x01, 0x33, 0x33, 0x01, 0x01, 0x33, 0x34, 0x01, 0x01, 0x0D,
- 0x01, 0x0D, 0x0E, 0x01, 0x04, 0x34, 0x01, 0x01, 0x01, 0x07, 0x33, 0x04, 0x04, 0x01, 0x0D,
- 0x00, 0x0F, 0x0E, 0x0E, 0x01, 0x07, 0x33, 0x33, 0x01, 0x01, 0x33, 0x34, 0x07, 0x07, 0x06, 0x01, 0x0E,
- 0x01, 0x0D, 0x0F, 0x0F, 0x06, 0x07, 0x34, 0x33, 0x33, 0x34, 0x07, 0x07, 0x06, 0x0F, 0x0E,
- 0x03, 0x09, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0E,
- 0x01, 0x01, 0x07,
- 0x00, 0x03, 0x07, 0x01, 0x07,
- 0x01, 0x01, 0x07,
- 0x00, 0x00,
- 0x00, 0x00,
- 0x00, 0x00,
- 0x00, 0x00,
- 0x00, 0x00,
- 0x00, 0x00
-};
-
-const byte CURSHAND[] = {
- // hotspot x and y, uint16 LE
- 0x02, 0x00, 0x03, 0x00,
- // byte 1: number of skipped pixels
- // byte 2: number of plotted pixels
- // then, pixels
- 0x07, 0x02, 0x17, 0x0E,
- 0x05, 0x07, 0x0E, 0x12, 0x17, 0x0E, 0x13, 0x17, 0x0E,
- 0x02, 0x0C, 0x07, 0x00, 0x17, 0x0E, 0x11, 0x0F, 0x0E, 0x11, 0x17, 0x0E, 0x00, 0x17,
- 0x01, 0x0E, 0x07, 0x01, 0x07, 0x0F, 0x0E, 0x11, 0x17, 0x0E, 0x11, 0x0F, 0x0E, 0x12, 0x17, 0x0E,
- 0x02, 0x0D, 0x07, 0x00, 0x17, 0x0F, 0x12, 0x0F, 0x0F, 0x11, 0x17, 0x0E, 0x12, 0x0F, 0x0E,
- 0x04, 0x0B, 0x0F, 0x0E, 0x11, 0x17, 0x0E, 0x12, 0x0F, 0x0F, 0x11, 0x17, 0x0E,
- 0x04, 0x0B, 0x17, 0x0E, 0x12, 0x17, 0x0E, 0x12, 0x17, 0x0E, 0x11, 0x0F, 0x0E,
- 0x00, 0x0F, 0x0E, 0x0D, 0x12, 0x00, 0x17, 0x0F, 0x0F, 0x0F, 0x0F, 0x12, 0x0F, 0x0E, 0x12, 0x17, 0x0F,
- 0x00, 0x0F, 0x0F, 0x17, 0x0D, 0x11, 0x0F, 0x0E, 0x0D, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0E, 0x0D,
- 0x01, 0x0E, 0x0F, 0x17, 0x0F, 0x0E, 0x0F, 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, 0x0F, 0x0F, 0x0E, 0x0D,
- 0x02, 0x0D, 0x0F, 0x17, 0x0F, 0x0E, 0x0D, 0x0D, 0x0F, 0x0F, 0x0E, 0x0F, 0x0E, 0x0E, 0x12,
- 0x03, 0x0C, 0x0F, 0x17, 0x0F, 0x0F, 0x0F, 0x0E, 0x0F, 0x0F, 0x0F, 0x0E, 0x0D, 0x12,
- 0x04, 0x0A, 0x0F, 0x17, 0x0F, 0x0F, 0x0F, 0x0E, 0x0F, 0x0F, 0x0E, 0x0D,
- 0x05, 0x09, 0x0F, 0x17, 0x0F, 0x0F, 0x0F, 0x0F, 0x0E, 0x0D, 0x12,
- 0x06, 0x08, 0x17, 0x0F, 0x0F, 0x0F, 0x0F, 0x0E, 0x0D, 0x12,
- 0x06, 0x07, 0x17, 0x0F, 0x0F, 0x0F, 0x3D, 0x0E, 0x0D
-};
-
-const byte CURSGET[] = {
- // hotspot x and y, uint16 LE
- 0x07, 0x00, 0x0E, 0x00,
- // byte 1: number of skipped pixels
- // byte 2: number of plotted pixels
- // then, pixels
- 0x0A, 0x05, 0x1C, 0x07, 0x0F, 0x0F, 0x0F,
- 0x08, 0x08, 0x1C, 0x07, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0C,
- 0x06, 0x0A, 0x1C, 0x07, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0C,
- 0x05, 0x0A, 0x07, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0C,
- 0x03, 0x0C, 0x07, 0x1C, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0C,
- 0x02, 0x0D, 0x1C, 0x0F, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0C,
- 0x01, 0x0E, 0x07, 0x0F, 0x0E, 0x0D, 0x0F, 0x0E, 0x0D, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0C,
- 0x00, 0x0F, 0x1C, 0x0F, 0x0E, 0x0D, 0x0F, 0x0E, 0x0D, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0C,
- 0x00, 0x0F, 0x1C, 0x0E, 0x0D, 0x0F, 0x0E, 0x0D, 0x0F, 0x0F, 0x0C, 0x0C, 0x0E, 0x0F, 0x0F, 0x0F, 0x0C,
- 0x00, 0x0E, 0x1C, 0x0D, 0x0F, 0x0E, 0x0D, 0x0F, 0x0F, 0x0C, 0x00, 0x00, 0x0E, 0x0F, 0x0F, 0x0C,
- 0x00, 0x0E, 0x1C, 0x0E, 0x0F, 0x0D, 0x0F, 0x0F, 0x0C, 0x00, 0x00, 0x0E, 0x1C, 0x0F, 0x0F, 0x0C,
- 0x00, 0x0D, 0x1C, 0x0D, 0x0F, 0x0D, 0x0F, 0x0C, 0x00, 0x00, 0x00, 0x0E, 0x1C, 0x0F, 0x0C,
- 0x01, 0x0B, 0x0E, 0x0F, 0x0E, 0x0F, 0x0C, 0x00, 0x00, 0x0E, 0x07, 0x0F, 0x0C,
- 0x02, 0x09, 0x0E, 0x0D, 0x0F, 0x0C, 0x00, 0x07, 0x0E, 0x0F, 0x0C,
- 0x03, 0x06, 0x0E, 0x0F, 0x0E, 0x07, 0x01, 0x07,
- 0x07, 0x01, 0x07
-};
-
-const byte CURSCLIMB[] = {
- // hotspot x and y, uint16 LE
- 0x03, 0x00, 0x0E, 0x00,
- // byte 1: number of skipped pixels
- // byte 2: number of plotted pixels
- // then, pixels
- 0x06, 0x04, 0x01, 0x01, 0x01, 0x01,
- 0x06, 0x04, 0x0F, 0x0E, 0x01, 0x01,
- 0x06, 0x04, 0x0F, 0x0E, 0x0D, 0x01,
- 0x07, 0x02, 0x0F, 0x0D,
- 0x00, 0x0C, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x13, 0x12, 0x12, 0x12, 0x12, 0x11, 0x11,
- 0x00, 0x0D, 0x0D, 0x0E, 0x00, 0x00, 0x13, 0x14, 0x13, 0x12, 0x12, 0x12, 0x11, 0x11, 0x0E,
- 0x01, 0x0C, 0x0D, 0x0D, 0x0D, 0x0E, 0x11, 0x13, 0x13, 0x12, 0x11, 0x11, 0x0E, 0x0D,
- 0x02, 0x0C, 0x0E, 0x0E, 0x00, 0x00, 0x00, 0x13, 0x12, 0x11, 0x00, 0x00, 0x0E, 0x0D,
- 0x03, 0x0B, 0x04, 0x04, 0x04, 0x22, 0x21, 0x21, 0x20, 0x00, 0x00, 0x00, 0x0D,
- 0x02, 0x0D, 0x22, 0x04, 0x20, 0x22, 0x04, 0x21, 0x04, 0x20, 0x00, 0x00, 0x00, 0x0E, 0x0E,
- 0x03, 0x07, 0x22, 0x21, 0x20, 0x20, 0x22, 0x04, 0x20,
- 0x04, 0x06, 0x01, 0x01, 0x00, 0x04, 0x22, 0x20,
- 0x02, 0x09, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x04, 0x20,
- 0x03, 0x09, 0x07, 0x01, 0x01, 0x00, 0x00, 0x00, 0x22, 0x04, 0x20,
- 0x02, 0x0B, 0x07, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20,
- 0x03, 0x0A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01
-};
-
-const byte CURSTALK[] = {
- // hotspot x and y, uint16 LE
- 0x02, 0x00, 0x0B, 0x00,
- // byte 1: number of skipped pixels
- // byte 2: number of plotted pixels
- // then, pixels
- 0x03, 0x08, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
- 0x01, 0x0C, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06,
- 0x00, 0x0E, 0x06, 0x06, 0x06, 0x06, 0x07, 0x06, 0x07, 0x07, 0x06, 0x07, 0x07, 0x06, 0x07, 0x06,
- 0x00, 0x0F, 0x06, 0x08, 0x08, 0x08, 0x06, 0x08, 0x06, 0x06, 0x08, 0x06, 0x06, 0x08, 0x06, 0x08, 0x06,
- 0x00, 0x0F, 0x06, 0x06, 0x08, 0x06, 0x08, 0x06, 0x08, 0x06, 0x08, 0x06, 0x06, 0x08, 0x08, 0x06, 0x06,
- 0x00, 0x0F, 0x06, 0x06, 0x08, 0x06, 0x08, 0x08, 0x08, 0x06, 0x08, 0x06, 0x06, 0x08, 0x06, 0x08, 0x06,
- 0x01, 0x0E, 0x06, 0x08, 0x06, 0x08, 0x06, 0x08, 0x06, 0x08, 0x08, 0x06, 0x08, 0x06, 0x08, 0x06,
- 0x02, 0x0C, 0x06, 0x06, 0x06, 0x07, 0x06, 0x07, 0x06, 0x06, 0x07, 0x06, 0x07, 0x06,
- 0x04, 0x09, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06,
- 0x07, 0x04, 0x06, 0x07, 0x07, 0x06,
- 0x02, 0x08, 0x07, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06,
- 0x01, 0x06, 0x07, 0x01, 0x07, 0x06, 0x06, 0x06,
- 0x02, 0x01, 0x07,
- 0x00, 0x00,
- 0x00, 0x00,
- 0x00, 0x00
-};
-const byte CURSHELP[] = {
- // hotspot x and y, uint16 LE
- 0x02, 0x00, 0x0B, 0x00,
- // byte 1: number of skipped pixels
- // byte 2: number of plotted pixels
- // then, pixels
- 0x04, 0x06, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
- 0x02, 0x0A, 0x24, 0x24, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x20, 0x20,
- 0x01, 0x0C, 0x24, 0x22, 0x22, 0x22, 0x20, 0x20, 0x20, 0x22, 0x22, 0x22, 0x22, 0x20,
- 0x00, 0x0E, 0x24, 0x22, 0x22, 0x22, 0x20, 0x00, 0x00, 0x00, 0x24, 0x22, 0x22, 0x22, 0x22, 0x20,
- 0x00, 0x0E, 0x24, 0x22, 0x22, 0x22, 0x22, 0x20, 0x00, 0x00, 0x00, 0x24, 0x22, 0x22, 0x22, 0x20,
- 0x00, 0x0E, 0x24, 0x22, 0x22, 0x22, 0x22, 0x20, 0x00, 0x00, 0x00, 0x24, 0x22, 0x22, 0x22, 0x20,
- 0x01, 0x0D, 0x24, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x24, 0x22, 0x22, 0x22, 0x22, 0x20,
- 0x07, 0x06, 0x24, 0x22, 0x22, 0x22, 0x22, 0x20,
- 0x05, 0x07, 0x24, 0x22, 0x22, 0x22, 0x22, 0x20, 0x20,
- 0x04, 0x05, 0x24, 0x22, 0x22, 0x22, 0x20,
- 0x02, 0x07, 0x07, 0x00, 0x24, 0x20, 0x20, 0x20, 0x20,
- 0x01, 0x03, 0x07, 0x01, 0x07,
- 0x02, 0x07, 0x07, 0x00, 0x00, 0x24, 0x24, 0x24, 0x24,
- 0x04, 0x06, 0x24, 0x22, 0x22, 0x22, 0x22, 0x20,
- 0x04, 0x06, 0x24, 0x22, 0x22, 0x22, 0x22, 0x20,
- 0x05, 0x04, 0x20, 0x20, 0x20, 0x20
-};
-const byte *const CURSORS[10] = {
- MOUSE0, MOUSE1, MOUSE2, MOUSE3, CURSEYE, CURSHAND, CURSGET, CURSCLIMB, CURSTALK, CURSHELP
-};
-
-const int _travelPos[][2] = {
- { -1, 0 },
- { 228, 117 },
- { 28, 98 },
- { 161, 140 },
- { 130, 139 },
- { 884, 95 },
- { 0, 0 },
- { 0, 0 },
- { 0, 0 },
- { 41, 185 },
- { 60, 138 },
- { 0, 0 },
- { 0, 0 },
- { 0, 0 },
- { 0, 0 },
- { 0, 0 },
- { 170, 155 },
- { 0, 0 },
- { 0, 0 },
- { 0, 0 },
- { 108, 95 },
- { 0, 0 },
- { 0, 0 },
- { 0, 0 },
- { 100, 115 },
- { 480, 90 },
- { 154, 63 },
- { 0, 0 },
- { 145, 85 },
- { 0, 0 },
- { 110, 107 },
- { 0, 0 },
- { 105, 154 },
- { 0, 0 },
- { 0, 0 },
- { 0, 0 },
- { 0, 0 },
- { 20, 160 },
- { 130, 314 },
- { 0, 0 },
- { 50, 125 },
- { 0, 0 },
- { 0, 0 },
- { 123, 123 },
- { -1, 7 },
- { 266, 168 },
- { 0, 0 },
- { 0, 0 },
- { 0, 0 },
- { -1, 18 },
- { -1, 19 },
- { 0, 0 },
- { 0, 0 },
- { 0, 0 },
- { 0, 0 },
- { 0, 0 },
- { 203, 160 },
- { 0, 0 },
- { 283, 163 },
- { 0, 0 },
- { 0, 0 },
- { 0, 0 },
- { 180, 165 },
- { 0, 0 },
- { 0, 0 },
- { 0, 0 }
-};
-
const int OVEROFFR[] = { 2, 2, 1, 2, 2, 1, 0, 0, 0 };
const int OVEROFFL[] = { 2, 2, 1, 2, 2, 1, 0, 0, 0 };
const int OVEROFFU[] = { 1, 1, 1, 1, 1, 1, 0, 0, 0 };
@@ -408,1528 +108,6 @@ const int OVEROFFULY[] = { 1, 0, 0, 2, 1, 0, 0, 0, 0 };
const int OVEROFFDLX[] = { 1, 2, 1, 1, 2, 1, 0, 0, 0 };
const int OVEROFFDLY[] = { 0, 1, 0, 0, 1, 1, 0, 0, 0 };
-const byte CREDITS[] = {
- 0x2, 0xFF, 0xFF, 0x61, 0x0, 0x3, 0x0, 0x30, 0x22, 0x30, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0xFF, 0xFF,
- 0x0, 0x0, 0xFF, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-const byte ALLISTER[] = {
- 0x0, 0xFF, 0xFF, 0x61, 0x0, 0x0, 0x0, 0x36, 0x0F, 0x5E, 0x4, 0x0, 0x0,
- 0x0, 0x4, 0x4, 0x0, 0x3, 0x0, 0xFF, 0x4, 0x0, 0x2, 0x0, 0x4, 0x0, 0x1, 0x0, 0x8C,
- 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x0, 0x0, 0x0,
- 0x1, 0x0, 0x62, 0x0, 0x0B, 0x0, 0x1, 0x0, 0x62, 0x0, 0x0C, 0x0, 0x1, 0x0, 0x62,
- 0x0, 0x0D, 0x0, 0x1, 0x0, 0xFF, 0xFF
-};
-
-const byte HALL[] = {
- 0x0, 0xFF, 0xFF, 0x61, 0x0, 0x0, 0x0, 0x40, 0x3E, 0x1A, 0x5, 0x0, 0x0,
- 0x0, 0x5, 0x5, 0x0, 0x3, 0x0, 0xFF, 0x5, 0x0, 0x2, 0x0, 0x5, 0x0, 0x1, 0x0, 0xFF,
- 0x30, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x0, 0x0,
- 0x0, 0x2, 0x0, 0x62, 0x0, 0x0D, 0x0, 0x1, 0x0, 0x62, 0x0, 0x13, 0x0, 0x1, 0x0,
- 0x62, 0x0, 0x14, 0x0, 0x2, 0x0, 0x62, 0x0, 0x4, 0x0, 0x1, 0x0, 0xFF, 0xFF
-};
-
-const byte JASONLAB[] = {
- 0x1, 0x6, 0x0, 0x61, 0x0, 0x0D, 0x0, 0x40, 0x20, 0x0C4, 0x6, 0x0, 0x0, 0x0,
- 0x6, 0x6, 0x0, 0x3, 0x0, 0xFF, 0x6, 0x0, 0x2, 0x0, 0x6, 0x0, 0x1, 0x0, 0xFF, 0x0,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x0, 0x0, 0x0, 0x1,
- 0x0, 0x62, 0x0, 0x1, 0x0, 0x1, 0x0, 0x62, 0x0, 0x2, 0x0, 0x1, 0x0, 0x62, 0x0, 0x3,
- 0x0, 0x2, 0x0, 0x62, 0x0, 0x26, 0x0, 0x1, 0x0, 0x62, 0x0, 0x0D, 0x0, 0x1, 0x0,
- 0x62, 0x0, 0x35, 0x0, 0x2, 0x0, 0xFF, 0xFF
-};
-
-const byte ALLENLAB[] = {
- 0x1, 0x8, 0x0, 0x61, 0x0, 0x0D, 0x0, 0x40, 0x20, 0x0C4, 0x8, 0x0, 0x0, 0x0,
- 0x8, 0x8, 0x0, 0x3, 0x0, 0xFF, 0x8, 0x0, 0x2, 0x0, 0x8, 0x0, 0x1, 0x0, 0xFF, 0x0,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x0, 0x0, 0x0, 0x1,
- 0x0, 0x62, 0x0, 0x7, 0x0, 0x1, 0x0, 0x62, 0x0, 0x8, 0x0, 0x2, 0x0, 0x62, 0x0, 0x9,
- 0x0, 0x1, 0x0, 0x62, 0x0, 0x0A, 0x0, 0x1, 0x0, 0x62, 0x0, 0x0D, 0x0, 0x1, 0x0,
- 0xFF, 0xFF
-};
-
-const byte OUTVAULT[] = {
- 0x0, 0x9, 0x0, 0x61, 0x0, 0x2B, 0x0, 0x30, 0x18, 0x9B, 0x9, 0x0, 0x0, 0x0,
- 0x9, 0x9, 0x0, 0x3, 0x0, 0xFF, 0x9, 0x0, 0x2, 0x0, 0x9, 0x0, 0x1, 0x0, 0x0B4, 0x10,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x0, 0x0, 0x0, 0x3,
- 0x0, 0x62, 0x0, 0x4, 0x0, 0x1, 0x0, 0x62, 0x0, 0x5, 0x0, 0x2, 0x0, 0x62, 0x0, 0x6,
- 0x0, 0x2, 0x0, 0x62, 0x0, 0x36, 0x0, 0x1, 0x0, 0x62, 0x0, 0x47, 0x0, 0x1, 0x0,
- 0xFF, 0xFF
-};
-
-const byte VAULT[] = {
- 0x0, 0xFF, 0xFF, 0x61, 0x0, 0x29, 0x0, 0x40, 0x3A, 0x37, 0x0A, 0x0,
- 0x0, 0x0, 0x0A, 0x0A, 0x0, 0x3, 0x0, 0xFF, 0x0A, 0x0, 0x2, 0x0, 0x0A, 0x0,
- 0x1, 0x0, 0xFF, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62,
- 0x0, 0x0, 0x0, 0x1, 0x0, 0x62, 0x0, 0x37, 0x0, 0x2, 0x0, 0x62, 0x0, 0x39, 0x0,
- 0x1, 0x0, 0x62, 0x0, 0x38, 0x0, 0x2, 0x0, 0x62, 0x0, 0x15, 0x0, 0x2, 0x0, 0xFF,
- 0xFF
-};
-
-const byte LIBRARY[] = {
- 0x1, 0xFF, 0xFF, 0x61, 0x0, 0x0C, 0x0, 0x40, 0x3A, 0x22, 0x0B, 0x0,
- 0x0, 0x0, 0x0B, 0x0B, 0x0, 0x3, 0x0, 0xFF, 0x0B, 0x0, 0x2, 0x0, 0x0B, 0x0,
- 0x1, 0x0, 0xFF, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62,
- 0x0, 0x0, 0x0, 0x1, 0x0, 0x62, 0x0, 0x1, 0x0, 0x1, 0x0, 0xFF, 0xFF,
-};
-
-const byte JASAPT[] = {
- 0x1, 0x0C, 0x0, 0x61, 0x0, 0x19, 0x0, 0x40, 0x30, 0x14, 0x0C, 0x0, 0x0,
- 0x0, 0x0C, 0x0C, 0x0, 0x3, 0x0, 0xFF, 0x0C, 0x0, 0x2, 0x0, 0x0C, 0x0, 0x1,
- 0x0, 0xFF, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62,
- 0x0, 0x18, 0x0, 0x2, 0x0, 0x62, 0x0, 0x17, 0x0, 0x1, 0x0, 0x62, 0x0, 0x11,
- 0x0, 0x1, 0x0, 0x62, 0x0, 0x0D, 0x0, 0x1, 0x0, 0xFF, 0xFF
-};
-
-const byte RANSACKED[] = {
- 0x1, 0x0D, 0x0, 0x61, 0x0, 0x2D, 0x0, 0x40, 0x36, 0x2C, 0x0D, 0x0, 0x0,
- 0x0, 0x0D, 0x0D, 0x0, 0x3, 0x0, 0xFF, 0x0D, 0x0, 0x2, 0x0, 0x0D, 0x0, 0x1,
- 0x0, 0xFF, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62,
- 0x0, 0x17, 0x0, 0x1, 0x0, 0xFF, 0xFF
-};
-
-const byte MEAN1[] = {
- 0x1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x3E, 0x33,
- 0xFF, 0xFF, 0x0, 0x0, 0xFF, 0x0E, 0x0, 0x5, 0x0, 0x0E, 0x0, 0x4, 0x0,
- 0xFF, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-const byte FLYSOUTH[] = {
- 0x1, 0xFF, 0xFF, 0x61, 0x0, 0x10, 0x0, 0x28, 0x0C, 0x5E, 0x0F, 0x0,
- 0x0, 0x0, 0x0F, 0x0F, 0x0, 0x2, 0x0, 0xFF, 0x0F, 0x0, 0x1, 0x0, 0xFF, 0xFF,
- 0x1, 0x0, 0xFF, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62,
- 0x0, 0x44, 0x0, 0x1, 0x0, 0xFF, 0xFF
-};
-
-const byte CUZCO[] = {
- 0x2, 0x10, 0x0, 0x61, 0x0, 0x10, 0x0, 0x40, 0x20, 0x30, 0x10, 0x0, 0x0,
- 0x0, 0x10, 0x10, 0x0, 0x3, 0x0, 0xFF, 0x10, 0x0, 0x2, 0x0, 0x10, 0x0, 0x1,
- 0x0, 0x6E, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62,
- 0x0, 0x0, 0x0, 0x2, 0x0, 0x62, 0x0, 0x44, 0x0, 0x1, 0x0, 0xFF, 0xFF
-};
-
-const byte INAIR[] = {
- 0x1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x28, 0x19, 0x2B,
- 0x11, 0x0, 0x0, 0x0, 0x11, 0x11, 0x0, 0x3, 0x0, 0xFF, 0x11, 0x0, 0x2, 0x0,
- 0x11, 0x0, 0x1, 0x0, 0xFF, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF
-};
-
-const byte GREENMONKEY[] = {
- 0x1, 0xFF, 0xFF, 0x61, 0x0, 0x11, 0x0, 0x2D, 0x14, 0x3C, 0x12, 0x0,
- 0x0, 0x0, 0x12, 0x12, 0x0, 0x3, 0x0, 0xFF, 0x12, 0x0, 0x2, 0x0, 0x12, 0x0,
- 0x1, 0x0, 0xFF, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-const byte INPLANE[] = {
- 0x2, 0x13, 0x0, 0x61, 0x0, 0x26, 0x0, 0x2D, 0x28, 0x28, 0x13, 0x0, 0x0,
- 0x0, 0x13, 0x13, 0x0, 0x3, 0x0, 0xFF, 0x13, 0x0, 0x2, 0x0, 0x13, 0x0, 0x1,
- 0x0, 0xFF, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x0, 0x0, 0x0,
- 0x2, 0x0, 0x62, 0x0, 0x29, 0x0, 0x2, 0x0, 0x62, 0x0, 0x1F, 0x0, 0x1, 0x0,
- 0x62, 0x0, 0x38, 0x0, 0x2, 0x0, 0x62, 0x0, 0x33, 0x0, 0x1, 0x0, 0xFF, 0xFF
-};
-
-const byte PILFALL[] = {
- 0x1, 0xFF, 0xFF, 0x61, 0x0, 0x16, 0x0, 0x28, 0x0C, 0x5E, 0x14, 0x0,
- 0x0, 0x0, 0x14, 0x14, 0x0, 0x2, 0x0, 0xFF, 0x14, 0x0, 0x1, 0x0, 0xFF, 0xFF,
- 0x1, 0x0, 0xFF, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62,
- 0x0, 0x3A, 0x0, 0x1, 0x0, 0xFF, 0xFF
-};
-
-const byte COCKPIT[] = {
- 0x1, 0xFF, 0xFF, 0x61, 0x0, 0x12, 0x0, 0x3C, 0x2A, 0x29, 0x15, 0x0,
- 0x0, 0x0, 0x15, 0x15, 0x0, 0x3, 0x0, 0xFF, 0x15, 0x0, 0x2, 0x0, 0x15, 0x0,
- 0x1, 0x0, 0xFF, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62,
- 0x0, 0x23, 0x0, 0x1, 0x0, 0xFF, 0xFF
-};
-
-const byte CRASH[] = {
- 0x1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x2D, 0x64,
- 0x16, 0x0, 0x0, 0x0, 0xFF, 0x16, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0x0, 0x0,
- 0xFF, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0x16, 0x0, 0x2, 0x0, 0xFF,
- 0xFF, 0x62, 0x0, 0x2A, 0x0, 0x1, 0x0, 0xFF, 0xFF
-};
-
-const byte SINKING[] = {
- 0x2, 0xFF, 0xFF, 0x61, 0x0, 0x14, 0x0, 0x40, 0x3C, 0x19, 0x17, 0x0,
- 0x0, 0x0, 0x17, 0x17, 0x0, 0x3, 0x0, 0xFF, 0x17, 0x0, 0x2, 0x0, 0x17, 0x0,
- 0x1, 0x0, 0xFF, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62,
- 0x0, 0x0, 0x0, 0x1, 0x0, 0x62, 0x0, 0x48, 0x0, 0x1, 0x0, 0x62, 0x0, 0x17, 0x0,
- 0x1, 0x0, 0xFF, 0xFF
-};
-
-const byte JNGLWLK[] = {
- 0x2, 0xFF, 0xFF, 0x61, 0x0, 0x17, 0x0, 0x40, 0x3F, 0x5A, 0x18, 0x0,
- 0x0, 0x0, 0x18, 0x18, 0x0, 0x2, 0x0, 0xFF, 0x18, 0x0, 0x1, 0x0, 0xFF, 0xFF,
- 0x0, 0x0, 0x0DC, 0x0A0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x62, 0x0, 0x0, 0x0, 0x1, 0x0, 0xFF, 0xFF
-};
-
-const byte TOWN[] = {
- 0x2, 0x19, 0x0, 0x61, 0x0, 0x18, 0x0, 0x3E, 0x32, 0x80, 0x19, 0x0, 0x0,
- 0x0, 0x19, 0x19, 0x0, 0x3, 0x0, 0xFF, 0x19, 0x0, 0x2, 0x0, 0x19, 0x0, 0x1,
- 0x0, 0x64, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62,
- 0x0, 0x0, 0x0, 0x1, 0x0, 0x62, 0x0, 0x3D, 0x0, 0x1, 0x0, 0x62, 0x0, 0x3B, 0x0,
- 0x2, 0x0, 0xFF, 0xFF
-};
-
-const byte HOTEL[] = {
- 0x1, 0xFF, 0xFF, 0x61, 0x0, 0x19, 0x0, 0x34, 0x28, 0x28, 0x1A, 0x0,
- 0x0, 0x0, 0x1A, 0x1A, 0x0, 0x3, 0x0, 0xFF, 0x1A, 0x0, 0x2, 0x0, 0x1A, 0x0,
- 0x1, 0x0, 0xFF, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62,
- 0x0, 0x28, 0x0, 0x1, 0x0, 0x62, 0x0, 0x2B, 0x0, 0x1, 0x0, 0x62, 0x0, 0x46,
- 0x0, 0x2, 0x0, 0x62, 0x0, 0x45, 0x0, 0x1, 0x0, 0x62, 0x0, 0x0E, 0x0, 0x1, 0x0,
- 0xFF, 0xFF
-};
-
-const byte CANTINA[] = {
- 0x2, 0xFF, 0xFF, 0x61, 0x0, 0x27, 0x0, 0x40, 0x3A, 0x6C, 0x1B, 0x0,
- 0x0, 0x0, 0x1B, 0x1B, 0x0, 0x3, 0x0, 0xFF, 0x1B, 0x0, 0x2, 0x0, 0x1B, 0x0,
- 0x1, 0x0, 0x0C8, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62,
- 0x0, 0x0, 0x0, 0x1, 0x0, 0xFF, 0xFF
-};
-
-const byte MASSACRE[] = {
- 0x2, 0x1D, 0x0, 0x61, 0x0, 0x32, 0x0, 0x20, 0x18, 0x73, 0x1D, 0x0, 0x0,
- 0x0, 0x1D, 0x1D, 0x0, 0x3, 0x0, 0xFF, 0x1D, 0x0, 0x2, 0x0, 0x1D, 0x0, 0x1,
- 0x0, 0x96, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62,
- 0x0, 0x0, 0x0, 0x1, 0x0, 0x62, 0x0, 0x0C, 0x0, 0x1, 0x0, 0x62, 0x0, 0x3, 0x0, 0x2,
- 0x0, 0x62, 0x0, 0x49, 0x0, 0x2, 0x0, 0x62, 0x0, 0x4A, 0x0, 0x2, 0x0, 0xFF, 0xFF
-};
-
-const byte TRADE[] = {
- 0x1, 0xFF, 0xFF, 0x61, 0x0, 0x18, 0x0, 0x3F, 0x1C, 0x27, 0x1E, 0x0,
- 0x0, 0x0, 0x1E, 0x1E, 0x0, 0x3, 0x0, 0xFF, 0x1E, 0x0, 0x2, 0x0, 0x1E, 0x0,
- 0x1, 0x0, 0xFF, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-const byte BRIDGE[] = {
- 0x2, 0x1F, 0x0, 0x61, 0x0, 0x1B, 0x0, 0x40, 0x3F, 0x78, 0x1F, 0x0, 0x0,
- 0x0, 0x1F, 0x1F, 0x0, 0x3, 0x0, 0xFF, 0x1F, 0x0, 0x2, 0x0, 0x1F, 0x0, 0x1,
- 0x0, 0xFF, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62,
- 0x0, 0x0, 0x0, 0x2, 0x0, 0x62, 0x0, 0x1F, 0x0, 0x1, 0x0, 0xFF, 0xFF
-};
-
-const byte DOCK[] = {
- 0x1, 0xFF, 0xFF, 0x61, 0x0, 0x1E, 0x0, 0x40, 0x3B, 0x4B, 0x20, 0x0,
- 0x0, 0x0, 0xFF, 0x20, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0x1, 0x0, 0xFF, 0x0,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-const byte DRIVER[] = {
- 0x1, 0x21, 0x0, 0x61, 0x0, 0x28, 0x0, 0x30, 0x10, 0x51, 0x21, 0x0, 0x0,
- 0x0, 0x21, 0x21, 0x0, 0x2, 0x0, 0xFF, 0x21, 0x0, 0x1, 0x0, 0xFF, 0xFF,
- 0x0, 0x0, 0xFF, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62,
- 0x0, 0x2E, 0x0, 0x1, 0x0, 0x62, 0x0, 0x2F, 0x0, 0x1, 0x0, 0xFF, 0xFF
-};
-
-const byte SHORE[] = {
- 0x2, 0x24, 0x0, 0x61, 0x0, 0x4, 0x0, 0x3E, 0x3A, 0x32, 0x24, 0x0, 0x0, 0x0,
- 0x24, 0x24, 0x0, 0x3, 0x0, 0xFF, 0x24, 0x0, 0x2, 0x0, 0x24, 0x0, 0x1, 0x0,
- 0x0B4, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x0,
- 0x2D, 0x0, 0x2, 0x0, 0x62, 0x0, 0x1F, 0x0, 0x1, 0x0, 0x62, 0x0, 0x2E, 0x0,
- 0x1, 0x0, 0x62, 0x0, 0x2F, 0x0, 0x1, 0x0, 0xFF, 0xFF
-};
-
-const byte BOAT[] = {
- 0x3, 0xFF, 0xFF, 0x61, 0x0, 0x8, 0x0, 0x3F, 0x3F, 0xFF, 0x25, 0x0,
- 0x0, 0x0, 0x25, 0x25, 0x0, 0x3, 0x0, 0xFF, 0x25, 0x0, 0x2, 0x0, 0x25, 0x0,
- 0x1, 0x0, 0xFF, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x62, 0x0, 0x0, 0x0, 0x2, 0x0, 0x62, 0x0, 0x21, 0x0, 0x1, 0x0, 0x62, 0x0, 0x25,
- 0x0, 0x1, 0x0, 0x62, 0x0, 0x1F, 0x0, 0x1, 0x0, 0x62, 0x0, 0x30, 0x0, 0x1, 0x0,
- 0x62, 0x0, 0x32, 0x0, 0x1, 0x0, 0xFF, 0xFF
-};
-
-const byte CABIN[] = {
- 0x1, 0xFF, 0xFF, 0x61, 0x0, 0x8, 0x0, 0x40, 0x32, 0x50, 0x26, 0x0,
- 0x0, 0x0, 0x26, 0x26, 0x0, 0x3, 0x0, 0xFF, 0x26, 0x0, 0x2, 0x0, 0x26, 0x0,
- 0x1, 0x0, 0xFF, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62,
- 0x0, 0x0, 0x0, 0x1, 0x0, 0x62, 0x0, 0x22, 0x0, 0x2, 0x0, 0x62, 0x0, 0x31, 0x0,
- 0x1, 0x0, 0xFF, 0xFF
-};
-
-const byte CAPTIVE[] = {
- 0x2, 0x27, 0x0, 0x61, 0x0, 0x9, 0x0, 0x40, 0x3F, 0x37, 0x27, 0x0, 0x0, 0x0,
- 0x27, 0x27, 0x0, 0x3, 0x0, 0xFF, 0x27, 0x0, 0x2, 0x0, 0x27, 0x0, 0x1, 0x0,
- 0xFF, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x0,
- 0x0, 0x0, 0x4, 0x0, 0x62, 0x0, 0x1B, 0x0, 0x3, 0x0, 0x62, 0x0, 0x1C, 0x0, 0x1,
- 0x0, 0x62, 0x0, 0x1F, 0x0, 0x2, 0x0, 0x62, 0x0, 0x23, 0x0, 0x1, 0x0, 0x62,
- 0x0, 0x32, 0x0, 0x1, 0x0, 0x62, 0x0, 0x33, 0x0, 0x1, 0x0, 0xFF, 0xFF
-};
-
-const byte VILLAGE[] = {
- 0x2, 0x2A, 0x0, 0x61, 0x0, 0x2E, 0x0, 0x1E, 0x1B, 0x6E, 0x2A, 0x0, 0x0,
- 0x0, 0x2A, 0x2A, 0x0, 0x3, 0x0, 0xFF, 0x2A, 0x0, 0x2, 0x0, 0x2A, 0x0, 0x1,
- 0x0, 0x0A5, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62,
- 0x0, 0x2D, 0x0, 0x3, 0x0, 0x62, 0x0, 0x3F, 0x0, 0x1, 0x0, 0x62, 0x0, 0x40,
- 0x0, 0x2, 0x0, 0xFF, 0xFF
-};
-
-const byte TREE[] = {
- 0x2, 0x2C, 0x0, 0x61, 0x0, 0x31, 0x0, 0x1E, 0x1D, 0x0BE, 0x2C, 0x0, 0x0,
- 0x0, 0x2C, 0x2C, 0x0, 0x3, 0x0, 0xFF, 0x2C, 0x0, 0x2, 0x0, 0x2C, 0x0, 0x1,
- 0x0, 0x50, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62,
- 0x0, 0x0, 0x0, 0x2, 0x0, 0x62, 0x0, 0x2E, 0x0, 0x1, 0x0, 0x62, 0x0, 0x2F, 0x0,
- 0x1, 0x0, 0x62, 0x0, 0x4, 0x0, 0x1, 0x0, 0x62, 0x0, 0x42, 0x0, 0x1, 0x0, 0xFF,
- 0xFF
-};
-
-const byte CANOE[] = {
- 0x1, 0x2D, 0x0, 0x61, 0x0, 0x2F, 0x0, 0x1E, 0x1D, 0x78, 0x2D, 0x0, 0x0,
- 0x0, 0x2D, 0x2D, 0x0, 0x3, 0x0, 0xFF, 0x2D, 0x0, 0x2, 0x0, 0x2D, 0x0, 0x1,
- 0x0, 0xFF, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62,
- 0x0, 0x40, 0x0, 0x3, 0x0, 0x62, 0x0, 0x41, 0x0, 0x2, 0x0, 0x62, 0x0, 0x2E,
- 0x0, 0x2, 0x0, 0x62, 0x0, 0x2F, 0x0, 0x2, 0x0, 0x62, 0x0, 0x16, 0x0, 0x1, 0x0,
- 0xFF, 0xFF
-};
-
-const byte INTREE[] = {
- 0x1, 0xFF, 0xFF, 0x61, 0x0, 0x33, 0x0, 0x28, 0x1E, 0x32, 0x2E, 0x0,
- 0x0, 0x0, 0x2E, 0x2E, 0x0, 0x3, 0x0, 0xFF, 0x2E, 0x0, 0x2, 0x0, 0x2E, 0x0,
- 0x1, 0x0, 0x0F0, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-const byte FALLS[] = {
- 0x1, 0xFF, 0xFF, 0x61, 0x0, 0x3B, 0x0, 0x28, 0x1E, 0x32, 0x2F, 0x0,
- 0x0, 0x0, 0x2F, 0x2F, 0x0, 0x3, 0x0, 0xFF, 0x2F, 0x0, 0x2, 0x0, 0x2F, 0x0,
- 0x1, 0x0, 0xFF, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62,
- 0x0, 0x4, 0x0, 0x1, 0x0, 0x62, 0x0, 0x2A, 0x0, 0x1, 0x0, 0xFF, 0xFF
-};
-
-const byte WATERFALL[] = {
- 0x1, 0x36, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0x28, 0x1E, 0x6E, 0x36,
- 0x0, 0x0, 0x0, 0x36, 0x36, 0x0, 0x3, 0x0, 0xFF, 0x36, 0x0, 0x2, 0x0, 0x36,
- 0x0, 0x1, 0x0, 0xFF, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0x36, 0x0, 0x4,
- 0x0, 0xFF, 0xFF, 0x62, 0x0, 0x1F, 0x0, 0x1, 0x0, 0xFF, 0xFF
-};
-
-const byte INWATER[] = {
- 0x2, 0xFF, 0xFF, 0x61, 0x0, 0x36, 0x0, 0x40, 0x3F, 0x2A, 0x37, 0x0,
- 0x0, 0x0, 0x37, 0x37, 0x0, 0x3, 0x0, 0xFF, 0x37, 0x0, 0x2, 0x0, 0x37, 0x0,
- 0x1, 0x0, 0xFF, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62,
- 0x0, 0x0, 0x0, 0x1, 0x0, 0x62, 0x0, 0x38, 0x0, 0x1, 0x0, 0xFF, 0xFF
-};
-
-const byte CAVE[] = {
- 0x2, 0x39, 0x0, 0x61, 0x0, 0x37, 0x0, 0x32, 0x14, 0x73, 0x39, 0x0, 0x0,
- 0x0, 0x39, 0x39, 0x0, 0x3, 0x0, 0xFF, 0x39, 0x0, 0x2, 0x0, 0x39, 0x0, 0x1,
- 0x0, 0x0B4, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62,
- 0x0, 0x0, 0x0, 0x1, 0x0, 0x62, 0x0, 0x1F, 0x0, 0x1, 0x0, 0x62, 0x0, 0x4B, 0x0,
- 0x2, 0x0, 0x62, 0x0, 0x4C, 0x0, 0x2, 0x0, 0xFF, 0xFF
-};
-
-const byte PIT[] = {
- 0x2, 0xFF, 0xFF, 0x61, 0x0, 0x38, 0x0, 0x41, 0x3F, 0x19, 0x3D, 0x0,
- 0x0, 0x0, 0x3D, 0x3D, 0x0, 0x3, 0x0, 0x3E, 0x3D, 0x0, 0x4, 0x0, 0xFF, 0x3D,
- 0x0, 0x2, 0x0, 0x3D, 0x0, 0x1, 0x0, 0x0BE, 0x0, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0x62, 0x0, 0x0, 0x0, 0x2, 0x0, 0x62, 0x0, 0x27, 0x0, 0x1, 0x0,
- 0x62, 0x0, 0x4D, 0x0, 0x2, 0x0, 0xFF, 0xFF, 0x0
-};
-
-const byte *const ROOM_TABLE[] = {
- CREDITS, nullptr, nullptr, nullptr, ALLISTER, HALL, JASONLAB, nullptr,
- ALLENLAB, OUTVAULT, VAULT, LIBRARY, JASAPT, RANSACKED, MEAN1, FLYSOUTH,
- CUZCO, INAIR, GREENMONKEY, INPLANE, PILFALL, COCKPIT, CRASH, SINKING,
- JNGLWLK, TOWN, HOTEL, CANTINA, nullptr, MASSACRE, TRADE, BRIDGE, DOCK,
- DRIVER, nullptr, nullptr, SHORE, BOAT, CABIN, CAPTIVE, nullptr,
- nullptr, VILLAGE, nullptr, TREE, CANOE, INTREE, FALLS, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr, WATERFALL, INWATER, nullptr,
- CAVE, nullptr, nullptr, nullptr, PIT, nullptr, nullptr
-};
-
-const char *const ROOM_DESCR[] = {
- "Credits", nullptr, nullptr, nullptr, "Outside of Allister Center",
- "Hall", "Jason's Lab", nullptr, "Allen's Lab", "Outside of the Vault",
- "Inside the Vault", "Reader", "Jason's Apartment", "Jason's ransacked apartment", "Cutscene 1",
- "TBD FLYSOUTH", "Cuzco Airport", "TBD INAIR", "Green Monkey Club", "In Plane",
- "TBD PILFALL", "TBD COCKPIT", "TBD CRASH", "TBD SINKING", "Cutscene Jungle Walk",
- "TBD TOWN", "TBD HOTEL", "TBD CANTINA", nullptr, "TBD MASSACRE",
- "TBD TRADE", "TBD BRIDGE", "TBD DOCK", "TBD DRIVER", nullptr,
- nullptr, "TBD SHORE", "TBD BOAT", "TBD CABIN", "TBD CAPTIVE",
- nullptr, nullptr, "TBD VILLAGE", nullptr, "TBD TREE",
- "TBD CANOE", "TBD INTREE", "TBD FALLS", nullptr, nullptr,
- nullptr, nullptr, nullptr, nullptr, "TBD WATERFALL",
- "TBD INWATER", nullptr, "Cave Bridge", nullptr, nullptr,
- nullptr, "Pit with Ants", nullptr, nullptr
-};
-
-const byte ROOM_TABLE1_DEMO[] = {
- 0x02, 0x61, 0x00, 0x03, 0x00, 0x30, 0x22, 0x30, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF,
- 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE5_DEMO[] = {
- 0x00, 0x61, 0x00, 0x0E, 0x00, 0x36, 0x0F, 0x5E, 0x04, 0x00,
- 0x00, 0x00, 0x04, 0x04, 0x00, 0x03, 0x00, 0xFF, 0x04, 0x00,
- 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x8C, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x62, 0x00, 0x0B, 0x00, 0x01, 0x00, 0x62, 0x00, 0x0C, 0x00,
- 0x01, 0x00, 0x62, 0x00, 0x0D, 0x00, 0x01, 0x00, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE6_DEMO[] = {
- 0x00, 0x61, 0x00, 0x0E, 0x00, 0x40, 0x3E, 0x1A, 0x05, 0x00,
- 0x00, 0x00, 0x05, 0x05, 0x00, 0x03, 0x00, 0xFF, 0x05, 0x00,
- 0x02, 0x00, 0x05, 0x00, 0x01, 0x00, 0xFF, 0x30, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x00, 0x00, 0x00, 0x02, 0x00,
- 0x62, 0x00, 0x12, 0x00, 0x03, 0x00, 0x62, 0x00, 0x13, 0x00,
- 0x01, 0x00, 0x62, 0x00, 0x14, 0x00, 0x02, 0x00, 0x62, 0x00,
- 0x04, 0x00, 0x01, 0x00, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE7_DEMO[] = {
- 0x01, 0x61, 0x00, 0x0D, 0x00, 0x40, 0x20, 0xC4, 0x06, 0x00,
- 0x00, 0x00, 0x06, 0x06, 0x00, 0x03, 0x00, 0xFF, 0x06, 0x00,
- 0x02, 0x00, 0x06, 0x00, 0x01, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x62, 0x00, 0x01, 0x00, 0x01, 0x00, 0x62, 0x00, 0x02, 0x00,
- 0x01, 0x00, 0x62, 0x00, 0x03, 0x00, 0x02, 0x00, 0x62, 0x00,
- 0x26, 0x00, 0x01, 0x00, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE9_DEMO[] = {
- 0x01, 0x61, 0x00, 0x0D, 0x00, 0x40, 0x20, 0xC4, 0x08, 0x00,
- 0x00, 0x00, 0x08, 0x08, 0x00, 0x03, 0x00, 0xFF, 0x08, 0x00,
- 0x02, 0x00, 0x08, 0x00, 0x01, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x62, 0x00, 0x07, 0x00, 0x01, 0x00, 0x62, 0x00, 0x08, 0x00,
- 0x02, 0x00, 0x62, 0x00, 0x09, 0x00, 0x01, 0x00, 0x62, 0x00,
- 0x0A, 0x00, 0x01, 0x00, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE10_DEMO[] = {
- 0x00, 0x61, 0x00, 0x0E, 0x00, 0x30, 0x18, 0x9B, 0x09, 0x00,
- 0x00, 0x00, 0x09, 0x09, 0x00, 0x03, 0x00, 0xFF, 0x09, 0x00,
- 0x02, 0x00, 0x09, 0x00, 0x01, 0x00, 0xB4, 0x10, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x00, 0x00, 0x00, 0x03, 0x00,
- 0x62, 0x00, 0x04, 0x00, 0x01, 0x00, 0x62, 0x00, 0x05, 0x00,
- 0x02, 0x00, 0x62, 0x00, 0x06, 0x00, 0x02, 0x00, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE11_DEMO[] = {
- 0x01, 0x61, 0x00, 0x0E, 0x00, 0x40, 0x30, 0x14, 0x0A, 0x00,
- 0x00, 0x00, 0x0A, 0x0A, 0x00, 0x03, 0x00, 0xFF, 0x0A, 0x00,
- 0x02, 0x00, 0x0A, 0x00, 0x01, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x62, 0x00, 0x15, 0x00, 0x01, 0x00, 0x62, 0x00, 0x16, 0x00,
- 0x01, 0x00, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE12_DEMO[] = {
- 0x01, 0x61, 0x00, 0x0E, 0x00, 0x40, 0x3A, 0x22, 0x0B, 0x00,
- 0x00, 0x00, 0x0B, 0x0B, 0x00, 0x03, 0x00, 0xFF, 0x0B, 0x00,
- 0x02, 0x00, 0x0B, 0x00, 0x01, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x62, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE13_DEMO[] = {
- 0x01, 0x61, 0x00, 0x08, 0x00, 0x40, 0x30, 0x14, 0x0C, 0x00,
- 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x03, 0x00, 0xFF, 0x0C, 0x00,
- 0x02, 0x00, 0x0C, 0x00, 0x01, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x00, 0x18, 0x00, 0x02, 0x00,
- 0x62, 0x00, 0x17, 0x00, 0x01, 0x00, 0x62, 0x00, 0x11, 0x00,
- 0x01, 0x00, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE14_DEMO[] = {
- 0x01, 0x61, 0x00, 0x0D, 0x00, 0x40, 0x36, 0x2C, 0x0D, 0x00,
- 0x00, 0x00, 0x0D, 0x0D, 0x00, 0x03, 0x00, 0xFF, 0x0D, 0x00,
- 0x02, 0x00, 0x0D, 0x00, 0x01, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE15_DEMO[] = {
- 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x3E, 0x33, 0xFF, 0xFF,
- 0x00, 0x00, 0xFF, 0x0E, 0x00, 0x05, 0x00, 0x0E, 0x00, 0x04,
- 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF
-};
-
-const byte ROOM_TABLE16_DEMO[] = {
- 0x01, 0x61, 0x00, 0x10, 0x00, 0x28, 0x0C, 0x5E, 0x0F, 0x00,
- 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x02, 0x00, 0xFF, 0x0F, 0x00,
- 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE17_DEMO[] = {
- 0x02, 0x61, 0x00, 0x10, 0x00, 0x40, 0x20, 0x30, 0x10, 0x00,
- 0x00, 0x00, 0x10, 0x10, 0x00, 0x03, 0x00, 0xFF, 0x10, 0x00,
- 0x02, 0x00, 0x10, 0x00, 0x01, 0x00, 0x6E, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE18_DEMO[] = {
- 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x28, 0x19, 0x2B, 0x11, 0x00,
- 0x00, 0x00, 0x11, 0x11, 0x00, 0x03, 0x00, 0xFF, 0x11, 0x00,
- 0x02, 0x00, 0x11, 0x00, 0x01, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE19_DEMO[] = {
- 0x01, 0x61, 0x00, 0x11, 0x00, 0x2D, 0x14, 0x3C, 0x12, 0x00,
- 0x00, 0x00, 0x12, 0x12, 0x00, 0x03, 0x00, 0xFF, 0x12, 0x00,
- 0x02, 0x00, 0x12, 0x00, 0x01, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE20_DEMO[] = {
- 0x02, 0x61, 0x00, 0x12, 0x00, 0x2D, 0x28, 0x28, 0x13, 0x00,
- 0x00, 0x00, 0x13, 0x13, 0x00, 0x03, 0x00, 0xFF, 0x13, 0x00,
- 0x02, 0x00, 0x13, 0x00, 0x01, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x00, 0x00, 0x00, 0x02, 0x00,
- 0x62, 0x00, 0x29, 0x00, 0x01, 0x00, 0x62, 0x00, 0x24, 0x00,
- 0x01, 0x00, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE21_DEMO[] = {
- 0x01, 0x61, 0x00, 0x16, 0x00, 0x28, 0x0C, 0x5E, 0x14, 0x00,
- 0x00, 0x00, 0x14, 0x14, 0x00, 0x02, 0x00, 0xFF, 0x14, 0x00,
- 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE22_DEMO[] = {
- 0x01, 0x61, 0x00, 0x12, 0x00, 0x3C, 0x2A, 0x29, 0x15, 0x00,
- 0x00, 0x00, 0x15, 0x15, 0x00, 0x03, 0x00, 0xFF, 0x15, 0x00,
- 0x02, 0x00, 0x15, 0x00, 0x01, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x00, 0x23, 0x00, 0x01, 0x00,
- 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE23_DEMO[] = {
- 0x01, 0x61, 0x00, 0x13, 0x00, 0x40, 0x2D, 0x64, 0x16, 0x00,
- 0x00, 0x00, 0xFF, 0x16, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x00,
- 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x16, 0x00, 0x02,
- 0x00, 0xFF, 0xFF, 0x62, 0x00, 0x2A, 0x00, 0x01, 0x00, 0xFF,
- 0xFF
-};
-
-const byte ROOM_TABLE24_DEMO[] = {
- 0x02, 0x61, 0x00, 0x14, 0x00, 0x40, 0x3C, 0x19, 0x17, 0x00,
- 0x00, 0x00, 0x17, 0x17, 0x00, 0x03, 0x00, 0xFF, 0x17, 0x00,
- 0x02, 0x00, 0x17, 0x00, 0x01, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE25_DEMO[] = {
- 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x3F, 0x5A, 0x18, 0x00,
- 0x00, 0x00, 0x18, 0x18, 0x00, 0x02, 0x00, 0xFF, 0x18, 0x00,
- 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xDC, 0xA0, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE26_DEMO[] = {
- 0x02, 0x61, 0x00, 0x17, 0x00, 0x3E, 0x32, 0x80, 0x19, 0x00,
- 0x00, 0x00, 0x19, 0x19, 0x00, 0x03, 0x00, 0xFF, 0x19, 0x00,
- 0x02, 0x00, 0x19, 0x00, 0x01, 0x00, 0x64, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE27_DEMO[] = {
- 0x01, 0x61, 0x00, 0x19, 0x00, 0x34, 0x28, 0x28, 0x1A, 0x00,
- 0x00, 0x00, 0x1A, 0x1A, 0x00, 0x03, 0x00, 0xFF, 0x1A, 0x00,
- 0x02, 0x00, 0x1A, 0x00, 0x01, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x00, 0x28, 0x00, 0x01, 0x00,
- 0x62, 0x00, 0x2B, 0x00, 0x01, 0x00, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE28_DEMO[] = {
- 0x02, 0x61, 0x00, 0x18, 0x00, 0x40, 0x3A, 0x6C, 0x1B, 0x00,
- 0x00, 0x00, 0x1B, 0x1B, 0x00, 0x03, 0x00, 0xFF, 0x1B, 0x00,
- 0x02, 0x00, 0x1B, 0x00, 0x01, 0x00, 0xC8, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE30_DEMO[] = {
- 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0x20, 0x18, 0x73, 0x1D, 0x00,
- 0x00, 0x00, 0x1D, 0x1D, 0x00, 0x03, 0x00, 0xFF, 0x1D, 0x00,
- 0x02, 0x00, 0x1D, 0x00, 0x01, 0x00, 0x80, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE31_DEMO[] = {
- 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x1C, 0x27, 0x1E, 0x00,
- 0x00, 0x00, 0x1E, 0x1E, 0x00, 0x03, 0x00, 0xFF, 0x1E, 0x00,
- 0x02, 0x00, 0x1E, 0x00, 0x01, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE32_DEMO[] = {
- 0x02, 0x61, 0x00, 0x1B, 0x00, 0x40, 0x10, 0x78, 0x1F, 0x00,
- 0x00, 0x00, 0x1F, 0x1F, 0x00, 0x03, 0x00, 0xFF, 0x1F, 0x00,
- 0x02, 0x00, 0x1F, 0x00, 0x01, 0x00, 0xFE, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x00, 0x00, 0x00, 0x02, 0x00,
- 0x62, 0x00, 0x1F, 0x00, 0x01, 0x00, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE33_DEMO[] = {
- 0x01, 0x61, 0x00, 0x1E, 0x00, 0x40, 0x3B, 0x4B, 0x20, 0x00,
- 0x00, 0x00, 0x20, 0x20, 0x00, 0x03, 0x00, 0xFF, 0x20, 0x00,
- 0x02, 0x00, 0x20, 0x00, 0x01, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE34_DEMO[] = {
- 0x01, 0x61, 0x00, 0x04, 0x00, 0x30, 0x10, 0x51, 0x21, 0x00,
- 0x00, 0x00, 0x21, 0x21, 0x00, 0x02, 0x00, 0xFF, 0x21, 0x00,
- 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x00, 0x2E, 0x00, 0x01, 0x00,
- 0x62, 0x00, 0x2F, 0x00, 0x01, 0x00, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE37_DEMO[] = {
- 0x02, 0x61, 0x00, 0x04, 0x00, 0x3E, 0x3A, 0x32, 0x24, 0x00,
- 0x00, 0x00, 0x24, 0x24, 0x00, 0x03, 0x00, 0xFF, 0x24, 0x00,
- 0x02, 0x00, 0x24, 0x00, 0x01, 0x00, 0xB4, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x00, 0x2D, 0x00, 0x02, 0x00,
- 0x62, 0x00, 0x1F, 0x00, 0x01, 0x00, 0x62, 0x00, 0x2E, 0x00,
- 0x01, 0x00, 0x62, 0x00, 0x2F, 0x00, 0x01, 0x00, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE38_DEMO[] = {
- 0x03, 0x61, 0x00, 0x08, 0x00, 0x3F, 0x3F, 0xFF, 0x25, 0x00,
- 0x00, 0x00, 0x25, 0x25, 0x00, 0x03, 0x00, 0xFF, 0x25, 0x00,
- 0x02, 0x00, 0x25, 0x00, 0x01, 0x00, 0xFF, 0x40, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x00, 0x00, 0x00, 0x02, 0x00,
- 0x62, 0x00, 0x21, 0x00, 0x01, 0x00, 0x62, 0x00, 0x25, 0x00,
- 0x01, 0x00, 0x62, 0x00, 0x1F, 0x00, 0x01, 0x00, 0x62, 0x00,
- 0x30, 0x00, 0x01, 0x00, 0x62, 0x00, 0x32, 0x00, 0x01, 0x00,
- 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE39_DEMO[] = {
- 0x01, 0x61, 0x00, 0x08, 0x00, 0x40, 0x32, 0x50, 0x26, 0x00,
- 0x00, 0x00, 0x26, 0x26, 0x00, 0x03, 0x00, 0xFF, 0x26, 0x00,
- 0x02, 0x00, 0x26, 0x00, 0x01, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x62, 0x00, 0x22, 0x00, 0x02, 0x00, 0x62, 0x00, 0x31, 0x00,
- 0x01, 0x00, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE40_DEMO[] = {
- 0x02, 0x61, 0x00, 0x09, 0x00, 0x40, 0x3F, 0x37, 0x27, 0x00,
- 0x00, 0x00, 0x27, 0x27, 0x00, 0x03, 0x00, 0xFF, 0x27, 0x00,
- 0x02, 0x00, 0x27, 0x00, 0x01, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x00, 0x00, 0x00, 0x04, 0x00,
- 0x62, 0x00, 0x1B, 0x00, 0x03, 0x00, 0x62, 0x00, 0x1C, 0x00,
- 0x01, 0x00, 0x62, 0x00, 0x1F, 0x00, 0x02, 0x00, 0x62, 0x00,
- 0x23, 0x00, 0x01, 0x00, 0x62, 0x00, 0x32, 0x00, 0x01, 0x00,
- 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE43_DEMO[] = {
- 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0x1E, 0x1B, 0x6E, 0x2A, 0x00,
- 0x00, 0x00, 0x2A, 0x2A, 0x00, 0x03, 0x00, 0xFF, 0x2A, 0x00,
- 0x02, 0x00, 0x2A, 0x00, 0x01, 0x00, 0xA5, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE45_DEMO[] = {
- 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0x1E, 0x1D, 0xBE, 0x2C, 0x00,
- 0x00, 0x00, 0x2C, 0x2C, 0x00, 0x03, 0x00, 0xFF, 0x2C, 0x00,
- 0x02, 0x00, 0x2C, 0x00, 0x01, 0x00, 0x50, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE46_DEMO[] = {
- 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x1E, 0x1D, 0x78, 0x2D, 0x00,
- 0x00, 0x00, 0x2D, 0x2D, 0x00, 0x03, 0x00, 0xFF, 0x2D, 0x00,
- 0x02, 0x00, 0x2D, 0x00, 0x01, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE47_DEMO[] = {
- 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x28, 0x1E, 0x32, 0x2E, 0x00,
- 0x00, 0x00, 0x2E, 0x2E, 0x00, 0x03, 0x00, 0xFF, 0x2E, 0x00,
- 0x02, 0x00, 0x2E, 0x00, 0x01, 0x00, 0xF0, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE48_DEMO[] = {
- 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x28, 0x1E, 0x32, 0x2F, 0x00,
- 0x00, 0x00, 0x2F, 0x2F, 0x00, 0x03, 0x00, 0xFF, 0x2F, 0x00,
- 0x02, 0x00, 0x2F, 0x00, 0x01, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE51_DEMO[] = {
- 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x28, 0x1E, 0x32, 0xFF, 0xFF,
- 0x00, 0x00, 0xFF, 0x32, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x04,
- 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x32,
- 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE55_DEMO[] = {
- 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x28, 0x1E, 0x6E, 0x36, 0x00,
- 0x00, 0x00, 0x36, 0x36, 0x00, 0x03, 0x00, 0xFF, 0x36, 0x00,
- 0x02, 0x00, 0x36, 0x00, 0x01, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0x36, 0x00, 0x04, 0x00, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE58_DEMO[] = {
- 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0x32, 0x14, 0x73, 0x39, 0x00,
- 0x00, 0x00, 0x39, 0x39, 0x00, 0x03, 0x00, 0xFF, 0x39, 0x00,
- 0x02, 0x00, 0x39, 0x00, 0x01, 0x00, 0xB4, 0x00, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0xFF, 0xFF
-};
-
-const byte ROOM_TABLE62_DEMO[] = {
- 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0x41, 0x3F, 0x19, 0x3D, 0x00,
- 0x00, 0x00, 0x3D, 0x3D, 0x00, 0x03, 0x00, 0x3E, 0x3D, 0x00,
- 0x04, 0x00, 0xFF, 0x3D, 0x00, 0x02, 0x00, 0x3D, 0x00, 0x01,
- 0x00, 0xBE, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62,
- 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x00
-};
-
-const byte *const ROOM_TABLE_DEMO[] = {
- ROOM_TABLE1_DEMO, nullptr, nullptr, nullptr, ROOM_TABLE5_DEMO,
- ROOM_TABLE6_DEMO, ROOM_TABLE7_DEMO, nullptr, ROOM_TABLE9_DEMO, ROOM_TABLE10_DEMO,
- ROOM_TABLE11_DEMO, ROOM_TABLE12_DEMO, ROOM_TABLE13_DEMO, ROOM_TABLE14_DEMO, ROOM_TABLE15_DEMO,
- ROOM_TABLE16_DEMO, ROOM_TABLE17_DEMO, ROOM_TABLE18_DEMO, ROOM_TABLE19_DEMO, ROOM_TABLE20_DEMO,
- ROOM_TABLE21_DEMO, ROOM_TABLE22_DEMO, ROOM_TABLE23_DEMO, ROOM_TABLE24_DEMO, ROOM_TABLE25_DEMO,
- ROOM_TABLE26_DEMO, ROOM_TABLE27_DEMO, ROOM_TABLE28_DEMO, nullptr, ROOM_TABLE30_DEMO,
- ROOM_TABLE31_DEMO, ROOM_TABLE32_DEMO, ROOM_TABLE33_DEMO, ROOM_TABLE34_DEMO, nullptr,
- nullptr, ROOM_TABLE37_DEMO, ROOM_TABLE38_DEMO, ROOM_TABLE39_DEMO, ROOM_TABLE40_DEMO,
- nullptr, nullptr, ROOM_TABLE43_DEMO, nullptr, ROOM_TABLE45_DEMO,
- ROOM_TABLE46_DEMO, ROOM_TABLE47_DEMO, ROOM_TABLE48_DEMO, nullptr, nullptr,
- ROOM_TABLE51_DEMO, nullptr, nullptr, nullptr, ROOM_TABLE55_DEMO,
- nullptr, nullptr, ROOM_TABLE58_DEMO, nullptr, nullptr,
- nullptr, ROOM_TABLE62_DEMO, nullptr, nullptr
-};
-
-const int ROOM_NUMB = 63;
-
-const byte ELAINE[] = {
- 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0x0, 0x0, 0x0, 0x0, 0x41, 0x41, 0x0, 0x1, 0x0, 0xFF, 0x41, 0x0, 0x2,
- 0x0, 0x41, 0x0, 0x0, 0x0, 0x41, 0x0, 0x3, 0x0, 0x41, 0x0, 0x25, 0x0, 0x41,
- 0x0, 0x4, 0x0, 0x41, 0x0, 0x26, 0x0, 0x41, 0x0, 0x5, 0x0, 0x41, 0x0, 0x27,
- 0x0, 0x41, 0x0, 0x6, 0x0, 0x41, 0x0, 0x28, 0x0, 0x41, 0x0, 0x7, 0x0, 0x41,
- 0x0, 0x29, 0x0, 0x41, 0x0, 0x8, 0x0, 0x41, 0x0, 0x2A, 0x0, 0x41, 0x0, 0x9,
- 0x0, 0x41, 0x0, 0x2B, 0x0, 0x41, 0x0, 0x0A, 0x0, 0x41, 0x0, 0x2C, 0x0, 0x41,
- 0x0, 0x0B, 0x0, 0x41, 0x0, 0x2D, 0x0, 0x41, 0x0, 0x0C, 0x0, 0x41, 0x0, 0x2E,
- 0x0, 0x41, 0x0, 0x0D, 0x0, 0x41, 0x0, 0x2F, 0x0, 0x41, 0x0, 0x0E, 0x0, 0x41,
- 0x0, 0x30, 0x0, 0x41, 0x0, 0x0F, 0x0, 0x41, 0x0, 0x31, 0x0, 0x41, 0x0, 0x10,
- 0x0, 0x41, 0x0, 0x32, 0x0, 0x41, 0x0, 0x11, 0x0, 0x41, 0x0, 0x33, 0x0, 0x41,
- 0x0, 0x12, 0x0, 0x41, 0x0, 0x34, 0x0, 0x41, 0x0, 0x13, 0x0, 0x41, 0x0, 0x35,
- 0x0, 0x41, 0x0, 0x14, 0x0, 0x41, 0x0, 0x36, 0x0, 0x41, 0x0, 0x15, 0x0, 0x41,
- 0x0, 0x37, 0x0, 0x41, 0x0, 0x16, 0x0, 0x41, 0x0, 0x38, 0x0, 0x41, 0x0, 0x17,
- 0x0, 0x41, 0x0, 0x39, 0x0, 0x41, 0x0, 0x18, 0x0, 0x41, 0x0, 0x3A, 0x0, 0x41,
- 0x0, 0x19, 0x0, 0x41, 0x0, 0x3B, 0x0, 0x41, 0x0, 0x1A, 0x0, 0x41, 0x0, 0x3C,
- 0x0, 0x41, 0x0, 0x1B, 0x0, 0x41, 0x0, 0x3D, 0x0, 0x41, 0x0, 0x1C, 0x0, 0x41,
- 0x0, 0x3E, 0x0, 0x41, 0x0, 0x1D, 0x0, 0x41, 0x0, 0x3F, 0x0, 0x41, 0x0, 0x1E,
- 0x0, 0x41, 0x0, 0x40, 0x0, 0x41, 0x0, 0x1F, 0x0, 0x41, 0x0, 0x41, 0x0, 0x41,
- 0x0, 0x20, 0x0, 0x41, 0x0, 0x42, 0x0, 0x41, 0x0, 0x21, 0x0, 0x41, 0x0, 0x43,
- 0x0, 0x41, 0x0, 0x22, 0x0, 0x41, 0x0, 0x44, 0x0, 0x41, 0x0, 0x23, 0x0, 0x41,
- 0x0, 0x45, 0x0, 0x41, 0x0, 0x24, 0x0, 0x41, 0x0, 0x46, 0x0, 0xFF, 0xFF
-};
-
-const byte LIB[] = {
- 0x1, 0xFF, 0xFF, 0x42, 0x0, 0x2, 0x0, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x0, 0x0, 0x0, 0x0, 0x42, 0x42, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0x2,
- 0x0, 0x42, 0x0, 0x0, 0x0, 0x42, 0x0, 0x3, 0x0, 0x42, 0x0, 0x18, 0x0, 0x42,
- 0x0, 0x4, 0x0, 0x42, 0x0, 0x19, 0x0, 0x42, 0x0, 0x5, 0x0, 0x42, 0x0, 0x1A,
- 0x0, 0x42, 0x0, 0x6, 0x0, 0x42, 0x0, 0x1B, 0x0, 0x42, 0x0, 0x7, 0x0, 0x42,
- 0x0, 0x1C, 0x0, 0x42, 0x0, 0x8, 0x0, 0x42, 0x0, 0x1D, 0x0, 0x42, 0x0, 0x9,
- 0x0, 0x42, 0x0, 0x1E, 0x0, 0x42, 0x0, 0x0A, 0x0, 0x42, 0x0, 0x1F, 0x0, 0x42,
- 0x0, 0x0B, 0x0, 0x42, 0x0, 0x20, 0x0, 0x42, 0x0, 0x0C, 0x0, 0x42, 0x0, 0x21,
- 0x0, 0x42, 0x0, 0x0D, 0x0, 0x42, 0x0, 0x22, 0x0, 0x42, 0x0, 0x0E, 0x0, 0x42,
- 0x0, 0x23, 0x0, 0x42, 0x0, 0x0F, 0x0, 0x42, 0x0, 0x24, 0x0, 0x42, 0x0, 0x10,
- 0x0, 0x42, 0x0, 0x25, 0x0, 0x42, 0x0, 0x11, 0x0, 0x42, 0x0, 0x26, 0x0, 0x42,
- 0x0, 0x12, 0x0, 0x42, 0x0, 0x27, 0x0, 0x42, 0x0, 0x13, 0x0, 0x42, 0x0, 0x28,
- 0x0, 0x42, 0x0, 0x14, 0x0, 0x42, 0x0, 0x29, 0x0, 0x42, 0x0, 0x15, 0x0, 0x42,
- 0x0, 0x2A, 0x0, 0x42, 0x0, 0x16, 0x0, 0x42, 0x0, 0x2B, 0x0, 0x42, 0x0, 0x17,
- 0x0, 0x42, 0x0, 0x2C, 0x0, 0xFF, 0xFF
-};
-
-const byte FLASHBACK[] = {
- 0x2, 0x1B, 0x0, 0x1C, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0,
- 0x0, 0x0, 0x0, 0xFF, 0xFF, 0xFF, 0x26, 0x0, 0x1C, 0x0, 0x0, 0x0, 0x1C,
- 0x0, 0x5, 0x0, 0x1C, 0x0, 0x0E, 0x0, 0x1C, 0x0, 0x6, 0x0, 0x1C, 0x0, 0x0F,
- 0x0, 0x1C, 0x0, 0x7, 0x0, 0x1C, 0x0, 0x0C, 0x0, 0x1C, 0x0, 0x8, 0x0, 0x1C,
- 0x0, 0x0D, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1C, 0x0, 0x10, 0x0, 0x2, 0x0, 0x2, 0x0, 0x1C,
- 0x0, 0x11, 0x0, 0x1C, 0x0, 0x9, 0x0, 0x1C, 0x0, 0x12, 0x0, 0x1C, 0x0, 0x0A,
- 0x0, 0x1C, 0x0, 0x13, 0x0, 0x1C, 0x0, 0x0B, 0x0, 0x1C, 0x0, 0x14, 0x0, 0x1C,
- 0x0, 0x0B, 0x0, 0x1C, 0x0, 0x15, 0x0, 0x1C, 0x0, 0x0B, 0x0, 0x1C, 0x0, 0x16,
- 0x0, 0x1C, 0x0, 0x0B, 0x0, 0x1C, 0x0, 0x17, 0x0, 0x1C, 0x0, 0x0B, 0x0, 0x1C,
- 0x0, 0x18, 0x0, 0x1C, 0x0, 0x0B, 0x0, 0x1C, 0x0, 0x19, 0x0, 0x1C, 0x0, 0x0B,
- 0x0, 0x1C, 0x0, 0x1A, 0x0, 0x1C, 0x0, 0x0B, 0x0, 0x1C, 0x0, 0x1B, 0x0, 0x1C,
- 0x0, 0x0B, 0x0, 0x1C, 0x0, 0x1C, 0x0, 0x1C, 0x0, 0x0B, 0x0, 0x1C, 0x0, 0x1D,
- 0x0, 0x1C, 0x0, 0x0B, 0x0, 0x1C, 0x0, 0x1E, 0x0, 0x1C, 0x0, 0x0B, 0x0, 0x1C,
- 0x0, 0x1F, 0x0, 0x1C, 0x0, 0x0B, 0x0, 0x1C, 0x0, 0x20, 0x0, 0x1C, 0x0, 0x0B,
- 0x0, 0x1C, 0x0, 0x21, 0x0, 0x1C, 0x0, 0x0B, 0x0, 0x1C, 0x0, 0x22, 0x0, 0x1C,
- 0x0, 0x0B, 0x0, 0x1C, 0x0, 0x23, 0x0, 0x1C, 0x0, 0x0B, 0x0, 0x1C, 0x0, 0x24,
- 0x0, 0xFF, 0xFF
-};
-
-const byte ALLENDIE[] = {
- 0x2, 0xFF, 0xFF, 0x49, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x0, 0x0, 0x0, 0x0, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x49, 0x0, 0x0, 0x0, 0x49,
- 0x0, 0x4, 0x0, 0x62, 0x0, 0x1F, 0x0, 0x49, 0x0, 0x5, 0x0, 0x62, 0x0, 0x3A,
- 0x0, 0x49, 0x0, 0x6, 0x0, 0x49, 0x0, 0x7, 0x0, 0xFF, 0xFF
-};
-
-const byte OVERBOARD[] = {
- 0x2, 0xFF, 0xFF, 0x22, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x0, 0x0, 0x0, 0x0, 0x22, 0x22, 0x0, 0x2, 0x0, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0x22, 0x0, 0x0, 0x0, 0x22, 0x0, 0x3, 0x0, 0x22, 0x0, 0x6, 0x0, 0x22,
- 0x0, 0x4, 0x0, 0x22, 0x0, 0x7, 0x0, 0x22, 0x0, 0x5, 0x0, 0x62, 0x0, 0x1D, 0x0,
- 0x22, 0x0, 0x5, 0x0, 0x62, 0x0, 0x24, 0x0, 0xFF, 0xFF
-};
-
-const byte PILOT2[] = {
- 0x0, 0x12, 0x0, 0xFF, 0xFF, 0x0, 0x0, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x0, 0x0, 0x0, 0x0, 0x46, 0x46, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0x46, 0x0, 0x0, 0x0, 0x46, 0x0, 0x2, 0x0, 0x46, 0x0, 0x0A, 0x0, 0x46,
- 0x0, 0x3, 0x0, 0x46, 0x0, 0x0B, 0x0, 0x46, 0x0, 0x4, 0x0, 0x46, 0x0, 0x0C,
- 0x0, 0x46, 0x0, 0x5, 0x0, 0x46, 0x0, 0x0D, 0x0, 0x46, 0x0, 0x6, 0x0, 0x46,
- 0x0, 0x0E, 0x0, 0x46, 0x0, 0x7, 0x0, 0x46, 0x0, 0x0F, 0x0, 0x46, 0x0, 0x8,
- 0x0, 0x46, 0x0, 0x10, 0x0, 0x46, 0x0, 0x9, 0x0, 0x46, 0x0, 0x11, 0x0, 0x46,
- 0x0, 0x9, 0x0, 0x62, 0x0, 0x1F, 0x0, 0xFF, 0xFF
-};
-
-const byte TIKAGENT[] = {
- 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x0, 0x0, 0x0, 0x0, 0x43, 0x43, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0x2,
- 0x0, 0x43, 0x0, 0x0, 0x0, 0x43, 0x0, 0x2, 0x0, 0x43, 0x0, 0x12, 0x0, 0x43,
- 0x0, 0x3, 0x0, 0x43, 0x0, 0x13, 0x0, 0x43, 0x0, 0x4, 0x0, 0x43, 0x0, 0x14,
- 0x0, 0x43, 0x0, 0x5, 0x0, 0x43, 0x0, 0x15, 0x0, 0x43, 0x0, 0x6, 0x0, 0x43,
- 0x0, 0x16, 0x0, 0x43, 0x0, 0x7, 0x0, 0x43, 0x0, 0x17, 0x0, 0x43, 0x0, 0x8,
- 0x0, 0x43, 0x0, 0x18, 0x0, 0x43, 0x0, 0x9, 0x0, 0x43, 0x0, 0x19, 0x0, 0x43,
- 0x0, 0x0A, 0x0, 0x43, 0x0, 0x1A, 0x0, 0x43, 0x0, 0x0B, 0x0, 0x43, 0x0, 0x1B,
- 0x0, 0x43, 0x0, 0x0C, 0x0, 0x43, 0x0, 0x1C, 0x0, 0x43, 0x0, 0x0D, 0x0, 0x43,
- 0x0, 0x1D, 0x0, 0x43, 0x0, 0x0E, 0x0, 0x43, 0x0, 0x1E, 0x0, 0x43, 0x0, 0x0F,
- 0x0, 0x43, 0x0, 0x1F, 0x0, 0x43, 0x0, 0x10, 0x0, 0x43, 0x0, 0x20, 0x0, 0x43,
- 0x0, 0x11, 0x0, 0x43, 0x0, 0x21, 0x0, 0xFF, 0xFF
-};
-
-const byte BARTENDER[] = {
- 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x0, 0x0, 0x0, 0x0, 0x44, 0x44, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0x0,
- 0x0, 0x44, 0x0, 0x0, 0x0, 0x44, 0x0, 0x2, 0x0, 0x44, 0x0, 0x8, 0x0, 0x44, 0x0,
- 0x3, 0x0, 0x44, 0x0, 0x9, 0x0, 0x44, 0x0, 0x4, 0x0, 0x44, 0x0, 0x0A, 0x0, 0x44,
- 0x0, 0x5, 0x0, 0x44, 0x0, 0x0B, 0x0, 0x44, 0x0, 0x6, 0x0, 0x44, 0x0, 0x0C,
- 0x0, 0x44, 0x0, 0x7, 0x0, 0x44, 0x0, 0x0D, 0x0, 0xFF, 0xFF
-};
-
-const byte PILOT1[] = {
- 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0x0, 0x0, 0x0, 0x0, 0x45, 0x45, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0x0,
- 0x0, 0x45, 0x0, 0x0, 0x0, 0x45, 0x0, 0x2, 0x0, 0x45, 0x0, 0x3, 0x0, 0xFF, 0xFF
-};
-
-const byte COOK[] = {
- 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0x0, 0x0, 0x0, 0x0, 0x47, 0x47, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF,
- 0x2, 0x0, 0x47, 0x0, 0x0, 0x0, 0x47, 0x0, 0x2, 0x0, 0x47, 0x0, 0x10, 0x0, 0x47,
- 0x0, 0x3, 0x0, 0x47, 0x0, 0x11, 0x0, 0x47, 0x0, 0x4, 0x0, 0x47, 0x0, 0x12,
- 0x0, 0x47, 0x0, 0x5, 0x0, 0x47, 0x0, 0x13, 0x0, 0x47, 0x0, 0x6, 0x0, 0x47,
- 0x0, 0x14, 0x0, 0x47, 0x0, 0x7, 0x0, 0x47, 0x0, 0x15, 0x0, 0x47, 0x0, 0x8,
- 0x0, 0x47, 0x0, 0x16, 0x0, 0x47, 0x0, 0x9, 0x0, 0x47, 0x0, 0x17, 0x0, 0x47,
- 0x0, 0x0A, 0x0, 0x47, 0x0, 0x18, 0x0, 0x47, 0x0, 0x0B, 0x0, 0x47, 0x0, 0x19,
- 0x0, 0x47, 0x0, 0x0C, 0x0, 0x47, 0x0, 0x1A, 0x0, 0x47, 0x0, 0x0D, 0x0, 0x47,
- 0x0, 0x1B, 0x0, 0x47, 0x0, 0x0E, 0x0, 0x47, 0x0, 0x1C, 0x0, 0x47, 0x0, 0x0F,
- 0x0, 0x47, 0x0, 0x1D, 0x0, 0xFF, 0xFF
-};
-
-const byte BEXPLODE[] = {
- 0x2, 0xFF, 0xFF, 0x28, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x0, 0x0, 0x0, 0x0, 0x28, 0x28, 0x0, 0x2, 0x0, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0x28, 0x0, 0x0, 0x0, 0x28, 0x0, 0x3, 0x0, 0x28, 0x0, 0x9, 0x0, 0x28,
- 0x0, 0x4, 0x0, 0x28, 0x0, 0x0A, 0x0, 0x28, 0x0, 0x5, 0x0, 0x28, 0x0, 0x0B,
- 0x0, 0x28, 0x0, 0x6, 0x0, 0x62, 0x0, 0x23, 0x0, 0x28, 0x0, 0x7, 0x0, 0x62,
- 0x0, 0x23, 0x0, 0x28, 0x0, 0x8, 0x0, 0x62, 0x0, 0x23, 0x0, 0xFF, 0xFF
-};
-
-const byte THORNICK[] = {
- 0x2, 0x7, 0x0, 0x7, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0,
- 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7, 0x0, 0x0, 0x0, 0x7, 0x0, 0x2, 0x0,
- 0x7, 0x0, 0x5, 0x0, 0x7, 0x0, 0x3, 0x0, 0x7, 0x0, 0x6, 0x0, 0x7, 0x0, 0x3,
- 0x0, 0x7, 0x0, 0x7, 0x0, 0x7, 0x0, 0x4, 0x0, 0x7, 0x0, 0x8, 0x0, 0xFF, 0xFF
-};
-
-const byte MAYA[] = {
- 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0,
- 0x0, 0x0, 0x0, 0x48, 0x48, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0x2, 0x0,
- 0x48, 0x0, 0x0, 0x0, 0x48, 0x0, 0x2, 0x0, 0x48, 0x0, 0x13, 0x0, 0x48,
- 0x0, 0x3, 0x0, 0x48, 0x0, 0x14, 0x0, 0x48, 0x0, 0x4, 0x0, 0x48, 0x0, 0x15,
- 0x0, 0x48, 0x0, 0x5, 0x0, 0x48, 0x0, 0x16, 0x0, 0x48, 0x0, 0x6, 0x0, 0x48,
- 0x0, 0x17, 0x0, 0x48, 0x0, 0x7, 0x0, 0x48, 0x0, 0x18, 0x0, 0x48, 0x0, 0x8,
- 0x0, 0x48, 0x0, 0x19, 0x0, 0x48, 0x0, 0x9, 0x0, 0x48, 0x0, 0x1A, 0x0, 0x48,
- 0x0, 0x0A, 0x0, 0x48, 0x0, 0x1B, 0x0, 0x48, 0x0, 0x0B, 0x0, 0x48, 0x0, 0x1C,
- 0x0, 0x48, 0x0, 0x0C, 0x0, 0x48, 0x0, 0x1D, 0x0, 0x48, 0x0, 0x0D, 0x0, 0x48,
- 0x0, 0x1E, 0x0, 0x48, 0x0, 0x0E, 0x0, 0x48, 0x0, 0x1F, 0x0, 0x48, 0x0, 0x0F,
- 0x0, 0x48, 0x0, 0x20, 0x0, 0x48, 0x0, 0x10, 0x0, 0x48, 0x0, 0x21, 0x0, 0x48,
- 0x0, 0x11, 0x0, 0x48, 0x0, 0x22, 0x0, 0x48, 0x0, 0x12, 0x0, 0x48, 0x0, 0x23,
- 0x0, 0xFF, 0xFF
-};
-
-const byte CAPTAIN[] = {
- 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0x0, 0x0, 0x0, 0x0, 0x4A, 0x4A, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF,
- 0x2, 0x0, 0x4A, 0x0, 0x0, 0x0, 0x4A, 0x0, 0x2, 0x0, 0x4A, 0x0, 0x0E, 0x0, 0x4A,
- 0x0, 0x3, 0x0, 0x4A, 0x0, 0x0F, 0x0, 0x4A, 0x0, 0x4, 0x0, 0x4A, 0x0, 0x10,
- 0x0, 0x4A, 0x0, 0x5, 0x0, 0x4A, 0x0, 0x11, 0x0, 0x4A, 0x0, 0x6, 0x0, 0x4A,
- 0x0, 0x12, 0x0, 0x4A, 0x0, 0x7, 0x0, 0x4A, 0x0, 0x13, 0x0, 0x4A, 0x0, 0x8,
- 0x0, 0x4A, 0x0, 0x14, 0x0, 0x4A, 0x0, 0x9, 0x0, 0x4A, 0x0, 0x15, 0x0, 0x4A,
- 0x0, 0x0A, 0x0, 0x4A, 0x0, 0x16, 0x0, 0x4A, 0x0, 0x0B, 0x0, 0x4A, 0x0, 0x17,
- 0x0, 0x4A, 0x0, 0x0C, 0x0, 0x4A, 0x0, 0x18, 0x0, 0x4A, 0x0, 0x0D, 0x0, 0x4A,
- 0x0, 0x19, 0x0, 0xFF, 0xFF
-};
-
-const byte ALLEN[] = {
- 0x3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0x0, 0x0, 0x0, 0x0, 0x1E, 0x4C, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0x4C, 0x0, 0x0, 0x0, 0x4C, 0x0, 0x2, 0x0, 0x4C, 0x0, 0x3, 0x0,
- 0xFF, 0xFF
-};
-
-const byte ARCH[] = {
- 0x1, 0x2B, 0x0, 0x4B, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0,
- 0x0, 0x0, 0x0, 0x2B, 0x4B, 0x0, 0x40, 0x0, 0xFF, 0x4B, 0x0, 0x41, 0x0,
- 0x4B, 0x0, 0x0, 0x0, 0x4B, 0x0, 0x2, 0x0, 0x4B, 0x0, 0x4, 0x0, 0x4B, 0x0, 0x3,
- 0x0, 0x4B, 0x0, 0x5, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x6, 0x0, 0x4B, 0x0,
- 0x3, 0x0, 0x4B, 0x0, 0x7, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x8, 0x0, 0x4B,
- 0x0, 0x3, 0x0, 0x4B, 0x0, 0x9, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x0A, 0x0,
- 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x0B, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0,
- 0x0C, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x0D, 0x0, 0x4B, 0x0, 0x3, 0x0,
- 0x4B, 0x0, 0x0E, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x0F, 0x0, 0x4B, 0x0,
- 0x3, 0x0, 0x4B, 0x0, 0x10, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x11, 0x0,
- 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x12, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0,
- 0x13, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x14, 0x0, 0x4B, 0x0, 0x3, 0x0,
- 0x4B, 0x0, 0x15, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x16, 0x0, 0x4B, 0x0,
- 0x3, 0x0, 0x4B, 0x0, 0x17, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x18, 0x0,
- 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x19, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0,
- 0x1A, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x1B, 0x0, 0x4B, 0x0, 0x3, 0x0,
- 0x4B, 0x0, 0x1C, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x1D, 0x0, 0x4B, 0x0,
- 0x3, 0x0, 0x4B, 0x0, 0x1E, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x1F, 0x0,
- 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x20, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0,
- 0x21, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x22, 0x0, 0x4B, 0x0, 0x3, 0x0,
- 0x4B, 0x0, 0x23, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x24, 0x0, 0x4B, 0x0,
- 0x3, 0x0, 0x4B, 0x0, 0x25, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x26, 0x0,
- 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x27, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0,
- 0x28, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x29, 0x0, 0x4B, 0x0, 0x3, 0x0,
- 0x4B, 0x0, 0x2A, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x2B, 0x0, 0x4B, 0x0,
- 0x3, 0x0, 0x4B, 0x0, 0x2C, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x2D, 0x0,
- 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x2E, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0,
- 0x2F, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x30, 0x0, 0x4B, 0x0, 0x3, 0x0,
- 0x4B, 0x0, 0x31, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x32, 0x0, 0x4B, 0x0,
- 0x3, 0x0, 0x4B, 0x0, 0x33, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x34, 0x0,
- 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x35, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0,
- 0x36, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x37, 0x0, 0x4B, 0x0, 0x3, 0x0,
- 0x4B, 0x0, 0x38, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x39, 0x0, 0x4B, 0x0,
- 0x3, 0x0, 0x4B, 0x0, 0x3A, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x3B, 0x0,
- 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x3C, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0,
- 0x3D, 0x0, 0x4B, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x3E, 0x0, 0x4B, 0x0, 0x3, 0x0,
- 0x4B, 0x0, 0x3F, 0x0, 0xFF, 0xFF
-};
-
-const byte GUARD1[] = {
- 0x3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0x0, 0x0, 0x0, 0x0, 0x4D, 0x4D, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0x4D, 0x0, 0x0, 0x0, 0x4D, 0x0, 0x2, 0x0, 0x4D, 0x0, 0x3, 0x0,
- 0xFF, 0xFF
-};
-
-const byte MCANOE[] = {
- 0x3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0x0, 0x0, 0x0, 0x0, 0x4E, 0x4E, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0x4E, 0x0, 0x0, 0x0, 0x4E, 0x0, 0x2, 0x0, 0x4E, 0x0, 0x3, 0x0,
- 0xFF, 0xFF
-};
-
-const byte CAMPFIRE[] = {
- 0x2, 0x35, 0x0, 0x35, 0x0, 0x3, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0,
- 0x0, 0x0, 0x0, 0x35, 0x35, 0x0, 0x1, 0x0, 0xFF, 0x35, 0x0, 0x2, 0x0, 0x35,
- 0x0, 0x0, 0x0, 0x35, 0x0, 0x4, 0x0, 0x35, 0x0, 0x18, 0x0, 0x35, 0x0, 0x5, 0x0,
- 0x35, 0x0, 0x19, 0x0, 0x35, 0x0, 0x6, 0x0, 0x35, 0x0, 0x1A, 0x0, 0x35, 0x0,
- 0x7, 0x0, 0x35, 0x0, 0x1B, 0x0, 0x35, 0x0, 0x8, 0x0, 0x35, 0x0, 0x1C, 0x0,
- 0x35, 0x0, 0x9, 0x0, 0x35, 0x0, 0x1D, 0x0, 0x35, 0x0, 0x0A, 0x0, 0x35, 0x0,
- 0x1E, 0x0, 0x35, 0x0, 0x0B, 0x0, 0x35, 0x0, 0x1F, 0x0, 0x35, 0x0, 0x0C,
- 0x0, 0x35, 0x0, 0x20, 0x0, 0x35, 0x0, 0x0D, 0x0, 0x35, 0x0, 0x21, 0x0, 0x35,
- 0x0, 0x0E, 0x0, 0x35, 0x0, 0x22, 0x0, 0x35, 0x0, 0x0F, 0x0, 0x35, 0x0, 0x23,
- 0x0, 0x35, 0x0, 0x10, 0x0, 0x35, 0x0, 0x24, 0x0, 0x35, 0x0, 0x11, 0x0, 0x35,
- 0x0, 0x25, 0x0, 0x35, 0x0, 0x12, 0x0, 0x35, 0x0, 0x26, 0x0, 0x35, 0x0, 0x13,
- 0x0, 0x35, 0x0, 0x27, 0x0, 0x35, 0x0, 0x14, 0x0, 0x35, 0x0, 0x28, 0x0, 0x35,
- 0x0, 0x15, 0x0, 0x35, 0x0, 0x29, 0x0, 0x35, 0x0, 0x16, 0x0, 0x35, 0x0, 0x2A,
- 0x0, 0x35, 0x0, 0x17, 0x0, 0x35, 0x0, 0x2B, 0x0, 0xFF, 0xFF
-};
-
-const byte COLONEL[] = {
- 0x2, 0xFF, 0xFF, 0x0E, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x0, 0x0, 0x0, 0x0, 0x0E, 0x0E, 0x0, 0x5, 0x0, 0xFF, 0xFF, 0xFF, 0x2,
- 0x0, 0x4F, 0x0, 0x0, 0x0, 0x4F, 0x0, 0x1, 0x0, 0x4F, 0x0, 0x2, 0x0, 0x0E, 0x0,
- 0x8, 0x0, 0x4F, 0x0, 0x3, 0x0, 0xFF, 0xFF
-};
-
-const byte SOLDIERS[] = {
- 0x2, 0xFF, 0xFF, 0x50, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x0, 0x0, 0x0, 0x0, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x50, 0x0, 0x0, 0x0, 0x50,
- 0x0, 0x2, 0x0, 0x50, 0x0, 0x0, 0x0, 0xFF, 0xFF
-};
-
-const byte JWATER[] = {
- 0x2, 0xFF, 0xFF, 0x51, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x0, 0x0, 0x0, 0x0, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x51, 0x0, 0x0, 0x0, 0x51,
- 0x0, 0x2, 0x0, 0x51, 0x0, 0x3, 0x0, 0xFF, 0xFF
-};
-
-const byte SHOOT[] = {
- 0x2, 0xFF, 0xFF, 0x52, 0x0, 0x2, 0x0, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x0, 0x0, 0x0, 0x0, 0x38, 0x52, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0x0,
- 0x0, 0x52, 0x0, 0x0, 0x0, 0x52, 0x0, 0x3, 0x0, 0x52, 0x0, 0x5, 0x0, 0x52,
- 0x0, 0x4, 0x0, 0x62, 0x0, 0x1F, 0x0, 0xFF, 0xFF
-};
-
-const byte ADIE[] = {
- 0x2, 0xFF, 0xFF, 0x53, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x0, 0x0, 0x0, 0x0, 0xFF, 0xFF, 0xFF, 0x2, 0x0, 0x53, 0x0, 0x0, 0x0, 0x53,
- 0x0, 0x2, 0x0, 0x62, 0x0, 0x4, 0x0, 0x53, 0x0, 0x3, 0x0, 0x62, 0x0, 0x4,
- 0x0, 0x53, 0x0, 0x4, 0x0, 0x62, 0x0, 0x4, 0x0, 0xFF, 0xFF
-};
-
-const byte DYNAMITE[] = {
- 0x2, 0xFF, 0xFF, 0x54, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x0, 0x0, 0x0, 0x0, 0xFF, 0xFF, 0xFF, 0x2, 0x0, 0x54, 0x0, 0x0, 0x0, 0x54,
- 0x0, 0x2, 0x0, 0x62, 0x0, 0x23, 0x0, 0xFF, 0xFF
-};
-
-const byte MAYASHOT[] = {
- 0x3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0x0, 0x0, 0x0, 0x0, 0x36, 0x55, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF,
- 0x3, 0x0, 0x55, 0x0, 0x0, 0x0, 0x55, 0x0, 0x2, 0x0, 0x62, 0x0, 0x1F,
- 0x0, 0xFF, 0xFF
-};
-
-const byte OFFKEV[] = {
- 0x3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0,
- 0x0, 0x0, 0x0, 0x4D, 0x29, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x29, 0x0, 0x0, 0x0, 0x29, 0x0, 0x2, 0x0, 0x29, 0x0, 0x3, 0x0, 0xFF, 0xFF
-};
-
-const byte VALLEY[] = {
- 0x2, 0x3A, 0x0, 0x3A, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0,
- 0x0, 0x0, 0x0, 0x3A, 0x3A, 0x0, 0x2, 0x0, 0xFF, 0xFF, 0xFF, 0x3, 0x0,
- 0x3A, 0x0, 0x0, 0x0, 0x3A, 0x0, 0x3, 0x0, 0x3A, 0x0, 0x5, 0x0, 0x3A, 0x0,
- 0x4, 0x0, 0x62, 0x0, 0x27, 0x0, 0xFF, 0xFF
-};
-
-const byte MEANWHILE1[] = {
- 0x2, 0xFF, 0xFF, 0x0E, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x0, 0x0, 0x0, 0x0, 0x0E, 0x0E, 0x0, 0x5, 0x0, 0xFF, 0xFF, 0xFF, 0x3,
- 0x0, 0x0E, 0x0, 0x0, 0x0, 0x0E, 0x0, 0x6, 0x0, 0x0E, 0x0, 0x0A, 0x0, 0x0E,
- 0x0, 0x7, 0x0, 0x0E, 0x0, 0x0B, 0x0, 0x0E, 0x0, 0x8, 0x0, 0x0E, 0x0, 0x0C,
- 0x0, 0x0E, 0x0, 0x8, 0x0, 0x0E, 0x0, 0x0D, 0x0, 0x0E, 0x0, 0x8, 0x0, 0x0E,
- 0x0, 0x0E, 0x0, 0x0E, 0x0, 0x9, 0x0, 0x0E, 0x0, 0x0F, 0x0, 0x0E, 0x0, 0x9,
- 0x0, 0x0E, 0x0, 0x10, 0x0, 0x0E, 0x0, 0x9, 0x0, 0x0E, 0x0, 0x11, 0x0, 0x0E,
- 0x0, 0x9, 0x0, 0x0E, 0x0, 0x12, 0x0, 0x0E, 0x0, 0x9, 0x0, 0x62, 0x0, 0x1A,
- 0x0, 0xFF, 0xFF
-};
-
-const byte MAYATREE[] = {
- 0x3, 0xFF, 0xFF, 0xFF, 0xFF, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x0, 0x0, 0x0, 0x0, 0x30, 0x56, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0x0,
- 0x0, 0x56, 0x0, 0x0, 0x0, 0x56, 0x0, 0x2, 0x0, 0x56, 0x0, 0x3, 0x0, 0xFF, 0xFF
-};
-
-const byte LOCO[] = {
- 0x3, 0xFF, 0xFF, 0xFF, 0xFF, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x0, 0x0, 0x0, 0x0, 0x31, 0x57, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0x0,
- 0x0, 0x57, 0x0, 0x0, 0x0, 0x57, 0x0, 0x2, 0x0, 0x57, 0x0, 0x3, 0x0, 0xFF, 0xFF
-};
-
-const byte KISS[] = {
- 0x2, 0xFF, 0xFF, 0x3A, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x0, 0x0, 0x0, 0x0, 0x40, 0x40, 0x0, 0x5, 0x0, 0xFF, 0xFF, 0xFF, 0x0,
- 0x0, 0x40, 0x0, 0x0, 0x0, 0x40, 0x0, 0x6, 0x0, 0x40, 0x0, 0x26, 0x0, 0x40,
- 0x0, 0x7, 0x0, 0x40, 0x0, 0x27, 0x0, 0x40, 0x0, 0x8, 0x0, 0x40, 0x0, 0x28,
- 0x0, 0x40, 0x0, 0x9, 0x0, 0x62, 0x0, 0x4E, 0x0, 0x40, 0x0, 0x0A, 0x0, 0x40,
- 0x0, 0x29, 0x0, 0x40, 0x0, 0x0B, 0x0, 0x40, 0x0, 0x2A, 0x0, 0x40, 0x0, 0x0C,
- 0x0, 0x40, 0x0, 0x2B, 0x0, 0x40, 0x0, 0x0D, 0x0, 0x40, 0x0, 0x2C, 0x0, 0x40,
- 0x0, 0x0E, 0x0, 0x40, 0x0, 0x2D, 0x0, 0x40, 0x0, 0x0F, 0x0, 0x40, 0x0, 0x2E,
- 0x0, 0x40, 0x0, 0x10, 0x0, 0x40, 0x0, 0x2F, 0x0, 0x40, 0x0, 0x11, 0x0, 0x40,
- 0x0, 0x30, 0x0, 0x40, 0x0, 0x12, 0x0, 0x40, 0x0, 0x31, 0x0, 0x40, 0x0, 0x13,
- 0x0, 0x40, 0x0, 0x32, 0x0, 0x40, 0x0, 0x14, 0x0, 0x40, 0x0, 0x33, 0x0, 0x40,
- 0x0, 0x15, 0x0, 0x40, 0x0, 0x34, 0x0, 0x40, 0x0, 0x16, 0x0, 0x40, 0x0, 0x35,
- 0x0, 0x40, 0x0, 0x17, 0x0, 0x40, 0x0, 0x36, 0x0, 0x40, 0x0, 0x18, 0x0, 0x40,
- 0x0, 0x37, 0x0, 0x40, 0x0, 0x19, 0x0, 0x40, 0x0, 0x38, 0x0, 0x40, 0x0, 0x1A,
- 0x0, 0x40, 0x0, 0x39, 0x0, 0x40, 0x0, 0x1B, 0x0, 0x40, 0x0, 0x3A, 0x0, 0x40,
- 0x0, 0x1C, 0x0, 0x40, 0x0, 0x3B, 0x0, 0x40, 0x0, 0x1D, 0x0, 0x40, 0x0, 0x3C,
- 0x0, 0x40, 0x0, 0x1E, 0x0, 0x40, 0x0, 0x3D, 0x0, 0x40, 0x0, 0x1F, 0x0, 0x40,
- 0x0, 0x3E, 0x0, 0x40, 0x0, 0x20, 0x0, 0x40, 0x0, 0x3F, 0x0, 0x40, 0x0, 0x21,
- 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x22, 0x0, 0x40, 0x0, 0x41, 0x0, 0x40,
- 0x0, 0x23, 0x0, 0x40, 0x0, 0x42, 0x0, 0x40, 0x0, 0x24, 0x0, 0x40, 0x0, 0x43,
- 0x0, 0x40, 0x0, 0x25, 0x0, 0x40, 0x0, 0x44, 0x0, 0x40, 0x0, 0x25, 0x0, 0x40,
- 0x0, 0x45, 0x0, 0x40, 0x0, 0x25, 0x0, 0x40, 0x0, 0x46, 0x0, 0x40, 0x0, 0x25,
- 0x0, 0x40, 0x0, 0x47, 0x0, 0xFF, 0xFF
-};
-
-const byte ROBOT[] = {
- 0x3, 0xFF, 0xFF, 0xFF, 0xFF, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x0, 0x0, 0x0, 0x0, 0x9, 0x58, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0x0, 0x0,
- 0x58, 0x0, 0x0, 0x0, 0x58, 0x0, 0x0, 0x0, 0x58, 0x0, 0x2, 0x0, 0xFF, 0xFF
-};
-
-const byte ANTKILL[] = {
- 0x3, 0xFF, 0xFF, 0xFF, 0xFF, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0,
- 0x0, 0x0, 0x3C, 0x59, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x59,
- 0x0, 0x0, 0x0, 0x59, 0x0, 0x2, 0x0, 0x62, 0x0, 0x0E, 0x0, 0xFF, 0xFF
-};
-
-const byte LOCOHOT[] = {
- 0x3, 0xFF, 0xFF, 0xFF, 0xFF, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0,
- 0x0, 0x0, 0x19, 0x5A, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x5A,
- 0x0, 0x0, 0x0, 0x5A, 0x0, 0x2, 0x0, 0x62, 0x0, 0x3C, 0x0, 0xFF, 0xFF
-};
-
-const byte CRACK[] = {
- 0x2, 0x38, 0x0, 0x38, 0x0, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0,
- 0x0, 0x0, 0x0, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x38, 0x0, 0x0, 0x0, 0x38,
- 0x0, 0x0, 0x0, 0x38, 0x0, 0x2, 0x0, 0xFF, 0xFF
-};
-
-const byte LETTER[] = {
- 0x3, 0xFF, 0xFF, 0xFF, 0xFF, 0x1, 0x0, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x0, 0x0, 0x0, 0x0, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x30,
- 0x0, 0x0, 0x0, 0x30, 0x0, 0x1, 0x0, 0x30, 0x0, 0x0, 0x0, 0x30, 0x0, 0x6, 0x0, 0x30,
- 0x0, 0x0, 0x0, 0x30, 0x0, 0x7, 0x0, 0x30, 0x0, 0x0, 0x0, 0x30, 0x0, 0x8, 0x0, 0x30,
- 0x0, 0x0, 0x0, 0x30, 0x0, 0x9, 0x0, 0x30, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0A, 0x0,
- 0x30, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0B, 0x0, 0x30, 0x0, 0x0, 0x0, 0x30, 0x0,
- 0x0C, 0x0, 0x30, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0D, 0x0, 0x30, 0x0, 0x0, 0x0,
- 0x30, 0x0, 0x0E, 0x0, 0x30, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0F, 0x0, 0x30, 0x0,
- 0x0, 0x0, 0x30, 0x0, 0x10, 0x0, 0x30, 0x0, 0x0, 0x0, 0x30, 0x0, 0x2, 0x0, 0x30,
- 0x0, 0x0, 0x0, 0x30, 0x0, 0x3, 0x0, 0x30, 0x0, 0x0, 0x0, 0x30, 0x0, 0x4, 0x0, 0x30,
- 0x0, 0x0, 0x0, 0x30, 0x0, 0x5, 0x0, 0xFF, 0xFF
-};
-
-const byte OVERBOARD_DEMO[] = {
- 0x02, 0xFF, 0xFF, 0x22, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF,
- 0xFF, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x00, 0x02, 0x00,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x22, 0x00, 0x00, 0x00, 0x22,
- 0x00, 0x03, 0x00, 0x22, 0x00, 0x06, 0x00, 0x22, 0x00, 0x04,
- 0x00, 0x22, 0x00, 0x07, 0x00, 0x22, 0x00, 0x05, 0x00, 0x62,
- 0x00, 0x1D, 0x00, 0x60, 0x00, 0x00, 0x00, 0x22, 0x00, 0x06,
- 0x00, 0x60, 0x00, 0x01, 0x00, 0x22, 0x00, 0x07, 0x00, 0xFF,
- 0xFF
-};
-
-const byte SHORE1[] = {
- 0x02, 0xFF, 0xFF, 0x55, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF,
- 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x03, 0x00,
- 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x02, 0x00, 0x62, 0x00,
- 0x2E, 0x00, 0x55, 0x00, 0x02, 0x00, 0x62, 0x00, 0x2F, 0x00,
- 0xFF, 0xFF
-};
-
-const byte CHAP8[] = {
- 0x02, 0xFF, 0xFF, 0x60, 0x00, 0x03, 0x00, 0xFF, 0xFF, 0xFF,
- 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x60, 0x00, 0x02, 0x00, 0xFF, 0xFF
-};
-
-const byte *const CHARTBL[] = {
- ELAINE, LIB, FLASHBACK, ALLENDIE, OVERBOARD, PILOT2, TIKAGENT,
- BARTENDER, PILOT1, COOK, BEXPLODE, THORNICK, MAYA, CAPTAIN,
- ALLEN, ARCH, GUARD1, MCANOE, CAMPFIRE, COLONEL, SOLDIERS,
- JWATER, SHOOT, ADIE, DYNAMITE, MAYASHOT, OFFKEV, VALLEY,
- MEANWHILE1, MAYATREE, LOCO, KISS, ROBOT, ANTKILL, LOCOHOT,
- CRACK, LETTER
-};
-
-const byte *const CHARTBL_DEMO[] = {
- ELAINE, LIB, FLASHBACK, ALLENDIE, OVERBOARD_DEMO, PILOT2, TIKAGENT,
- BARTENDER, PILOT1, COOK, BEXPLODE, THORNICK, MAYA, CAPTAIN,
- ALLEN, ARCH, GUARD1, MCANOE, CAMPFIRE, COLONEL, SOLDIERS,
- JWATER, SHOOT, ADIE, DYNAMITE, SHORE1, CHAP8
-};
-
-const char *const INVENTORY_NAMES[] = {
- "RAT", "ALCOHOL", "SAFE COMBINATION", "BEAKER", "MICROFILM",
- "VAULT KEY", "BOLT CUTTERS", "BLOWGUN", "LOVE POTION", "MONEY",
- "DARTS", "TAPE", "JUNGLE POTION", "MOVIE", "CABINET KEY",
- "DISPLAY CASE KEY", "FLITCH'S CAR KEYS", "COAT HANGER",
- "CROWBAR", "COMPASS", "MAP", "LETTER OPENER", "LETTER",
- "DECODER", "DIPPED DART", "LOADED BLOWGUN", "CARD", "JERRYCAN",
- "CIGARETTES", "BIKE PUMP", "PARACHUTE", "PESO", "PEPPERS",
- "MACHETE", "POISON ROOT", "AMMUNITION", "PADDLE", "FISHING NET",
- "RAT TRAP", "CHEESE", "LOADED TRAP", "KNIFE", "CHOPPED PEPPERS",
- "LIGHTER", "LADDER", "SMALL POLE", "JEEP KEY", "CHAIN", "ARROW",
- "FILLED JERRY CAN", "EXPLOSIVES", "GEIGER COUNTER", "VINE",
- "GOLD NUGGET", "HOLLOW REED", "AMAZON QUEEN KEYS", "FISHING POLE",
- "HARPOON", "RAG", "BOTTLE OF RUM", "RAG IN BOTTLE", "MOLOTOV COCKTAIL",
- "JUNGLE PLANT", "LADLE", "WORM", "FISH", "FIREWORKS", "BAITED POLE",
- "FILLED LADLE", "EMERALD", "SMALL KEY", "SCROLL", "LIT EXPLOSIVES",
- "LIGHTER", "BROKEN SPEAR", "SHOE LACES", "TORCH", "LACES AND SPEAR",
- "KNIFE SPEAR", "GARBAGE CAN", "RAFT", "INFLATED RAFT",
- "JASON'S CAR KEYS", "PESO BILLS", "PLANK"
-};
-
-const int FONT2_INDEX[] = {
- 62, 2, 6,
- 0x0000, 0x0019, 0x0021, 0x002e, 0x0041, 0x005a, 0x0073, 0x008c, 0x0093, 0x009b,
- 0x00a3, 0x00bc, 0x00d5, 0x00dd, 0x00ea, 0x00f1, 0x00fe, 0x010b, 0x0118, 0x0125,
- 0x0132, 0x013f, 0x014c, 0x0159, 0x0166, 0x0173, 0x0180, 0x0187, 0x018e, 0x01a7,
- 0x01b4, 0x01cd, 0x01dc, 0x01f5, 0x0208, 0x0215, 0x0222, 0x022f, 0x023c, 0x0249,
- 0x025c, 0x0269, 0x0276, 0x0285, 0x0292, 0x029f, 0x02b2, 0x02c5, 0x02d2, 0x02df,
- 0x02ee, 0x02fb, 0x0308, 0x0315, 0x0322, 0x032f, 0x0342, 0x034f, 0x0362, 0x036f,
- 0x0388, 0x03a1,
-};
-
-const byte FONT2_DATA[] = {
- 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0xf0, 0xf0, 0xf0,
- 0x00, 0xf0, 0x00, 0x06, 0xf3, 0xc0, 0xc3, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x07, 0x1c, 0x00,
- 0x67, 0x9e, 0xc0, 0x07, 0x1c, 0x00, 0x67, 0x9e, 0xc0, 0x07,
- 0x1c, 0x00, 0x00, 0x00, 0x00, 0x09, 0x02, 0xc0, 0x00, 0x3f,
- 0xfc, 0x00, 0xb2, 0xc0, 0x00, 0x3f, 0xfc, 0x00, 0x02, 0xcb,
- 0x00, 0x3f, 0xfc, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00,
- 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x18, 0x60,
- 0x70, 0x70, 0x60, 0x1c, 0x00, 0x04, 0x60, 0x18, 0x1c, 0x1c,
- 0x1c, 0x70, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x30,
- 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc0,
- 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf0, 0xf0,
- 0x00, 0x07, 0x00, 0xf0, 0x03, 0xc0, 0x0f, 0x00, 0x3c, 0x00,
- 0xf0, 0x00, 0x00, 0x00, 0x07, 0x3f, 0xc0, 0x70, 0x70, 0x70,
- 0x70, 0x70, 0x70, 0x3f, 0xc0, 0x00, 0x00, 0x07, 0x1f, 0x00,
- 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0xff, 0xf0, 0x00, 0x00,
- 0x08, 0x2b, 0xf0, 0xb0, 0x2c, 0x00, 0xa0, 0x0a, 0x00, 0xff,
- 0xfc, 0x00, 0x00, 0x07, 0xff, 0xc0, 0x00, 0x70, 0x03, 0xc0,
- 0x00, 0x70, 0xff, 0xc0, 0x00, 0x00, 0x07, 0x0b, 0xc0, 0x2d,
- 0xc0, 0xb1, 0xc0, 0xaa, 0xa0, 0x01, 0xc0, 0x00, 0x00, 0x07,
- 0xff, 0xf0, 0x70, 0x00, 0x7f, 0xc0, 0x00, 0xb0, 0xbf, 0xc0,
- 0x00, 0x00, 0x07, 0x2f, 0xc0, 0x70, 0x00, 0x7f, 0xc0, 0x70,
- 0x70, 0x3f, 0xc0, 0x00, 0x00, 0x08, 0xff, 0xfc, 0x00, 0xb0,
- 0x02, 0xc0, 0x02, 0xc0, 0x0b, 0x00, 0x00, 0x00, 0x08, 0x2f,
- 0xf0, 0xb0, 0x1c, 0x2f, 0xf0, 0xb0, 0x1c, 0x2f, 0xf0, 0x00,
- 0x00, 0x07, 0x3f, 0xc0, 0x70, 0x70, 0x3f, 0xf0, 0x00, 0x70,
- 0x3f, 0xc0, 0x00, 0x00, 0x03, 0xf0, 0xf0, 0x00, 0xf0, 0xf0,
- 0x00, 0x03, 0xf0, 0xf0, 0x00, 0xf0, 0x30, 0x00, 0x09, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0xff, 0xc0, 0x00, 0x00,
- 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x06, 0xff, 0x00, 0x03, 0xc0, 0x0f, 0x00, 0x3c, 0x00,
- 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x0a, 0x00, 0x40, 0x00, 0x01, 0xf0, 0x00, 0x07, 0x1c,
- 0x00, 0x1f, 0xff, 0x00, 0x70, 0x01, 0xc0, 0x00, 0x00, 0x00,
- 0x08, 0x7f, 0xf0, 0x70, 0x1c, 0x7f, 0xf0, 0x70, 0x1c, 0x6a,
- 0xb0, 0x00, 0x00, 0x08, 0x2f, 0xfc, 0x70, 0x00, 0x70, 0x00,
- 0x70, 0x00, 0x2a, 0xa8, 0x00, 0x00, 0x08, 0x7f, 0xf0, 0x70,
- 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x6a, 0xb0, 0x00, 0x00, 0x07,
- 0x7f, 0xf0, 0x70, 0x00, 0x7f, 0xc0, 0x70, 0x00, 0x6a, 0xa0,
- 0x00, 0x00, 0x07, 0x7f, 0xf0, 0x70, 0x00, 0x7f, 0xc0, 0x70,
- 0x00, 0x60, 0x00, 0x00, 0x00, 0x09, 0x3f, 0xfc, 0x00, 0x70,
- 0x00, 0x00, 0x70, 0xff, 0x00, 0x70, 0x1c, 0x00, 0x2a, 0xbc,
- 0x00, 0x00, 0x00, 0x00, 0x08, 0x70, 0x1c, 0x70, 0x1c, 0x7f,
- 0xfc, 0x70, 0x1c, 0x70, 0x1c, 0x00, 0x00, 0x07, 0xff, 0xf0,
- 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0xaa, 0xa0, 0x00, 0x00,
- 0x08, 0x0f, 0xfc, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x70,
- 0x70, 0x2a, 0x40, 0x00, 0x00, 0x08, 0x70, 0x2c, 0x72, 0xc0,
- 0x7f, 0x00, 0x72, 0xc0, 0x70, 0x28, 0x00, 0x00, 0x07, 0x70,
- 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x6a, 0xa0, 0x00,
- 0x00, 0x0a, 0x70, 0x02, 0xc0, 0x7c, 0x09, 0xc0, 0x77, 0x2d,
- 0xc0, 0x71, 0xb1, 0xc0, 0x60, 0xc1, 0x80, 0x00, 0x00, 0x00,
- 0x09, 0x70, 0x07, 0x00, 0x77, 0x07, 0x00, 0x71, 0xc7, 0x00,
- 0x70, 0x77, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x08,
- 0x2f, 0xf0, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x2a, 0xa0,
- 0x00, 0x00, 0x08, 0x7f, 0xf0, 0x70, 0x1c, 0x7f, 0xf0, 0x70,
- 0x00, 0x60, 0x00, 0x00, 0x00, 0x08, 0x2f, 0xf0, 0x70, 0x1c,
- 0x70, 0x1c, 0x71, 0xdc, 0x2a, 0xa0, 0x00, 0x1c, 0x00, 0x00,
- 0x08, 0x7f, 0xf0, 0x70, 0x1c, 0x7f, 0xc0, 0x70, 0x70, 0x60,
- 0x18, 0x00, 0x00, 0x07, 0x2f, 0xf0, 0x70, 0x00, 0x2f, 0xc0,
- 0x00, 0xb0, 0xbf, 0xc0, 0x00, 0x00, 0x07, 0xff, 0xf0, 0x0b,
- 0x00, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08,
- 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0xdc, 0x1f, 0x1c,
- 0x00, 0x00, 0x08, 0xf0, 0x1c, 0xb0, 0x1c, 0x70, 0xb0, 0x72,
- 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x0b, 0xf0, 0x00, 0xb0, 0xb0,
- 0x00, 0x70, 0x70, 0xc0, 0x70, 0x72, 0x72, 0xc0, 0x7c, 0x1f,
- 0x00, 0x00, 0x00, 0x00, 0x08, 0xf0, 0x3c, 0x1c, 0xe0, 0x07,
- 0xc0, 0x1c, 0x70, 0x70, 0x1c, 0x00, 0x00, 0x09, 0x70, 0x07,
- 0x00, 0x1c, 0x1c, 0x00, 0x07, 0xf0, 0x00, 0x01, 0xc0, 0x00,
- 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x08, 0xff, 0xfc, 0x00,
- 0x70, 0x07, 0x00, 0x1c, 0x00, 0xaa, 0xac, 0x00, 0x00, 0x09,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-const int FONT6x6_INDEX[] = {
- 62, 1, 6,
- 0x0000, 0x0007, 0x000e, 0x0015, 0x001c, 0x0023, 0x002a, 0x0031, 0x0038, 0x003f,
- 0x0046, 0x004d, 0x0054, 0x005b, 0x0062, 0x0069, 0x0070, 0x0077, 0x007e, 0x0085,
- 0x008c, 0x0093, 0x009a, 0x00a1, 0x00a8, 0x00af, 0x00b6, 0x00bd, 0x00c4, 0x00cb,
- 0x00d2, 0x00d9, 0x00e0, 0x00e7, 0x00ee, 0x00f5, 0x00fc, 0x0103, 0x010a, 0x0111,
- 0x0118, 0x011f, 0x0126, 0x012d, 0x0134, 0x013b, 0x0142, 0x0149, 0x0150, 0x0157,
- 0x015e, 0x0165, 0x016c, 0x0173, 0x017a, 0x0181, 0x0188, 0x018f, 0x0196, 0x019d,
- 0x01a4, 0x01ab,
-};
-
-const byte FONT6x6_DATA[] = {
- 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x30, 0x30,
- 0x30, 0x30, 0x00, 0x30, 0x06, 0xd8, 0xd8, 0x90, 0x00, 0x00,
- 0x00, 0x06, 0x50, 0xf8, 0x50, 0xf8, 0x50, 0x00, 0x06, 0x78,
- 0xa0, 0x70, 0x28, 0xf0, 0x20, 0x06, 0xc8, 0xd0, 0x20, 0x58,
- 0x98, 0x00, 0x06, 0x60, 0xd0, 0x60, 0xe8, 0xd0, 0x68, 0x06,
- 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x06, 0x30, 0x60, 0x60,
- 0x60, 0x30, 0x00, 0x07, 0x30, 0x18, 0x18, 0x18, 0x30, 0x00,
- 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, 0x20,
- 0xf8, 0x20, 0x20, 0x00, 0x06, 0x00, 0x00, 0x00, 0x30, 0x30,
- 0x60, 0x06, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x06, 0x00,
- 0x00, 0x00, 0x60, 0x60, 0x00, 0x06, 0x18, 0x30, 0x60, 0xc0,
- 0x80, 0x00, 0x06, 0x70, 0x98, 0xa8, 0xc8, 0x70, 0x00, 0x06,
- 0x10, 0x30, 0x10, 0x10, 0x10, 0x00, 0x06, 0xf0, 0x08, 0x70,
- 0x80, 0xf8, 0x00, 0x06, 0xf0, 0x08, 0x70, 0x08, 0xf0, 0x00,
- 0x06, 0x30, 0x50, 0x90, 0xf8, 0x10, 0x00, 0x06, 0xf0, 0x80,
- 0xf0, 0x08, 0xf0, 0x00, 0x06, 0x70, 0x80, 0xf0, 0x88, 0x70,
- 0x00, 0x06, 0xf8, 0x08, 0x10, 0x20, 0x20, 0x00, 0x06, 0x70,
- 0x88, 0x70, 0x88, 0x70, 0x00, 0x06, 0x70, 0x88, 0x78, 0x08,
- 0x70, 0x00, 0x06, 0x60, 0x60, 0x00, 0x60, 0x60, 0x00, 0x06,
- 0x60, 0x60, 0x00, 0x60, 0x20, 0x40, 0x06, 0x18, 0x30, 0x60,
- 0x30, 0x18, 0x00, 0x06, 0x00, 0x78, 0x00, 0x78, 0x00, 0x00,
- 0x06, 0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0x06, 0x70, 0x98,
- 0x30, 0x30, 0x00, 0x30, 0x06, 0x70, 0x88, 0xb8, 0xb0, 0x80,
- 0x78, 0x06, 0x70, 0x88, 0xf8, 0x88, 0x88, 0x00, 0x06, 0xf0,
- 0x88, 0xf0, 0x88, 0xf0, 0x00, 0x06, 0x78, 0x80, 0x80, 0x80,
- 0x78, 0x00, 0x06, 0xf0, 0x88, 0x88, 0x88, 0xf0, 0x00, 0x06,
- 0xf8, 0x80, 0xf0, 0x80, 0xf8, 0x00, 0x06, 0xf8, 0x80, 0xf0,
- 0x80, 0x80, 0x00, 0x06, 0x78, 0x80, 0x98, 0x88, 0x78, 0x00,
- 0x06, 0x88, 0x88, 0xf8, 0x88, 0x88, 0x00, 0x06, 0x70, 0x20,
- 0x20, 0x20, 0x70, 0x00, 0x06, 0x08, 0x08, 0x08, 0x88, 0x70,
- 0x00, 0x06, 0x90, 0xa0, 0xc0, 0xa0, 0x90, 0x00, 0x06, 0x80,
- 0x80, 0x80, 0x80, 0xf0, 0x00, 0x06, 0x88, 0xd8, 0xa8, 0x88,
- 0x88, 0x00, 0x06, 0x88, 0xc8, 0xa8, 0x98, 0x88, 0x00, 0x06,
- 0x70, 0x88, 0x88, 0x88, 0x70, 0x00, 0x06, 0xf0, 0x88, 0xf0,
- 0x80, 0x80, 0x00, 0x06, 0x70, 0x88, 0x88, 0x88, 0x70, 0x18,
- 0x06, 0xf0, 0x88, 0xf0, 0xa0, 0x98, 0x00, 0x06, 0x78, 0x80,
- 0x70, 0x08, 0xf0, 0x00, 0x06, 0xf8, 0x20, 0x20, 0x20, 0x20,
- 0x00, 0x06, 0x88, 0x88, 0x88, 0x88, 0x78, 0x00, 0x06, 0x88,
- 0x88, 0x88, 0x50, 0x20, 0x00, 0x06, 0x88, 0x88, 0xa8, 0xd8,
- 0x88, 0x00, 0x06, 0x88, 0x50, 0x20, 0x50, 0x88, 0x00, 0x06,
- 0x88, 0x88, 0x50, 0x20, 0x20, 0x00, 0x06, 0xf8, 0x10, 0x20,
- 0x40, 0xf8, 0x00, 0x06, 0x78, 0x60, 0x60, 0x60, 0x78, 0x00,
- 0x06, 0xc0, 0x60, 0x30, 0x18, 0x08, 0x00, 0x06, 0x78, 0x18,
- 0x18, 0x18, 0x78, 0x00, 0x00, 0x52, 0x41, 0x54, 0x00, 0x41,
- 0x4c, 0x43, 0x4f, 0x48, 0x4f, 0x4c, 0x00, 0x53, 0x41, 0x46,
- 0x45, 0x20, 0x43, 0x4f, 0x4d, 0x42, 0x49, 0x4e, 0x41, 0x54,
- 0x49, 0x4f, 0x4e, 0x00, 0x42, 0x45, 0x41, 0x4b, 0x45, 0x52,
- 0x00, 0x4d, 0x49, 0x43, 0x52, 0x4f, 0x46, 0x49, 0x4c, 0x4d,
- 0x00, 0x56, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x4b, 0x45, 0x59,
- 0x00, 0x42, 0x4f, 0x4c, 0x54, 0x20, 0x43, 0x55, 0x54, 0x54,
- 0x45, 0x52, 0x53, 0x00, 0x42, 0x4c, 0x4f, 0x57, 0x47, 0x55,
- 0x4e, 0x00, 0x4c, 0x4f, 0x56, 0x45, 0x20, 0x50, 0x4f, 0x54,
- 0x49, 0x4f, 0x4e, 0x00, 0x4d, 0x4f, 0x4e, 0x45, 0x59, 0x00,
- 0x44, 0x41, 0x52, 0x54, 0x53, 0x00, 0x54, 0x41, 0x50, 0x45,
- 0x00, 0x4a, 0x55, 0x4e, 0x47, 0x4c, 0x45, 0x20, 0x50, 0x4f,
- 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x4d, 0x4f, 0x56, 0x49,
-};
-
-const char *const NO_HELP_MESSAGE =
- "WE ARE UNABLE TO PROVIDE YOU WITH ANY MORE HINTS. YOUR IQ \
-HAS DECREASED SO FAR THAT WE CAN NO LONGER PUT THE HINTS IN TERMS \
-YOU CAN UNDERSTAND.";
-const char *const NO_HINTS_MESSAGE = "THE HELP SYSTEM HAS BEEN TURNED OFF FOR THIS GAME.";
-const char *const RIVER_HIT1 = "YOU HIT THE ROCKS AND THE CANOE BEGINS TO LEAK.";
-const char *const RIVER_HIT2 = "YOU HIT THE ROCKS AND THE CANOE DEVELOPS SERIOUS LEAKS.";
-const char *const BAR_MESSAGE = "YOU ARE TOO BUSY TRYING TO KEEP FROM SINKING TO DO THAT";
-const char *const HELPLVLTXT[3] = {
- " LEVEL 1 ",
- " LEVEL 2 ",
- " LEVEL 3 "
-};
-
-const char *const IQLABELS[9] = {
- "VEGETABLE",
- "NEANDERTHAL",
- "LOBOTOMIZED",
- "DENSE",
- "AVERAGE",
- "INTELLIGENT",
- "MURPHYITE",
- "BRILLIANT",
- "GENIUS"
-};
-
-const byte DEATH_SCREENS[58] = {
- 0, 1, 0, 0, 0, 0, 0, 0, 2, 0,
- 0, 2, 4, 2, 1, 0, 0, 0, 0, 0,
- 0, 2, 7, 7, 4, 6, 7, 10, 4, 2,
- 0, 0, 0, 0, 5, 5, 3, 3, 3, 5,
- 8, 8, 11, 9, 8, 12, 0, 1, 9, 8,
- 8, 0, 5, 8, 0, 12, 12, 11
-};
-
-const byte DEATH_SCREENS_DEMO[34] = {
- 1, 2, 1, 1, 1, 1, 1, 1, 4, 1,
- 3, 4, 2, 4, 2, 1, 1, 1, 1, 1,
- 1, 4, 2, 4, 2, 4, 2, 4, 4, 4,
- 1, 1, 1, 1
-};
-
-const char *const DEATH_TEXT[58] = {
- "SAM SALVADOR SPOTS YOU AND LETS YOU HAVE IT.",
- "WHILE TAKING A MOONLIGHT SWIM YOU DISCOVER THAT PIRANHA REALLY CAN STRIP FLESH TO THE BONE.",
- "THE GUARD FILLS YOU FULL OF HOLES BEFORE TOSSING YOU TO THE PIRANHA.",
- "YOU'RE ONLY ABLE TO SWIM HALFWAY ACROSS THE RIVER BEFORE RUNNING OUT OF AIR. "
- "YOU MAKE SO MUCH NOISE GASPING FOR BREATH THAT SAM EASILY FINDS YOU AND LEAVES "
- "YOU IN THE RIVER PERMANENTLY.",
- "SAM SALVADOR NOTICES SOMEONE HAS BEEN PLAYING WITH THE CARGO. "
- "HE TRACKS YOU DOWN AND LETS YOU HAVE IT.",
- "THE GUARD COMES AROUND THE CORNER. HE DECIDES THAT THREE LEAD SLUGS WILL "
- "TEACH YOU TO BE MORE POLITE.",
- "THE CAPTAIN IS WAITING OUTSIDE THE DOOR.",
- "THE CAPTAIN'S RANDOM SHOOTING FINALLY FINDS ITS TARGET.",
- "THE CRATE OUTSIDE THE WINDOW EXPLODES, DESTROYING THE SHIP. "
- "UNFORTUNATELY, YOU'RE STILL ABOARD.",
- "THE DOOR WAS NOT BARRED AND THE CAPTAIN WALKS RIGHT IN AND PARTS YOUR HAIR.",
-
- "",
- "YOU RUN OUT ON DECK, THEN REALIZE THAT MAYA IS STILL TIED UP. "
- "AS YOU TURN TO GO BACK THE BOAT BLOWS UP.",
- "AFTER YOU FAIL TO PROVE YOUR DIVINITY THE NATIVES EAT YOU FOR LUNCH.",
- "THIS IS THE GENERIC DEATH SCENE",
- "YOU ONLY MAKE IT HALFWAY ACROSS THE RIVER BEFORE THE PIRANHA STRIKE.",
- "WITH NOTHING TO PROTECT HIM FROM THE HAIL OF BULLETS ALLEN IS QUICKLY GUNNED DOWN. "
- "JASON AND MAYA SOON FOLLOW...",
- "THE COMBINATION OF THE WIND AND GUNFIRE KNOCK THE CORRUGATED IRON OVER, "
- "LEAVING YOU WITHOUT PROTECTION.",
- "WITHOUT SUFFICIENT AMMUNITION, ALLEN IS UNABLE TO HOLD OFF THE ATTACKERS FOR LONG. "
- "THIS RESULTS IN A SERIOUS CASE OF LEAD POISONING. ADDITIONAL AMMUNITION SHOULD "
- "HAVE BEEN PURCHASED AT THE RIO BLANCO TRADING POST (CHAPTER 6).",
- "ALLEN IS A MARVELOUS SHOT, BUT HIS AMMUNITION IS NOT UNLIMITED. "
- "SOON IT IS ALL OVER.",
- "THE PILOT FEELS YOU ARE TOO CLOSE AND PULLS THE TRIGGER.",
-
- "THE PILOT SHOOTS YOU IN THE HEART, THEN TOSSES YOUR LIFELESS BODY OUT THE DOOR.",
- "THE PLANE CRASHES INTO THE JUNGLE CANOPY AT 200 MPH.",
- "THE CANOE HITS THE ROCKS AND CAPSIZES, AND THE PIRANHA MAKE YOU THEIR LUNCH GUESTS.",
- "YOU TAKE THE WRONG BRANCH AND ACCIDENTALLY DISCOVER THE FOURTH TALLEST WATERFALL "
- "IN SOUTH AMERICA.",
- "YOU TAKE THE WRONG BRANCH AND DISCOVER A VERY HUNGRY TRIBE OF CANNIBALS.",
- "YOU TAKE THE WRONG BRANCH AND BECOME LOST IN THE WINDING WATERWAYS. "
- "YOU WANDER UNTIL YOU STARVE TO DEATH.",
- "YOU TAKE THE WRONG BRANCH AND BECOME TRAPPED IN THE RAPIDS. "
- "EVENTUALLY YOU AND MAYA ARE CRUSHED BETWEEN THE ROCKS.",
- "YOU WAIT AROUND FOR SOME TIME, BUT HANS STROHEIM NEVER SPEAKS TO YOU AGAIN. "
- "FINALLY YOU RETURN HOME KNOWING YOU HAVE FAILED.",
- "DECIDING THAT YOU THREATEN HIM AND HIS WORK, HANS STROHEIM HAS THE NATIVES "
- "IN THE VILLAGE KILL YOU.",
- "YOU DO NOT GET FAR ENOUGH AWAY BEFORE THE DYNAMITE EXPLODES AND YOU ARE BLOWN "
- "INTO A THOUSAND PIECES.",
-
- "YOU ARE STANDING SO CLOSE TO THE ENTRANCE WHEN SANCEZ AND HIS MEN BREAK THROUGH "
- "THE WALL THAT YOU ARE QUICKLY SPOTTED AND SHOT",
- "THE AMAZON SENTINELS SPOT YOU AND FILL YOU FULL OF ARROWS.",
- "SAM MAY BE UGLY, BUT HE'S NOT DEAF. HE HEARS ALL THE NOISE YOU ARE MAKING AND "
- "CANCELS YOUR BOARDING PASS.",
- "WITH THE BAR OFF THE DOOR THE CAPTAIN WALTZES IN AND BLOWS YOU AWAY",
- "THE BEAR WANDERS OFF INTO THE WOODS AND DISTURBS THE TWO LOVEBIRDS. "
- "WHEN THEY COME OUT THEY FIND YOU AND PUT YOU IN THE BIG HOUSE FOR TWENTY YEARS.",
- "WHEN YOU DO NOT LEAVE THE SECURITY AREA QUICKLY ENOUGH YOU ARE ARRESTED AND CONVICTED "
- "AS A COMMIE SPY. YOU EMBARK ON A NEW CAREER STAMPING OUT LICENSE PLATES.",
- "THE HUNGRY BEAR SPOTS YOU AND DECIDES YOU WILL MAKE A NICE APPETIZER.",
- "YOU DISTURB THE BEAR'S LUNCH AND HE EATS YOU FOR DESSERT.",
- "AFTER FAILING TO FIND ANY LUNCH AT THE GARBAGE CAN THE BEAR EATS YOU INSTEAD.",
- "THE SUSPICIOUS LIBRARIAN CALLS SECURITY AND YOU ARE SENT TO JAIL.",
-
- "YOU PLUMMET 10,000 FEET TO YOUR DEATH.",
- "EL LOCO FLIES INTO AN INSANE RAGE AND BEATS YOU TO A BLOODY PULP.",
- "THE WOMAN WALKS OUT THE DOOR AND NEVER RETURNS. YOU SPEND THE REST OF YOUR LIFE "
- "IN A FUTILE ATTEMPT TO LOCATE ALLEN.",
- "YOU SLIP OFF THE PLATFORM AND FALL TO YOUR DEATH.",
- "YOU SLIP OFF THE PLATFORM AND FALL TO YOUR DEATH.",
- "YOU COME TOO CLOSE TO THE POWERFUL JAWS OF THE ANT AND HE SNIPS YOU IN TWO BEFORE "
- "DEVOURING YOU.",
- "B.O.B. HAS A FLAW IN HIS PROGRAMMING THAT DIRECTS HIM TO SHOOT FIRST AND ASK QUESTIONS LATER.",
- "THE PLANE SINKS AND THE PIRHANA ATTACK BEFORE YOU EVEN GET OUT THE DOOR.",
- "MAYA FALLS OFF THE END OF THE BROKEN BRIDGE.",
- "YOUR WEIGHT IS JUST ENOUGH TO CAUSE THE REMAINING SUPPORT CABLE TO SNAP AND YOU "
- "FALL TO THE BOTTOM OF THE GORGE.",
-
- "EVEN WITH REPAIRS THE BRIDGE IS NOT STRONG ENOUGH TO HOLD TWO PEOPLE.",
- "SANCHEZ AND HIS MEN FIND YOU AND HOLD FIRING SQUAD PRACTICE.",
- "THE TWO GUARDS ARE DISTURBED IN THEIR LOVE NEST AND COME LOOKING FOR ANYONE ACTING SUSPICIOUS. "
- "THEY FIND YOU AND SEND YOU UP THE RIVER.",
- "THE PARACHUTE IS NOT LARGE ENOUGH TO SUPPORT YOU, AND YOU HIT THE TREES AT 140 M.P.H.",
- "SANCHEZ AND HIS MEN FOLLOW YOU ACROSS THE BRIDGE AND CUT YOU DOWN IN A HAIL OF GUNFIRE",
- "YOU TRIED TO STAB THE ANT BUT HIS SHELL IS TOO DIFFICULT TO PENETRATE. "
- "YOU NOTICE A SLIGHT CUT IN THE SHELL UNDERNEATH BUT YOU CAN'T GET TO IT "
- "AND HE SNIPS YOU INTO DELICIOUS MEATY CHUNKS.",
- "AFTER THE ANT FINISHES SUCKING ALL OF THE SAP OUT OF THE VINE HE TURNS HIS ATTENTION BACK TO YOU "
- "AND BITES YOUR HEAD OFF.",
- "THE CANTINA OWNER NOTICES YOU ARE TRYING TO STEAL OBJECTS FROM THE TABLES. "
- "TWENTY YEARS LATER YOU ARE RELEASED FROM A SOUTH AMERICAN PRISON."
-};
-
-const char *const DEATH_TEXT_DEMO[34] = {
- "SAM SALVADOR SPOTS YOU AND LETS YOU HAVE IT.",
- "WHILE TAKING A MOONLIGHT SWIM YOU DISCOVER THAT PIRANHA REALLY CAN STRIP FLESH TO THE BONE.",
- "THE GUARD FILLS YOU FULL OF HOLES BEFORE TOSSING YOU TO THE PIRANHA.",
- "YOU'RE ONLY ABLE TO SWIM HALFWAY ACROSS THE RIVER BEFORE RUNNING OUT OF AIR. YOU MAKE SO MUCH NOISE GASPING FOR BREATH THAT SAM EASILY FINDS YOU AND LEAVES YOU IN THE RIVER PERMANENTLY.",
- "SAM SALVADOR NOTICES SOMEONE HAS BEEN PLAYING WITH THE CARGO. HE TRACKS YOU DOWN AND LETS YOU HAVE IT.",
- "THE GUARD COMES AROUND THE CORNER. HE DECIDES THAT THREE LEAD SLUGS WILL TEACH YOU TO BE MORE POLITE.",
- "THE CAPTAIN IS WAITING OUTSIDE THE DOOR.",
- "THE CAPTAIN'S RANDOM SHOOTING FINALLY FINDS ITS TARGET.",
- "THE CRATE OUTSIDE THE WINDOW EXPLODES, DESTROYING THE SHIP. UNFORTUNATELY, YOU'RE STILL ABOARD.",
- "THE DOOR WAS NOT BARRED AND THE CAPTAIN WALKS RIGHT IN AND PARTS YOUR HAIR.",
- "",
- "YOU RUN OUT ON DECK, THEN REALIZE THAT MAYA IS STILL TIED UP. AS YOU TURN TO GO BACK THE BOAT BLOWS UP.",
- "AFTER YOU FAIL TO PROVE YOUR DIVINITY THE NATIVES EAT YOU FOR LUNCH.",
- "THIS IS THE GENERIC DEATH SCENE",
- "YOU ONLY MAKE IT HALFWAY ACROSS THE RIVER BEFORE THE PIRANHA STRIKE.",
- "WITH NOTHING TO PROTECT HIM FROM THE HAIL OF BULLETS ALLEN IS QUICKLY GUNNED DOWN. JASON AND MAYA SOON FOLLOW...",
- "THE COMBINATION OF THE WIND AND GUNFIRE KNOCK THE CORRUGATED IRON OVER, LEAVING YOU WITHOUT PROTECTION.",
- "WITHOUT SUFFICIENT AMMUNITION, ALLEN IS UNABLE TO HOLD OFF THE ATTACKERS FOR LONG. THIS RESULTS IN A SERIOUS CASE OF LEAD POISONING.",
- "ALLEN IS A MARVELOUS SHOT, BUT HIS AMMUNITION IS NOT UNLIMITED. SOON IT IS ALL OVER.",
- "THE PILOT FEELS YOU ARE TOO CLOSE AND PULLS THE TRIGGER.",
- "THE PILOT SHOOTS YOU IN THE HEAD, THEN TOSSES YOUR LIFELESS",
- "THE PLANE CRASHES INTO THE JUNGLE CANOPY AT 200 MPH.",
- "THE CANOE HITS THE ROCKS AND CAPSIZES, AND THE PIRANHA MAKE YOU THEIR LUNCH GUESTS.",
- "YOU ACCIDENTALLY DISCOVER THE FOURTH TALLEST WATERFALL IN SOUTH AMERICA.",
- "YOU DISCOVER A VERY HUNGRY TRIBE OF CANNIBALS.",
- "YOU BECOME LOST IN THE WINDING WATERWAYS AND WANDER UNTIL YOU STARVE TO DEATH.",
- "YOU BECOME TRAPPED IN THE RAPIDS AND ARE CRUSHED BETWEEN THE ROCKS.",
- "YOU WAIT AROUND FOR SOME TIME, BUT HANS STROHEIM NEVER SPEAKS TO YOU AGAIN. FINALLY YOU RETURN HOME KNOWING YOU HAVE FAILED.",
- "DECIDING THAT YOU THREATEN HIM AND HIS WORK, HANS STROHEIM HAS THE NATIVES IN THE VILLAGE KILL YOU.",
- "YOU DO NOT GET FAR ENOUGH AWAY BEFORE THE DYNAMITE EXPLODES AND YOU ARE BLOWN INTO A THOUSAND PIECES.",
- "STANDING OUT IN THE OPEN YOU ARE EXPOSED TO THE HAIL OF BULLETS FROM SANCHEZ' MEN.",
- "THE AMAZON SENTINELS SPOT YOU AND FILL YOU FULL OF ARROWS.",
- "SAM MAY BE UGLY, BUT HE'S NOT DEAF. HE HEARS ALL THE NOISE YOU ARE MAKING AND CANCELS YOUR BOARDING PASS.",
- "WITH THE BAR OFF THE DOOR THE CAPTAIN WALTZES IN AND BLOWS YOU AWAY"
-};
-
const int DEATH_CELLS[13][3] = {
{ 0, 94, 2 },
{ 0, 94, 3 },
@@ -1984,94 +162,6 @@ const int CHAPTER_JUMP[14] = {
0, 12, 10, 15, 19, 25, 31, 36, 45, 46, 29, 55, 61, 0
};
-const int COMBO_TABLE[85][4] = {
- { -1, -1, -1, -1 },
- { 12, 3, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { 24, 25, -1, -1 },
- { 10, 24, -1, -1 },
- { -1, -1, -1, -1 },
- { 8, 24, -1, -1 },
- { -1, -1, -1, -1 },
- { 1, 3, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { 7, 25, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { 80, 81, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { 41, 42, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { 39, 40, -1, -1 },
- { 38, 40, -1, -1 },
- { -1, -1, -1, -1 },
- { 32, 42, 77, 78 },
- { -1, -1, -1, -1 },
- { 60, 61, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { 73, 72, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { 64, 67, -1, -1 },
- { -1, -1, -1, -1 },
- { 59, 60, -1, -1 },
- { 58, 60, -1, -1 },
- { 43, 61, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { 56, 67, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { 50, 72, -1, -1 },
- { 75, 77, -1, -1 },
- { 74, 77, -1, -1 },
- { -1, -1, -1, -1 },
- { 41, 78, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { 29, 81, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 },
- { -1, -1, -1, -1 }
-};
-
const int ANTWALK[24] = {
0, 3, 0,
1, 5, 0,
@@ -2349,8 +439,8 @@ RiverStruct RIVER2OBJECTS[54] = {
RiverStruct *RIVER_OBJECTS[3][2] = {
{ RIVER0OBJECTS, RIVER0OBJECTS + 46 - 1},
- { RIVER1OBJECTS, RIVER0OBJECTS + 50 - 1 },
- { RIVER2OBJECTS, RIVER0OBJECTS + 54 - 1 }
+ { RIVER1OBJECTS, RIVER1OBJECTS + 50 - 1 },
+ { RIVER2OBJECTS, RIVER2OBJECTS + 54 - 1 }
};
const int HELP1COORDS[2][4] = {
diff --git a/engines/access/amazon/amazon_resources.h b/engines/access/amazon/amazon_resources.h
index 10dea02abc..20d90cc5b6 100644
--- a/engines/access/amazon/amazon_resources.h
+++ b/engines/access/amazon/amazon_resources.h
@@ -24,6 +24,8 @@
#define ACCESS_AMAZON_RESOURCES_H
#include "common/scummsys.h"
+#include "common/array.h"
+#include "access/resources.h"
namespace Access {
@@ -42,9 +44,6 @@ struct RiverStruct {
int _offsetY;
};
-extern const char *const FILENAMES[];
-extern const char *const FILENAMES_DEMO[];
-
extern const int SIDEOFFR[];
extern const int SIDEOFFL[];
extern const int SIDEOFFU[];
@@ -58,8 +57,6 @@ extern const int DIAGOFFULY[];
extern const int DIAGOFFDLX[];
extern const int DIAGOFFDLY[];
-extern const byte *const CURSORS[10];
-
extern const int _travelPos[][2];
extern const int OVEROFFR[];
@@ -75,37 +72,6 @@ extern const int OVEROFFULY[];
extern const int OVEROFFDLX[];
extern const int OVEROFFDLY[];
-extern const byte *const ROOM_TABLE[];
-extern const char *const ROOM_DESCR[];
-extern const byte *const ROOM_TABLE_DEMO[];
-extern const int ROOM_NUMB;
-
-extern const byte *const CHARTBL[];
-extern const byte *const CHARTBL_DEMO[];
-
-extern const char *const INVENTORY_NAMES[];
-
-extern const int FONT2_INDEX[];
-
-extern const byte FONT2_DATA[];
-
-extern const int FONT6x6_INDEX[];
-
-extern const byte FONT6x6_DATA[];
-
-extern const char *const NO_HELP_MESSAGE;
-extern const char *const NO_HINTS_MESSAGE;
-extern const char *const RIVER_HIT1;
-extern const char *const RIVER_HIT2;
-extern const char *const BAR_MESSAGE;
-extern const char *const HELPLVLTXT[3];
-extern const char *const IQLABELS[9];
-extern const byte DEATH_SCREENS[58];
-extern const byte DEATH_SCREENS_DEMO[34];
-
-extern const char *const DEATH_TEXT[58];
-extern const char *const DEATH_TEXT_DEMO[34];
-
extern const int DEATH_CELLS[13][3];
extern const int CHAPTER_CELLS[17][3];
@@ -155,6 +121,31 @@ extern const int CAST_END_OBJ1[4][4];
extern const int RMOUSE[10][2];
+class AmazonResources: public Resources {
+protected:
+ /**
+ * Load data from the access.dat file
+ */
+ virtual void load(Common::SeekableReadStream &s);
+public:
+ Common::Array<int> FONT2_INDEX;
+ Common::Array<byte> FONT2_DATA;
+ Common::Array<int> FONT6x6_INDEX;
+ Common::Array<byte> FONT6x6_DATA;
+ Common::String NO_HELP_MESSAGE;
+ Common::String NO_HINTS_MESSAGE;
+ Common::String RIVER_HIT1;
+ Common::String RIVER_HIT2;
+ Common::String BAR_MESSAGE;
+ Common::String HELPLVLTXT[3];
+ Common::String IQLABELS[9];
+public:
+ AmazonResources(AccessEngine *vm) : Resources(vm) {}
+ virtual ~AmazonResources() {}
+};
+
+#define AMRES (*((Amazon::AmazonResources *)_vm->_res))
+
} // End of namespace Amazon
} // End of namespace Access
diff --git a/engines/access/amazon/amazon_room.cpp b/engines/access/amazon/amazon_room.cpp
index 29742f66bd..c027f4e7c6 100644
--- a/engines/access/amazon/amazon_room.cpp
+++ b/engines/access/amazon/amazon_room.cpp
@@ -41,10 +41,7 @@ AmazonRoom::~AmazonRoom() {
}
void AmazonRoom::loadRoom(int roomNumber) {
- if (_vm->isDemo())
- loadRoomData(ROOM_TABLE_DEMO[roomNumber]);
- else
- loadRoomData(ROOM_TABLE[roomNumber]);
+ loadRoomData(&AMRES.ROOMTBL[roomNumber]._data[0]);
}
void AmazonRoom::reloadRoom() {
diff --git a/engines/access/amazon/amazon_scripts.cpp b/engines/access/amazon/amazon_scripts.cpp
index d8f4663401..48438e9c95 100644
--- a/engines/access/amazon/amazon_scripts.cpp
+++ b/engines/access/amazon/amazon_scripts.cpp
@@ -401,10 +401,10 @@ void AmazonScripts::cmdHelp_v2() {
_game->_useItem = 0;
if (_game->_noHints) {
- printString(NO_HELP_MESSAGE);
+ printString(AMRES.NO_HELP_MESSAGE);
return;
} else if (_game->_hintLevel == 0) {
- printString(NO_HINTS_MESSAGE);
+ printString(AMRES.NO_HINTS_MESSAGE);
return;
}
}
@@ -473,12 +473,29 @@ void AmazonScripts::cmdCycleBack() {
if (_vm->_startup == -1)
_vm->_screen->cyclePaletteBackwards();
}
+
void AmazonScripts::cmdChapter() {
+ Resource *activeScript = nullptr;
+
if (_vm->isDemo()) {
cmdSetHelp();
} else {
int chapter = _data->readByte();
+
+ if (!_vm->isCD()) {
+ // For floppy version, the current script remains active even
+ // after the end of the chapter start, so we need to save it
+ activeScript = _resource;
+ _resource = nullptr;
+ _data = nullptr;
+ }
+
_game->startChapter(chapter);
+
+ if (!_vm->isCD()) {
+ assert(!_resource);
+ setScript(activeScript, false);
+ }
}
}
diff --git a/engines/access/animation.cpp b/engines/access/animation.cpp
index 14d7c0d4cc..22de0fcb60 100644
--- a/engines/access/animation.cpp
+++ b/engines/access/animation.cpp
@@ -53,6 +53,18 @@ Animation::Animation(AccessEngine *vm, Common::SeekableReadStream *stream) : Man
uint32 startOfs = stream->pos();
_type = stream->readByte();
+
+ // WORKAROUND: In Amazon floppy English, there's an animation associated with
+ // the librarian that isn't used, and has junk data. Luckily, it's animation
+ // type is also invalid, so if the _type isn't in range, exit immediately
+ if (_type < 0 || _type > 7) {
+ _scaling = -1;
+ _frameNumber = -1;
+ _initialTicks = _countdownTicks = 0;
+ _loopCount = _currentLoopCount = 0;
+ return;
+ }
+
_scaling = stream->readSByte();
stream->readByte(); // unk
_frameNumber = stream->readByte();
diff --git a/engines/access/asurface.cpp b/engines/access/asurface.cpp
index 526690807a..37f4c7082e 100644
--- a/engines/access/asurface.cpp
+++ b/engines/access/asurface.cpp
@@ -28,6 +28,8 @@
namespace Access {
+const int TRANSPARENCY = 0;
+
SpriteResource::SpriteResource(AccessEngine *vm, Resource *res) {
Common::Array<uint32> offsets;
int count = res->_stream->readUint16LE();
@@ -64,7 +66,7 @@ SpriteFrame::SpriteFrame(AccessEngine *vm, Common::SeekableReadStream *stream, i
// Empty surface
byte *data = (byte *)getPixels();
- Common::fill(data, data + w * h, 0);
+ Common::fill(data, data + w * h, TRANSPARENCY);
// Decode the data
for (int y = 0; y < h; ++y) {
@@ -105,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;
@@ -119,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);
@@ -193,108 +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 != 0)
- *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(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::saveBlock(const Common::Rect &bounds) {
+void BaseSurface::copyTo(BaseSurface *dest) {
+ if (dest->empty())
+ dest->create(this->w, this->h);
+
+ dest->blitFrom(*this);
+}
+
+void BaseSurface::saveBlock(const Common::Rect &bounds) {
_savedBounds = bounds;
_savedBounds.clip(Common::Rect(0, 0, this->w, this->h));
@@ -304,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));
@@ -314,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);
@@ -344,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 022e2534c1..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,16 +62,12 @@ public:
public:
static int _clipWidth, _clipHeight;
public:
- ASurface();
-
- virtual ~ASurface();
+ BaseSurface();
- void create(uint16 width, uint16 height);
+ virtual ~BaseSurface();
void clearBuffer();
- bool clip(Common::Rect &r);
-
void plotImage(SpriteResource *sprite, int frameNum, const Common::Point &pt);
/**
@@ -89,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();
@@ -100,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(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) { dest->blitFrom(*this); }
+ void copyTo(BaseSurface *dest);
void saveBlock(const Common::Rect &bounds);
@@ -124,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 df8adc1bc6..29b58a3f1b 100644
--- a/engines/access/bubble_box.cpp
+++ b/engines/access/bubble_box.cpp
@@ -46,6 +46,9 @@ BubbleBox::BubbleBox(AccessEngine *vm, Access::BoxType type, int x, int y, int w
}
_btnUpPos = Common::Rect(0, 0, 0, 0);
_btnDownPos = Common::Rect(0, 0, 0, 0);
+ _startItem = _startBox = 0;
+ _charCol = 0;
+ _rowOff = 0;
}
void BubbleBox::load(Common::SeekableReadStream *stream) {
@@ -95,8 +98,9 @@ void BubbleBox::placeBubble1(const Common::String &msg) {
void BubbleBox::calcBubble(const Common::String &msg) {
// Save points
- Common::Point printOrg = _vm->_screen->_printOrg;
- Common::Point printStart = _vm->_screen->_printStart;
+ Screen &screen = *_vm->_screen;
+ Common::Point printOrg = screen._printOrg;
+ Common::Point printStart = screen._printStart;
// Figure out maximum width allowed
if (_type == kBoxTypeFileDialog) {
@@ -114,15 +118,15 @@ void BubbleBox::calcBubble(const Common::String &msg) {
int width = 0;
bool lastLine;
do {
- lastLine = _vm->_fonts._font2.getLine(s, _vm->_screen->_maxChars * 6, line, width);
+ lastLine = _vm->_fonts._font2.getLine(s, screen._maxChars * 6, line, width);
_vm->_fonts._printMaxX = MAX(width, _vm->_fonts._printMaxX);
- _vm->_screen->_printOrg.y += 6;
- _vm->_screen->_printOrg.x = _vm->_screen->_printStart.x;
+ screen._printOrg.y += 6;
+ screen._printOrg.x = screen._printStart.x;
} while (!lastLine);
if (_type == kBoxTypeFileDialog)
- ++_vm->_screen->_printOrg.y += 6;
+ ++screen._printOrg.y += 6;
// Determine the width for the area
width = (((_vm->_fonts._printMaxX >> 4) + 1) << 4) + 5;
@@ -131,7 +135,7 @@ void BubbleBox::calcBubble(const Common::String &msg) {
bounds.setWidth(width);
// Determine the height for area
- int y = _vm->_screen->_printOrg.y + 6;
+ int y = screen._printOrg.y + 6;
if (_type == kBoxTypeFileDialog)
y += 6;
int height = y - bounds.top;
@@ -141,6 +145,9 @@ void BubbleBox::calcBubble(const Common::String &msg) {
if (height >= 0)
bounds.setHeight(bounds.height() + 13 - (height % 13));
+ if (bounds.bottom > screen.h)
+ bounds.translate(0, screen.h - bounds.bottom);
+
// Add the new bounds to the bubbles list
_bubbles.push_back(bounds);
@@ -158,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;
@@ -221,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;
@@ -362,7 +369,7 @@ void BubbleBox::displayBoxData() {
_vm->_screen->drawRect();
_vm->_events->showCursor();
}
-
+
_vm->_events->hideCursor();
int oldPStartY = _boxPStartY;
++_boxPStartY;
@@ -467,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();
@@ -604,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_;
}
@@ -635,7 +643,9 @@ int BubbleBox::doBox_v1(int item, int box, int &btnSelected) {
}
}
}
-
+
+ delete icons;
+
_vm->_screen->restoreScreen();
_vm->_boxDataStart = _startItem;
_vm->_boxSelectYOld = -1;
@@ -725,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 aca7262952..f6d3033b1b 100644
--- a/engines/access/char.cpp
+++ b/engines/access/char.cpp
@@ -31,7 +31,7 @@ CharEntry::CharEntry(const byte *data, AccessEngine *vm) {
Common::MemoryReadStream s(data, 999);
_charFlag = s.readByte();
- if (vm->getGameID() == GType_MartianMemorandum) {
+ if (vm->getGameID() != GType_Amazon || !vm->isCD()) {
_screenFile.load(s);
_estabIndex = s.readSint16LE();
} else {
@@ -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
@@ -78,25 +78,12 @@ CharEntry::CharEntry() {
/*------------------------------------------------------------------------*/
CharManager::CharManager(AccessEngine *vm) : Manager(vm) {
- switch (vm->getGameID()) {
- case GType_Amazon:
- // Setup character list
- if (_vm->isDemo()) {
- for (int i = 0; i < 27; ++i)
- _charTable.push_back(CharEntry(Amazon::CHARTBL_DEMO[i], vm));
- } else {
- for (int i = 0; i < 37; ++i)
- _charTable.push_back(CharEntry(Amazon::CHARTBL[i], vm));
- }
- break;
-
- case GType_MartianMemorandum:
- for (int i = 0; i < 27; ++i)
- _charTable.push_back(CharEntry(Martian::CHARTBL_MM[i], vm));
- break;
-
- default:
- error("Unknown game");
+ // Setup character list
+ for (uint idx = 0; idx < _vm->_res->CHARTBL.size(); ++idx) {
+ if (_vm->_res->CHARTBL[idx].size() == 0)
+ _charTable.push_back(CharEntry());
+ else
+ _charTable.push_back(CharEntry(&_vm->_res->CHARTBL[idx][0], _vm));
}
_charFlag = 0;
@@ -144,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
@@ -177,6 +165,10 @@ void CharManager::charMenu() {
} else
error("Game not supported");
+ // Make a backup copy of the screen including the character buttons,
+ // for restoring when erasing conversation boxes
+ screen.copyTo(&_vm->_buffer1);
+
screen.restoreScreen();
delete spr;
}
diff --git a/engines/access/configure.engine b/engines/access/configure.engine
index b1defce946..0082430062 100644
--- a/engines/access/configure.engine
+++ b/engines/access/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 access "Access" no
+add_engine access "Access" yes
diff --git a/engines/access/debugger.cpp b/engines/access/debugger.cpp
index 6cb2bb606c..48c7290249 100644
--- a/engines/access/debugger.cpp
+++ b/engines/access/debugger.cpp
@@ -52,35 +52,26 @@ Debugger *Debugger::init(AccessEngine *vm) {
}
}
+void Debugger::postEnter() {
+ if (!_playMovieFile.empty()) {
+ _vm->playMovie(_playMovieFile, Common::Point(0, 0));
+
+ _playMovieFile.clear();
+ }
+
+ _vm->pauseEngine(false);
+}
+
/*------------------------------------------------------------------------*/
Debugger::Debugger(AccessEngine *vm) : GUI::Debugger(), _vm(vm) {
registerCmd("continue", WRAP_METHOD(Debugger, cmdExit));
registerCmd("scene", WRAP_METHOD(Debugger, Cmd_LoadScene));
registerCmd("cheat", WRAP_METHOD(Debugger, Cmd_Cheat));
-
- switch (vm->getGameID()) {
- case GType_Amazon:
- _sceneNumb = Amazon::ROOM_NUMB;
- _sceneDescr = new Common::String[_sceneNumb];
- for (int i = 0; i < _sceneNumb; i++)
- _sceneDescr[i] = Common::String(Amazon::ROOM_DESCR[i]);
- break;
- case GType_MartianMemorandum:
- _sceneNumb = Martian::ROOM_NUMB;
- _sceneDescr = new Common::String[_sceneNumb];
- for (int i = 0; i < _sceneNumb; i++)
- _sceneDescr[i] = Common::String(Martian::ROOM_DESCR[i]);
- break;
- default:
- _sceneDescr = nullptr;
- _sceneNumb = 0;
- break;
- }
+ registerCmd("playmovie", WRAP_METHOD(Debugger, Cmd_PlayMovie));
}
Debugger::~Debugger() {
- delete[] _sceneDescr;
}
bool Debugger::Cmd_LoadScene(int argc, const char **argv) {
@@ -88,18 +79,18 @@ bool Debugger::Cmd_LoadScene(int argc, const char **argv) {
case 1:
debugPrintf("Current scene is: %d\n\n", _vm->_player->_roomNumber);
- for (int i = 0; i < _sceneNumb; i++)
- if (_sceneDescr[i].size())
- debugPrintf("%d - %s\n", i, _sceneDescr[i].c_str());
+ for (uint i = 0; i < _vm->_res->ROOMTBL.size(); i++)
+ if (!_vm->_res->ROOMTBL[i]._desc.empty())
+ debugPrintf("%d - %s\n", i, _vm->_res->ROOMTBL[i]._desc.c_str());
return true;
case 2: {
int newRoom = strToInt(argv[1]);
- if (newRoom < 0 || newRoom >= _sceneNumb) {
+ if (newRoom < 0 || newRoom >= (int)_vm->_res->ROOMTBL.size()) {
debugPrintf("Invalid Room Number\n");
return true;
}
- if (!_sceneDescr[newRoom].size()) {
+ if (_vm->_res->ROOMTBL[newRoom]._desc.empty()) {
debugPrintf("Unused Room Number\n");
return true;
}
@@ -133,6 +124,19 @@ bool Debugger::Cmd_Cheat(int argc, const char **argv) {
return true;
}
+bool Debugger::Cmd_PlayMovie(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("Format: playmovie <movie-file>\n");
+ return true;
+ }
+
+ // play gets postponed until debugger is closed
+ Common::String filename = argv[1];
+ _playMovieFile = filename;
+
+ return cmdExit(0, 0);
+}
+
/*------------------------------------------------------------------------*/
namespace Amazon {
diff --git a/engines/access/debugger.h b/engines/access/debugger.h
index f4d8df7634..641b85c19b 100644
--- a/engines/access/debugger.h
+++ b/engines/access/debugger.h
@@ -35,13 +35,14 @@ class AccessEngine;
class Debugger : public GUI::Debugger {
protected:
AccessEngine *_vm;
+ Common::String _playMovieFile;
bool Cmd_LoadScene(int argc, const char **argv);
bool Cmd_Cheat(int argc, const char **argv);
- Common::String *_sceneDescr;
- int _sceneNumb;
+ bool Cmd_PlayMovie(int argc, const char **argv);
public:
static Debugger *init(AccessEngine *vm);
+ void postEnter();
public:
Debugger(AccessEngine *vm);
virtual ~Debugger();
diff --git a/engines/access/detection.cpp b/engines/access/detection.cpp
index 441740c1b2..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;
@@ -142,11 +142,10 @@ SaveStateList AccessMetaEngine::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);
+ Common::String pattern = Common::String::format("%s.0##", target);
Access::AccessSavegameHeader header;
filenames = saveFileMan->listSavefiles(pattern);
- sort(filenames.begin(), filenames.end()); // Sort to get the files in numerical order
SaveStateList saveList;
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
@@ -167,6 +166,8 @@ SaveStateList AccessMetaEngine::listSaves(const char *target) const {
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
diff --git a/engines/access/detection_tables.h b/engines/access/detection_tables.h
index 124f5fcf0d..7d9509ca43 100644
--- a/engines/access/detection_tables.h
+++ b/engines/access/detection_tables.h
@@ -40,6 +40,22 @@ static const AccessGameDescription gameDescriptions[] = {
0
},
+ {
+ // Amazon Guardians of Eden - Spanish
+ // Provided by dianiu in bug report #6958
+ {
+ "amazon",
+ 0,
+ AD_ENTRY1s("c00.ap", "aeb429ff015596144c0df06886c84825", 303753),
+ Common::ES_ESP,
+ Common::kPlatformDOS,
+ ADGF_UNSTABLE,
+ GUIO1(GUIO_NONE)
+ },
+ GType_Amazon,
+ 0
+ },
+
// Amazon Guardians of Eden - Demo English
{
{
diff --git a/engines/access/events.cpp b/engines/access/events.cpp
index 6ffe67acfb..21ff0d0928 100644
--- a/engines/access/events.cpp
+++ b/engines/access/events.cpp
@@ -74,7 +74,7 @@ void EventsManager::setCursor(CursorType cursorId) {
_invCursor.w / 2, _invCursor.h / 2, 0);
} else {
// Get a pointer to the mouse data to use, and get the cursor hotspot
- const byte *srcP = Amazon::CURSORS[cursorId];
+ const byte *srcP = &_vm->_res->CURSORS[cursorId][0];
int hotspotX = (int16)READ_LE_UINT16(srcP);
int hotspotY = (int16)READ_LE_UINT16(srcP + 2);
srcP += 4;
@@ -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 4d734a67a9..48276ee477 100644
--- a/engines/access/files.cpp
+++ b/engines/access/files.cpp
@@ -84,20 +84,6 @@ byte *Resource::data() {
/*------------------------------------------------------------------------*/
FileManager::FileManager(AccessEngine *vm) : _vm(vm) {
- switch (vm->getGameID()) {
- case GType_Amazon:
- if (_vm->isDemo())
- _filenames = &Amazon::FILENAMES_DEMO[0];
- else
- _filenames = &Amazon::FILENAMES[0];
- break;
- case GType_MartianMemorandum:
- _filenames = &Martian::FILENAMES[0];
- break;
- default:
- error("Unknown game");
- }
-
_fileNumber = -1;
_setPaletteFlag = true;
}
@@ -144,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();
@@ -161,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) {
@@ -215,8 +198,8 @@ void FileManager::handleFile(Resource *res) {
void FileManager::setAppended(Resource *res, int fileNum) {
// Open the file for access
- if (!res->_file.open(_filenames[fileNum]))
- error("Could not open file %s", _filenames[fileNum]);
+ if (!res->_file.open(_vm->_res->FILENAMES[fileNum]))
+ error("Could not open file %s", _vm->_res->FILENAMES[fileNum].c_str());
// If a different file has been opened then previously, load its index
if (_fileNumber != fileNum) {
diff --git a/engines/access/files.h b/engines/access/files.h
index 714ea44c75..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 {
@@ -70,7 +70,6 @@ public:
class FileManager {
private:
AccessEngine *_vm;
- const char * const *_filenames;
void openFile(Resource *res, const Common::String &filename);
@@ -82,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
@@ -134,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 3823b17283..e9874cd8d6 100644
--- a/engines/access/inventory.cpp
+++ b/engines/access/inventory.cpp
@@ -66,27 +66,9 @@ InventoryManager::InventoryManager(AccessEngine *vm) : Manager(vm) {
_iconDisplayFlag = true;
_boxNum = 0;
- const char *const *names;
- const int *combineP;
-
- switch (vm->getGameID()) {
- case GType_Amazon:
- names = Amazon::INVENTORY_NAMES;
- combineP = &Amazon::COMBO_TABLE[0][0];
- _inv.resize(85);
- for (uint i = 0; i < _inv.size(); ++i, combineP += 4)
- _inv[i].load(names[i], combineP);
- break;
- case GType_MartianMemorandum:
- names = Martian::INVENTORY_NAMES;
- combineP = nullptr;
- _inv.resize(55);
- for (uint i = 0; i < _inv.size(); ++i)
- _inv[i].load(names[i], nullptr);
- break;
- default:
- error("Unknown game");
- }
+ _inv.resize(_vm->_res->INVENTORY.size());
+ for (uint idx = 0; idx < _inv.size(); ++idx)
+ _inv[idx].load(_vm->_res->INVENTORY[idx]._desc, _vm->_res->INVENTORY[idx]._combo);
for (uint i = 0; i < 26; ++i) {
const int *r = INVCOORDS[i];
@@ -138,6 +120,7 @@ int InventoryManager::newDisplayInv() {
getList();
initFields();
+ files._setPaletteFlag = false;
files.loadScreen(&_vm->_buffer1, 99, 0);
_vm->_buffer1.copyTo(&_vm->_buffer2);
_vm->copyBF2Vid();
@@ -217,12 +200,15 @@ int InventoryManager::newDisplayInv() {
}
int InventoryManager::displayInv() {
- int *inv = (int *) malloc (Martian::INVENTORY_SIZE * sizeof(int));
+ int *inv = (int *) malloc(_vm->_res->INVENTORY.size() * sizeof(int));
+ const char **names = (const char **)malloc(_vm->_res->INVENTORY.size() * sizeof(const char *));
- for (int i = 0; i < Martian::INVENTORY_SIZE; i++)
+ for (uint i = 0; i < _vm->_res->INVENTORY.size(); i++) {
inv[i] = _inv[i]._value;
+ names[i] = _inv[i]._name.c_str();
+ }
_vm->_events->forceSetCursor(CURSOR_CROSSHAIRS);
- _vm->_invBox->getList(Martian::INVENTORY_NAMES, inv);
+ _vm->_invBox->getList(names, inv);
int btnSelected = 0;
int boxX = _vm->_invBox->doBox_v1(_startInvItem, _startInvBox, btnSelected);
@@ -237,6 +223,7 @@ int InventoryManager::displayInv() {
else
_vm->_useItem = -1;
+ free(names);
free(inv);
return 0;
}
diff --git a/engines/access/martian/martian_game.cpp b/engines/access/martian/martian_game.cpp
index 3fdba8d260..00ee6c9776 100644
--- a/engines/access/martian/martian_game.cpp
+++ b/engines/access/martian/martian_game.cpp
@@ -36,6 +36,8 @@ MartianEngine::MartianEngine(OSystem *syst, const AccessGameDescription *gameDes
MartianEngine::~MartianEngine() {
_introObjects = _spec7Objects = nullptr;
+ _skipStart = false;
+ _creditsStream = nullptr;
}
void MartianEngine::initObjects() {
@@ -68,8 +70,8 @@ void MartianEngine::initVariables() {
_timers.push_back(te);
}
- _player->_playerX = _player->_rawPlayer.x = _travelPos[_player->_roomNumber][0];
- _player->_playerY = _player->_rawPlayer.y = _travelPos[_player->_roomNumber][1];
+ _player->_playerX = _player->_rawPlayer.x = _res->ROOMTBL[_player->_roomNumber]._travelPos.x;
+ _player->_playerY = _player->_rawPlayer.y = _res->ROOMTBL[_player->_roomNumber]._travelPos.y;
_room->_selectCommand = -1;
_events->setNormalCursor(CURSOR_CROSSHAIRS);
_mouseMode = 0;
@@ -280,10 +282,10 @@ void MartianEngine::doCredits() {
void MartianEngine::setupGame() {
// Load death list
- _deaths.resize(20);
- for (int i = 0; i < 20; ++i) {
- _deaths[i]._screenId = Martian::DEATH_SCREENS[i];
- _deaths[i]._msg = Martian::DEATHMESSAGE[i];
+ _deaths.resize(_res->DEATHS.size());
+ for (uint idx = 0; idx < _deaths.size(); ++idx) {
+ _deaths[idx]._screenId = _res->DEATHS[idx]._screenId;
+ _deaths[idx]._msg = _res->DEATHS[idx]._msg;
}
// Setup timers
@@ -297,14 +299,14 @@ void MartianEngine::setupGame() {
}
// Miscellaneous
- // TODO: Replace with Martian fonts when located
- _fonts._font1.load(Amazon::FONT6x6_INDEX, Amazon::FONT6x6_DATA);
- _fonts._font2.load(Amazon::FONT2_INDEX, Amazon::FONT2_DATA);
+ Amazon::AmazonResources &res = *((Amazon::AmazonResources *)_res);
+ _fonts._font1.load(&res.FONT6x6_INDEX[0], &res.FONT6x6_DATA[0]);
+ _fonts._font2.load(&res.FONT2_INDEX[0], &res.FONT2_DATA[0]);
// Set player room and position
_player->_roomNumber = 7;
- _player->_playerX = _player->_rawPlayer.x = _travelPos[_player->_roomNumber][0];
- _player->_playerY = _player->_rawPlayer.y = _travelPos[_player->_roomNumber][1];
+ _player->_playerX = _player->_rawPlayer.x = _res->ROOMTBL[_player->_roomNumber]._travelPos.x;
+ _player->_playerY = _player->_rawPlayer.y = _res->ROOMTBL[_player->_roomNumber]._travelPos.y;
}
void MartianEngine::showDeathText(Common::String msg) {
diff --git a/engines/access/martian/martian_resources.cpp b/engines/access/martian/martian_resources.cpp
index 474ec2f71c..070fa0f7e3 100644
--- a/engines/access/martian/martian_resources.cpp
+++ b/engines/access/martian/martian_resources.cpp
@@ -27,691 +27,6 @@ namespace Access {
namespace Martian {
-const char *const FILENAMES[] = {
- "R00.AP", "R01.AP", "R02.AP", "R03.AP", "R04.AP", "R05.AP", "R06.AP", "R07.AP",
- "R08.AP", "R09.AP", "R10.AP", "R11.AP", "R12.AP", "R13.AP", "R14.AP", "R15.AP",
- "R16.AP", "R17.AP", "R18.AP", "R19.AP", "R20.AP", "R21.AP", "R22.AP", "R23.AP",
- "R24.AP", "R25.AP", "R26.AP", "R27.AP", "R28.AP", "R29.AP", "R30.AP", "R31.AP",
- "R32.AP", "R33.AP", "R34.AP", "R35.AP", "R36.AP", "R37.AP", "R38.AP", "R39.AP",
- "R40.AP","TITLE.AP","R42.AP","S01.AP", "R44.AP", "R45.AP","SOUND.AP","MUSIC.AP",
- "DEAD.AP","EST.AP", "W02.AP", "C02.AP", "C05.AP", "C04.AP", "C10.AP", "C03.AP",
- "C07.AP", "LOVE.AP","CAFE.AP","C08.AP", "C18.AP", "C19.AP", "C21.AP", "C23.AP",
- "C12.AP", "C16.AP","CAFE1.AP","C05A.AP","C06.AP","C11.AP", "C13.AP", "C20.AP",
- "C16A.AP","C09.AP", "R45.AP", "R46.AP", "R47.AP", "R48.AP", "R49.AP"
-};
-
-const byte MOUSE0[] = {
- // hotspot x and y, uint16 LE
- 0, 0, 0, 0,
- // byte 1: number of skipped pixels
- // byte 2: number of plotted pixels
- // then, pixels
- 0, 2, 0xF7, 5,
- 0, 3, 0xF7, 0xF7, 5,
- 0, 3, 0xF7, 0xF7, 5,
- 0, 4, 0xF7, 0xF7, 0xF7, 5,
- 0, 4, 0xF7, 0xF7, 0xF7, 5,
- 0, 5, 0xF7, 0xF7, 0xF7, 0xF7, 5,
- 0, 5, 0xF7, 0xF7, 0xF7, 0xF7, 5,
- 0, 6, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 5,
- 0, 6, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 5,
- 0, 7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 5,
- 0, 6, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 5,
- 0, 5, 0xF7, 0xF7, 0xF7, 0xF7, 5,
- 2, 3, 0xF7, 0xF7, 5,
- 3, 3, 0xF7, 0xF7, 5,
- 3, 3, 0xF7, 0xF7, 5,
- 4, 2, 0xF7, 5
-};
-const byte MOUSE1[] = {
- // hotspot x and y, uint16 LE
- 7, 0, 7, 0,
- // byte 1: number of skipped pixels
- // byte 2: number of plotted pixels
- // then, pixels
- 6, 1, 0xF7,
- 4, 5, 0xFF, 0xFF, 0, 0xFF, 0xFF,
- 3, 7, 0xFF, 0, 0, 0, 0, 0, 0xFF,
- 2, 9, 0xFF, 0, 0, 0, 0xF7, 0, 0, 0, 0xFF,
- 1, 11, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF,
- 1, 11, 0xFF, 0, 0, 0, 0, 0xF7, 0, 0, 0, 0, 0xFF,
- 0, 13, 0xF7, 0, 0, 0xF7, 0, 0xF7, 0, 0xF7, 0, 0xF7, 0, 0, 0xF7,
- 1, 11, 0xFF, 0, 0, 0, 0, 0xF7, 0, 0, 0, 0, 0xFF,
- 1, 11, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF,
- 2, 9, 0xFF, 0, 0, 0, 0xF7, 0, 0, 0, 0xFF,
- 3, 7, 0xFF, 0, 0, 0, 0, 0, 0xFF,
- 4, 5, 0xFF, 0xFF, 0, 0xFF, 0xFF,
- 6, 1, 0xF7,
- 0, 0,
- 0, 0,
- 0, 0
-};
-const byte MOUSE2[] = {
- // hotspot x and y, uint16 LE
- 8, 0, 8, 0,
- // byte 1: number of skipped pixels
- // byte 2: number of plotted pixels
- // then, pixels
- 0, 0,
- 0, 0,
- 7, 2, 4, 5,
- 7, 2, 4, 5,
- 7, 2, 4, 5,
- 7, 2, 4, 5,
- 7, 2, 4, 5,
- 2, 12, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 5,
- 7, 2, 4, 5,
- 7, 2, 4, 5,
- 7, 2, 4, 5,
- 7, 2, 4, 5,
- 7, 2, 4, 5,
- 0, 0,
- 0, 0,
- 0, 0
-};
-const byte MOUSE3[] = {
- // hotspot x and y, uint16 LE
- 0, 0, 0, 0,
- // byte 1: number of skipped pixels
- // byte 2: number of plotted pixels
- // then, pixels
- 0, 11, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 0, 12, 6, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 5,
- 0, 12, 6, 7, 7, 7, 7, 7, 7, 7, 7, 6, 5, 5,
- 0, 12, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5,
- 0, 12, 6, 6, 6, 6, 6, 5, 6, 6, 6, 6, 6, 5,
- 0, 12, 6, 6, 6, 6, 5, 0, 0, 6, 6, 6, 6, 5,
- 0, 12, 6, 6, 6, 6, 6, 0, 6, 6, 6, 6, 6, 5,
- 0, 12, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5,
- 0, 12, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5,
- 0, 12, 6, 6, 6, 6, 6, 5, 6, 6, 6, 6, 6, 5,
- 0, 12, 6, 6, 6, 6, 6, 5, 6, 6, 6, 6, 6, 5,
- 0, 12, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5,
- 1, 11, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 0, 0,
- 0, 0,
- 0, 0
-};
-const byte *const CURSORS[4] = { MOUSE0, MOUSE1, MOUSE2, MOUSE3 };
-
-const int _travelPos[][2] = {
- { -1, 0 },
- { 228, 117 },
- { 28, 98 },
- { 161, 140 },
- { 160, 116 },
- { 34, 119 },
- { 166, 105 },
- { 260, 126 },
- { 37, 107 },
- { 78, 139 },
- { 0, 0 },
- { 13, 112 },
- { 0, 0 },
- { 16, 122 },
- { 33, 126 },
- { 10, 160 },
- { 150, 102 },
- { 134, 160 },
- { 160, 76 },
- { 0, 0 },
- { 0, 0 },
- { 36, 116 },
- { 214, 113 },
- { 30, 127 },
- { 143, 131 },
- { 163, 103 },
- { 254, 106 },
- { 28, 161 },
- { 11, 164 },
- { 276, 134 },
- { 93, 118 },
- { 22, 150 },
- { 282, 156 },
- { 149, 92 },
- { 0, 0 },
- { 43, 410 },
- { 0, 0 },
- { 10, 136 },
- { 41, 100 },
- { 157, 97 },
- { -1, 5 },
- { -1, 4 },
- { -1, 10 },
- { -1, 7 },
- { -1, 3 },
- { -1, 8 },
- { -1, 6 },
- { -1, 20 },
- { -1, 18 },
- { -1, 19 },
- { -1, 21 }
-};
-
-const int INVENTORY_SIZE = 55;
-const char *const INVENTORY_NAMES[] = {
- "CAMERA", "LENS", "PHOTOS", "MAIL", "GUN",
- "CASH", "COMLINK", "AMMO", "LOCKPICK KIT", "EARRING",
- "RECIEPTS", "PAPER", "LADDER", "BOOTS", "DOCUMENTS",
- "KNIFE", "DAGGER", "KEYS", "ROCK", "LOG",
- "SHOVEL", "STONE", "REMOTE CONTROL", "FOOD AND WATER", "DOOR CARD KEY",
- "FLASHLIGHT", "INTERLOCK KEY", "TOOLS", "REBREATHER", "JET PACK",
- "ROD", "HCL2", "SAFE CARD KEY", "TUNING FORK", "STONE",
- "ROSE", "KEY", "NOTE", "ALLEN WRENCH", "HOVER BOARD",
- "BLUE PRINTS", "LETTER", "MEMORANDUM", "MARKERS", "FILM",
- "ANDRETTI FILM", "GLASSES", "AMULET", "FACIAL KIT", "CAT FOOD",
- "MONKEY WRENCH", "BIG DICK CARD", "BRA", "BOLT", nullptr
-};
-
-const byte ROOM_TABLE1[] = {
- 0x00, 0x2f, 0x00, 0x0d, 0x00, 0x30, 0x22, 0x30, 0x01, 0x00,
- 0x00, 0x00, 0x01, 0x01, 0x00, 0x03, 0x00, 0xff, 0x01, 0x00,
- 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0xc0, 0x00, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x2e, 0x00, 0x05, 0x00, 0x01, 0x00, 0xff, 0xff,
-};
-const byte ROOM_TABLE2[] = {
- 0x00, 0x2f, 0x00, 0x0d, 0x00, 0x32, 0x28, 0x25, 0x02, 0x00,
- 0x00, 0x00, 0x02, 0x02, 0x00, 0x03, 0x00, 0xff, 0x02, 0x00,
- 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0xc8, 0x00, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x2e, 0x00, 0x06, 0x00, 0x01, 0x00, 0xff, 0xff,
-};
-const byte ROOM_TABLE3[] = {
- 0x00, 0x2f, 0x00, 0x0f, 0x00, 0x1e, 0x19, 0x24, 0x03, 0x00,
- 0x00, 0x00, 0x03, 0x03, 0x00, 0x03, 0x00, 0xff, 0x03, 0x00,
- 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x78, 0x00, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x02, 0x00,
- 0x03, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x05, 0x00,
- 0x01, 0x00, 0x03, 0x00, 0x06, 0x00, 0x01, 0x00, 0x2e, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0xff, 0xff,
-};
-const byte ROOM_TABLE4[] = {
- 0x00, 0x2f, 0x00, 0x06, 0x00, 0x36, 0x27, 0x32, 0x04, 0x00,
- 0x00, 0x00, 0x04, 0x04, 0x00, 0x03, 0x00, 0xff, 0x04, 0x00,
- 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0xc8, 0x00, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x2e, 0x00, 0x07, 0x00, 0x01, 0x00, 0x2e, 0x00, 0x05, 0x00,
- 0x01, 0x00, 0xff, 0xff,
-};
-const byte ROOM_TABLE5[] = {
- 0x00, 0x2f, 0x00, 0x00, 0x00, 0x28, 0x19, 0x36, 0x05, 0x00,
- 0x00, 0x00, 0x05, 0x05, 0x00, 0x03, 0x00, 0xff, 0x05, 0x00,
- 0x02, 0x00, 0x05, 0x00, 0x01, 0x00, 0xa0, 0x20, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x2e, 0x00, 0x02, 0x00, 0x01, 0x00, 0x2e, 0x00, 0x03, 0x00,
- 0x01, 0x00, 0xff, 0xff,
-};
-const byte ROOM_TABLE6[] = {
- 0x00, 0x2f, 0x00, 0x07, 0x00, 0x40, 0x36, 0x36, 0x06, 0x00,
- 0x00, 0x00, 0x06, 0x06, 0x00, 0x03, 0x00, 0xff, 0x06, 0x00,
- 0x02, 0x00, 0x06, 0x00, 0x01, 0x00, 0xfe, 0x00, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x2e, 0x00, 0x13, 0x00, 0x01, 0x00, 0x2e, 0x00, 0x08, 0x00,
- 0x01, 0x00, 0x2e, 0x00, 0x14, 0x00, 0x01, 0x00, 0x2e, 0x00,
- 0x07, 0x00, 0x01, 0x00, 0xff, 0xff,
-};
-const byte ROOM_TABLE7[] = {
- 0x00, 0x2f, 0x00, 0x0e, 0x00, 0x40, 0x32, 0x3b, 0x07, 0x00,
- 0x00, 0x00, 0x07, 0x07, 0x00, 0x03, 0x00, 0xff, 0x07, 0x00,
- 0x02, 0x00, 0x07, 0x00, 0x01, 0x00, 0xfe, 0x00, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x2e, 0x00, 0x14, 0x00, 0x01, 0x00, 0x2e, 0x00, 0x07, 0x00,
- 0x01, 0x00, 0xff, 0xff,
-};
-const byte ROOM_TABLE8[] = {
- 0x00, 0x2f, 0x00, 0x0a, 0x00, 0x30, 0x22, 0x46, 0x08, 0x00,
- 0x00, 0x00, 0x08, 0x08, 0x00, 0x03, 0x00, 0xff, 0x08, 0x00,
- 0x02, 0x00, 0x08, 0x00, 0x01, 0x00, 0xc0, 0x00, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0xff, 0xff,
-};
-const byte ROOM_TABLE9[] = {
- 0x00, 0x2f, 0x00, 0x07, 0x00, 0x32, 0x0c, 0x29, 0x09, 0x00,
- 0x00, 0x00, 0x09, 0x09, 0x00, 0x03, 0x00, 0xff, 0x09, 0x00,
- 0x02, 0x00, 0x09, 0x00, 0x01, 0x00, 0xc8, 0x00, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0xff, 0xff,
-};
-const byte ROOM_TABLE11[] = {
- 0x00, 0x2f, 0x00, 0x00, 0x00, 0x40, 0x3a, 0x22, 0x0b, 0x00,
- 0x00, 0x00, 0x0b, 0x0b, 0x00, 0x03, 0x00, 0xff, 0x0b, 0x00,
- 0x02, 0x00, 0x0b, 0x00, 0x01, 0x00, 0xfe, 0x00, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0xff, 0xff,
-};
-const byte ROOM_TABLE13[] = {
- 0x00, 0x2f, 0x00, 0x0c, 0x00, 0x40, 0x36, 0x2c, 0x0d, 0x00,
- 0x00, 0x00, 0x0d, 0x0d, 0x00, 0x03, 0x00, 0xff, 0x0d, 0x00,
- 0x02, 0x00, 0x0d, 0x00, 0x01, 0x00, 0xe6, 0x40, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x2e, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x2e, 0x00, 0x07, 0x00,
- 0x01, 0x00, 0x2e, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x2e, 0x00,
- 0x15, 0x00, 0x01, 0x00, 0xff, 0xff,
-};
-const byte ROOM_TABLE14[] = {
- 0x00, 0x2f, 0x00, 0x05, 0x00, 0x40, 0x3e, 0x33, 0x0e, 0x00,
- 0x00, 0x00, 0x0e, 0x0e, 0x00, 0x03, 0x00, 0xff, 0x0e, 0x00,
- 0x02, 0x00, 0x0e, 0x00, 0x01, 0x00, 0xfe, 0x40, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x2e, 0x00, 0x09, 0x00, 0x01, 0x00, 0x2e, 0x00, 0x07, 0x00,
- 0x01, 0x00, 0x2e, 0x00, 0x13, 0x00, 0x01, 0x00, 0x2e, 0x00,
- 0x0a, 0x00, 0x01, 0x00, 0xff, 0xff,
-};
-const byte ROOM_TABLE15[] = {
- 0x00, 0x2f, 0x00, 0x0c, 0x00, 0x28, 0x0c, 0x5e, 0x0f, 0x00,
- 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x03, 0x00, 0xff, 0x0f, 0x00,
- 0x02, 0x00, 0x0f, 0x00, 0x01, 0x00, 0xb4, 0x00, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x2e, 0x00, 0x11, 0x00, 0x01, 0x00, 0xff, 0xff,
-};
-const byte ROOM_TABLE16[] = {
- 0x00, 0x2f, 0x00, 0x05, 0x00, 0x28, 0x1e, 0x24, 0x10, 0x00,
- 0x00, 0x00, 0x10, 0x10, 0x00, 0x03, 0x00, 0xff, 0x10, 0x00,
- 0x02, 0x00, 0x10, 0x00, 0x01, 0x00, 0xa0, 0x00, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x2e, 0x00, 0x07, 0x00, 0x01, 0x00, 0xff, 0xff,
-};
-const byte ROOM_TABLE17[] = {
- 0x00, 0x2f, 0x00, 0x06, 0x00, 0x28, 0x19, 0x2b, 0x11, 0x00,
- 0x00, 0x00, 0x11, 0x11, 0x00, 0x03, 0x00, 0xff, 0x11, 0x00,
- 0x02, 0x00, 0x11, 0x00, 0x01, 0x00, 0xa0, 0x00, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x2e, 0x00, 0x05, 0x00, 0x01, 0x00, 0xff, 0xff,
-};
-const byte ROOM_TABLE18[] = {
- 0x00, 0x2f, 0x00, 0x00, 0x00, 0x2d, 0x14, 0x3c, 0x12, 0x00,
- 0x00, 0x00, 0x12, 0x12, 0x00, 0x03, 0x00, 0xff, 0x12, 0x00,
- 0x02, 0x00, 0x12, 0x00, 0x01, 0x00, 0xb1, 0x40, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x2e, 0x00, 0x05, 0x00, 0x01, 0x00, 0xff, 0xff,
-};
-const byte ROOM_TABLE21[] = {
- 0x00, 0x2f, 0x00, 0x07, 0x00, 0x3c, 0x2a, 0x29, 0x15, 0x00,
- 0x00, 0x00, 0x15, 0x15, 0x00, 0x03, 0x00, 0xff, 0x15, 0x00,
- 0x02, 0x00, 0x15, 0x00, 0x01, 0x00, 0xf0, 0x00, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x2e, 0x00, 0x12, 0x00, 0x01, 0x00, 0x2e, 0x00, 0x07, 0x00,
- 0x01, 0x00, 0xff, 0xff,
-};
-const byte ROOM_TABLE22[] = {
- 0x00, 0x2f, 0x00, 0x0a, 0x00, 0x40, 0x2d, 0x27, 0x16, 0x00,
- 0x00, 0x00, 0x16, 0x16, 0x00, 0x03, 0x00, 0xff, 0x16, 0x00,
- 0x02, 0x00, 0x16, 0x00, 0x01, 0x00, 0xfe, 0x00, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x2e, 0x00, 0x16, 0x00, 0x01, 0x00, 0x2e, 0x00, 0x07, 0x00,
- 0x01, 0x00, 0xff, 0xff,
-};
-const byte ROOM_TABLE23[] = {
- 0x00, 0x2f, 0x00, 0x0a, 0x00, 0x40, 0x38, 0x24, 0x17, 0x00,
- 0x00, 0x00, 0x17, 0x17, 0x00, 0x03, 0x00, 0xff, 0x17, 0x00,
- 0x02, 0x00, 0x17, 0x00, 0x01, 0x00, 0xfe, 0x40, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x2e, 0x00, 0x0f, 0x00, 0x01, 0x00, 0x2e, 0x00, 0x17, 0x00,
- 0x01, 0x00, 0xff, 0xff,
-};
-const byte ROOM_TABLE24[] = {
- 0x00, 0x2f, 0x00, 0x06, 0x00, 0x3e, 0x10, 0x62, 0x18, 0x00,
- 0x00, 0x00, 0x18, 0x18, 0x00, 0x03, 0x00, 0xff, 0x18, 0x00,
- 0x02, 0x00, 0x18, 0x00, 0x01, 0x00, 0xf8, 0x00, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x2e, 0x00, 0x16, 0x00, 0x01, 0x00, 0xff, 0xff,
-};
-const byte ROOM_TABLE25[] = {
- 0x00, 0x2f, 0x00, 0x0e, 0x00, 0x3e, 0x37, 0x19, 0x19, 0x00,
- 0x00, 0x00, 0x19, 0x19, 0x00, 0x03, 0x00, 0xff, 0x19, 0x00,
- 0x02, 0x00, 0x19, 0x00, 0x01, 0x00, 0xf8, 0x00, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x2e, 0x00, 0x10, 0x00, 0x01, 0x00, 0x2e, 0x00, 0x07, 0x00,
- 0x01, 0x00, 0xff, 0xff,
-};
-const byte ROOM_TABLE26[] = {
- 0x00, 0x2f, 0x00, 0x06, 0x00, 0x34, 0x28, 0x28, 0x1a, 0x00,
- 0x00, 0x00, 0x1a, 0x1a, 0x00, 0x03, 0x00, 0xff, 0x1a, 0x00,
- 0x02, 0x00, 0x1a, 0x00, 0x01, 0x00, 0xd0, 0x00, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x2e, 0x00, 0x07, 0x00, 0x01, 0x00, 0xff, 0xff,
-};
-const byte ROOM_TABLE27[] = {
- 0x00, 0x2f, 0x00, 0x0f, 0x00, 0x1b, 0x16, 0x18, 0x1b, 0x00,
- 0x00, 0x00, 0x1b, 0x1b, 0x00, 0x03, 0x00, 0xff, 0x1b, 0x00,
- 0x02, 0x00, 0x1b, 0x00, 0x01, 0x00, 0x70, 0x00, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x2e, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x2e, 0x00, 0x07, 0x00,
- 0x01, 0x00, 0xff, 0xff,
-};
-const byte ROOM_TABLE28[] = {
- 0x00, 0x2f, 0x00, 0x09, 0x00, 0x25, 0x10, 0x43, 0x1c, 0x00,
- 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x03, 0x00, 0xff, 0x1c, 0x00,
- 0x02, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x94, 0x00, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0xff, 0xff,
-};
-const byte ROOM_TABLE29[] = {
- 0x00, 0x2f, 0x00, 0x0a, 0x00, 0x20, 0x18, 0x56, 0x1d, 0x00,
- 0x00, 0x00, 0x1d, 0x1d, 0x00, 0x03, 0x00, 0xff, 0x1d, 0x00,
- 0x02, 0x00, 0x1d, 0x00, 0x01, 0x00, 0x80, 0x00, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x2e, 0x00, 0x17, 0x00, 0x01, 0x00, 0x2e, 0x00, 0x10, 0x00,
- 0x02, 0x00, 0xff, 0xff,
-};
-const byte ROOM_TABLE30[] = {
- 0x00, 0x2f, 0x00, 0x07, 0x00, 0x3f, 0x1c, 0x27, 0x1e, 0x00,
- 0x00, 0x00, 0x1e, 0x1e, 0x00, 0x03, 0x00, 0xff, 0x1e, 0x00,
- 0x02, 0x00, 0x1e, 0x00, 0x01, 0x00, 0xfe, 0x00, 0xff, 0xff,
- 0xff, 0xff, 0x1e, 0x00, 0x04, 0x00, 0xff, 0xff, 0x2e, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x2e, 0x00, 0x07, 0x00, 0x01, 0x00,
- 0x2e, 0x00, 0x15, 0x00, 0x01, 0x00, 0xff, 0xff,
-};
-const byte ROOM_TABLE31[] = {
- 0x00, 0x2f, 0x00, 0x0d, 0x00, 0x32, 0x2e, 0x69, 0x1f, 0x00,
- 0x00, 0x00, 0x1f, 0x1f, 0x00, 0x03, 0x00, 0xff, 0x1f, 0x00,
- 0x02, 0x00, 0x1f, 0x00, 0x01, 0x00, 0xc8, 0x00, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0xff, 0xff,
-};
-const byte ROOM_TABLE32[] = {
- 0x00, 0x2f, 0x00, 0x07, 0x00, 0x40, 0x3b, 0x4b, 0x20, 0x00,
- 0x00, 0x00, 0x20, 0x20, 0x00, 0x03, 0x00, 0xff, 0x20, 0x00,
- 0x02, 0x00, 0x20, 0x00, 0x01, 0x00, 0xfe, 0x00, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x2e, 0x00, 0x05, 0x00, 0x01, 0x00, 0xff, 0xff,
-};
-const byte ROOM_TABLE33[] = {
- 0x00, 0x2f, 0x00, 0x0b, 0x00, 0x30, 0x10, 0x51, 0x21, 0x00,
- 0x00, 0x00, 0x21, 0x21, 0x00, 0x03, 0x00, 0xff, 0x21, 0x00,
- 0x02, 0x00, 0x21, 0x00, 0x01, 0x00, 0xc0, 0x40, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0xff, 0xff,
-};
-const byte ROOM_TABLE35[] = {
- 0x00, 0x2f, 0x00, 0x0f, 0x00, 0x1e, 0x18, 0x25, 0x23, 0x00,
- 0x00, 0x00, 0x23, 0x23, 0x00, 0x03, 0x00, 0xff, 0x23, 0x00,
- 0x02, 0x00, 0x23, 0x00, 0x01, 0x00, 0x78, 0x18, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x2e, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x2e, 0x00, 0x07, 0x00,
- 0x01, 0x00, 0x2e, 0x00, 0x16, 0x00, 0x01, 0x00, 0x2e, 0x00,
- 0x0c, 0x00, 0x01, 0x00, 0xff, 0xff,
-};
-const byte ROOM_TABLE37[] = {
- 0x00, 0x2f, 0x00, 0x0f, 0x00, 0x3f, 0x3a, 0x1a, 0x25, 0x00,
- 0x00, 0x00, 0x25, 0x25, 0x00, 0x03, 0x00, 0xff, 0x25, 0x00,
- 0x02, 0x00, 0x25, 0x00, 0x01, 0x00, 0xfe, 0x40, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x2e, 0x00, 0x0d, 0x00, 0x01, 0x00, 0xff, 0xff,
-};
-const byte ROOM_TABLE38[] = {
- 0x00, 0x2f, 0x00, 0x0d, 0x00, 0x40, 0x32, 0x32, 0x26, 0x00,
- 0x00, 0x00, 0x26, 0x26, 0x00, 0x03, 0x00, 0xff, 0x26, 0x00,
- 0x02, 0x00, 0x26, 0x00, 0x01, 0x00, 0xf0, 0x00, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x2e, 0x00, 0x0b, 0x00, 0x01, 0x00, 0xff, 0xff,
-};
-const byte ROOM_TABLE39[] = {
- 0x00, 0x2f, 0x00, 0x0a, 0x00, 0x3c, 0x10, 0x4c, 0x27, 0x00,
- 0x00, 0x00, 0x27, 0x27, 0x00, 0x03, 0x00, 0xff, 0x27, 0x00,
- 0x02, 0x00, 0x27, 0x00, 0x01, 0x00, 0xf0, 0x00, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x2e, 0x00, 0x11, 0x00, 0x01, 0x00, 0x2e, 0x00, 0x0f, 0x00,
- 0x01, 0x00, 0xff, 0xff,
-};
-const byte ROOM_TABLE47[] = {
- 0x00, 0x2f, 0x00, 0x06, 0x00, 0x28, 0x1e, 0x32, 0x2b, 0x00,
- 0x00, 0x00, 0x46, 0x2b, 0x00, 0x03, 0x00, 0xff, 0x2b, 0x00,
- 0x02, 0x00, 0x2b, 0x00, 0x01, 0x00, 0xf0, 0x00, 0xff, 0xff,
- 0xff, 0xff, 0x2b, 0x00, 0x04, 0x00, 0xff, 0xff, 0x2e, 0x00,
- 0x04, 0x00, 0x01, 0x00, 0xff, 0xff, 0x00,
-};
-const byte *const ROOM_TABLE[] = {
- nullptr, ROOM_TABLE1, ROOM_TABLE2, ROOM_TABLE3, ROOM_TABLE4, ROOM_TABLE5, ROOM_TABLE6,
- ROOM_TABLE7, ROOM_TABLE8, ROOM_TABLE9, nullptr, ROOM_TABLE11, nullptr, ROOM_TABLE13,
- ROOM_TABLE14, ROOM_TABLE15, ROOM_TABLE16, ROOM_TABLE17, ROOM_TABLE18, nullptr, nullptr,
- ROOM_TABLE21, ROOM_TABLE22, ROOM_TABLE23, ROOM_TABLE24, ROOM_TABLE25, ROOM_TABLE26, ROOM_TABLE27,
- ROOM_TABLE28, ROOM_TABLE29, ROOM_TABLE30, ROOM_TABLE31, ROOM_TABLE32, ROOM_TABLE33, nullptr,
- ROOM_TABLE35, nullptr, ROOM_TABLE37, ROOM_TABLE38, ROOM_TABLE39, nullptr, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr, ROOM_TABLE47
-};
-
-const char *const ROOM_DESCR[] = {
- nullptr, "TBD ROOM_TABLE1", "TBD ROOM_TABLE2", "TBD ROOM_TABLE3", "TBD ROOM_TABLE4",
- "TBD ROOM_TABLE5", "TBD ROOM_TABLE6", "TBD ROOM_TABLE7", "TBD ROOM_TABLE8", "TBD ROOM_TABLE9",
- nullptr, "TBD ROOM_TABLE11", nullptr, "TBD ROOM_TABLE13", "TBD ROOM_TABLE14",
- "TBD ROOM_TABLE15", "TBD ROOM_TABLE16", "TBD ROOM_TABLE17", "TBD ROOM_TABLE18", nullptr,
- nullptr, "TBD ROOM_TABLE21", "TBD ROOM_TABLE22", "TBD ROOM_TABLE23", "TBD ROOM_TABLE24",
- "TBD ROOM_TABLE25", "TBD ROOM_TABLE26", "TBD ROOM_TABLE27", "TBD ROOM_TABLE28", "TBD ROOM_TABLE29",
- "TBD ROOM_TABLE30", "TBD ROOM_TABLE31", "TBD ROOM_TABLE32", "TBD ROOM_TABLE33", nullptr,
- "TBD ROOM_TABLE35", nullptr, "TBD ROOM_TABLE37", "TBD ROOM_TABLE38", "TBD ROOM_TABLE39",
- nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, "TBD ROOM_TABLE47"
-};
-
-const int ROOM_NUMB = 48;
-
-const byte MMCHAR_0[] = {
- 0x02, 0x31, 0x00, 0x08, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
- 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
-};
-const byte MMCHAR_2[] = {
- 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0x00, 0x00, 0x00, 0x00, 0x32, 0x33, 0x00, 0x01, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0x33, 0x00, 0x00, 0x00, 0x33,
- 0x00, 0x02, 0x00, 0x33, 0x00, 0x0b, 0x00, 0x33, 0x00, 0x03,
- 0x00, 0x33, 0x00, 0x0c, 0x00, 0x33, 0x00, 0x04, 0x00, 0x33,
- 0x00, 0x0d, 0x00, 0x33, 0x00, 0x05, 0x00, 0x33, 0x00, 0x0e,
- 0x00, 0x33, 0x00, 0x06, 0x00, 0x33, 0x00, 0x0f, 0x00, 0x33,
- 0x00, 0x07, 0x00, 0x33, 0x00, 0x10, 0x00, 0x33, 0x00, 0x08,
- 0x00, 0x33, 0x00, 0x11, 0x00, 0x33, 0x00, 0x09, 0x00, 0x33,
- 0x00, 0x12, 0x00, 0x33, 0x00, 0x0a, 0x00, 0x33, 0x00, 0x13,
- 0x00, 0xff, 0xff,
-};
-const byte MMCHAR_3[] = {
- 0x02, 0x31, 0x00, 0x03, 0x00, 0x35, 0x00, 0x37, 0x00, 0x02,
- 0x00, 0x80, 0x00, 0xf7, 0x00, 0x4b, 0x37, 0x00, 0x01, 0x00,
- 0xff, 0x37, 0x00, 0x03, 0x00, 0x37, 0x00, 0x00, 0x00, 0xff,
- 0xff,
-};
-const byte MMCHAR_4[] = {
- 0x01, 0x31, 0x00, 0x0a, 0x00, 0x36, 0x00, 0x35, 0x00, 0x02,
- 0x00, 0x80, 0x00, 0xf7, 0x00, 0x49, 0x35, 0x00, 0x01, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0x35, 0x00, 0x00, 0x00, 0x35,
- 0x00, 0x03, 0x00, 0x35, 0x00, 0x0c, 0x00, 0x35, 0x00, 0x04,
- 0x00, 0x35, 0x00, 0x0d, 0x00, 0x35, 0x00, 0x05, 0x00, 0x35,
- 0x00, 0x0e, 0x00, 0x35, 0x00, 0x06, 0x00, 0x35, 0x00, 0x0f,
- 0x00, 0x35, 0x00, 0x07, 0x00, 0x35, 0x00, 0x10, 0x00, 0x35,
- 0x00, 0x08, 0x00, 0x35, 0x00, 0x11, 0x00, 0x35, 0x00, 0x09,
- 0x00, 0x35, 0x00, 0x12, 0x00, 0x35, 0x00, 0x0a, 0x00, 0x35,
- 0x00, 0x13, 0x00, 0x35, 0x00, 0x0b, 0x00, 0x35, 0x00, 0x14,
- 0x00, 0xff, 0xff,
-};
-const byte MMCHAR_5[] = {
- 0x01, 0x31, 0x00, 0x08, 0x00, 0x37, 0x00, 0x34, 0x00, 0x02,
- 0x00, 0x80, 0x00, 0xf7, 0x00, 0x48, 0x34, 0x00, 0x01, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0x34, 0x00, 0x00, 0x00, 0x43,
- 0x00, 0x00, 0x00, 0x34, 0x00, 0x03, 0x00, 0x43, 0x00, 0x01,
- 0x00, 0x34, 0x00, 0x04, 0x00, 0x43, 0x00, 0x02, 0x00, 0x34,
- 0x00, 0x05, 0x00, 0x43, 0x00, 0x03, 0x00, 0x34, 0x00, 0x06,
- 0x00, 0x43, 0x00, 0x04, 0x00, 0x34, 0x00, 0x07, 0x00, 0x43,
- 0x00, 0x05, 0x00, 0x34, 0x00, 0x08, 0x00, 0x43, 0x00, 0x06,
- 0x00, 0x34, 0x00, 0x09, 0x00, 0x43, 0x00, 0x07, 0x00, 0x34,
- 0x00, 0x0a, 0x00, 0x43, 0x00, 0x08, 0x00, 0x34, 0x00, 0x0b,
- 0x00, 0x43, 0x00, 0x09, 0x00, 0x34, 0x00, 0x0c, 0x00, 0x43,
- 0x00, 0x0a, 0x00, 0x34, 0x00, 0x0d, 0x00, 0x43, 0x00, 0x0b,
- 0x00, 0x34, 0x00, 0x0e, 0x00, 0x43, 0x00, 0x0c, 0x00, 0x34,
- 0x00, 0x0f, 0x00, 0x43, 0x00, 0x0d, 0x00, 0x34, 0x00, 0x10,
- 0x00, 0xff, 0xff,
-};
-const byte MMCHAR_6[] = {
- 0x02, 0x31, 0x00, 0x03, 0x00, 0x38, 0x00, 0x44, 0x00, 0x03,
- 0x00, 0x80, 0x00, 0xf7, 0x00, 0x4e, 0x44, 0x00, 0x01, 0x00,
- 0xff, 0x44, 0x00, 0x02, 0x00, 0x44, 0x00, 0x00, 0x00, 0xff,
- 0xff,
-};
-const byte MMCHAR_7[] = {
- 0x02, 0x31, 0x00, 0x01, 0x00, 0x39, 0x00, 0x38, 0x00, 0x02,
- 0x00, 0x80, 0x00, 0xf7, 0x00, 0x4c, 0x38, 0x00, 0x01, 0x00,
- 0xff, 0x38, 0x00, 0x03, 0x00, 0x38, 0x00, 0x00, 0x00, 0xff,
- 0xff,
-};
-const byte MMCHAR_8[] = {
- 0x03, 0xff, 0xff, 0xff, 0xff, 0x3a, 0x00, 0xff, 0xff, 0xff,
- 0xff, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x3b, 0x00, 0x01, 0x00,
- 0xff, 0x3b, 0x00, 0x02, 0x00, 0x3b, 0x00, 0x00, 0x00, 0xff,
- 0xff,
-};
-const byte MMCHAR_9[] = {
- 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0x00, 0x00, 0x00, 0x00, 0x59, 0x4a, 0x00, 0x01, 0x00,
- 0xff, 0x4a, 0x00, 0x02, 0x00, 0x4a, 0x00, 0x00, 0x00, 0xff,
- 0xff,
-};
-const byte MMCHAR_10[] = {
- 0x01, 0x31, 0x00, 0x0a, 0x00, 0x3c, 0x00, 0x36, 0x00, 0x02,
- 0x00, 0x80, 0x00, 0xf7, 0x00, 0x4a, 0x36, 0x00, 0x01, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0x36, 0x00, 0x00, 0x00, 0x36,
- 0x00, 0x03, 0x00, 0x36, 0x00, 0x13, 0x00, 0x36, 0x00, 0x04,
- 0x00, 0x36, 0x00, 0x14, 0x00, 0x36, 0x00, 0x05, 0x00, 0x36,
- 0x00, 0x15, 0x00, 0x36, 0x00, 0x06, 0x00, 0x36, 0x00, 0x16,
- 0x00, 0x36, 0x00, 0x07, 0x00, 0x36, 0x00, 0x17, 0x00, 0x36,
- 0x00, 0x08, 0x00, 0x36, 0x00, 0x18, 0x00, 0x36, 0x00, 0x09,
- 0x00, 0x36, 0x00, 0x19, 0x00, 0x36, 0x00, 0x0a, 0x00, 0x36,
- 0x00, 0x1a, 0x00, 0x36, 0x00, 0x0b, 0x00, 0x36, 0x00, 0x1b,
- 0x00, 0x36, 0x00, 0x0c, 0x00, 0x36, 0x00, 0x1c, 0x00, 0x36,
- 0x00, 0x0d, 0x00, 0x36, 0x00, 0x1d, 0x00, 0x36, 0x00, 0x0e,
- 0x00, 0x36, 0x00, 0x1e, 0x00, 0x36, 0x00, 0x0f, 0x00, 0x36,
- 0x00, 0x1f, 0x00, 0x36, 0x00, 0x10, 0x00, 0x36, 0x00, 0x20,
- 0x00, 0x36, 0x00, 0x11, 0x00, 0x36, 0x00, 0x21, 0x00, 0x36,
- 0x00, 0x12, 0x00, 0x36, 0x00, 0x22, 0x00, 0xff, 0xff,
-};
-const byte MMCHAR_11[] = {
- 0x03, 0xff, 0xff, 0xff, 0xff, 0x3d, 0x00, 0xff, 0xff, 0xff,
- 0xff, 0x00, 0x00, 0x00, 0x00, 0x55, 0x45, 0x00, 0x01, 0x00,
- 0xff, 0x45, 0x00, 0x02, 0x00, 0x45, 0x00, 0x00, 0x00, 0xff,
- 0xff,
-};
-const byte MMCHAR_12[] = {
- 0x03, 0xff, 0xff, 0xff, 0xff, 0x3e, 0x00, 0xff, 0xff, 0xff,
- 0xff, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x40, 0x00, 0x01, 0x00,
- 0xff, 0x40, 0x00, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0xff,
- 0xff,
-};
-const byte MMCHAR_13[] = {
- 0x00, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x46, 0x00, 0x02,
- 0x00, 0x80, 0x00, 0xf7, 0x00, 0x56, 0x46, 0x00, 0x01, 0x00,
- 0xff, 0x46, 0x00, 0x03, 0x00, 0x46, 0x00, 0x00, 0x00, 0x46,
- 0x00, 0x04, 0x00, 0x46, 0x00, 0x0d, 0x00, 0x46, 0x00, 0x05,
- 0x00, 0x46, 0x00, 0x0e, 0x00, 0x46, 0x00, 0x06, 0x00, 0x46,
- 0x00, 0x0f, 0x00, 0x46, 0x00, 0x07, 0x00, 0x46, 0x00, 0x10,
- 0x00, 0x46, 0x00, 0x08, 0x00, 0x46, 0x00, 0x11, 0x00, 0x46,
- 0x00, 0x09, 0x00, 0x46, 0x00, 0x12, 0x00, 0x46, 0x00, 0x0a,
- 0x00, 0x46, 0x00, 0x13, 0x00, 0x46, 0x00, 0x0b, 0x00, 0x46,
- 0x00, 0x14, 0x00, 0x46, 0x00, 0x0c, 0x00, 0x46, 0x00, 0x15,
- 0x00, 0xff, 0xff,
-};
-const byte MMCHAR_15[] = {
- 0x00, 0xff, 0xff, 0xff, 0xff, 0x41, 0x00, 0xff, 0xff, 0xff,
- 0xff, 0x00, 0x00, 0x00, 0x00, 0x57, 0x47, 0x00, 0x01, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0x47, 0x00, 0x00, 0x00, 0x47,
- 0x00, 0x02, 0x00, 0x47, 0x00, 0x05, 0x00, 0x47, 0x00, 0x03,
- 0x00, 0x47, 0x00, 0x06, 0x00, 0x47, 0x00, 0x04, 0x00, 0x47,
- 0x00, 0x07, 0x00, 0xff, 0xff,
-};
-const byte MMCHAR_16[] = {
- 0x03, 0xff, 0xff, 0xff, 0xff, 0x42, 0x00, 0xff, 0xff, 0xff,
- 0xff, 0x00, 0x00, 0x00, 0x00, 0x54, 0x41, 0x00, 0x01, 0x00,
- 0xff, 0x41, 0x00, 0x02, 0x00, 0x41, 0x00, 0x00, 0x00, 0xff,
- 0xff,
-};
-const byte MMCHAR_18[] = {
- 0x02, 0x31, 0x00, 0x07, 0x00, 0x44, 0x00, 0x3c, 0x00, 0x03,
- 0x00, 0x80, 0x00, 0xf7, 0x00, 0x50, 0x3c, 0x00, 0x01, 0x00,
- 0xff, 0x3c, 0x00, 0x02, 0x00, 0x3c, 0x00, 0x00, 0x00, 0xff,
- 0xff,
-};
-const byte MMCHAR_19[] = {
- 0x02, 0x31, 0x00, 0x07, 0x00, 0x45, 0x00, 0x3d, 0x00, 0x03,
- 0x00, 0x80, 0x00, 0xf7, 0x00, 0x51, 0x3d, 0x00, 0x01, 0x00,
- 0xff, 0x3d, 0x00, 0x02, 0x00, 0x3d, 0x00, 0x00, 0x00, 0xff,
- 0xff,
-};
-const byte MMCHAR_20[] = {
- 0x02, 0x31, 0x00, 0x02, 0x00, 0x46, 0x00, 0x48, 0x00, 0x02,
- 0x00, 0x80, 0x00, 0xf7, 0x00, 0x58, 0x48, 0x00, 0x01, 0x00,
- 0xff, 0x48, 0x00, 0x03, 0x00, 0x48, 0x00, 0x00, 0x00, 0xff,
- 0xff,
-};
-const byte MMCHAR_21[] = {
- 0x02, 0x31, 0x00, 0x07, 0x00, 0x47, 0x00, 0x3e, 0x00, 0x03,
- 0x00, 0x80, 0x00, 0xf7, 0x00, 0x52, 0x3e, 0x00, 0x01, 0x00,
- 0xff, 0x3e, 0x00, 0x02, 0x00, 0x3e, 0x00, 0x00, 0x00, 0xff,
- 0xff,
-};
-const byte MMCHAR_23[] = {
- 0x02, 0x31, 0x00, 0x08, 0x00, 0x49, 0x00, 0x3f, 0x00, 0x03,
- 0x00, 0x80, 0x00, 0xf7, 0x00, 0x53, 0x3f, 0x00, 0x01, 0x00,
- 0xff, 0x3f, 0x00, 0x02, 0x00, 0x3f, 0x00, 0x00, 0x00, 0xff,
- 0xff,
-};
-const byte MMCHAR_24[] = {
- 0x02, 0x32, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0x00, 0x00, 0x00, 0x00, 0x47, 0x32, 0x00, 0x02, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0x32, 0x00, 0x01, 0x00, 0x32,
- 0x00, 0x03, 0x00, 0x32, 0x00, 0x0a, 0x00, 0x32, 0x00, 0x04,
- 0x00, 0x32, 0x00, 0x0b, 0x00, 0x32, 0x00, 0x05, 0x00, 0x32,
- 0x00, 0x0c, 0x00, 0x32, 0x00, 0x06, 0x00, 0x32, 0x00, 0x0d,
- 0x00, 0x32, 0x00, 0x07, 0x00, 0x32, 0x00, 0x0e, 0x00, 0x32,
- 0x00, 0x08, 0x00, 0x32, 0x00, 0x0f, 0x00, 0x32, 0x00, 0x09,
- 0x00, 0x32, 0x00, 0x10, 0x00, 0xff, 0xff
-};
-const byte MMCHAR_25[] = {
- 0x02, 0x39, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x39, 0x00, 0x00, 0x00, 0x39, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xFF, 0xFF
-};
-const byte MMCHAR_26[] = {
- 0x01, 0x3a, 0x00, 0x01, 0x00, 0x0a, 0x00, 0xff, 0xff, 0xff,
- 0xff, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x3a, 0x00, 0x02, 0x00,
- 0xff, 0x3a, 0x00, 0x03, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x42,
- 0x00, 0x00, 0x00, 0x3a, 0x00, 0x04, 0x00, 0x42, 0x00, 0x01,
- 0x00, 0x3a, 0x00, 0x05, 0x00, 0x42, 0x00, 0x02, 0x00, 0x3a,
- 0x00, 0x06, 0x00, 0x42, 0x00, 0x03, 0x00, 0x3a, 0x00, 0x07,
- 0x00, 0x42, 0x00, 0x04, 0x00, 0x3a, 0x00, 0x08, 0x00, 0x42,
- 0x00, 0x05, 0x00, 0x3a, 0x00, 0x09, 0x00, 0x42, 0x00, 0x06,
- 0x00, 0x3a, 0x00, 0x0a, 0x00, 0x42, 0x00, 0x07, 0x00, 0x3a,
- 0x00, 0x0b, 0x00, 0x42, 0x00, 0x08, 0x00, 0x3a, 0x00, 0x0c,
- 0x00, 0x42, 0x00, 0x09, 0x00, 0x3a, 0x00, 0x0d, 0x00, 0x42,
- 0x00, 0x0a, 0x00, 0x3a, 0x00, 0x0e, 0x00, 0x42, 0x00, 0x0b,
- 0x00, 0x3a, 0x00, 0x0f, 0x00, 0x42, 0x00, 0x0c, 0x00, 0x3a,
- 0x00, 0x10, 0x00, 0x42, 0x00, 0x0d, 0x00, 0x3a, 0x00, 0x11,
- 0x00, 0x42, 0x00, 0x0e, 0x00, 0x3a, 0x00, 0x12, 0x00, 0x42,
- 0x00, 0x0f, 0x00, 0x3a, 0x00, 0x13, 0x00, 0x42, 0x00, 0x10,
- 0x00, 0x3a, 0x00, 0x14, 0x00, 0x42, 0x00, 0x11, 0x00, 0x3a,
- 0x00, 0x15, 0x00, 0xff, 0xff
-};
-const byte MMCHAR_27[] = {
- 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0x00, 0x00, 0x00, 0x00, 0x58, 0x49, 0x00, 0x01, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0x49, 0x00, 0x00, 0x00, 0x49,
- 0x00, 0x02, 0x00, 0x49, 0x00, 0x0a, 0x00, 0x49, 0x00, 0x03,
- 0x00, 0x49, 0x00, 0x0b, 0x00, 0x49, 0x00, 0x04, 0x00, 0x49,
- 0x00, 0x0c, 0x00, 0x49, 0x00, 0x05, 0x00, 0x49, 0x00, 0x0d,
- 0x00, 0x49, 0x00, 0x06, 0x00, 0x49, 0x00, 0x0e, 0x00, 0x49,
- 0x00, 0x07, 0x00, 0x49, 0x00, 0x0f, 0x00, 0x49, 0x00, 0x08,
- 0x00, 0x49, 0x00, 0x10, 0x00, 0x49, 0x00, 0x09, 0x00, 0x49,
- 0x00, 0x11, 0x00, 0xff, 0xff,
-};
-
-// HACK: MMCHAR_0 has been used to replace the missing CHAR: 1, 14, 17 and 22
-const byte *const CHARTBL_MM[] = {
- MMCHAR_0, MMCHAR_0, MMCHAR_2, MMCHAR_3, MMCHAR_4,
- MMCHAR_5, MMCHAR_6, MMCHAR_7, MMCHAR_8, MMCHAR_9,
- MMCHAR_10, MMCHAR_11, MMCHAR_12, MMCHAR_13, MMCHAR_0,
- MMCHAR_15, MMCHAR_16, MMCHAR_0, MMCHAR_18, MMCHAR_19,
- MMCHAR_20, MMCHAR_21, MMCHAR_0, MMCHAR_23, MMCHAR_24,
- MMCHAR_25, MMCHAR_26, MMCHAR_27
-};
-
const int SIDEOFFR[] = { 4, 0, 7, 10, 3, 1, 2, 13, 0, 0, 0, 0 };
const int SIDEOFFL[] = { 11, 6, 1, 4, 10, 6, 1, 4, 0, 0, 0, 0 };
const int SIDEOFFU[] = { 1, 2, 0, 2, 2, 1, 1, 0, 0, 0, 0, 0 };
@@ -765,7 +80,7 @@ const char *const TRAVDATA[] = {
"COOPER BRADBURY", nullptr
};
-const char *const _askTBL[] = {
+const char *const ASK_TBL[] = {
"NONE", "MARSHALL ALEXANDER", "TERRAFORM CORP.", "COLLIER STANTON", "ROCKWELL BACHE",
"JOCQUES SPARROW", "NORA DESMOND ALEXANDER", "GALACTIC PICTURES", "LAWRENCE BARKLEY", "TMS",
"MAC MALDEN", "STANTON EXPEDITION", "LOWELL PERCIVAL", "CHANTAL VARGAS", "RICK LOGAN",
@@ -783,33 +98,6 @@ byte HELP[] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1
};
-const byte DEATH_SCREENS[] = {
- 5, 5, 3, 3, 7, 4, 6, 2, 2, 2, 1, 5, 3, 5, 2, 8, 5, 3, 8, 5
-};
-
-const char *const DEATHMESSAGE[] = {
- "A VICIOUS THUG PULLS OUT HIS GUN AND AIR CONDITIONS YOUR BRAIN.",
- "BIG DICK COMES BACK AND ANNOUNCES YOUR TIME IS UP. ONE OF HIS BOYS PROCEEDS TO PART YOUR EYEBROWS.",
- "ALTHOUGH HIS FIRST SHOT MISSED, THE PUNK FINDS YOU AND TURNS YOU INTO A DOUGHNUT.",
- "THE CREEP SPOTS YOU. HE TURNS AND FIRES HIS WEAPON. IT BURNS A HOLE A BUZZARD CAN FLY THROUGH.",
- "OBVIOUSLY RICK LOGAN HAS A FEW TRICK UP HIS SLEEVE. A TREMENDOUS WEIGHT HITS YOUR HEAD. YOU MUMBLE; WATCH OUT FOR THAT TREE...",
- "SLOWLY SINKING IN THE SLIMY OOZE, YOU THINK OF SEVERAL JELLO WRESTLING MATCHES YOU'VE ATTENDED. BUT NO MORE...",
- "THE PATH SUDDENLY GIVES WAY AND YOU FEEL MANY STAKES TEAR THROUGH YOUR FLESH. HOW DO YOU LIKE YOUR STAKE",
- "THE SNAKE SINKS ITS FANGS INTO YOU LEG. THE POISON WORKS QUICKLY. THE SNAKE THEN SWALLOWS YOU WHOLE.",
- "YOU FADE AWAY, GLOWING LIKE A LIGHTBULB.",
- "YOU TOUCH THE BUBBLING RADIOACTIVE SELTZER. IT IMMEDIATELY CAUSES VITAL ORGANS TO ELONGATE AND EXPLODE. YOU DIE WITH AN ABSURD AND FOOLISH LOOK ON YOUR FACE.",
- "THE DOGS PRETTY HUNGRY. IT WON'T TAKE HIM LONG TO FINISH SO SIT BACK AND ENJOY IT.",
- "ROCKY DOESN'T LIKE BEING FOLLOWED. HE DECIDES TO BEAT YOU. WITHIN AND INCH OF YOUR LIFE. UNFORTUNATELY, HE MISJUDGED THE DISTANCE",
- "YOU STUMBLE INTO DEADLY LASER FIRE.",
- "THE OUTPOST AND YOUR BODY PARTS ARE BLOWN TO KINGDOM COME.",
- "YOU REACH THE TOP, BUT YOUR AIR SOON RUNS OUT LEAVING YOU BREATHLESS.",
- "YOU DIE IN THE FIERY EXPLOSION.",
- "YOU FALL HUNDREDS OF FEET TO YOUR DEATH.",
- "YOU WALK ONTO A PRESSURE SENSITIVE SECURITY PAD. A LASER ZEROS IN AND BLOWS A HOLE THE SIZE OF A SUBARU TIRE THROUGH YOU.",
- "DANGERFIELD'S EXPERIMENT BACKFIRES. IT RELEASES A DEMON FROM HIS SUBCONSCIOUS WHICH DESTROYS THE ENTIRE PLANET.",
- "ONCE DANGERFIELD GETS OUT OF HIS CHAMBER, HE PULLS OUT A WEAPON AND LETS YOU HAVE IT."
-};
-
const char *const SPEC7MESSAGE = {
"THOMAS DANGERFIELD'S MAD EXPERIMENT OF ATTEMPTING TO HARNESS THE STONE'S POWER, ENDED HIS LIFE. DANGERFIELD WAS A DECENT HUMAN " \
"BEING ONCE, BUT WAS DRIVEN INSANE BY HIS QUEST FOR THE ULTIMATE POWER. ALEXIS AND I DECIDE THAT DEACON HAWKE IS THE ONLY " \
diff --git a/engines/access/martian/martian_resources.h b/engines/access/martian/martian_resources.h
index 2eb810ac80..46cf6a71c1 100644
--- a/engines/access/martian/martian_resources.h
+++ b/engines/access/martian/martian_resources.h
@@ -24,31 +24,17 @@
#define ACCESS_MARTIAN_RESOURCES_H
#include "common/scummsys.h"
+#include "access/resources.h"
namespace Access {
namespace Martian {
-extern const char *const FILENAMES[];
-
extern const int SIDEOFFR[];
extern const int SIDEOFFL[];
extern const int SIDEOFFU[];
extern const int SIDEOFFD[];
-extern const byte *const CURSORS[4];
-
-extern const int _travelPos[][2];
-
-extern const int INVENTORY_SIZE;
-extern const char *const INVENTORY_NAMES[];
-
-extern const byte *const ROOM_TABLE[];
-extern const char *const ROOM_DESCR[];
-extern const int ROOM_NUMB;
-
-extern const byte *const CHARTBL_MM[];
-
extern const int SIDEOFFR[];
extern const int SIDEOFFL[];
extern const int SIDEOFFU[];
@@ -60,16 +46,24 @@ extern const byte ICON_PALETTE[];
extern const int RMOUSE[10][2];
extern byte HELP[];
-extern const char *const _askTBL[];
+extern const char *const ASK_TBL[];
extern const char *const TRAVDATA[];
-extern const byte DEATH_SCREENS[];
-extern const char *const DEATHMESSAGE[];
extern const char *const SPEC7MESSAGE;
extern const byte _byte1EEB5[];
extern const int PICTURERANGE[][2];
+class MartianResources : public Resources {
+public:
+
+public:
+ MartianResources(AccessEngine *vm) : Resources(vm) {}
+ virtual ~MartianResources() {}
+};
+
+#define MMRES (*((Martian::MartianResources *)_vm->_res))
+
} // End of namespace Martian
} // End of namespace Access
diff --git a/engines/access/martian/martian_room.cpp b/engines/access/martian/martian_room.cpp
index d5b03db246..0b8b4a842a 100644
--- a/engines/access/martian/martian_room.cpp
+++ b/engines/access/martian/martian_room.cpp
@@ -39,7 +39,7 @@ MartianRoom::~MartianRoom() {
}
void MartianRoom::loadRoom(int roomNumber) {
- loadRoomData(ROOM_TABLE[roomNumber]);
+ loadRoomData(&MMRES.ROOMTBL[roomNumber]._data[0]);
}
void MartianRoom::reloadRoom() {
diff --git a/engines/access/module.mk b/engines/access/module.mk
index f7cf7f2261..cccb603d31 100644
--- a/engines/access/module.mk
+++ b/engines/access/module.mk
@@ -21,6 +21,7 @@ MODULE_OBJS := \
scripts.o \
sound.o \
video.o \
+ video/movie_decoder.o \
amazon/amazon_game.o \
amazon/amazon_logic.o \
amazon/amazon_player.o \
diff --git a/engines/access/resources.cpp b/engines/access/resources.cpp
index 8699a4a82f..096fb15b35 100644
--- a/engines/access/resources.cpp
+++ b/engines/access/resources.cpp
@@ -22,9 +22,140 @@
#include "access/resources.h"
#include "access/access.h"
+#include "access/amazon/amazon_resources.h"
+#include "access/martian/martian_resources.h"
namespace Access {
+Resources *Resources::init(AccessEngine *vm) {
+ if (vm->getGameID() == GType_Amazon)
+ return new Amazon::AmazonResources(vm);
+ else if (vm->getGameID() == GType_MartianMemorandum)
+ return new Martian::MartianResources(vm);
+
+ error("Unknown game");
+}
+
+bool Resources::load(Common::String &errorMessage) {
+ Common::File f;
+ if (!f.open("access.dat")) {
+ errorMessage = "Could not locate required access.dat file";
+ return false;
+ }
+
+ // Check for the magic identifier
+ char buffer[4];
+ f.read(buffer, 4);
+ if (strncmp(buffer, "SVMA", 4)) {
+ errorMessage = "Located access.dat file had invalid contents";
+ return false;
+ }
+
+ // Validate the version number
+ uint expectedVersion = 1;
+ uint version = f.readUint16LE();
+ if (version != expectedVersion) {
+ errorMessage = Common::String::format(
+ "Incorrect version of access.dat found. Expected %d but got %d",
+ expectedVersion, version);
+ return false;
+ }
+
+ // Load in the index
+ uint count = f.readUint16LE();
+ _datIndex.resize(count);
+ for (uint idx = 0; idx < _datIndex.size(); ++idx) {
+ _datIndex[idx]._gameId = f.readByte();
+ _datIndex[idx]._discType = f.readByte();
+ _datIndex[idx]._demoType = f.readByte();
+ _datIndex[idx]._language = (Common::Language)f.readByte();
+ _datIndex[idx]._fileOffset = f.readUint32LE();
+ }
+
+ // Load in the data for the game
+ load(f);
+
+ return true;
+}
+
+void Resources::load(Common::SeekableReadStream &s) {
+ uint count;
+
+ // Get the offset of the data for the game
+ uint entryOffset = findEntry(_vm->getGameID(), _vm->isCD() ? 1 : 0,
+ _vm->isDemo() ? 1 : 0, _vm->getLanguage());
+ s.seek(entryOffset);
+
+ // Load filename list
+ count = s.readUint16LE();
+ FILENAMES.resize(count);
+ for (uint idx = 0; idx < count; ++idx)
+ FILENAMES[idx] = readString(s);
+
+ // Load the character data
+ count = s.readUint16LE();
+ CHARTBL.resize(count);
+ for (uint idx = 0; idx < count; ++idx) {
+ uint count2 = s.readUint16LE();
+ CHARTBL[idx].resize(count2);
+ if (count2 > 0)
+ s.read(&CHARTBL[idx][0], count2);
+ }
+
+ // Load the room data
+ count = s.readUint16LE();
+ ROOMTBL.resize(count);
+ for (uint idx = 0; idx < count; ++idx) {
+ ROOMTBL[idx]._desc = readString(s);
+ ROOMTBL[idx]._travelPos.x = s.readSint16LE();
+ ROOMTBL[idx]._travelPos.y = s.readSint16LE();
+ uint count2 = s.readUint16LE();
+ ROOMTBL[idx]._data.resize(count2);
+ if (count2 > 0)
+ s.read(&ROOMTBL[idx]._data[0], count2);
+ }
+
+ // Load the deaths list
+ count = s.readUint16LE();
+ DEATHS.resize(count);
+ for (uint idx = 0; idx < count; ++idx) {
+ DEATHS[idx]._screenId = s.readByte();
+ DEATHS[idx]._msg = readString(s);
+ }
+
+ // Load in the inventory list
+ count = s.readUint16LE();
+ INVENTORY.resize(count);
+ for (uint idx = 0; idx < count; ++idx) {
+ INVENTORY[idx]._desc = readString(s);
+ for (uint idx2 = 0; idx2 < 4; ++idx2)
+ INVENTORY[idx]._combo[idx2] = s.readSint16LE();
+ }
+}
+
+uint Resources::findEntry(byte gameId, byte discType, byte demoType, Common::Language language) {
+ for (uint idx = 0; idx < _datIndex.size(); ++idx) {
+ DATEntry &de = _datIndex[idx];
+ if (de._gameId == gameId && de._discType == discType &&
+ de._demoType == demoType && de._language == language)
+ return de._fileOffset;
+ }
+
+ error("Could not locate appropriate access.dat entry");
+}
+
+Common::String Resources::readString(Common::SeekableReadStream &s) {
+ Common::String result;
+ char c;
+
+ while ((c = s.readByte()) != 0)
+ result += c;
+
+ return result;
+}
+
+/*------------------------------------------------------------------------*/
+
const byte INITIAL_PALETTE[18 * 3] = {
0x00, 0x00, 0x00,
0xff, 0xff, 0xff,
@@ -49,14 +180,14 @@ const byte INITIAL_PALETTE[18 * 3] = {
const char *const GENERAL_MESSAGES[] = {
"LOOKING THERE REVEALS NOTHING OF INTEREST.", // LOOK_MESSAGE
"THAT DOESN'T OPEN.", // OPEN_MESSAGE
- "THAT WON'T MOVE." // MOVE_MESSAGE
+ "THAT WON'T MOVE.", // MOVE_MESSAGE
"YOU CAN'T TAKE THAT.", // GET_MESSAGE
"THAT DOESN'T SEEM TO WORK.", // USE_MESSAGE
"YOU CAN'T CLIMB THAT.", // GO_MESSAGE
"THERE SEEMS TO BE NO RESPONSE.", // TALK_MESSAGE
"THIS OBJECT REQUIRES NO HINTS", // HELP_MESSAGE
"THIS OBJECT REQUIRES NO HINTS", // HELP_MESSAGE
- "THAT DOESN'T SEEM TO WORK.", // USE_MESSAGE
+ "THAT DOESN'T SEEM TO WORK." // USE_MESSAGE
};
const int INVCOORDS[][4] = {
diff --git a/engines/access/resources.h b/engines/access/resources.h
index 07b8e5ada9..bb5c3f9f61 100644
--- a/engines/access/resources.h
+++ b/engines/access/resources.h
@@ -24,6 +24,11 @@
#define ACCESS_RESOURCES_H
#include "common/scummsys.h"
+#include "common/array.h"
+#include "common/language.h"
+#include "common/rect.h"
+#include "common/str-array.h"
+#include "common/stream.h"
namespace Access {
@@ -33,6 +38,66 @@ extern const char *const GENERAL_MESSAGES[];
extern const int INVCOORDS[][4];
+class AccessEngine;
+
+class Resources {
+ struct DATEntry {
+ byte _gameId;
+ byte _discType;
+ byte _demoType;
+ Common::Language _language;
+ uint _fileOffset;
+ };
+ struct RoomEntry {
+ Common::String _desc;
+ Common::Point _travelPos;
+ Common::Array<byte> _data;
+ };
+ struct DeathEntry {
+ byte _screenId;
+ Common::String _msg;
+ };
+ struct InventoryEntry {
+ Common::String _desc;
+ int _combo[4];
+ };
+protected:
+ AccessEngine *_vm;
+ Common::Array<DATEntry> _datIndex;
+
+ /**
+ * Locate a specified entry in the index and return it's file offset
+ */
+ uint findEntry(byte gameId, byte discType, byte demoType, Common::Language language);
+
+ /**
+ * Read a string in from the passed stream
+ */
+ Common::String readString(Common::SeekableReadStream &s);
+
+ /**
+ * Load data from the access.dat file
+ */
+ virtual void load(Common::SeekableReadStream &s);
+public:
+ Common::StringArray FILENAMES;
+ Common::Array< Common::Array<byte> > CHARTBL;
+ Common::Array<RoomEntry> ROOMTBL;
+ Common::Array<DeathEntry> DEATHS;
+ Common::Array<InventoryEntry> INVENTORY;
+ Common::Array< Common::Array<byte> > CURSORS;
+ Common::String CANT_GET_THERE;
+public:
+ Resources(AccessEngine *vm) : _vm(vm) {}
+ virtual ~Resources() {}
+ static Resources *init(AccessEngine *vm);
+
+ /**
+ * Load the access.dat file
+ */
+ bool load(Common::String &errorMessage);
+};
+
} // End of namespace Access
#endif /* ACCESS_RESOURCES_H */
diff --git a/engines/access/room.cpp b/engines/access/room.cpp
index c91b37c65d..a41de63bf6 100644
--- a/engines/access/room.cpp
+++ b/engines/access/room.cpp
@@ -111,8 +111,7 @@ void Room::takePicture() {
return;
}
- // TODO: simplify the second part of the test when tested
- if ((_vm->_scrollCol < 35) || ((_vm->_scrollRow >= 10) && (_vm->_scrollRow >= 20))){
+ if ((_vm->_scrollCol < 35) || (_vm->_scrollRow >= 20)){
Common::String msg = "THAT ISN'T INTERESTING ENOUGH TO WASTE FILM ON.";
_vm->_scripts->doCmdPrint_v1(msg);
return;
@@ -143,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;
@@ -173,12 +172,14 @@ void Room::doRoom() {
reloadFlag = false;
_vm->_startup = 8;
_function = FN_NONE;
+ _vm->_screen->_fadeIn = false;
while (!_vm->shouldQuit()) {
_vm->_images.clear();
- if (_vm->_startup != -1 && --_vm->_startup == 0) {
+ if (_vm->_screen->_fadeIn) {
_vm->_events->showCursor();
_vm->_screen->fadeIn();
+ _vm->_screen->_fadeIn = false;
}
// Poll for events
@@ -397,6 +398,7 @@ void Room::setWallCodes() {
_vm->_player->_rawXTemp = _vm->_player->_rawPlayer.x;
_vm->_player->_rawYTemp = _vm->_player->_rawPlayer.y;
+ codeWalls();
}
void Room::buildScreen() {
@@ -612,6 +614,7 @@ void Room::handleCommand(int commandId) {
void Room::executeCommand(int commandId) {
EventsManager &events = *_vm->_events;
+ Screen &screen = *_vm->_screen;
_selectCommand = commandId;
if (_vm->getGameID() == GType_MartianMemorandum) {
@@ -698,8 +701,8 @@ void Room::executeCommand(int commandId) {
break;
}
}
- _vm->_screen->saveScreen();
- _vm->_screen->setDisplayScan();
+ screen.saveScreen();
+ screen.setDisplayScan();
// Get the toolbar icons resource
Resource *iconData = _vm->_files->loadFile("ICONS.LZ");
@@ -707,9 +710,13 @@ void Room::executeCommand(int commandId) {
delete iconData;
// Draw the button as selected
- _vm->_screen->plotImage(spr, _selectCommand + 2,
+ screen.plotImage(spr, 0, Common::Point(0, 177));
+ screen.plotImage(spr, 1, Common::Point(143, 177));
+ screen.plotImage(spr, _selectCommand + 2,
Common::Point(_rMouse[_selectCommand][0], (_vm->getGameID() == GType_MartianMemorandum) ? 184 : 176));
+ delete spr;
+
_vm->_screen->restoreScreen();
_vm->_boxSelect = true;
}
@@ -928,16 +935,9 @@ RoomInfo::RoomInfo(const byte *data, int gameType, bool isCD, bool isDemo) {
_roomFlag = stream.readByte();
- if (gameType == GType_Amazon) {
- if (isCD)
- _estIndex = stream.readSint16LE();
- else {
- _estIndex = -1;
- if (!isDemo)
- stream.readSint16LE();
- }
- } else
- _estIndex = -1;
+ _estIndex = -1;
+ if (gameType == GType_Amazon && isCD)
+ _estIndex = stream.readSint16LE();
_musicFile.load(stream);
_scaleH1 = stream.readByte();
diff --git a/engines/access/screen.cpp b/engines/access/screen.cpp
index 41f6194238..2d29ad0718 100644
--- a/engines/access/screen.cpp
+++ b/engines/access/screen.cpp
@@ -62,14 +62,13 @@ Screen::Screen(AccessEngine *vm) : _vm(vm) {
_startCycle = 0;
_cycleStart = 0;
_endCycle = 0;
+ _fadeIn = false;
}
void Screen::clearScreen() {
clearBuffer();
if (_vesaMode)
_vm->_clearSummaryFlag = true;
-
- addDirtyRect(Common::Rect(0, 0, this->w, this->h));
}
void Screen::setDisplayScan() {
@@ -88,22 +87,14 @@ void Screen::setPanel(int num) {
_msVirtualOffset = _virtualOffsetsTable[num];
}
-void Screen::updateScreen() {
- // 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());
+void Screen::update() {
+ if (_vm->_startup >= 0) {
+ if (--_vm->_startup == -1)
+ _fadeIn = true;
+ return;
}
-
- // Signal the physical screen to update
- g_system->updateScreen();
- _dirtyRects.clear();
+ markAllDirty();//****DEBUG****
+ Graphics::Screen::update();
}
void Screen::setInitialPalettte() {
@@ -146,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() {
@@ -181,7 +172,7 @@ void Screen::forceFadeOut() {
int v = *srcP;
if (v) {
repeatFlag = true;
- *srcP = MAX(*srcP - FADE_AMOUNT, 0);
+ *srcP = MAX((int)*srcP - FADE_AMOUNT, 0);
}
}
@@ -262,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);
@@ -273,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(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) {
@@ -342,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);
+ // No implementation needed in ScummVM
}
-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;
- }
- }
- }
-}
-
-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 52485e5c7c..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;
@@ -85,8 +79,14 @@ public:
int _bufferBytesWide;
int _vWindowLinesTall;
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();
@@ -94,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(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);
@@ -113,11 +105,6 @@ public:
void setPanel(int num);
/**
- * Update the underlying screen
- */
- void updateScreen();
-
- /**
* Fade out screen
*/
void forceFadeOut();
diff --git a/engines/access/scripts.cpp b/engines/access/scripts.cpp
index 41dd5cc0d0..38313640f1 100644
--- a/engines/access/scripts.cpp
+++ b/engines/access/scripts.cpp
@@ -164,7 +164,7 @@ void Scripts::charLoop() {
_sequence = 2000;
searchForSequence();
_vm->_images.clear();
- _vm->_buffer2.blitFrom(_vm->_buffer1);
+ _vm->_buffer2.copyBlock(&_vm->_buffer1, Common::Rect(0, 0, _vm->_buffer2.w, _vm->_buffer2.h));
_vm->_newRects.clear();
executeScript();
@@ -536,6 +536,7 @@ void Scripts::cmdDispInv_v1() {
void Scripts::cmdDispInv_v2() {
_vm->_inventory->newDisplayInv();
+ _vm->_events->forceSetCursor(CURSOR_ARROW);
}
void Scripts::cmdSetAbout() {
@@ -689,19 +690,20 @@ void Scripts::cmdDoTravel() {
int idx = _vm->_travelBox->_tempListIdx[boxX];
if (Martian::_byte1EEB5[idx] != _vm->_byte26CB5) {
_vm->_bubbleBox->_bubbleTitle = "_travel";
- _vm->_bubbleBox->printString("YOU CAN'T GET THERE FROM HERE.");
+ _vm->_bubbleBox->printString(_vm->_res->CANT_GET_THERE);
continue;
}
if (_vm->_player->_roomNumber != idx) {
_vm->_player->_roomNumber = idx;
_vm->_room->_function = FN_CLEAR1;
- if (Martian::_travelPos[idx][0] == -1) {
+ if (_vm->_res->ROOMTBL[idx]._travelPos.x == -1) {
+ // For x == -1, the y value is a script Id, not a co-ordinate
_vm->_player->_roomNumber = idx;
_vm->_room->_conFlag = true;
- _vm->_scripts->converse1(Martian::_travelPos[idx][1]);
+ _vm->_scripts->converse1(_vm->_res->ROOMTBL[idx]._travelPos.y);
return;
}
- _vm->_player->_rawPlayer = Common::Point(Martian::_travelPos[idx][0], Martian::_travelPos[idx][1]);
+ _vm->_player->_rawPlayer = _vm->_res->ROOMTBL[idx]._travelPos;
cmdRetPos();
return;
}
@@ -769,6 +771,11 @@ void Scripts::cmdSpecial() {
if (_specialFunction == 1) {
_vm->_screen->restorePalette();
_vm->_room->_function = FN_RELOAD;
+
+ // WORKAROUND: This fixes scene establishment being re-shown
+ // when restoring savegames in rooms which have one
+ if (_vm->getGameID() == GType_Amazon && !_vm->isCD())
+ _vm->_establishTable[p2] = true;
}
}
@@ -998,10 +1005,7 @@ void Scripts::cmdFreeSound() {
} while (!_vm->shouldQuit() && sound.isSFXPlaying());
// Free the sounds
- while (sound._soundTable.size() > 0) {
- delete sound._soundTable[0]._res;
- sound._soundTable.remove_at(0);
- }
+ sound.freeSounds();
}
}
@@ -1033,7 +1037,7 @@ void Scripts::cmdPrintWatch() {
}
void Scripts::cmdDispAbout() {
- _vm->_travelBox->getList(Martian::_askTBL, _vm->_ask);
+ _vm->_travelBox->getList(Martian::ASK_TBL, _vm->_ask);
int btnSelected = 0;
int boxX = _vm->_aboutBox->doBox_v1(_vm->_startAboutItem, _vm->_startAboutBox, btnSelected);
_vm->_startAboutItem = _vm->_boxDataStart;
diff --git a/engines/access/scripts.h b/engines/access/scripts.h
index 07fd6acfb1..4cfedf3b3f 100644
--- a/engines/access/scripts.h
+++ b/engines/access/scripts.h
@@ -39,13 +39,13 @@ typedef void(Scripts::*ScriptMethodPtr)();
class Scripts : public Manager {
private:
- Resource *_resource;
int _specialFunction;
void clearWatch();
void printWatch();
protected:
+ Resource *_resource;
Common::SeekableReadStream *_data;
ScriptMethodPtr COMMAND_LIST[100];
diff --git a/engines/access/sound.cpp b/engines/access/sound.cpp
index 51ffb88f37..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,15 +51,24 @@ 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];
+ delete _queue[0]._stream;
_queue.remove_at(0);
}
}
+bool SoundManager::isSoundQueued(int soundId) const {
+ for (uint idx = 0; idx < _queue.size(); ++idx) {
+ if (_queue[idx]._soundId == soundId)
+ return true;
+ }
+
+ return false;
+}
+
void SoundManager::loadSoundTable(int idx, int fileNum, int subfile, int priority) {
debugC(1, kDebugSound, "loadSoundTable(%d, %d, %d)", idx, fileNum, subfile);
@@ -77,12 +90,15 @@ Resource *SoundManager::loadSound(int fileNum, int subfile) {
void SoundManager::playSound(int soundIndex, bool loop) {
debugC(1, kDebugSound, "playSound(%d, %d)", soundIndex, loop);
+ if (isSoundQueued(soundIndex))
+ // Prevent duplicate copies of a sound from being queued
+ return;
int priority = _soundTable[soundIndex]._priority;
- playSound(_soundTable[soundIndex]._res, priority, loop);
+ playSound(_soundTable[soundIndex]._res, priority, loop, soundIndex);
}
-void SoundManager::playSound(Resource *res, int priority, bool loop) {
+void SoundManager::playSound(Resource *res, int priority, bool loop, int soundIndex) {
debugC(1, kDebugSound, "playSound");
byte *resourceData = res->data();
@@ -109,7 +125,7 @@ void SoundManager::playSound(Resource *res, int priority, bool loop) {
byte internalSampleRate = resourceData[5];
int sampleSize = READ_LE_UINT16(resourceData + 7);
- assert( (sampleSize + 32) == res->_size);
+ assert( (sampleSize + 32) <= res->_size);
int sampleRate = 0;
switch (internalSampleRate) {
@@ -139,34 +155,35 @@ void SoundManager::playSound(Resource *res, int priority, bool loop) {
error("Unknown format");
if (loop) {
- _queue.push_back(new Audio::LoopingAudioStream(audioStream, 0, DisposeAfterUse::NO));
+ _queue.push_back(QueuedSound(new Audio::LoopingAudioStream(audioStream, 0,
+ DisposeAfterUse::NO), soundIndex));
} else {
- _queue.push_back(audioStream);
+ _queue.push_back(QueuedSound(audioStream, soundIndex));
}
- if (!_mixer->isSoundHandleActive(_effectsHandle))
- _mixer->playStream(Audio::Mixer::kSFXSoundType, &_effectsHandle,
- _queue[0], -1, _mixer->kMaxChannelVolume, 0,
+ if (!_mixer->isSoundHandleActive(*_effectsHandle))
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, _effectsHandle,
+ _queue[0]._stream, -1, _mixer->kMaxChannelVolume, 0,
DisposeAfterUse::NO);
}
void SoundManager::checkSoundQueue() {
debugC(5, kDebugSound, "checkSoundQueue");
- if (_queue.empty() || _mixer->isSoundHandleActive(_effectsHandle))
+ if (_queue.empty() || _mixer->isSoundHandleActive(*_effectsHandle))
return;
- delete _queue[0];
+ delete _queue[0]._stream;
_queue.remove_at(0);
- if (_queue.size() && _queue[0])
- _mixer->playStream(Audio::Mixer::kSFXSoundType, &_effectsHandle,
- _queue[0], -1, _mixer->kMaxChannelVolume, 0,
+ if (_queue.size() && _queue[0]._stream)
+ _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) {
@@ -183,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() {
@@ -213,7 +230,7 @@ MusicManager::MusicManager(AccessEngine *vm) : _vm(vm) {
//
switch (musicType) {
case MT_ADLIB: {
- if (_vm->getGameID() == GType_Amazon) {
+ if (_vm->getGameID() == GType_Amazon && !_vm->isDemo()) {
Resource *midiDrvResource = _vm->_files->loadFile(92, 1);
Common::MemoryReadStream *adLibInstrumentStream = new Common::MemoryReadStream(midiDrvResource->data(), midiDrvResource->_size);
diff --git a/engines/access/sound.h b/engines/access/sound.h
index e11a6b9730..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;
@@ -45,15 +47,24 @@ struct SoundEntry {
};
class SoundManager {
+ struct QueuedSound {
+ Audio::AudioStream *_stream;
+ int _soundId;
+
+ QueuedSound() : _stream(nullptr), _soundId(-1) {}
+ QueuedSound(Audio::AudioStream *stream, int soundId) : _stream(stream), _soundId(soundId) {}
+ };
private:
AccessEngine *_vm;
Audio::Mixer *_mixer;
- Audio::SoundHandle _effectsHandle;
- Common::Array<Audio::AudioStream *> _queue;
+ Audio::SoundHandle *_effectsHandle;
+ Common::Array<QueuedSound> _queue;
void clearSounds();
- void playSound(Resource *res, int priority, bool loop);
+ void playSound(Resource *res, int priority, bool loop, int soundIndex = -1);
+
+ bool isSoundQueued(int soundId) const;
public:
Common::Array<SoundEntry> _soundTable;
bool _playingSound;
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
new file mode 100644
index 0000000000..1406e549ad
--- /dev/null
+++ b/engines/access/video/movie_decoder.cpp
@@ -0,0 +1,741 @@
+/* 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/stream.h"
+#include "common/textconsole.h"
+
+#include "audio/audiostream.h"
+#include "audio/decoders/raw.h"
+
+#include "access/access.h"
+#include "access/video/movie_decoder.h"
+
+// for Test-Code
+#include "common/system.h"
+#include "common/events.h"
+#include "common/keyboard.h"
+#include "engines/engine.h"
+#include "engines/util.h"
+#include "graphics/palette.h"
+#include "graphics/pixelformat.h"
+#include "graphics/surface.h"
+
+namespace Access {
+
+AccessVIDMovieDecoder::AccessVIDMovieDecoder()
+ : _stream(0), _videoTrack(0), _audioTrack(0) {
+ _streamSeekOffset = 0;
+ _streamVideoIndex = 0;
+ _streamAudioIndex = 0;
+}
+
+AccessVIDMovieDecoder::~AccessVIDMovieDecoder() {
+ close();
+}
+
+bool AccessVIDMovieDecoder::loadStream(Common::SeekableReadStream *stream) {
+ uint32 videoCodecTag = 0;
+ uint32 videoHeight = 0;
+ uint32 videoWidth = 0;
+ uint16 regularDelay = 0;
+ uint32 audioSampleRate = 0;
+
+ close();
+
+ _stream = stream;
+ _streamSeekOffset = 15; // offset of first chunk
+ _streamVideoIndex = 0;
+ _streamAudioIndex = 0;
+
+ // read header
+ // ID [dword] "VID"
+ // ?? [byte]
+ // ?? [word]
+ // width [word]
+ // height [word]
+ // regular delay between frames (60 per second) [word]
+ // ?? [word]
+
+ videoCodecTag = _stream->readUint32BE();
+ if (videoCodecTag != MKTAG('V','I','D',0x00)) {
+ warning("AccessVIDMoviePlay: bad codec tag, not a video file?");
+ close();
+ return false;
+ }
+ _stream->skip(3);
+ videoWidth = _stream->readUint16LE();
+ videoHeight = _stream->readUint16LE();
+ regularDelay = _stream->readUint16LE();
+ _stream->skip(2);
+
+ if (!regularDelay) {
+ warning("AccessVIDMoviePlay: delay between frames is zero?");
+ close();
+ return false;
+ }
+
+ // create video track
+ _videoTrack = new StreamVideoTrack(videoWidth, videoHeight, regularDelay);
+ addTrack(_videoTrack);
+
+ //warning("width %d, height %d", videoWidth, videoHeight);
+
+ // Look through the first few packets
+ static const int maxPacketCheckCount = 10;
+
+ for (int i = 0; i < maxPacketCheckCount; i++) {
+ byte chunkId = _stream->readByte();
+
+ // Bail out if done
+ if (_stream->eos())
+ break;
+
+ // Bail also in case end of file chunk was found
+ if (chunkId == kVIDMovieChunkId_EndOfFile)
+ break;
+
+ uint32 chunkStartOffset = _stream->pos();
+ //warning("data chunk at %x", chunkStartOffset);
+
+ switch (chunkId) {
+ case kVIDMovieChunkId_FullFrame:
+ case kVIDMovieChunkId_FullFrameCompressed:
+ case kVIDMovieChunkId_PartialFrameCompressed:
+ case kVIDMovieChunkId_FullFrameCompressedFill: {
+ if (!_videoTrack->skipOverFrame(_stream, chunkId)) {
+ close();
+ return false;
+ }
+ break;
+ }
+
+ case kVIDMovieChunkId_Palette: {
+ if (!_videoTrack->skipOverPalette(_stream)) {
+ close();
+ return false;
+ }
+ break;
+ }
+
+ case kVIDMovieChunkId_AudioFirstChunk:
+ case kVIDMovieChunkId_Audio: {
+ // sync [word]
+ // sampling rate [byte]
+ // size of audio data [word]
+ // sample data [] (mono, 8-bit, unsigned)
+ //
+ // Only first chunk has sync + sampling rate
+ if (chunkId == kVIDMovieChunkId_AudioFirstChunk) {
+ byte soundblasterRate;
+
+ _stream->skip(2); // skip over sync
+ soundblasterRate = _stream->readByte();
+ audioSampleRate = 1000000 / (256 - soundblasterRate);
+
+ _audioTrack = new StreamAudioTrack(audioSampleRate);
+ addTrack(_audioTrack);
+
+ _stream->seek(chunkStartOffset); // seek back
+ }
+
+ if (!_audioTrack) {
+ warning("AccessVIDMoviePlay: regular audio chunk, before audio chunk w/ header");
+ close();
+ return false;
+ }
+ if (!_audioTrack->skipOverAudio(_stream, chunkId)) {
+ close();
+ return false;
+ }
+ break;
+ }
+
+ default:
+ warning("AccessVIDMoviePlay: Unknown chunk-id '%x' inside VID movie", chunkId);
+ close();
+ return false;
+ }
+
+ // Remember this chunk inside our cache
+ IndexCacheEntry indexCacheEntry;
+
+ indexCacheEntry.chunkId = chunkId;
+ indexCacheEntry.offset = chunkStartOffset;
+
+ _indexCacheTable.push_back(indexCacheEntry);
+
+ // Got an audio chunk now? -> exit b/c we are done
+ if (audioSampleRate)
+ break;
+ }
+
+ // Remember offset of latest not-indexed-yet chunk
+ _streamSeekOffset = _stream->pos();
+
+ // If sample rate was found, create an audio track
+ if (audioSampleRate) {
+ _audioTrack = new StreamAudioTrack(audioSampleRate);
+ addTrack(_audioTrack);
+ }
+
+ // Rewind back to the beginning right to the first chunk
+ _stream->seek(15);
+
+ return true;
+}
+
+void AccessVIDMovieDecoder::close() {
+ Video::VideoDecoder::close();
+
+ delete _stream; _stream = 0;
+ _videoTrack = 0;
+
+ _indexCacheTable.clear();
+}
+
+// We try to at least decode 1 frame
+// and also try to get at least 0.5 seconds of audio queued up
+void AccessVIDMovieDecoder::readNextPacket() {
+ uint32 currentMovieTime = getTime();
+ uint32 wantedAudioQueued = currentMovieTime + 500; // always try to be 0.500 seconds in front of movie time
+
+ uint32 streamIndex = 0;
+ IndexCacheEntry indexEntry;
+ bool currentlySeeking = false;
+
+ bool videoDone = false;
+ bool audioDone = false;
+
+ // Seek to smallest stream offset
+ if ((_streamVideoIndex <= _streamAudioIndex) || (!_audioTrack)) {
+ streamIndex = _streamVideoIndex;
+ } else {
+ streamIndex = _streamAudioIndex;
+ }
+
+ if (_audioTrack) {
+ if (wantedAudioQueued <= _audioTrack->getTotalAudioQueued()) {
+ // already got enough audio queued up
+ audioDone = true;
+ }
+ } else {
+ // no audio track, audio is always done
+ audioDone = true;
+ }
+
+ while (1) {
+ // Check, if stream-index is already cached
+ if (streamIndex < _indexCacheTable.size()) {
+ indexEntry.chunkId = _indexCacheTable[streamIndex].chunkId;
+ indexEntry.offset = _indexCacheTable[streamIndex].offset;
+ currentlySeeking = false;
+
+ } else {
+ // read from file
+ _stream->seek(_streamSeekOffset);
+ indexEntry.chunkId = _stream->readByte();
+ indexEntry.offset = _stream->pos();
+ currentlySeeking = true;
+
+ // and store that as well
+ _indexCacheTable.push_back(indexEntry);
+ }
+
+ // end of stream -> exit
+ if (_stream->eos())
+ break;
+
+ // end of file chunk -> exit
+ if (indexEntry.chunkId == kVIDMovieChunkId_EndOfFile)
+ break;
+
+// warning("chunk %x", indexEntry.chunkId);
+
+ switch (indexEntry.chunkId) {
+ case kVIDMovieChunkId_FullFrame:
+ case kVIDMovieChunkId_FullFrameCompressed:
+ case kVIDMovieChunkId_PartialFrameCompressed:
+ case kVIDMovieChunkId_FullFrameCompressedFill: {
+ if ((_streamVideoIndex <= streamIndex) && (!videoDone)) {
+ // We are at an index, that is still relevant for video decoding
+ // and we are not done with video yet
+ if (!currentlySeeking) {
+ // seek to stream position in case we used the cache
+ _stream->seek(indexEntry.offset);
+ }
+ //warning("video decode chunk %x at %lx", indexEntry.chunkId, _stream->pos());
+ _videoTrack->decodeFrame(_stream, indexEntry.chunkId);
+ videoDone = true;
+ _streamVideoIndex = streamIndex + 1;
+ } else {
+ if (currentlySeeking) {
+ // currently seeking, so we have to skip the frame bytes manually
+ _videoTrack->skipOverFrame(_stream, indexEntry.chunkId);
+ }
+ }
+ break;
+ }
+
+ case kVIDMovieChunkId_Palette: {
+ if ((_streamVideoIndex <= streamIndex) && (!videoDone)) {
+ // We are at an index, that is still relevant for video decoding
+ // and we are not done with video yet
+ if (!currentlySeeking) {
+ // seek to stream position in case we used the cache
+ _stream->seek(indexEntry.offset);
+ }
+ _videoTrack->decodePalette(_stream);
+ _streamVideoIndex = streamIndex + 1;
+ } else {
+ if (currentlySeeking) {
+ // currently seeking, so we have to skip the frame bytes manually
+ _videoTrack->skipOverPalette(_stream);
+ }
+ }
+ break;
+ }
+
+ case kVIDMovieChunkId_AudioFirstChunk:
+ case kVIDMovieChunkId_Audio: {
+ if ((_streamAudioIndex <= streamIndex) && (!audioDone)) {
+ // We are at an index that is still relevant for audio decoding
+ if (!currentlySeeking) {
+ // seek to stream position in case we used the cache
+ _stream->seek(indexEntry.offset);
+ }
+ _audioTrack->queueAudio(_stream, indexEntry.chunkId);
+ _streamAudioIndex = streamIndex + 1;
+
+ if (wantedAudioQueued <= _audioTrack->getTotalAudioQueued()) {
+ // Got enough audio
+ audioDone = true;
+ }
+ } else {
+ if (!_audioTrack) {
+ error("AccessVIDMoviePlay: audio chunks found without audio track active");
+ }
+ if (currentlySeeking) {
+ // currently seeking, so we have to skip the audio bytes manually
+ _audioTrack->skipOverAudio(_stream, indexEntry.chunkId);
+ }
+ }
+ break;
+ }
+
+ default:
+ error("AccessVIDMoviePlay: Unknown chunk-id '%x' inside VID movie", indexEntry.chunkId);
+ }
+
+ if (currentlySeeking) {
+ // remember currently stream offset in case we are seeking
+ _streamSeekOffset = _stream->pos();
+ }
+
+ // go to next index
+ streamIndex++;
+
+ if ((videoDone) && (audioDone)) {
+ return;
+ }
+ }
+
+ if (!videoDone) {
+ // no more video frames? set end of video track
+ _videoTrack->setEndOfTrack();
+ }
+}
+
+AccessVIDMovieDecoder::StreamVideoTrack::StreamVideoTrack(uint32 width, uint32 height, uint16 regularFrameDelay) {
+ _width = width;
+ _height = height;
+ _regularFrameDelay = regularFrameDelay;
+ _curFrame = -1;
+ _nextFrameStartTime = 0;
+ _endOfTrack = false;
+ _dirtyPalette = false;
+
+ memset(&_palette, 0, sizeof(_palette));
+
+ _surface = new Graphics::Surface();
+ _surface->create(_width, _height, Graphics::PixelFormat::createFormatCLUT8());
+}
+
+AccessVIDMovieDecoder::StreamVideoTrack::~StreamVideoTrack() {
+ delete _surface;
+}
+
+bool AccessVIDMovieDecoder::StreamVideoTrack::endOfTrack() const {
+ return _endOfTrack;
+}
+
+Graphics::PixelFormat AccessVIDMovieDecoder::StreamVideoTrack::getPixelFormat() const {
+ return _surface->format;
+}
+
+void AccessVIDMovieDecoder::StreamVideoTrack::decodeFrame(Common::SeekableReadStream *stream, byte chunkId) {
+ byte *framePixelsPtr = (byte *)_surface->getPixels();
+ byte *pixelsPtr = framePixelsPtr;
+ byte rleByte = 0;
+ uint16 additionalDelay = 0;
+ int32 expectedPixels = 0;
+
+ switch (chunkId) {
+ case kVIDMovieChunkId_FullFrame: {
+ // Full frame is:
+ // data [width * height]
+ additionalDelay = stream->readUint16LE();
+ stream->read(framePixelsPtr, _width * _height);
+ break;
+ }
+
+ case kVIDMovieChunkId_FullFrameCompressed:
+ case kVIDMovieChunkId_PartialFrameCompressed: {
+ // Skip manually over compressed data
+ // Full frame compressed is:
+ // additional delay [word]
+ // REPEAT:
+ // RLE [byte]
+ // RLE upper bit set: skip over RLE & 0x7F pixels
+ // RLE upper bit not set: draw RLE amount of pixels (those pixels follow right after RLE byte)
+ //
+ // Partial frame compressed is:
+ // sync [word]
+ // horizontal start position [word]
+ // REPEAT:
+ // see full frame compressed
+ uint16 horizontalStartPosition = 0;
+
+ additionalDelay = stream->readUint16LE();
+
+ if (chunkId == kVIDMovieChunkId_PartialFrameCompressed) {
+ horizontalStartPosition = stream->readUint16LE();
+ if (horizontalStartPosition >= _height) {
+ error("AccessVIDMoviePlay: starting position larger than height during partial frame compressed, data corrupt?");
+ return;
+ }
+ }
+
+ expectedPixels = _width * (_height - horizontalStartPosition);
+
+ // adjust frame destination pointer
+ pixelsPtr += (horizontalStartPosition * _width);
+
+ while (expectedPixels >= 0) {
+ rleByte = stream->readByte();
+ if (!rleByte) // NUL means end of stream
+ break;
+
+ if (rleByte & 0x80) {
+ rleByte = rleByte & 0x7F;
+ expectedPixels -= rleByte;
+ } else {
+ // skip over pixels
+ expectedPixels -= rleByte;
+ stream->read(pixelsPtr, rleByte); // read pixel data into frame
+ }
+ pixelsPtr += rleByte;
+ }
+ // expectedPixels may be positive here in case stream got terminated with a NUL
+ if (expectedPixels < 0) {
+ error("AccessVIDMoviePlay: pixel count mismatch during full/partial frame compressed, data corrupt?");
+ }
+ break;
+ }
+
+ case kVIDMovieChunkId_FullFrameCompressedFill: {
+ // Full frame compressed fill is:
+ // additional delay [word]
+ // REPEAT:
+ // RLE [byte]
+ // RLE upper bit set: draw RLE amount (& 0x7F) of pixels with specified color (color byte follows after RLE byte)
+ // RLE upper bit not set: draw RLE amount of pixels (those pixels follow right after RLE byte)
+ additionalDelay = stream->readUint16LE();
+ expectedPixels = _width * _height;
+
+ while (expectedPixels > 0) {
+ rleByte = stream->readByte();
+
+ if (rleByte & 0x80) {
+ rleByte = rleByte & 0x7F;
+ expectedPixels -= rleByte;
+
+ byte fillColor = stream->readByte();
+ memset(pixelsPtr, fillColor, rleByte);
+ } else {
+ // skip over pixels
+ expectedPixels -= rleByte;
+ stream->read(pixelsPtr, rleByte); // read pixel data into frame
+ }
+ pixelsPtr += rleByte;
+ }
+ if (expectedPixels < 0) {
+ error("AccessVIDMoviePlay: pixel count mismatch during full frame compressed fill, data corrupt?");
+ }
+ break;
+ }
+ default:
+ assert(0);
+ break;
+ }
+
+ _curFrame++;
+
+ // TODO: not sure, if additionalDelay is supposed to affect the follow-up frame or the current frame
+ // the videos, that I found, don't have it set
+ uint32 currentFrameStartTime = getNextFrameStartTime();
+ uint32 nextFrameStartTime = (_regularFrameDelay * _curFrame) * 1000 / 60;
+ if (additionalDelay) {
+ nextFrameStartTime += additionalDelay * 1000 / 60;
+ }
+ assert(currentFrameStartTime <= nextFrameStartTime);
+ setNextFrameStartTime(nextFrameStartTime);
+}
+
+bool AccessVIDMovieDecoder::StreamVideoTrack::skipOverFrame(Common::SeekableReadStream *stream, byte chunkId) {
+ byte rleByte = 0;
+ int32 expectedPixels = 0;
+
+ switch (chunkId) {
+ case kVIDMovieChunkId_FullFrame: {
+ // Full frame is:
+ // additional delay [word]
+ // data [width * height]
+ stream->skip(2);
+ stream->skip(_width * _height);
+ break;
+ }
+
+ case kVIDMovieChunkId_FullFrameCompressed:
+ case kVIDMovieChunkId_PartialFrameCompressed: {
+ // Skip manually over compressed data
+ // Full frame compressed is:
+ // additional delay [word]
+ // REPEAT:
+ // RLE [byte]
+ // RLE upper bit set: skip over RLE & 0x7F pixels
+ // RLE upper bit not set: draw RLE amount of pixels (those pixels follow right after RLE byte)
+ //
+ // Partial frame compressed is:
+ // sync [word]
+ // horizontal start position [word]
+ // REPEAT:
+ // see full frame compressed
+ uint16 horizontalStartPosition = 0;
+
+ stream->skip(2);
+
+ if (chunkId == kVIDMovieChunkId_PartialFrameCompressed) {
+ horizontalStartPosition = stream->readUint16LE();
+ if (horizontalStartPosition >= _height) {
+ warning("AccessVIDMoviePlay: starting position larger than height during partial frame compressed, data corrupt?");
+ return false;
+ }
+ }
+
+ expectedPixels = _width * (_height - horizontalStartPosition);
+
+ while (expectedPixels >= 0) {
+ rleByte = stream->readByte();
+ if (!rleByte) // NUL means end of stream
+ break;
+
+ if (rleByte & 0x80) {
+ expectedPixels -= rleByte & 0x7F;
+ } else {
+ // skip over pixels
+ expectedPixels -= rleByte;
+ stream->skip(rleByte); // skip over pixel data
+ }
+ }
+ // expectedPixels may be positive here in case stream got terminated with a NUL
+ if (expectedPixels < 0) {
+ warning("AccessVIDMoviePlay: pixel count mismatch during full/partial frame compressed, data corrupt?");
+ return false;
+ }
+ break;
+ }
+
+ case kVIDMovieChunkId_FullFrameCompressedFill: {
+ // Full frame compressed fill is:
+ // additional delay [word]
+ // REPEAT:
+ // RLE [byte]
+ // RLE upper bit set: draw RLE amount (& 0x7F) of pixels with specified color (color byte follows after RLE byte)
+ // RLE upper bit not set: draw RLE amount of pixels (those pixels follow right after RLE byte)
+ stream->skip(2);
+ expectedPixels = _width * _height;
+
+ while (expectedPixels > 0) {
+ rleByte = stream->readByte();
+
+ if (rleByte & 0x80) {
+ expectedPixels -= rleByte & 0x7F;
+ stream->skip(1);
+ } else {
+ // skip over pixels
+ expectedPixels -= rleByte;
+ stream->skip(rleByte); // skip over pixel data
+ }
+ }
+ if (expectedPixels < 0) {
+ warning("AccessVIDMoviePlay: pixel count mismatch during full frame compressed fill, data corrupt?");
+ return false;
+ }
+ break;
+ }
+ default:
+ assert(0);
+ break;
+ }
+ return true;
+}
+
+bool AccessVIDMovieDecoder::StreamVideoTrack::skipOverPalette(Common::SeekableReadStream *stream) {
+ stream->skip(0x300); // 3 bytes per color, 256 colors
+ return true;
+}
+
+void AccessVIDMovieDecoder::StreamVideoTrack::decodePalette(Common::SeekableReadStream *stream) {
+ byte red, green, blue;
+ assert(stream);
+
+ // VID files use a 6-bit palette and not a 8-bit one, we change it to 8-bit
+ for (uint16 curColor = 0; curColor < 256; curColor++) {
+ red = stream->readByte() & 0x3F;
+ green = stream->readByte() & 0x3F;
+ blue = stream->readByte() & 0x3F;
+ _palette[curColor * 3] = (red << 2) | (red >> 4);
+ _palette[curColor * 3 + 1] = (green << 2) | (green >> 4);
+ _palette[curColor * 3 + 2] = (blue << 2) | (blue >> 4);
+ }
+
+ _dirtyPalette = true;
+}
+
+const byte *AccessVIDMovieDecoder::StreamVideoTrack::getPalette() const {
+ _dirtyPalette = false;
+ return _palette;
+}
+
+bool AccessVIDMovieDecoder::StreamVideoTrack::hasDirtyPalette() const {
+ return _dirtyPalette;
+}
+
+AccessVIDMovieDecoder::StreamAudioTrack::StreamAudioTrack(uint32 sampleRate) {
+ _totalAudioQueued = 0; // currently 0 milliseconds queued
+
+ _sampleRate = sampleRate;
+ _stereo = false; // always mono
+
+ _audioStream = Audio::makeQueuingAudioStream(sampleRate, _stereo);
+}
+
+AccessVIDMovieDecoder::StreamAudioTrack::~StreamAudioTrack() {
+ delete _audioStream;
+}
+
+void AccessVIDMovieDecoder::StreamAudioTrack::queueAudio(Common::SeekableReadStream *stream, byte chunkId) {
+ Common::SeekableReadStream *rawAudioStream = 0;
+ Audio::RewindableAudioStream *audioStream = 0;
+ uint32 audioLengthMSecs = 0;
+
+ if (chunkId == kVIDMovieChunkId_AudioFirstChunk) {
+ stream->skip(3); // skip over additional delay + sample rate
+ }
+
+ uint32 audioSize = stream->readUint16LE();
+
+ // Read the specified chunk into memory
+ rawAudioStream = stream->readStream(audioSize);
+ audioLengthMSecs = audioSize * 1000 / _sampleRate; // 1 byte == 1 8-bit sample
+
+ audioStream = Audio::makeRawStream(rawAudioStream, _sampleRate, Audio::FLAG_UNSIGNED | Audio::FLAG_LITTLE_ENDIAN, DisposeAfterUse::YES);
+ if (audioStream) {
+ _totalAudioQueued += audioLengthMSecs;
+ _audioStream->queueAudioStream(audioStream, DisposeAfterUse::YES);
+ } else {
+ // in case there was an error
+ delete rawAudioStream;
+ }
+}
+
+bool AccessVIDMovieDecoder::StreamAudioTrack::skipOverAudio(Common::SeekableReadStream *stream, byte chunkId) {
+ if (chunkId == kVIDMovieChunkId_AudioFirstChunk) {
+ stream->skip(3); // skip over additional delay + sample rate
+ }
+ uint32 audioSize = stream->readUint16LE();
+ stream->skip(audioSize);
+ return true;
+}
+
+Audio::AudioStream *AccessVIDMovieDecoder::StreamAudioTrack::getAudioStream() const {
+ return _audioStream;
+}
+
+bool AccessEngine::playMovie(const Common::String &filename, const Common::Point &pos) {
+ AccessVIDMovieDecoder *videoDecoder = new AccessVIDMovieDecoder();
+
+ Common::Point framePos(pos.x, pos.y);
+
+ if (!videoDecoder->loadFile(filename)) {
+ warning("AccessVIDMoviePlay: could not open '%s'", filename.c_str());
+ return false;
+ }
+
+ bool skipVideo = false;
+
+ _events->clearEvents();
+ videoDecoder->start();
+
+ while (!shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) {
+ if (videoDecoder->needsUpdate()) {
+ const Graphics::Surface *frame = videoDecoder->decodeNextFrame();
+
+ if (frame) {
+ _screen->blitFrom(*frame);
+
+ if (videoDecoder->hasDirtyPalette()) {
+ const byte *palette = videoDecoder->getPalette();
+ g_system->getPaletteManager()->setPalette(palette, 0, 256);
+ }
+
+ _screen->update();
+ }
+ }
+
+ _events->pollEventsAndWait();
+
+ Common::KeyState keyState;
+ if (_events->getKey(keyState)) {
+ if (keyState.keycode == Common::KEYCODE_ESCAPE)
+ skipVideo = true;
+ }
+ }
+
+ videoDecoder->close();
+ delete videoDecoder;
+
+ return !skipVideo;
+}
+
+} // End of namespace Access
diff --git a/engines/access/video/movie_decoder.h b/engines/access/video/movie_decoder.h
new file mode 100644
index 0000000000..8b5d94836b
--- /dev/null
+++ b/engines/access/video/movie_decoder.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 ACCESS_VIDEO_MOVIE_DECODER_H
+#define ACCESS_VIDEO_MOVIE_DECODER_H
+
+#include "video/video_decoder.h"
+#include "audio/audiostream.h"
+
+namespace Common {
+class SeekableReadStream;
+}
+
+namespace Image {
+class Codec;
+}
+
+namespace Access {
+
+enum kDebugLevels {
+ kVIDMovieChunkId_FullFrame = 0x00,
+ kVIDMovieChunkId_FullFrameCompressed = 0x01,
+ kVIDMovieChunkId_Palette = 0x02,
+ kVIDMovieChunkId_FullFrameCompressedFill = 0x03,
+ kVIDMovieChunkId_PartialFrameCompressed = 0x04,
+ kVIDMovieChunkId_EndOfFile = 0x14,
+ kVIDMovieChunkId_AudioFirstChunk = 0x7C,
+ kVIDMovieChunkId_Audio = 0x7D
+};
+
+// This video format is used in at least the following Access engine games:
+// - Noctropolis
+// - Synnergist
+
+class AccessVIDMovieDecoder : public Video::VideoDecoder {
+public:
+ AccessVIDMovieDecoder();
+ ~AccessVIDMovieDecoder();
+
+ bool loadStream(Common::SeekableReadStream *stream);
+ void close();
+
+protected:
+ void readNextPacket();
+
+private:
+ bool streamSkipFullFrameCompressedFill();
+
+private:
+ int32 _streamSeekOffset; /* current stream offset, pointing to not-yet-indexed stream position */
+ uint32 _streamVideoIndex; /* current stream index for video decoding */
+ uint32 _streamAudioIndex; /* current stream index for audio decoding */
+
+ struct IndexCacheEntry {
+ byte chunkId;
+ int32 offset;
+ };
+
+ Common::Array<IndexCacheEntry> _indexCacheTable;
+
+private:
+ class StreamVideoTrack : public VideoTrack {
+ public:
+ StreamVideoTrack(uint32 width, uint32 height, uint16 regularFrameDelay);
+ ~StreamVideoTrack();
+
+ bool endOfTrack() const;
+
+ uint16 getWidth() const { return _width; }
+ uint16 getHeight() const { return _height; }
+ Graphics::PixelFormat getPixelFormat() const;
+ int getCurFrame() const { return _curFrame; }
+ void setNextFrameStartTime(uint32 nextFrameStartTime) { _nextFrameStartTime = nextFrameStartTime; }
+ uint32 getNextFrameStartTime() const { return _nextFrameStartTime; }
+ const Graphics::Surface *decodeNextFrame() { return _surface; }
+
+ const byte *getPalette() const;
+ bool hasDirtyPalette() const;
+
+ void decodePalette(Common::SeekableReadStream *stream);
+ void decodeFrame(Common::SeekableReadStream *stream, byte chunkId);
+ bool skipOverFrame(Common::SeekableReadStream *stream, byte chunkId);
+ bool skipOverPalette(Common::SeekableReadStream *stream);
+
+ void setEndOfTrack() { _endOfTrack = true; }
+
+ private:
+ Graphics::Surface *_surface;
+
+ int _curFrame;
+ uint32 _nextFrameStartTime;
+
+ byte _palette[3 * 256];
+ mutable bool _dirtyPalette;
+ uint16 _width, _height;
+
+ uint16 _regularFrameDelay; // delay between frames (1 = 1/60 of a second)
+ bool _endOfTrack;
+ };
+
+ class StreamAudioTrack : public AudioTrack {
+ public:
+ StreamAudioTrack(uint32 sampleRate);
+ ~StreamAudioTrack();
+
+ void queueAudio(Common::SeekableReadStream *stream, byte chunkId);
+ bool skipOverAudio(Common::SeekableReadStream *stream, byte chunkId);
+
+ protected:
+ Audio::AudioStream *getAudioStream() const;
+
+ private:
+ Audio::QueuingAudioStream *_audioStream;
+ uint32 _totalAudioQueued; /* total amount of milliseconds of audio, that we queued up already */
+
+ public:
+ uint32 getTotalAudioQueued() const { return _totalAudioQueued; }
+
+ private:
+ int16 decodeSample(uint8 dataNibble);
+
+ uint16 _sampleRate;
+ bool _stereo;
+ };
+
+ Common::SeekableReadStream *_stream;
+ StreamVideoTrack *_videoTrack;
+ StreamAudioTrack *_audioTrack;
+};
+
+} // End of namespace Access
+
+#endif
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/engines/sci/graphics/paint.h b/engines/adl/speaker.h
index b2277131d5..31aaac32d2 100644
--- a/engines/sci/graphics/paint.h
+++ b/engines/adl/speaker.h
@@ -20,20 +20,30 @@
*
*/
-#ifndef SCI_GRAPHICS_PAINT_H
-#define SCI_GRAPHICS_PAINT_H
+#ifndef ADL_SPEAKER_H
+#define ADL_SPEAKER_H
-namespace Sci {
+#include "common/types.h"
-class GfxPaint {
+#include "audio/mixer.h"
+
+namespace Audio {
+class AudioStream;
+}
+
+namespace Adl {
+
+class Speaker {
public:
- GfxPaint();
- virtual ~GfxPaint();
+ Speaker();
+ ~Speaker();
+
+ void bell(uint count);
- 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);
+private:
+ byte *_bell, *_silence;
};
-} // End of namespace Sci
+} // 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 2b5d7137bc..60c8d1f3ef 100644
--- a/engines/agi/agi.cpp
+++ b/engines/agi/agi.cpp
@@ -21,7 +21,6 @@
*/
#include "common/md5.h"
-#include "common/events.h"
#include "common/file.h"
#include "common/memstream.h"
#include "common/savefile.h"
@@ -38,13 +37,17 @@
#include "graphics/cursorman.h"
#include "audio/mididrv.h"
-#include "audio/mixer.h"
#include "agi/agi.h"
+#include "agi/font.h"
#include "agi/graphics.h"
+#include "agi/inv.h"
#include "agi/sprite.h"
+#include "agi/text.h"
#include "agi/keyboard.h"
#include "agi/menu.h"
+#include "agi/systemui.h"
+#include "agi/words.h"
#include "gui/predictivedialog.h"
@@ -54,274 +57,22 @@ void AgiEngine::allowSynthetic(bool allow) {
_allowSynthetic = allow;
}
-void AgiEngine::processEvents() {
- Common::Event event;
- int key = 0;
-
- while (_eventMan->pollEvent(event)) {
- switch (event.type) {
- case Common::EVENT_PREDICTIVE_DIALOG: {
- GUI::PredictiveDialog _predictiveDialog;
- _predictiveDialog.runModal();
- strcpy(_predictiveResult, _predictiveDialog.getResult());
- if (strcmp(_predictiveResult, "")) {
- if (_game.inputMode == INPUT_NORMAL) {
- strcpy((char *)_game.inputBuffer, _predictiveResult);
- handleKeys(KEY_ENTER);
- } else if (_game.inputMode == INPUT_GETSTRING) {
- strcpy(_game.strings[_stringdata.str], _predictiveResult);
- newInputMode(INPUT_NORMAL);
- _gfx->printCharacter(_stringdata.x + strlen(_game.strings[_stringdata.str]) + 1,
- _stringdata.y, ' ', _game.colorFg, _game.colorBg);
- } else if (_game.inputMode == INPUT_NONE) {
- for (int n = 0; _predictiveResult[n]; n++)
- keyEnqueue(_predictiveResult[n]);
- }
- }
- /*
- if (predictiveDialog()) {
- if (_game.inputMode == INPUT_NORMAL) {
- strcpy((char *)_game.inputBuffer, _predictiveResult);
- handleKeys(KEY_ENTER);
- } else if (_game.inputMode == INPUT_GETSTRING) {
- strcpy(_game.strings[_stringdata.str], _predictiveResult);
- newInputMode(INPUT_NORMAL);
- _gfx->printCharacter(_stringdata.x + strlen(_game.strings[_stringdata.str]) + 1,
- _stringdata.y, ' ', _game.colorFg, _game.colorBg);
- } else if (_game.inputMode == INPUT_NONE) {
- for (int n = 0; _predictiveResult[n]; n++)
- keyEnqueue(_predictiveResult[n]);
- }
- }
- */
- }
- break;
- case Common::EVENT_LBUTTONDOWN:
- if (_game.mouseEnabled) {
- key = BUTTON_LEFT;
- _mouse.button = kAgiMouseButtonLeft;
- keyEnqueue(key);
- _mouse.x = event.mouse.x;
- _mouse.y = event.mouse.y;
- }
- break;
- case Common::EVENT_RBUTTONDOWN:
- if (_game.mouseEnabled) {
- key = BUTTON_RIGHT;
- _mouse.button = kAgiMouseButtonRight;
- keyEnqueue(key);
- _mouse.x = event.mouse.x;
- _mouse.y = event.mouse.y;
- }
- break;
- case Common::EVENT_WHEELUP:
- if (_game.mouseEnabled) {
- key = WHEEL_UP;
- keyEnqueue(key);
- }
- break;
- case Common::EVENT_WHEELDOWN:
- if (_game.mouseEnabled) {
- key = WHEEL_DOWN;
- keyEnqueue(key);
- }
- break;
- case Common::EVENT_MOUSEMOVE:
- if (_game.mouseEnabled) {
- _mouse.x = event.mouse.x;
- _mouse.y = event.mouse.y;
-
- if (!_game.mouseFence.isEmpty()) {
- if (_mouse.x < _game.mouseFence.left)
- _mouse.x = _game.mouseFence.left;
- if (_mouse.x > _game.mouseFence.right)
- _mouse.x = _game.mouseFence.right;
- if (_mouse.y < _game.mouseFence.top)
- _mouse.y = _game.mouseFence.top;
- if (_mouse.y > _game.mouseFence.bottom)
- _mouse.y = _game.mouseFence.bottom;
-
- g_system->warpMouse(_mouse.x, _mouse.y);
- }
- }
-
- break;
- case Common::EVENT_LBUTTONUP:
- case Common::EVENT_RBUTTONUP:
- if (_game.mouseEnabled) {
- _mouse.button = kAgiMouseButtonUp;
- _mouse.x = event.mouse.x;
- _mouse.y = event.mouse.y;
- }
- break;
- case Common::EVENT_KEYDOWN:
- if (event.kbd.hasFlags(Common::KBD_CTRL) && event.kbd.keycode == Common::KEYCODE_d) {
- _console->attach();
- break;
- }
-
- switch (key = event.kbd.keycode) {
- case Common::KEYCODE_LEFT:
- case Common::KEYCODE_KP4:
- if (_allowSynthetic || !event.synthetic)
- key = KEY_LEFT;
- break;
- case Common::KEYCODE_RIGHT:
- case Common::KEYCODE_KP6:
- if (_allowSynthetic || !event.synthetic)
- key = KEY_RIGHT;
- break;
- case Common::KEYCODE_UP:
- case Common::KEYCODE_KP8:
- if (_allowSynthetic || !event.synthetic)
- key = KEY_UP;
- break;
- case Common::KEYCODE_DOWN:
- case Common::KEYCODE_KP2:
- if (_allowSynthetic || !event.synthetic)
- key = KEY_DOWN;
- break;
- case Common::KEYCODE_PAGEUP:
- case Common::KEYCODE_KP9:
- if (_allowSynthetic || !event.synthetic)
- key = KEY_UP_RIGHT;
- break;
- case Common::KEYCODE_PAGEDOWN:
- case Common::KEYCODE_KP3:
- if (_allowSynthetic || !event.synthetic)
- key = KEY_DOWN_RIGHT;
- break;
- case Common::KEYCODE_HOME:
- case Common::KEYCODE_KP7:
- if (_allowSynthetic || !event.synthetic)
- key = KEY_UP_LEFT;
- break;
- case Common::KEYCODE_END:
- case Common::KEYCODE_KP1:
- if (_allowSynthetic || !event.synthetic)
- key = KEY_DOWN_LEFT;
- break;
- case Common::KEYCODE_KP5:
- key = KEY_STATIONARY;
- break;
- case Common::KEYCODE_PLUS:
- key = '+';
- break;
- case Common::KEYCODE_MINUS:
- key = '-';
- break;
- case Common::KEYCODE_TAB:
- key = 0x0009;
- break;
- case Common::KEYCODE_F1:
- key = 0x3b00;
- break;
- case Common::KEYCODE_F2:
- key = 0x3c00;
- break;
- case Common::KEYCODE_F3:
- key = 0x3d00;
- break;
- case Common::KEYCODE_F4:
- key = 0x3e00;
- break;
- case Common::KEYCODE_F5:
- key = 0x3f00;
- break;
- case Common::KEYCODE_F6:
- key = 0x4000;
- break;
- case Common::KEYCODE_F7:
- key = 0x4100;
- break;
- case Common::KEYCODE_F8:
- key = 0x4200;
- break;
- case Common::KEYCODE_F9:
- key = 0x4300;
- break;
- case Common::KEYCODE_F10:
- key = 0x4400;
- break;
- case Common::KEYCODE_F11:
- key = KEY_STATUSLN;
- break;
- case Common::KEYCODE_F12:
- key = KEY_PRIORITY;
- break;
- case Common::KEYCODE_ESCAPE:
- key = 0x1b;
- break;
- case Common::KEYCODE_RETURN:
- case Common::KEYCODE_KP_ENTER:
- key = KEY_ENTER;
- break;
- case Common::KEYCODE_BACKSPACE:
- key = KEY_BACKSPACE;
- break;
- default:
- // Not a special key, so get the ASCII code for it
- key = event.kbd.ascii;
-
- if (Common::isAlpha(key)) {
- // Key is A-Z.
- // Map Ctrl-A to 1, Ctrl-B to 2, etc.
- if (event.kbd.flags & Common::KBD_CTRL) {
- key = toupper(key) - 'A' + 1;
- } else if (event.kbd.flags & Common::KBD_ALT) {
- // Map Alt-A, Alt-B etc. to special scancode values according to an internal scancode table.
- key = scancodeTable[toupper(key) - 'A'] << 8;
- }
- }
- break;
- }
- if (key)
- keyEnqueue(key);
- break;
-
- case Common::EVENT_KEYUP:
- if (_egoHoldKey)
- _game.viewTable[0].direction = 0;
+void AgiEngine::wait(uint32 msec, bool busy) {
+ uint32 endTime = _system->getMillis() + msec;
- default:
- break;
- }
+ if (busy) {
+ _gfx->setMouseCursor(true); // Busy mouse cursor
}
-}
-
-void AgiEngine::pollTimer() {
- _lastTick += 50;
- while (_system->getMillis() < _lastTick) {
- processEvents();
+ do {
+ processScummVMEvents();
_console->onFrame();
- _system->delayMillis(10);
- _system->updateScreen();
- }
-
- _lastTick = _system->getMillis();
-}
-
-void AgiEngine::pause(uint32 msec) {
- uint32 endTime = _system->getMillis() + msec;
-
- _gfx->setCursor(_renderMode == Common::kRenderAmiga, true);
-
- while (_system->getMillis() < endTime) {
- processEvents();
_system->updateScreen();
_system->delayMillis(10);
- }
- _gfx->setCursor(_renderMode == Common::kRenderAmiga);
-}
+ } while (_system->getMillis() < endTime);
-void AgiEngine::initPriTable() {
- int i, p, y = 0;
-
- for (p = 1; p < 15; p++) {
- for (i = 0; i < 12; i++) {
- _game.priTable[y++] = p < 4 ? 4 : p;
- }
+ if (busy) {
+ _gfx->setMouseCursor(); // regular mouse cursor
}
}
@@ -335,13 +86,11 @@ int AgiEngine::agiInit() {
_game.adjMouseX = _game.adjMouseY = 0;
// reset all flags to false and all variables to 0
- for (i = 0; i < MAX_FLAGS; i++)
- _game.flags[i] = 0;
- for (i = 0; i < MAX_VARS; i++)
- _game.vars[i] = 0;
+ memset(_game.flags, 0, sizeof(_game.flags));
+ memset(_game.vars, 0, sizeof(_game.vars));
// clear all resources and events
- for (i = 0; i < MAX_DIRS; i++) {
+ for (i = 0; i < MAX_DIRECTORY_ENTRIES; i++) {
memset(&_game.views[i], 0, sizeof(struct AgiView));
memset(&_game.pictures[i], 0, sizeof(struct AgiPicture));
memset(&_game.logics[i], 0, sizeof(struct AgiLogic));
@@ -353,15 +102,17 @@ int AgiEngine::agiInit() {
}
// clear view table
- for (i = 0; i < MAX_VIEWTABLE; i++)
- memset(&_game.viewTable[i], 0, sizeof(struct VtEntry));
+ for (i = 0; i < SCREENOBJECTS_MAX; i++)
+ memset(&_game.screenObjTable[i], 0, sizeof(struct ScreenObjEntry));
- initWords();
+ memset(&_game.addToPicView, 0, sizeof(struct ScreenObjEntry));
+
+ _words->clearEgoWords();
if (!_menu)
- _menu = new Menu(this, _gfx, _picture);
+ _menu = new GfxMenu(this, _gfx, _picture, _text);
- initPriTable();
+ _gfx->initPriorityTable();
// Clear the string buffer on startup, but not when the game restarts, as
// some scripts expect that the game strings remain unaffected after a
@@ -378,13 +129,13 @@ int AgiEngine::agiInit() {
switch (getVersion() >> 12) {
case 2:
debug("Emulating Sierra AGI v%x.%03x",
- (int)(getVersion() >> 12) & 0xF,
- (int)(getVersion()) & 0xFFF);
+ (int)(getVersion() >> 12) & 0xF,
+ (int)(getVersion()) & 0xFFF);
break;
case 3:
debug("Emulating Sierra AGI v%x.002.%03x",
- (int)(getVersion() >> 12) & 0xF,
- (int)(getVersion()) & 0xFFF);
+ (int)(getVersion() >> 12) & 0xF,
+ (int)(getVersion()) & 0xFFF);
break;
}
@@ -394,17 +145,13 @@ int AgiEngine::agiInit() {
if (getFeatures() & GF_AGDS)
_game.gameFlags |= ID_AGDS;
- // Make the 256 color AGI screen the default AGI screen when AGI256 or AGI256-2 is used
- if (getFeatures() & (GF_AGI256 | GF_AGI256_2))
- _game.sbuf = _game.sbuf256c;
-
if (_game.gameFlags & ID_AMIGA)
debug(1, "Amiga padded game detected.");
if (_game.gameFlags & ID_AGDS)
debug(1, "AGDS mode enabled.");
- ec = _loader->init(); // load vol files, etc
+ ec = _loader->init(); // load vol files, etc
if (ec == errOK)
ec = _loader->loadObjects(OBJECTS);
@@ -413,12 +160,9 @@ int AgiEngine::agiInit() {
if (ec == errOK)
ec = _loader->loadWords(WORDS);
- // FIXME: load IIgs instruments and samples
- // load_instruments("kq.sys16");
-
// Load logic 0 into memory
if (ec == errOK)
- ec = _loader->loadResource(rLOGIC, 0);
+ ec = _loader->loadResource(RESOURCETYPE_LOGIC, 0);
#ifdef __DS__
// Normally, the engine loads the predictive text dictionary when the predictive dialog
@@ -428,10 +172,16 @@ int AgiEngine::agiInit() {
// GUI Predictive Dialog, but DS Word Completion is probably broken due to this...
#endif
- _egoHoldKey = false;
+ _keyHoldMode = false;
_game.mouseFence.setWidth(0); // Reset
+ // Reset in-game timer
+ inGameTimerReset();
+
+ // Sync volume settings from ScummVM system settings
+ setVolumeViaSystemSetting();
+
return ec;
}
@@ -443,42 +193,45 @@ void AgiEngine::agiUnloadResources() {
int i;
// Make sure logic 0 is always loaded
- for (i = 1; i < MAX_DIRS; i++) {
- _loader->unloadResource(rLOGIC, i);
+ for (i = 1; i < MAX_DIRECTORY_ENTRIES; i++) {
+ _loader->unloadResource(RESOURCETYPE_LOGIC, i);
}
- for (i = 0; i < MAX_DIRS; i++) {
- _loader->unloadResource(rVIEW, i);
- _loader->unloadResource(rPICTURE, i);
- _loader->unloadResource(rSOUND, i);
+ for (i = 0; i < MAX_DIRECTORY_ENTRIES; i++) {
+ _loader->unloadResource(RESOURCETYPE_VIEW, i);
+ _loader->unloadResource(RESOURCETYPE_PICTURE, i);
+ _loader->unloadResource(RESOURCETYPE_SOUND, i);
}
}
int AgiEngine::agiDeinit() {
int ec;
- cleanInput(); // remove all words from memory
- agiUnloadResources(); // unload resources in memory
- _loader->unloadResource(rLOGIC, 0);
+ if (!_loader)
+ return errOK;
+
+ _words->clearEgoWords(); // remove all words from memory
+ agiUnloadResources(); // unload resources in memory
+ _loader->unloadResource(RESOURCETYPE_LOGIC, 0);
ec = _loader->deinit();
unloadObjects();
- unloadWords();
+ _words->unloadDictionary();
clearImageStack();
return ec;
}
-int AgiEngine::agiLoadResource(int r, int n) {
+int AgiEngine::agiLoadResource(int16 resourceType, int16 resourceNr) {
int i;
- i = _loader->loadResource(r, n);
+ i = _loader->loadResource(resourceType, resourceNr);
// WORKAROUND: Patches broken picture 147 in a corrupted Amiga version of Gold Rush! (v2.05 1989-03-09).
// The picture can be seen in room 147 after dropping through the outhouse's hole in room 146.
- if (i == errOK && getGameID() == GID_GOLDRUSH && r == rPICTURE && n == 147 && _game.dirPic[n].len == 1982) {
- uint8 *pic = _game.pictures[n].rdata;
- Common::MemoryReadStream picStream(pic, _game.dirPic[n].len);
- Common::String md5str = Common::computeStreamMD5AsString(picStream, _game.dirPic[n].len);
+ if (i == errOK && getGameID() == GID_GOLDRUSH && resourceType == RESOURCETYPE_PICTURE && resourceNr == 147 && _game.dirPic[resourceNr].len == 1982) {
+ uint8 *pic = _game.pictures[resourceNr].rdata;
+ Common::MemoryReadStream picStream(pic, _game.dirPic[resourceNr].len);
+ Common::String md5str = Common::computeStreamMD5AsString(picStream, _game.dirPic[resourceNr].len);
if (md5str == "1c685eb048656cedcee4eb6eca2cecea") {
pic[0x042] = 0x4B; // 0x49 -> 0x4B
pic[0x043] = 0x66; // 0x26 -> 0x66
@@ -492,8 +245,8 @@ int AgiEngine::agiLoadResource(int r, int n) {
return i;
}
-int AgiEngine::agiUnloadResource(int r, int n) {
- return _loader->unloadResource(r, n);
+int AgiEngine::agiUnloadResource(int16 resourceType, int16 resourceNr) {
+ return _loader->unloadResource(resourceType, resourceNr);
}
struct GameSettings {
@@ -505,18 +258,11 @@ struct GameSettings {
};
AgiBase::AgiBase(OSystem *syst, const AGIGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) {
- // Assign default values to the config manager, in case settings are missing
- ConfMan.registerDefault("originalsaveload", "false");
- ConfMan.registerDefault("altamigapalette", "false");
- ConfMan.registerDefault("mousesupport", "true");
-
_noSaveLoadAllowed = false;
_rnd = new Common::RandomSource("agi");
_sound = 0;
- _fontData = NULL;
-
initFeatures();
initVersion();
}
@@ -528,27 +274,79 @@ AgiBase::~AgiBase() {
}
void AgiBase::initRenderMode() {
+ Common::Platform platform = Common::parsePlatform(ConfMan.get("platform"));
+ Common::RenderMode configRenderMode = Common::parseRenderMode(ConfMan.get("render_mode").c_str());
+
+ // Default to EGA PC rendering
_renderMode = Common::kRenderEGA;
- if (ConfMan.hasKey("platform")) {
- Common::Platform platform = Common::parsePlatform(ConfMan.get("platform"));
- _renderMode = (platform == Common::kPlatformAmiga) ? Common::kRenderAmiga : Common::kRenderEGA;
+ switch (platform) {
+ case Common::kPlatformDOS:
+ // Keep EGA
+ break;
+ case Common::kPlatformAmiga:
+ _renderMode = Common::kRenderAmiga;
+ break;
+ case Common::kPlatformApple2GS:
+ _renderMode = Common::kRenderApple2GS;
+ break;
+ case Common::kPlatformAtariST:
+ _renderMode = Common::kRenderAtariST;
+ break;
+ case Common::kPlatformMacintosh:
+ _renderMode = Common::kRenderMacintosh;
+ break;
+ default:
+ break;
+ }
+
+ // If render mode is explicitly set, force rendermode
+ switch (configRenderMode) {
+ case Common::kRenderCGA:
+ _renderMode = Common::kRenderCGA;
+ break;
+ case Common::kRenderEGA:
+ _renderMode = Common::kRenderEGA;
+ break;
+ case Common::kRenderVGA:
+ _renderMode = Common::kRenderVGA;
+ break;
+ case Common::kRenderHercG:
+ _renderMode = Common::kRenderHercG;
+ break;
+ case Common::kRenderHercA:
+ _renderMode = Common::kRenderHercA;
+ break;
+ case Common::kRenderAmiga:
+ _renderMode = Common::kRenderAmiga;
+ break;
+ case Common::kRenderApple2GS:
+ _renderMode = Common::kRenderApple2GS;
+ break;
+ case Common::kRenderAtariST:
+ _renderMode = Common::kRenderAtariST;
+ break;
+ case Common::kRenderMacintosh:
+ _renderMode = Common::kRenderMacintosh;
+ break;
+ default:
+ break;
}
- if (ConfMan.hasKey("render_mode")) {
- Common::RenderMode tmpMode = Common::parseRenderMode(ConfMan.get("render_mode").c_str());
- if (tmpMode != Common::kRenderDefault)
- _renderMode = tmpMode;
+ if (getFeatures() & (GF_AGI256 | GF_AGI256_2)) {
+ // If current game is AGI256, switch (force) to VGA render mode
+ _renderMode = Common::kRenderVGA;
}
}
-AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBase(syst, gameDesc) {
+const byte *AgiBase::getFontData() {
+ return _font->getFontData();
+}
+AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBase(syst, gameDesc) {
// Setup mixer
syncSoundSettings();
- parseFeatures();
-
DebugMan.addDebugChannel(kDebugLevelMain, "Main", "Generic debug level");
DebugMan.addDebugChannel(kDebugLevelResources, "Resources", "Resources debugging");
DebugMan.addDebugChannel(kDebugLevelSprites, "Sprites", "Sprites debugging");
@@ -566,22 +364,17 @@ AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBas
memset(&_mouse, 0, sizeof(struct Mouse));
_game.mouseEnabled = true;
+ _game.mouseHidden = false;
+ // don't check for Amiga, Amiga doesn't allow disabling mouse support. It's mandatory.
if (!ConfMan.getBool("mousesupport")) {
// we effectively disable the mouse for games, that explicitly do not want mouse support to be enabled
_game.mouseEnabled = false;
- }
-
- // We are currently using the custom font for all fanmade games
- if (!(getFeatures() & (GF_FANMADE | GF_AGDS))) {
- _fontData = fontData_Sierra; // original Sierra font
- } else {
- _fontData = fontData_FanGames; // our (own?) custom font, that supports umlauts etc.
+ _game.mouseHidden = true;
}
_game._vm = this;
- _game.clockEnabled = false;
- _game.state = STATE_INIT;
+ _game.gfxMode = true;
_keyQueueStart = 0;
_keyQueueEnd = 0;
@@ -590,40 +383,49 @@ AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBas
_intobj = NULL;
- _menu = NULL;
- _menuSelected = false;
-
- _lastSentence[0] = 0;
memset(&_stringdata, 0, sizeof(struct StringData));
_objects = NULL;
_restartGame = false;
- _oldMode = INPUT_NONE;
-
_firstSlot = 0;
resetControllers();
setupOpcodes();
_game._curLogic = NULL;
- _timerHack = 0;
+ _veryFirstInitialCycle = true;
+ _instructionCounter = 0;
+ resetGetVarSecondsHeuristic();
- _lastSaveTime = 0;
- _lastTick = 0;
-
- memset(_keyQueue, 0, sizeof(_keyQueue));
- memset(_predictiveResult, 0, sizeof(_predictiveResult));
+ _setVolumeBrokenFangame = false; // for further study see AgiEngine::setVolumeViaScripts()
- _sprites = NULL;
- _picture = NULL;
- _loader = NULL;
- _console = NULL;
+ _lastSaveTime = 0;
- _egoHoldKey = false;
+ _playTimeInSecondsAdjust = 0;
+ _lastUsedPlayTimeInCycles = 0;
+ _lastUsedPlayTimeInSeconds = 0;
+ _passedPlayTimeCycles = 0;
+ memset(_keyQueue, 0, sizeof(_keyQueue));
+ _console = nullptr;
+ _font = nullptr;
+ _gfx = nullptr;
+ _sound = nullptr;
+ _picture = nullptr;
+ _sprites = nullptr;
+ _text = nullptr;
+ _loader = nullptr;
+ _menu = nullptr;
+ _systemUI = nullptr;
+ _inventory = nullptr;
+
+ _keyHoldMode = false;
+
+ _artificialDelayCurrentRoom = 0;
+ _artificialDelayCurrentPicture = 0;
}
void AgiEngine::initialize() {
@@ -641,7 +443,7 @@ void AgiEngine::initialize() {
// Default sound is the proper PCJr emulation
_soundemu = SOUND_EMU_PCJR;
} else {
- switch (MidiDriver::getMusicType(MidiDriver::detectDevice(MDT_PCSPK|MDT_AMIGA|MDT_ADLIB|MDT_PCJR|MDT_MIDI))) {
+ switch (MidiDriver::getMusicType(MidiDriver::detectDevice(MDT_PCSPK | MDT_AMIGA | MDT_ADLIB | MDT_PCJR | MDT_MIDI))) {
case MT_PCSPK:
_soundemu = SOUND_EMU_PC;
break;
@@ -663,38 +465,33 @@ void AgiEngine::initialize() {
initRenderMode();
- _buttonStyle = AgiButtonStyle(_renderMode);
- _defaultButtonStyle = AgiButtonStyle();
_console = new Console(this);
- _gfx = new GfxMgr(this);
+ _words = new Words(this);
+ _font = new GfxFont(this);
+ _gfx = new GfxMgr(this, _font);
_sound = new SoundMgr(this, _mixer);
_picture = new PictureMgr(this, _gfx);
_sprites = new SpritesMgr(this, _gfx);
+ _text = new TextMgr(this, _words, _gfx);
+ _systemUI = new SystemUI(this, _gfx, _text);
+ _inventory = new InventoryMgr(this, _gfx, _text, _systemUI);
- _gfx->initMachine();
+ _font->init();
+ _gfx->initVideo();
+
+ _text->init(_systemUI);
_game.gameFlags = 0;
- _game.colorFg = 15;
- _game.colorBg = 0;
+ _text->charAttrib_Set(15, 0);
_game.name[0] = '\0';
- _game.sbufOrig = (uint8 *)calloc(_WIDTH, _HEIGHT * 2); // Allocate space for two AGI screens vertically
- _game.sbuf16c = _game.sbufOrig + SBUF16_OFFSET; // Make sbuf16c point to the 16 color (+control line & priority info) AGI screen
- _game.sbuf256c = _game.sbufOrig + SBUF256_OFFSET; // Make sbuf256c point to the 256 color AGI screen
- _game.sbuf = _game.sbuf16c; // Make sbuf point to the 16 color (+control line & priority info) AGI screen by default
-
- _gfx->initVideo();
-
_lastSaveTime = 0;
- _lastTick = _system->getMillis();
-
debugC(2, kDebugLevelMain, "Detect game");
if (agiDetectGame() == errOK) {
- _game.state = STATE_LOADED;
debugC(2, kDebugLevelMain, "game loaded");
} else {
warning("Could not open AGI game");
@@ -703,34 +500,42 @@ void AgiEngine::initialize() {
debugC(2, kDebugLevelMain, "Init sound");
}
-AgiEngine::~AgiEngine() {
- // If the engine hasn't been initialized yet via
- // AgiEngine::initialize(), don't attempt to free any resources, as
- // they haven't been allocated. Fixes bug #1742432 - AGI: Engine
- // crashes if no game is detected
- if (_game.state == STATE_INIT) {
- return;
- }
+bool AgiEngine::promptIsEnabled() {
+ return _text->promptIsEnabled();
+}
+void AgiEngine::redrawScreen() {
+ _game.gfxMode = true; // enable graphics mode
+ _gfx->setPalette(true); // set graphics mode palette
+ _text->charAttrib_Set(_text->_textAttrib.foreground, _text->_textAttrib.background);
+ _gfx->clearDisplay(0);
+ _picture->showPic();
+ _text->statusDraw();
+ _text->promptRedraw();
+}
+
+AgiEngine::~AgiEngine() {
agiDeinit();
delete _loader;
- _gfx->deinitVideo();
+ if (_gfx) {
+ _gfx->deinitVideo();
+ }
+ delete _inventory;
+ delete _systemUI;
+ delete _menu;
+ delete _text;
delete _sprites;
delete _picture;
- free(_game.sbufOrig);
- _gfx->deinitMachine();
delete _gfx;
+ delete _font;
+ delete _words;
delete _console;
}
Common::Error AgiBase::init() {
-
- // Initialize backend
- initGraphics(320, 200, false);
-
initialize();
- _gfx->gfxSetPalette();
+ _gfx->setPalette(true);
return Common::kNoError;
}
@@ -739,87 +544,166 @@ Common::Error AgiEngine::go() {
if (_game.mouseEnabled) {
CursorMan.showMouse(true);
}
- setTotalPlayTime(0);
-
- if (_game.state < STATE_LOADED) {
- do {
- mainCycle();
- } while (_game.state < STATE_RUNNING);
- }
+ inGameTimerReset();
runGame();
return Common::kNoError;
}
-void AgiEngine::parseFeatures() {
-
- /* FIXME: Seems this method doesn't really do anything. It might
- be a leftover that could be removed, except that some of its
- intended purpose may still need to be reimplemented.
-
- [0:29] <Fingolfin> can you tell me what the point behind AgiEngine::parseFeatures() is?
- [0:30] <_sev> when games are created with WAGI studio
- [0:31] <_sev> it creates .wag site with game-specific features such as full game title, whether to use AGIMOUSE etc
- [0:32] <Fingolfin> ... and the "features" config key is created by our detector based on the wag file, I guess?
- [0:33] <_sev> yes
- [0:33] <Fingolfin> it's just that I cant seem to find a place we do that
- [0:33] <_sev> it is used for fallback
- [0:34] <_sev> ah, perhaps it was not updated
- [0:34] <Fingolfin> I only see us check the value, but never set it
- [0:34] <Fingolfin> maybe I am grepping wrong, who knows :)
- [0:44] <Fingolfin> _sev: so, unless I miss something, it seem that function does nothing right now
- [0:45] <_sev> Fingolfin: it could be unfinished. It was part of GSoC 3 years ago
- [0:45] <Fingolfin> well
- [0:45] <_sev> I just don't remember
- [0:45] <Fingolfin> but don't we just re-parse the wag when the game is loaded anyway?
- [0:45] <_sev> but it documents the format
- [0:45] <Fingolfin> the advanced meta engine would re-run the detector, wouldn't it?
- [0:45] <_sev> yep
- [0:47] <Fingolfin> so... shouldn't we at least add a comment to the function explaining what it does and that it's unfinished etc.? maybe add a TODO to the wiki?
- [0:47] <Fingolfin> otherwise it might stay as it is for another 3 years :)
- */
-
- if (!ConfMan.hasKey("features"))
- return;
-
- char *features = strdup(ConfMan.get("features").c_str());
- const char *feature[100];
- int numFeatures = 0;
-
- char *tok = strtok(features, " ");
- if (tok) {
- do {
- feature[numFeatures++] = tok;
- } while ((tok = strtok(NULL, " ")) != NULL);
- } else {
- feature[numFeatures++] = features;
+void AgiEngine::syncSoundSettings() {
+ Engine::syncSoundSettings();
+
+ setVolumeViaSystemSetting();
+}
+
+// WORKAROUND:
+// Sometimes Sierra printed some text on the screen and did a room change immediately afterwards expecting the
+// interpreter to load the data for a bit of time. This of course doesn't happen in our AGI, so we try to
+// detect such situations via heuristic and then delay the game for a bit.
+// In those cases a wait mouse cursor will be shown.
+//
+// Scenes that need this:
+//
+// Gold Rush:
+// - During Stagecoach path, after getting solving the steep hill "Congratulations!!!" (NewRoom)
+// - when following your mule "Yet right on his tail!!!" (NewRoom/NewPicture - but room 123 stays the same)
+// Manhunter 1:
+// - intro text screen (DrawPic)
+// - MAD "zooming in..." during intro and other scenes, for example room 124 (NewRoom)
+// The NewRoom call is not done during the same cycle as the "zooming in..." print call.
+// Space Quest 1:
+// - right at the start of the game (NewRoom)
+// - right at the end of the asteroids "That was mighty close!" (NewRoom)
+// Space Quest 2
+// - right at the start of the game (NewRoom)
+// - after exiting the very first room, a message pops up, that isn't readable without it (NewRoom)
+// - Climbing into shuttle on planet Labion. "You open the hatch and head on in." (NewRoom)
+
+
+// Games, that must not be triggered:
+//
+// Fanmade Voodoo Girl:
+// - waterfall (DrawPic, room 17)
+// - inside shop (NewRoom, changes to same room every new button, room 4)
+
+void AgiEngine::nonBlockingText_IsShown() {
+ _game.nonBlockingTextShown = true;
+ _game.nonBlockingTextCyclesLeft = 2; // 1 additional script cycle is counted too
+}
+void AgiEngine::nonBlockingText_Forget() {
+ _game.nonBlockingTextShown = false;
+ _game.nonBlockingTextCyclesLeft = 0;
+}
+
+void AgiEngine::artificialDelay_Reset() {
+ nonBlockingText_Forget();
+ _artificialDelayCurrentRoom = -1;
+ _artificialDelayCurrentPicture = -1;
+}
+
+void AgiEngine::artificialDelay_CycleDone() {
+ if (_game.nonBlockingTextCyclesLeft) {
+ _game.nonBlockingTextCyclesLeft--;
+
+ if (!_game.nonBlockingTextCyclesLeft) {
+ // cycle count expired, we assume that non-blocking text won't be a problem for room / pic change
+ _game.nonBlockingTextShown = false;
+ }
+ }
+}
+
+// WORKAROUND:
+// On Apple IIgs, there are situations like for example the Police Quest 1 intro, where music is playing
+// and then the scripts switch to a new room, expecting it to load for a bit of time. In ScummVM this results
+// in music getting cut off, because our loading is basically done in an instant. This also happens in the
+// original interpreter, when you use a faster CPU in emulation.
+//
+// That's why there is an additional table, where one can add such situations to it.
+// These issues are basically impossible to detect, because sometimes music is also supposed to play throughout
+// multiple rooms.
+//
+// Normally all text-based issues should get detected by the current heuristic. Do not add those in here.
+
+// script, description, signature patch
+static const AgiArtificialDelayEntry artificialDelayTable[] = {
+ { GID_GOLDRUSH, Common::kPlatformApple2GS, ARTIFICIALDELAYTYPE_NEWROOM, 14, 21, 2200 }, // Stagecoach path: right after getting on it in Brooklyn
+ { GID_PQ1, Common::kPlatformApple2GS, ARTIFICIALDELAYTYPE_NEWPICTURE, 1, 2, 2200 }, // Intro: music track is supposed to finish before credits screen. Developers must have assumed that room loading would take that long.
+ { GID_MH1, Common::kPlatformApple2GS, ARTIFICIALDELAYTYPE_NEWPICTURE, 155, 183, 2200 }, // Happens, when hitting fingers at bar
+ { GID_AGIDEMO, Common::kPlatformUnknown, ARTIFICIALDELAYTYPE_END, -1, -1, 0 }
+};
+
+uint16 AgiEngine::artificialDelay_SearchTable(AgiArtificialDelayTriggerType triggerType, int16 orgNr, int16 newNr) {
+ if (getPlatform() != Common::kPlatformApple2GS) {
+ return 0;
+ }
+
+ const AgiArtificialDelayEntry *delayEntry = artificialDelayTable;
+
+ while (delayEntry->triggerType != ARTIFICIALDELAYTYPE_END) {
+ if (triggerType == delayEntry->triggerType) {
+ if ((orgNr == delayEntry->orgNr) && (newNr == delayEntry->newNr)) {
+ if ((getGameID() == delayEntry->gameId) && (getPlatform() == delayEntry->platform)) {
+ warning("artificial delay forced");
+ return delayEntry->millisecondsDelay;
+ }
+ }
+ }
+
+ delayEntry++;
}
+ return 0;
+}
+
+void AgiEngine::artificialDelayTrigger_NewRoom(int16 newRoomNr) {
+ uint16 millisecondsDelay = 0;
+
+ //warning("artificial delay trigger: room %d -> new room %d", _artificialDelayCurrentRoom, newRoomNr);
- const struct Flags {
- const char *name;
- uint32 flag;
- } flags[] = {
- { "agimouse", GF_AGIMOUSE },
- { "agds", GF_AGDS },
- { "agi256", GF_AGI256 },
- { "agi256-2", GF_AGI256_2 },
- { "agipal", GF_AGIPAL },
- { 0, 0 }
- };
-
- for (int i = 0; i < numFeatures; i++) {
- for (const Flags *flag = flags; flag->name; flag++) {
- if (!scumm_stricmp(feature[i], flag->name)) {
- debug(2, "Added feature: %s", flag->name);
-
- setFeature(flag->flag);
- break;
+ if (!_game.automaticRestoreGame) {
+ millisecondsDelay = artificialDelay_SearchTable(ARTIFICIALDELAYTYPE_NEWROOM, _artificialDelayCurrentRoom, newRoomNr);
+
+ if (_game.nonBlockingTextShown) {
+ if (newRoomNr != _artificialDelayCurrentRoom) {
+ if (millisecondsDelay < 2000) {
+ // wait a bit, we detected non-blocking text
+ millisecondsDelay = 2000; // 2 seconds
+ }
}
}
+
+ if (millisecondsDelay) {
+ wait(millisecondsDelay, true); // set busy mouse cursor
+ _game.nonBlockingTextShown = false;
+ }
}
- free(features);
+ _artificialDelayCurrentRoom = newRoomNr;
+}
+
+void AgiEngine::artificialDelayTrigger_DrawPicture(int16 newPictureNr) {
+ uint16 millisecondsDelay = 0;
+
+ //warning("artificial delay trigger: picture %d -> new picture %d", _artificialDelayCurrentPicture, newPictureNr);
+
+ if (!_game.automaticRestoreGame) {
+ millisecondsDelay = artificialDelay_SearchTable(ARTIFICIALDELAYTYPE_NEWPICTURE, _artificialDelayCurrentPicture, newPictureNr);
+
+ if (_game.nonBlockingTextShown) {
+ if (newPictureNr != _artificialDelayCurrentPicture) {
+ if (millisecondsDelay < 2000) {
+ // wait a bit, we detected non-blocking text
+ millisecondsDelay = 2000; // 2 seconds, set busy
+ }
+ }
+ }
+
+ if (millisecondsDelay) {
+ wait(millisecondsDelay, true); // set busy mouse cursor
+ _game.nonBlockingTextShown = false;
+ }
+ }
+ _artificialDelayCurrentPicture = newPictureNr;
}
} // End of namespace Agi
diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index 04e02dcf87..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;
}
@@ -69,40 +67,37 @@ typedef signed int Err;
// Version and other definitions
//
-#define TITLE "AGI engine"
-
-#define DIR_ "dir"
-#define LOGDIR "logdir"
-#define PICDIR "picdir"
-#define VIEWDIR "viewdir"
-#define SNDDIR "snddir"
-#define OBJECTS "object"
-#define WORDS "words.tok"
-
-#define MAX_DIRS 256
-#define MAX_VARS 256
-#define MAX_FLAGS (256 >> 3)
-#define MAX_VIEWTABLE 255 // KQ3 uses o255!
-#define MAX_WORDS 20
-#define MAX_STRINGS 24 // MAX_STRINGS + 1 used for get.num
-#define MAX_STRINGLEN 40
-#define MAX_CONTROLLERS 39
-
-#define _EMPTY 0xfffff
-#define EGO_OWNED 0xff
-#define EGO_OWNED_V1 0xf9
-
-#define CRYPT_KEY_SIERRA "Avis Durgan"
-#define CRYPT_KEY_AGDS "Alex Simkin"
-
-#define MSG_BOX_COLOR 0x0f // White
-#define MSG_BOX_TEXT 0x00 // Black
-#define MSG_BOX_LINE 0x04 // Red
-#define BUTTON_BORDER 0x00 // Black
-#define STATUS_FG 0x00 // Black
-#define STATUS_BG 0x0f // White
-
-#define ADD_PIC 1
+#define TITLE "AGI engine"
+
+#define DIR_ "dir"
+#define LOGDIR "logdir"
+#define PICDIR "picdir"
+#define VIEWDIR "viewdir"
+#define SNDDIR "snddir"
+#define OBJECTS "object"
+#define WORDS "words.tok"
+
+#define MAX_DIRECTORY_ENTRIES 256
+#define MAX_CONTROLLERS 256
+#define MAX_VARS 256
+#define MAX_FLAGS (256 >> 3)
+#define SCREENOBJECTS_MAX 255 // KQ3 uses o255!
+#define SCREENOBJECTS_EGO_ENTRY 0 // first entry is ego
+#define MAX_WORDS 20
+#define MAX_STRINGS 24 // MAX_STRINGS + 1 used for get.num
+#define MAX_STRINGLEN 40
+#define MAX_CONTROLLER_KEYMAPPINGS 39
+
+#define SAVEDGAME_DESCRIPTION_LEN 30
+
+#define _EMPTY 0xfffff
+#define EGO_OWNED 0xff
+#define EGO_OWNED_V1 0xf9
+
+#define CRYPT_KEY_SIERRA "Avis Durgan"
+#define CRYPT_KEY_AGDS "Alex Simkin"
+
+#define ADD_PIC 1
#define ADD_VIEW 2
#define CMD_BSIZE 12
@@ -125,10 +120,10 @@ enum AgiGameID {
GID_SQ2,
GID_XMASCARD,
GID_FANMADE,
- GID_GETOUTTASQ, // Fanmade
- GID_MICKEY, // PreAGI
- GID_WINNIE, // PreAGI
- GID_TROLL // PreAGI
+ GID_GETOUTTASQ, // Fanmade
+ GID_MICKEY, // PreAGI
+ GID_WINNIE, // PreAGI
+ GID_TROLL // PreAGI
};
enum AgiGameType {
@@ -138,10 +133,10 @@ enum AgiGameType {
GType_V3 = 3
};
- enum BooterDisks {
- BooterDisk1 = 0,
- BooterDisk2 = 1
- };
+enum BooterDisks {
+ BooterDisk1 = 0,
+ BooterDisk2 = 1
+};
//
// GF_OLDAMIGAV20 means that the interpreter is an old Amiga AGI interpreter that
@@ -151,17 +146,17 @@ enum AgiGameType {
// position and position.v.
//
enum AgiGameFeatures {
- GF_AGIMOUSE = (1 << 0),
- GF_AGDS = (1 << 1),
- GF_AGI256 = (1 << 2),
- GF_AGI256_2 = (1 << 3),
- GF_AGIPAL = (1 << 4),
- GF_MACGOLDRUSH = (1 << 5),
- GF_FANMADE = (1 << 6),
- GF_MENUS = (1 << 7),
- GF_ESCPAUSE = (1 << 8),
+ GF_AGIMOUSE = (1 << 0), // this disables "Click-to-walk mouse interface"
+ GF_AGDS = (1 << 1),
+ GF_AGI256 = (1 << 2), // marks fanmade AGI-256 games
+ GF_AGI256_2 = (1 << 3), // marks fanmade AGI-256-2 games
+ GF_AGIPAL = (1 << 4), // marks game using fanmade AGIPAL extension
+ GF_MACGOLDRUSH = (1 << 5), // use "grdir" instead of "dir" for volume loading
+ GF_FANMADE = (1 << 6), // marks fanmade games
+ GF_MENUS = (1 << 7), // not used anymore
+ GF_ESCPAUSE = (1 << 8), // not used anymore, we detect this internally
GF_OLDAMIGAV20 = (1 << 9),
- GF_CLIPCOORDS = (1 << 10),
+ GF_CLIPCOORDS = (1 << 10), // not used atm
GF_2GSOLDSOUND = (1 << 11)
};
@@ -206,15 +201,17 @@ enum kDebugLevels {
* AGI resources.
*/
enum {
- rLOGIC = 1,
- rSOUND,
- rVIEW,
- rPICTURE
+ RESOURCETYPE_LOGIC = 1,
+ RESOURCETYPE_SOUND,
+ RESOURCETYPE_VIEW,
+ RESOURCETYPE_PICTURE
};
enum {
- RES_LOADED = 1,
- RES_COMPRESSED = 0x40
+ RES_LOADED = 0x01,
+ RES_COMPRESSED = 0x40,
+ RES_PICTURE_V3_NIBBLE_PARM = 0x80 // Flag that gets set for picture resources,
+ // which use a nibble instead of a byte as F0+F2 parameters
};
enum {
@@ -232,8 +229,7 @@ struct gameIdList {
struct Mouse {
int button;
- int x;
- int y;
+ Common::Point pos;
};
// Used by AGI Mouse protocol 1.0 for v27 (i.e. button pressed -variable).
@@ -244,44 +240,40 @@ enum AgiMouseButton {
kAgiMouseButtonMiddle // Middle mouse button
};
-enum GameId {
- GID_AGI = 1
-};
-
-#define WIN_TO_PIC_X(x) ((x) / 2)
-#define WIN_TO_PIC_Y(y) ((y) < 8 ? 999 : (y) >= (8 + _HEIGHT) ? 999 : (y) - 8)
-
/**
* AGI variables.
*/
enum {
- vCurRoom = 0, // 0
- vPrevRoom,
- vBorderTouchEgo,
- vScore,
- vBorderCode,
- vBorderTouchObj, // 5
- vEgoDir,
- vMaxScore,
- vFreePages,
- vWordNotFound,
- vTimeDelay, // 10
- vSeconds,
- vMinutes,
- vHours,
- vDays,
- vJoystickSensitivity, // 15
- vEgoViewResource,
- vAgiErrCode,
- vAgiErrCodeInfo,
- vKey,
- vComputer, // 20
- vWindowReset,
- vSoundgen,
- vVolume,
- vMaxInputChars,
- vSelItem, // 25
- vMonitor
+ VM_VAR_CURRENT_ROOM = 0, // 0
+ VM_VAR_PREVIOUS_ROOM, // 1
+ VM_VAR_BORDER_TOUCH_EGO, // 2
+ VM_VAR_SCORE, // 3
+ VM_VAR_BORDER_CODE, // 4
+ VM_VAR_BORDER_TOUCH_OBJECT, // 5
+ VM_VAR_EGO_DIRECTION, // 6
+ VM_VAR_MAX_SCORE, // 7
+ VM_VAR_FREE_PAGES, // 8
+ VM_VAR_WORD_NOT_FOUND, // 9
+ VM_VAR_TIME_DELAY, // 10
+ VM_VAR_SECONDS, // 11
+ VM_VAR_MINUTES, // 12
+ VM_VAR_HOURS, // 13
+ VM_VAR_DAYS, // 14
+ VM_VAR_JOYSTICK_SENSITIVITY, // 15
+ VM_VAR_EGO_VIEW_RESOURCE, // 16
+ VM_VAR_AGI_ERROR_CODE, // 17
+ VM_VAR_AGI_ERROR_INFO, // 18
+ VM_VAR_KEY, // 19
+ VM_VAR_COMPUTER, // 20
+ VM_VAR_WINDOW_AUTO_CLOSE_TIMER, // 21
+ VM_VAR_SOUNDGENERATOR, // 22
+ VM_VAR_VOLUME, // 23
+ VM_VAR_MAX_INPUT_CHARACTERS, // 24
+ VM_VAR_SELECTED_INVENTORY_ITEM, // 25
+ VM_VAR_MONITOR = 26, // 26
+ VM_VAR_MOUSE_BUTTONSTATE = 27, // 27
+ VM_VAR_MOUSE_X = 28, // 28
+ VM_VAR_MOUSE_Y = 29 // 29
};
/**
@@ -290,10 +282,10 @@ enum {
*/
enum AgiMonitorType {
kAgiMonitorCga = 0,
- // kAgiMonitorTandy = 1, // Not sure about this
+ //kAgiMonitorTandy = 1, // Not sure about this
kAgiMonitorHercules = 2,
kAgiMonitorEga = 3
- // kAgiMonitorVga = 4 // Not sure about this
+ //kAgiMonitorVga = 4 // Not sure about this
};
/**
@@ -335,33 +327,28 @@ enum AgiSoundType {
* AGI flags
*/
enum {
- fEgoWater = 0, // 0
- fEgoInvisible,
- fEnteredCli,
- fEgoTouchedP2,
- fSaidAcceptedInput,
- fNewRoomExec, // 5
- fRestartGame,
- fScriptBlocked,
- fJoySensitivity,
- fSoundOn,
- fDebuggerOn, // 10
- fLogicZeroFirsttime,
- fRestoreJustRan,
- fStatusSelectsItems,
- fMenusWork,
- fOutputMode, // 15
- fAutoRestart
-};
-
-enum AgiSlowliness {
- kPauseRoom = 1500,
- kPausePicture = 500
-};
-
-struct AgiController {
+ VM_FLAG_EGO_WATER = 0, // 0
+ VM_FLAG_EGO_INVISIBLE,
+ VM_FLAG_ENTERED_CLI,
+ VM_FLAG_EGO_TOUCHED_P2,
+ VM_FLAG_SAID_ACCEPTED_INPUT,
+ VM_FLAG_NEW_ROOM_EXEC, // 5
+ VM_FLAG_RESTART_GAME,
+ VM_FLAG_SCRIPT_BLOCKED,
+ VM_FLAG_JOY_SENSITIVITY,
+ VM_FLAG_SOUND_ON,
+ VM_FLAG_DEBUGGER_ON, // 10
+ VM_FLAG_LOGIC_ZERO_FIRST_TIME,
+ VM_FLAG_RESTORE_JUST_RAN,
+ VM_FLAG_STATUS_SELECTS_ITEMS,
+ VM_FLAG_MENUS_ACCESSIBLE,
+ VM_FLAG_OUTPUT_MODE, // 15
+ VM_FLAG_AUTO_RESTART
+};
+
+struct AgiControllerKeyMapping {
uint16 keycode;
- uint8 controller;
+ byte controllerSlot;
};
struct AgiObject {
@@ -369,11 +356,6 @@ struct AgiObject {
char *name;
};
-struct AgiWord {
- int id;
- char *word;
-};
-
struct AgiDir {
uint8 volume;
uint32 offset;
@@ -389,122 +371,9 @@ struct AgiDir {
};
struct AgiBlock {
- int active;
- int x1, y1;
- int x2, y2;
- uint8 *buffer; // used for window background
-};
-
-/** AGI text color (Background and foreground color). */
-struct AgiTextColor {
- /** Creates an AGI text color. Uses black text on white background by default. */
- AgiTextColor(int fgColor = 0x00, int bgColor = 0x0F) : fg(fgColor), bg(bgColor) {}
-
- /** Get an AGI text color with swapped foreground and background color. */
- AgiTextColor swap() const { return AgiTextColor(bg, fg); }
-
- int fg; ///< Foreground color (Used for text).
- int bg; ///< Background color (Used for text's background).
-};
-
-/**
- * AGI button style (Amiga or PC).
- *
- * Supports positive and negative button types (Used with Amiga-style only):
- * Positive buttons do what the dialog was opened for.
- * Negative buttons cancel what the dialog was opened for.
- * Restart-dialog example: Restart-button is positive, Cancel-button negative.
- * Paused-dialog example: Continue-button is positive.
- */
-struct AgiButtonStyle {
-// Public constants etc
-public:
- static const int
- // Amiga colors (Indexes into the Amiga-ish palette)
- amigaBlack = 0x00, ///< Accurate, is #000000 (24-bit RGB)
- amigaWhite = 0x0F, ///< Practically accurate, is close to #FFFFFF (24-bit RGB)
- amigaGreen = 0x02, ///< Quite accurate, should be #008A00 (24-bit RGB)
- amigaOrange = 0x0C, ///< Inaccurate, too much blue, should be #FF7500 (24-bit RGB)
- amigaPurple = 0x0D, ///< Inaccurate, too much green, should be #FF00FF (24-bit RGB)
- amigaRed = 0x04, ///< Quite accurate, should be #BD0000 (24-bit RGB)
- amigaCyan = 0x0B, ///< Inaccurate, too much red, should be #00FFDE (24-bit RGB)
- // PC colors (Indexes into the EGA-palette)
- pcBlack = 0x00,
- pcWhite = 0x0F;
-
-// Public methods
-public:
- /**
- * Get the color of the button with the given state and type using current style.
- *
- * @param hasFocus True if button has focus, false otherwise.
- * @param pressed True if button is being pressed, false otherwise.
- * @param positive True if button is positive, false if button is negative. Only matters for Amiga-style buttons.
- */
- AgiTextColor getColor(bool hasFocus, bool pressed, bool positive = true) const;
-
- /**
- * Get the color of a button with the given base color and state ignoring current style.
- * Swaps foreground and background color when the button has focus or is being pressed.
- *
- * @param hasFocus True if button has focus, false otherwise.
- * @param pressed True if button is being pressed, false otherwise.
- * @param baseFgColor Foreground color of the button when it has no focus and is not being pressed.
- * @param baseBgColor Background color of the button when it has no focus and is not being pressed.
- */
- AgiTextColor getColor(bool hasFocus, bool pressed, int baseFgColor, int baseBgColor) const;
-
- /**
- * Get the color of a button with the given base color and state ignoring current style.
- * Swaps foreground and background color when the button has focus or is being pressed.
- *
- * @param hasFocus True if button has focus, false otherwise.
- * @param pressed True if button is being pressed, false otherwise.
- * @param baseColor Color of the button when it has no focus and is not being pressed.
- */
- AgiTextColor getColor(bool hasFocus, bool pressed, const AgiTextColor &baseColor) const;
-
- /**
- * How many pixels to offset the shown text diagonally down and to the right.
- * Currently only used for pressed PC-style buttons.
- */
- int getTextOffset(bool hasFocus, bool pressed) const;
-
- /**
- * Show border around the button?
- * Currently border is only used for in focus or pressed Amiga-style buttons
- * when in inauthentic Amiga-style mode.
- */
- bool getBorder(bool hasFocus, bool pressed) const;
-
- /**
- * Set Amiga-button style.
- *
- * @param amigaStyle Set Amiga-button style if true, otherwise set PC-button style.
- * @param olderAgi If true then use older AGI style in Amiga-mode, otherwise use newer.
- * @param authenticAmiga If true then don't use a border around buttons in Amiga-mode, otherwise use.
- */
- void setAmigaStyle(bool amigaStyle = true, bool olderAgi = false, bool authenticAmiga = false);
-
- /**
- * Set PC-button style.
- * @param pcStyle Set PC-button style if true, otherwise set default Amiga-button style.
- */
- void setPcStyle(bool pcStyle = true);
-
-// Public constructors
-public:
- /**
- * Create a button style based on the given rendering mode.
- * @param renderMode If Common::kRenderAmiga then creates default Amiga-button style, otherwise PC-style.
- */
- AgiButtonStyle(Common::RenderMode renderMode = Common::kRenderDefault);
-
-// Private member variables
-private:
- bool _amigaStyle; ///< Use Amiga-style buttons if true, otherwise use PC-style buttons.
- bool _olderAgi; ///< Use older AGI style in Amiga-style mode.
- bool _authenticAmiga; ///< Don't use border around buttons in Amiga-style mode.
+ bool active;
+ int16 x1, y1;
+ int16 x2, y2;
};
struct ScriptPos {
@@ -512,32 +381,19 @@ struct ScriptPos {
int curIP;
};
-enum {
- EGO_VIEW_TABLE = 0,
- HORIZON = 36,
- _WIDTH = 160,
- _HEIGHT = 168
-};
-
-enum InputMode {
- INPUT_NORMAL = 0x01,
- INPUT_GETSTRING = 0x02,
- INPUT_MENU = 0x03,
- INPUT_NONE = 0x04
-};
-
-enum State {
- STATE_INIT = 0x00,
- STATE_LOADED = 0x01,
- STATE_RUNNING = 0x02
+enum CycleInnerLoopType {
+ CYCLE_INNERLOOP_GETSTRING = 0,
+ CYCLE_INNERLOOP_GETNUMBER,
+ CYCLE_INNERLOOP_INVENTORY,
+ CYCLE_INNERLOOP_MENU_VIA_KEYBOARD,
+ CYCLE_INNERLOOP_MENU_VIA_MOUSE,
+ CYCLE_INNERLOOP_SYSTEMUI_SELECTSAVEDGAMESLOT,
+ CYCLE_INNERLOOP_SYSTEMUI_VERIFICATION,
+ CYCLE_INNERLOOP_MESSAGEBOX,
+ CYCLE_INNERLOOP_HAVEKEY
};
-enum {
- SBUF16_OFFSET = 0,
- SBUF256_OFFSET = ((_WIDTH) * (_HEIGHT)),
- FROM_SBUF16_TO_SBUF256_OFFSET = ((SBUF256_OFFSET) - (SBUF16_OFFSET)),
- FROM_SBUF256_TO_SBUF16_OFFSET = ((SBUF16_OFFSET) - (SBUF256_OFFSET))
-};
+typedef Common::Array<int16> SavedGameSlotIdArray;
/**
* AGI game structure.
@@ -547,110 +403,94 @@ enum {
struct AgiGame {
AgiEngine *_vm;
- State state; /**< state of the interpreter */
-
// TODO: Check whether adjMouseX and adjMouseY must be saved and loaded when using savegames.
// If they must be then loading and saving is partially broken at the moment.
- int adjMouseX; /**< last given adj.ego.move.to.x.y-command's 1st parameter */
- int adjMouseY; /**< last given adj.ego.move.to.x.y-command's 2nd parameter */
+ int adjMouseX; /**< last given adj.ego.move.to.x.y-command's 1st parameter */
+ int adjMouseY; /**< last given adj.ego.move.to.x.y-command's 2nd parameter */
- char name[8]; /**< lead in id (e.g. `GR' for goldrush) */
- char id[8]; /**< game id */
- uint32 crc; /**< game CRC */
+ char name[8]; /**< lead in id (e.g. `GR' for goldrush) */
+ char id[8]; /**< game id */
+ uint32 crc; /**< game CRC */
// game flags and variables
- uint8 flags[MAX_FLAGS]; /**< 256 1-bit flags */
+ uint8 flags[MAX_FLAGS]; /**< 256 1-bit flags combined into a total of 32 bytes */
uint8 vars[MAX_VARS]; /**< 256 variables */
// internal variables
- int horizon; /**< horizon y coordinate */
- int lineStatus; /**< line number to put status on */
- int lineUserInput; /**< line to put user input on */
- int lineMinPrint; /**< num lines to print on */
- int cursorPos; /**< column where the input cursor is */
- byte inputBuffer[40]; /**< buffer for user input */
- byte echoBuffer[40]; /**< buffer for echo.line */
- int keypress;
-
- InputMode inputMode; /**< keyboard input mode */
- bool inputEnabled; /**< keyboard input enabled */
- int lognum; /**< current logic number */
+ int16 horizon; /**< horizon y coordinate */
+
+ bool cycleInnerLoopActive;
+ int16 cycleInnerLoopType;
+
+ int16 curLogicNr; /**< current logic number */
Common::Array<ScriptPos> execStack;
// internal flags
- int playerControl; /**< player is in control */
- int statusLine; /**< status line on/off */
- int clockEnabled; /**< clock is on/off */
- int exitAllLogics; /**< break cycle after new.room */
- int pictureShown; /**< show.pic has been issued */
- int hasPrompt; /**< input prompt has been printed */
-#define ID_AGDS 0x00000001
-#define ID_AMIGA 0x00000002
- int gameFlags; /**< agi options flags */
-
- uint8 priTable[_HEIGHT];/**< priority table */
+ bool playerControl; /**< player is in control */
+ bool exitAllLogics; /**< break cycle after new.room */
+ bool pictureShown; /**< show.pic has been issued */
+#define ID_AGDS 0x00000001
+#define ID_AMIGA 0x00000002
+ int gameFlags; /**< agi options flags */
// windows
- uint32 msgBoxTicks; /**< timed message box tick counter */
AgiBlock block;
- AgiBlock window;
- int hasWindow;
// graphics & text
- int gfxMode;
- char cursorChar;
- unsigned int colorFg;
- unsigned int colorBg;
-
- uint8 *sbufOrig; /**< Pointer to the 160x336 AGI screen buffer that contains vertically two 160x168 screens (16 color and 256 color). */
- uint8 *sbuf16c; /**< 160x168 16 color (+control line & priority information) AGI screen buffer. Points at sbufOrig + SBUF16_OFFSET. */
- uint8 *sbuf256c; /**< 160x168 256 color AGI screen buffer (For AGI256 and AGI256-2 support). Points at sbufOrig + SBUF256_OFFSET. */
- uint8 *sbuf; /**< Currently chosen AGI screen buffer (sbuf256c if AGI256 or AGI256-2 is used, otherwise sbuf16c). */
-
- // player command line
- AgiWord egoWords[MAX_WORDS];
- int numEgoWords;
+ bool gfxMode;
unsigned int numObjects;
- bool controllerOccured[MAX_DIRS]; /**< keyboard keypress events */
- AgiController controllers[MAX_CONTROLLERS];
+ bool controllerOccured[MAX_CONTROLLERS]; /**< keyboard keypress events */
+ AgiControllerKeyMapping controllerKeyMapping[MAX_CONTROLLER_KEYMAPPINGS];
char strings[MAX_STRINGS + 1][MAX_STRINGLEN]; /**< strings */
// directory entries for resources
- AgiDir dirLogic[MAX_DIRS];
- AgiDir dirPic[MAX_DIRS];
- AgiDir dirView[MAX_DIRS];
- AgiDir dirSound[MAX_DIRS];
+ AgiDir dirLogic[MAX_DIRECTORY_ENTRIES];
+ AgiDir dirPic[MAX_DIRECTORY_ENTRIES];
+ AgiDir dirView[MAX_DIRECTORY_ENTRIES];
+ AgiDir dirSound[MAX_DIRECTORY_ENTRIES];
// resources
- AgiPicture pictures[MAX_DIRS]; /**< AGI picture resources */
- AgiLogic logics[MAX_DIRS]; /**< AGI logic resources */
- AgiView views[MAX_DIRS]; /**< AGI view resources */
- AgiSound *sounds[MAX_DIRS]; /**< Pointers to AGI sound resources */
+ AgiPicture pictures[MAX_DIRECTORY_ENTRIES]; /**< AGI picture resources */
+ AgiLogic logics[MAX_DIRECTORY_ENTRIES]; /**< AGI logic resources */
+ AgiView views[MAX_DIRECTORY_ENTRIES]; /**< AGI view resources */
+ AgiSound *sounds[MAX_DIRECTORY_ENTRIES]; /**< Pointers to AGI sound resources */
AgiLogic *_curLogic;
- // words
- Common::Array<AgiWord *> words[26];
-
// view table
- VtEntry viewTable[MAX_VIEWTABLE];
+ ScreenObjEntry screenObjTable[SCREENOBJECTS_MAX];
+
+ ScreenObjEntry addToPicView;
- int32 ver; /**< detected game version */
+ int32 ver; /**< detected game version */
- int simpleSave; /**< select simple savegames */
+ bool automaticSave; /**< set by CmdSetSimple() */
+ char automaticSaveDescription[SAVEDGAME_DESCRIPTION_LEN + 1];
- Common::Rect mouseFence; /**< rectangle set by fence.mouse command */
+ Common::Rect mouseFence; /**< rectangle set by fence.mouse command */
bool mouseEnabled; /**< if mouse is supposed to be active */
+ bool mouseHidden; /**< if mouse is currently hidden */
// IF condition handling
int testResult;
-
int max_logics;
int logic_list[256];
+
+ // used to detect situations, where the game shows some text and changes rooms right afterwards
+ // for example Space Quest 2 intro right at the start
+ // or Space Quest 2, when entering the vent also right at the start
+ // The developers assumed that loading the new room would take a bit.
+ // In ScummVM it's basically done in an instant, which means that
+ // the text would only get shown for a split second.
+ // We delay a bit as soon as such situations get detected.
+ bool nonBlockingTextShown;
+ int16 nonBlockingTextCyclesLeft;
+
+ bool automaticRestoreGame;
};
class AgiLoader {
@@ -662,8 +502,8 @@ public:
virtual int init() = 0;
virtual int deinit() = 0;
virtual int detectGame() = 0;
- virtual int loadResource(int, int) = 0;
- virtual int unloadResource(int, int) = 0;
+ virtual int loadResource(int16 resourceType, int16 resourceNr) = 0;
+ virtual int unloadResource(int16 resourceType, int16 resourceNr) = 0;
virtual int loadObjects(const char *) = 0;
virtual int loadWords(const char *) = 0;
};
@@ -684,8 +524,8 @@ public:
virtual int init();
virtual int deinit();
virtual int detectGame();
- virtual int loadResource(int, int);
- virtual int unloadResource(int, int);
+ virtual int loadResource(int16 resourceType, int16 resourceNr);
+ virtual int unloadResource(int16 resourceType, int16 resourceNr);
virtual int loadObjects(const char *);
virtual int loadWords(const char *);
};
@@ -706,8 +546,8 @@ public:
virtual int init();
virtual int deinit();
virtual int detectGame();
- virtual int loadResource(int, int);
- virtual int unloadResource(int, int);
+ virtual int loadResource(int16 resourceType, int16 resourceNr);
+ virtual int unloadResource(int16 resourceType, int16 resourceNr);
virtual int loadObjects(const char *);
virtual int loadWords(const char *);
};
@@ -728,16 +568,20 @@ public:
virtual int init();
virtual int deinit();
virtual int detectGame();
- virtual int loadResource(int, int);
- virtual int unloadResource(int, int);
+ virtual int loadResource(int16 resourceType, int16 resourceNr);
+ virtual int unloadResource(int16 resourceType, int16 resourceNr);
virtual int loadObjects(const char *);
virtual int loadWords(const char *);
};
-
+class GfxFont;
class GfxMgr;
class SpritesMgr;
-class Menu;
+class InventoryMgr;
+class TextMgr;
+class GfxMenu;
+class SystemUI;
+class Words;
// Image stack support
struct ImageStackElement {
@@ -781,15 +625,13 @@ protected:
void initRenderMode();
- const uint8 *_fontData;
-
public:
- GfxMgr *_gfx;
+ Words *_words;
+
+ GfxFont *_font;
+ GfxMgr *_gfx;
- AgiButtonStyle _defaultButtonStyle;
- AgiButtonStyle _buttonStyle;
Common::RenderMode _renderMode;
- volatile uint32 _clockCount;
AgiDebug _debug;
AgiGame _game;
Common::RandomSource *_rnd;
@@ -800,7 +642,10 @@ public:
bool _noSaveLoadAllowed;
- virtual void pollTimer() = 0;
+ virtual bool promptIsEnabled() {
+ return false;
+ }
+
virtual int getKeypress() = 0;
virtual bool isKeypress() = 0;
virtual void clearKeyQueue() = 0;
@@ -810,16 +655,16 @@ public:
virtual void clearImageStack() = 0;
virtual void recordImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3,
- int16 p4, int16 p5, int16 p6, int16 p7) = 0;
+ int16 p4, int16 p5, int16 p6, int16 p7) = 0;
virtual void replayImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3,
- int16 p4, int16 p5, int16 p6, int16 p7) = 0;
+ int16 p4, int16 p5, int16 p6, int16 p7) = 0;
virtual void releaseImageStack() = 0;
int _soundemu;
- int getflag(int);
- void setflag(int, int);
- void flipflag(int);
+ bool getFlag(int16 flagNr);
+ void setFlag(int16 flagNr, bool newState);
+ void flipFlag(int16 flagNr);
const AGIGameDescription *_gameDescription;
@@ -843,10 +688,36 @@ public:
bool canLoadGameStateCurrently();
bool canSaveGameStateCurrently();
- const uint8 *getFontData() { return _fontData; };
+ const byte *getFontData();
+
+ void cycleInnerLoopActive(int16 loopType) {
+ _game.cycleInnerLoopActive = true;
+ _game.cycleInnerLoopType = loopType;
+ };
+ void cycleInnerLoopInactive() {
+ _game.cycleInnerLoopActive = false;
+ };
+ bool cycleInnerLoopIsActive() {
+ return _game.cycleInnerLoopActive;
+ }
+};
+
+enum AgiArtificialDelayTriggerType {
+ ARTIFICIALDELAYTYPE_NEWROOM = 0,
+ ARTIFICIALDELAYTYPE_NEWPICTURE = 1,
+ ARTIFICIALDELAYTYPE_END = -1
};
-typedef void (*AgiCommand)(AgiGame *state, uint8 *p);
+struct AgiArtificialDelayEntry {
+ uint32 gameId;
+ Common::Platform platform;
+ AgiArtificialDelayTriggerType triggerType;
+ int16 orgNr;
+ int16 newNr;
+ uint16 millisecondsDelay;
+};
+
+typedef void (*AgiCommand)(AgiGame *state, AgiEngine *vm, uint8 *p);
class AgiEngine : public AgiBase {
protected:
@@ -861,67 +732,64 @@ public:
AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc);
virtual ~AgiEngine();
+ bool promptIsEnabled();
+
Common::Error loadGameState(int slot);
- Common::Error saveGameState(int slot, const Common::String &desc);
+ Common::Error saveGameState(int slot, const Common::String &description);
private:
- uint32 _lastTick;
-
int _keyQueue[KEY_QUEUE_SIZE];
int _keyQueueStart;
int _keyQueueEnd;
bool _allowSynthetic;
- int checkPriority(VtEntry *v);
- int checkCollision(VtEntry *v);
- int checkPosition(VtEntry *v);
-
- void parseFeatures();
+ bool checkPriority(ScreenObjEntry *v);
+ bool checkCollision(ScreenObjEntry *v);
+ bool checkPosition(ScreenObjEntry *v);
int _firstSlot;
public:
- AgiObject *_objects; // objects in the game
+ AgiObject *_objects; // objects in the game
StringData _stringdata;
- Common::String getSavegameFilename(int num) const;
- void getSavegameDescription(int num, char *buf, bool showEmpty = true);
- int selectSlot();
- int saveGame(const Common::String &fileName, const Common::String &saveName);
+ SavedGameSlotIdArray getSavegameSlotIds();
+ Common::String getSavegameFilename(int16 slotId) const;
+ bool getSavegameInformation(int16 slotId, Common::String &saveDescription, uint32 &saveDate, uint32 &saveTime, bool &saveIsValid);
+
+ int saveGame(const Common::String &fileName, const Common::String &descriptionString);
int loadGame(const Common::String &fileName, bool checkId = true);
- int saveGameDialog();
- int saveGameSimple();
- int loadGameDialog();
- int loadGameSimple();
+ bool saveGameDialog();
+ bool saveGameAutomatic();
+ bool loadGameDialog();
+ bool loadGameAutomatic();
int doSave(int slot, const Common::String &desc);
int doLoad(int slot, bool showMessages);
int scummVMSaveLoadDialog(bool isSave);
uint8 *_intobj;
- InputMode _oldMode;
bool _restartGame;
- Menu* _menu;
- bool _menuSelected;
-
- char _lastSentence[40];
-
SpritesMgr *_sprites;
+ TextMgr *_text;
+ InventoryMgr *_inventory;
PictureMgr *_picture;
- AgiLoader *_loader; // loader
+ AgiLoader *_loader; // loader
+ GfxMenu *_menu;
+ SystemUI *_systemUI;
Common::Stack<ImageStackElement> _imageStack;
void clearImageStack();
void recordImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3,
- int16 p4, int16 p5, int16 p6, int16 p7);
+ int16 p4, int16 p5, int16 p6, int16 p7);
void replayImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3,
- int16 p4, int16 p5, int16 p6, int16 p7);
+ int16 p4, int16 p5, int16 p6, int16 p7);
void releaseImageStack();
- void pause(uint32 msec);
+ void wait(uint32 msec, bool busy = false);
Console *_console;
GUI::Debugger *getDebugger() { return _console; }
@@ -929,46 +797,42 @@ public:
int agiInit();
int agiDeinit();
int agiDetectGame();
- int agiLoadResource(int, int);
- int agiUnloadResource(int, int);
+ int agiLoadResource(int16 resourceType, int16 resourceNr);
+ int agiUnloadResource(int16 resourceType, int16 resourceNr);
void agiUnloadResources();
- virtual void pollTimer();
virtual int getKeypress();
virtual bool isKeypress();
virtual void clearKeyQueue();
- void initPriTable();
+ byte getVar(int16 varNr);
+ void setVar(int16 varNr, byte newValue);
+
+private:
+ void setVolumeViaScripts(byte newVolume);
+ void setVolumeViaSystemSetting();
- void newInputMode(InputMode mode);
- void oldInputMode();
+public:
+ void syncSoundSettings();
- int getvar(int);
- void setvar(int, int);
+public:
void decrypt(uint8 *mem, int len);
void releaseSprites();
- int mainCycle(bool onlyCheckForEvents = false);
+ uint16 processAGIEvents();
int viewPictures();
int runGame();
- void inventory();
- void updateTimer();
int getAppDir(char *appDir, unsigned int size);
int setupV2Game(int ver);
int setupV3Game(int ver);
- void newRoom(int n);
+ void newRoom(int16 newRoomNr);
void resetControllers();
void interpretCycle();
int playGame();
- void printItem(int n, int fg, int bg);
- int findItem();
- int showItems();
- void selectItems(int n);
-
void allowSynthetic(bool);
- void processEvents();
+ void processScummVMEvents();
void checkQuickLoad();
// Objects
@@ -977,9 +841,9 @@ public:
int loadObjects(const char *fname);
int loadObjects(Common::File &fp);
void unloadObjects();
- const char *objectName(unsigned int);
- int objectGetLocation(unsigned int);
- void objectSetLocation(unsigned int, int);
+ const char *objectName(uint16 objectNr);
+ int objectGetLocation(uint16 objectNr);
+ void objectSetLocation(uint16 objectNr, int);
private:
int decodeObjects(uint8 *mem, uint32 flen);
int readObjects(Common::File &fp, int flen);
@@ -987,13 +851,28 @@ private:
// Logic
public:
- int decodeLogic(int);
- void unloadLogic(int);
- int runLogic(int);
+ int decodeLogic(int16 logicNr);
+ void unloadLogic(int16 logicNr);
+ int runLogic(int16 logicNr);
void debugConsole(int, int, const char *);
int testIfCode(int);
void executeAgiCommand(uint8, uint8 *);
+private:
+ bool _veryFirstInitialCycle; /**< signals, that currently the very first cycle is executed (restarts, etc. do not count!) */
+ uint32 _instructionCounter; /**< counts every instruction, that got executed, can wrap around */
+
+ bool _setVolumeBrokenFangame;
+
+ void resetGetVarSecondsHeuristic();
+ void getVarSecondsHeuristicTrigger();
+ uint32 _getVarSecondsHeuristicLastInstructionCounter; /**< last time VM_VAR_SECONDS were read */
+ uint16 _getVarSecondsHeuristicCounter; /**< how many times heuristic was triggered */
+
+ uint32 _playTimeInSecondsAdjust; /**< milliseconds to adjust for calculating current play time in seconds, see setVarSecondsTrigger() */
+
+ void setVarSecondsTrigger(byte newSeconds);
+
public:
// Some submethods of testIfCode
void skipInstruction(byte op);
@@ -1004,110 +883,112 @@ public:
uint8 testPosn(uint8, uint8, uint8, uint8, uint8);
uint8 testSaid(uint8, uint8 *);
uint8 testController(uint8);
- uint8 testKeypressed();
uint8 testCompareStrings(uint8, uint8);
// View
private:
- void lSetCel(VtEntry *v, int n);
- void lSetLoop(VtEntry *v, int n);
- void updateView(VtEntry *v);
+ void lSetLoop(ScreenObjEntry *screenObj, int16 loopNr);
+ void updateView(ScreenObjEntry *screenObj);
public:
+ void setView(ScreenObjEntry *screenObj, int16 viewNr);
+ void setLoop(ScreenObjEntry *screenObj, int16 loopNr);
+ void setCel(ScreenObjEntry *screenObj, int16 celNr);
- void setCel(VtEntry *, int);
- void clipViewCoordinates(VtEntry *v);
- void setLoop(VtEntry *, int);
- void setView(VtEntry *, int);
- void startUpdate(VtEntry *);
- void stopUpdate(VtEntry *);
- void updateViewtable();
- void unloadView(int);
- int decodeView(int);
- void addToPic(int, int, int, int, int, int, int);
- void drawObj(int);
- bool isEgoView(const VtEntry *v);
+ void clipViewCoordinates(ScreenObjEntry *screenObj);
+
+ void startUpdate(ScreenObjEntry *);
+ void stopUpdate(ScreenObjEntry *);
+ void updateScreenObjTable();
+ void unloadView(int16 viewNr);
+ int decodeView(byte *resourceData, uint16 resourceSize, int16 viewNr);
+
+private:
+ void unpackViewCelData(AgiViewCel *celData, byte *compressedData, uint16 compressedSize);
+ void unpackViewCelDataAGI256(AgiViewCel *celData, byte *compressedData, uint16 compressedSize);
- // Words
public:
- int showWords();
- int loadWords(const char *);
- int loadWords_v1(Common::File &f);
- void unloadWords();
- int findWord(const char *word, int *flen);
- void dictionaryWords(char *);
+ void addToPic(int, int, int, int, int, int, int);
+ void drawObj(int);
+ bool isEgoView(const ScreenObjEntry *screenObj);
// Motion
private:
int checkStep(int delta, int step);
- int checkBlock(int x, int y);
- void changePos(VtEntry *v);
- void motionWander(VtEntry *v);
- void motionFollowEgo(VtEntry *v);
- void motionMoveObj(VtEntry *v);
- void checkMotion(VtEntry *v);
+ bool checkBlock(int16 x, int16 y);
+ void changePos(ScreenObjEntry *screenObj);
+ void motionWander(ScreenObjEntry *screenObj);
+ void motionFollowEgo(ScreenObjEntry *screenObj);
+ void motionMoveObj(ScreenObjEntry *screenObj);
+ void motionMoveObjStop(ScreenObjEntry *screenObj);
+ void checkMotion(ScreenObjEntry *screenObj);
public:
+ void motionActivated(ScreenObjEntry *screenObj);
+ void cyclerActivated(ScreenObjEntry *screenObj);
void checkAllMotions();
- void moveObj(VtEntry *);
- void inDestination(VtEntry *);
- void fixPosition(int);
+ void moveObj(ScreenObjEntry *screenObj);
+ void inDestination(ScreenObjEntry *screenObj);
+ void fixPosition(int16 screenObjNr);
+ void fixPosition(ScreenObjEntry *screenObj);
void updatePosition();
- int getDirection(int x0, int y0, int x, int y, int s);
+ int getDirection(int16 objX, int16 objY, int16 destX, int16 destY, int16 stepSize);
- bool _egoHoldKey;
+ bool _keyHoldMode;
// Keyboard
- void initWords();
- void cleanInput();
int doPollKeyboard();
void cleanKeyboard();
- void handleKeys(int);
- void handleGetstring(int);
- int handleController(int);
- void getString(int, int, int, int);
+
+ bool handleMouseClicks(uint16 &key);
+ bool handleController(uint16 key);
+
+ bool showPredictiveDialog();
+
uint16 agiGetKeypress();
int waitKey();
int waitAnyKey();
- // Text
-public:
- int messageBox(const char *);
- int selectionBox(const char *, const char **);
- void closeWindow();
- void drawWindow(int, int, int, int);
- void printText(const char *, int, int, int, int, int, int, bool checkerboard = false);
- void printTextConsole(const char *, int, int, int, int, int);
- int print(const char *, int, int, int);
- char *wordWrapString(const char *, int *);
- char *agiSprintf(const char *);
- void writeStatus();
- void writePrompt();
- void clearPrompt(bool useBlackBg = false);
- void clearLines(int, int, int);
- void flushLines(int, int);
+ void nonBlockingText_IsShown();
+ void nonBlockingText_Forget();
+
+ void artificialDelay_Reset();
+ void artificialDelay_CycleDone();
+
+ uint16 artificialDelay_SearchTable(AgiArtificialDelayTriggerType triggerType, int16 orgNr, int16 newNr);
+
+ void artificialDelayTrigger_NewRoom(int16 newRoomNr);
+ void artificialDelayTrigger_DrawPicture(int16 newPictureNr);
private:
- void printStatus(const char *message, ...) GCC_PRINTF(2, 3);
- void printText2(int l, const char *msg, int foff, int xoff, int yoff, int len, int fg, int bg, bool checkerboard = false);
- void blitTextbox(const char *p, int y, int x, int len);
- void eraseTextbox();
- bool matchWord();
+ int16 _artificialDelayCurrentRoom;
+ int16 _artificialDelayCurrentPicture;
public:
- char _predictiveResult[40];
+ void redrawScreen();
+
+ void inGameTimerReset(uint32 newPlayTime = 0);
+ void inGameTimerResetPassedCycles();
+ void inGameTimerPause();
+ void inGameTimerResume();
+ uint32 inGameTimerGet();
+ uint32 inGameTimerGetPassedCycles();
+
+ void inGameTimerUpdate();
+
+private:
+ uint32 _lastUsedPlayTimeInCycles; // 20 per second
+ uint32 _lastUsedPlayTimeInSeconds; // actual seconds
+ uint32 _passedPlayTimeCycles; // increased by 1 every time we passed a cycle
private:
AgiCommand _agiCommands[183];
AgiCommand _agiCondCommands[256];
void setupOpcodes();
-
-public:
- int _timerHack; // Workaround for timer loop in MH1 logic 153
};
} // End of namespace Agi
-#endif /* AGI_H */
+#endif /* AGI_AGI_H */
diff --git a/engines/agi/appleIIgs_timedelay_overwrite.h b/engines/agi/appleIIgs_timedelay_overwrite.h
new file mode 100644
index 0000000000..c24d7cb5bd
--- /dev/null
+++ b/engines/agi/appleIIgs_timedelay_overwrite.h
@@ -0,0 +1,91 @@
+/* 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 AGI_APPLEIIGS_DELAY_OVERWRITE_H
+#define AGI_APPLEIIGS_DELAY_OVERWRITE_H
+
+namespace Agi {
+
+struct AgiAppleIIgsDelayOverwriteRoomEntry {
+ int16 fromRoom;
+ int16 toRoom;
+ int16 timeDelayOverwrite; // time delay here is like on PC, so 0 - unlimited, 1 - 20 cycles, 2 - 10 cycles
+ bool onlyWhenPlayerNotInControl;
+};
+
+struct AgiAppleIIgsDelayOverwriteGameEntry {
+ uint32 gameId;
+ int16 defaultTimeDelayOverwrite; // time delay here is like on PC, so 0 - unlimited, 1 - 20 cycles, 2 - 10 cycles
+ const AgiAppleIIgsDelayOverwriteRoomEntry *roomTable;
+};
+
+static const AgiAppleIIgsDelayOverwriteRoomEntry appleIIgsDelayOverwriteKQ4[] = {
+ { 120, 121, -1, true }, // Part of the intro: Graham gets his hat, throws it and breaks down, don't touch speed (3 is set)
+ { 128, 128, -1, true }, // Part of the intro: first actual room for gameplay, but during intro, don't touch speed (3 is set)
+ { 92, 92, -1, true }, // Part of caught by gargoyle w/ Lolotte cutscene (3 is set)
+ // room 54 sets the speed for a short time to 3 right after entering "clean" command. It doesn't seem to hurt that we switch it down to 2
+ // room 92 is dual use, part of cutscenes, part of gameplay, that's why we only stop touching it, when player is not in control
+ { 135, 135, -1, true }, // Part of ending cutscene. Don't touch speed (3 is set)
+ { -1, -1, -1, false }
+};
+
+static const AgiAppleIIgsDelayOverwriteRoomEntry appleIIgsDelayOverwriteMH1[] = {
+ //{ 153, 153, 2, false }, // Intro w/ credits
+ //{ 104, 104, 2, false }, // Intro cutscene
+ //{ 117, 117, 2, false }, // Intro cutscene (ego waking up)
+ { 114, 114, -1, false }, // interactive MAD map
+ { 124, 125, -1, false }, // MAD during intro (tracking), seem to work properly at given speed
+ { 132, 133, -1, false }, // MAD day 2 intro (tracking)
+ { 137, 137, -1, false }, // Night Club 4th arcade game - game sets speed to 7
+ { 115, 116, -1, false }, // MAD day 3 intro (tracking)
+ { 148, 148, -1, false }, // day 3: arcade sequence under pawn shop (game sets speed to 6)
+ { 103, 103, -1, false }, // MAD day 4 intro (tracking)
+ { 105, 105, -1, false }, // day 4 tracking mini game right at the start (game sets speed to 3)
+ { 107, 107, -1, false }, // MAD day 4 intro (tracking)
+ { 112, 112, -1, false }, // MAD day 4 intro (tracking)
+ { -1, -1, -1, false }
+};
+
+static const AgiAppleIIgsDelayOverwriteRoomEntry appleIIgsDelayOverwriteSQ2[] = {
+ { 1, 1, -1, false }, // Intro: space ship entering space port, don't touch speed
+ { -1, -1, -1, false }
+};
+
+static const AgiAppleIIgsDelayOverwriteGameEntry appleIIgsDelayOverwriteGameTable[] = {
+ { GID_BC, 2, nullptr }, // sets the speed at the start and doesn't modify it
+ { GID_GOLDRUSH, 2, nullptr },
+ { GID_KQ1, 2, nullptr },
+ // KQ2 seems to work fine at speed given by scripts
+ { GID_KQ3, 2, nullptr },
+ { GID_KQ4, 2, appleIIgsDelayOverwriteKQ4 },
+ { GID_LSL1, 2, nullptr }, // Switch Larry 1 to 10 cycles per second (that's around PC Larry 1's "normal" speed
+ { GID_MH1, 2, appleIIgsDelayOverwriteMH1 },
+ { GID_MIXEDUP, 2, nullptr },
+ { GID_PQ1, 2, nullptr },
+ { GID_SQ1, 2, nullptr }, // completed, no issues using these settings
+ { GID_SQ2, 2, appleIIgsDelayOverwriteSQ2 },
+ { GID_AGIDEMO, -1, nullptr }
+};
+
+} // End of namespace Agi
+
+#endif /* AGI_APPLEIIGS_DELAY_OVERWRITE_H */
diff --git a/engines/agi/checks.cpp b/engines/agi/checks.cpp
index e61146e901..c67b6a5810 100644
--- a/engines/agi/checks.cpp
+++ b/engines/agi/checks.cpp
@@ -21,159 +21,153 @@
*/
#include "agi/agi.h"
+#include "agi/graphics.h"
namespace Agi {
-int AgiEngine::checkPosition(VtEntry *v) {
- debugC(4, kDebugLevelSprites, "check position @ %d, %d", v->xPos, v->yPos);
-
- if (v->xPos < 0 ||
- v->xPos + v->xSize > _WIDTH ||
- v->yPos - v->ySize + 1 < 0 ||
- v->yPos >= _HEIGHT ||
- ((~v->flags & fIgnoreHorizon) && v->yPos <= _game.horizon)) {
- debugC(4, kDebugLevelSprites, "check position failed: x=%d, y=%d, h=%d, w=%d",
- v->xPos, v->yPos, v->xSize, v->ySize);
- return 0;
+bool AgiEngine::checkPosition(ScreenObjEntry *screenObj) {
+ bool result = true; // position is fine
+ debugC(4, kDebugLevelSprites, "check position @ %d, %d", screenObj->xPos, screenObj->yPos);
+
+ if (screenObj->xPos < 0) {
+ result = false;
+ } else {
+ if (screenObj->xPos + screenObj->xSize > SCRIPT_WIDTH) {
+ result = false;
+ } else {
+ if (screenObj->yPos - screenObj->ySize < -1) {
+ result = false;
+ } else {
+ if (screenObj->yPos >= SCRIPT_HEIGHT) {
+ result = false;
+ } else {
+ if (((!(screenObj->flags & fIgnoreHorizon)) && screenObj->yPos <= _game.horizon)) {
+ result = false;
+ }
+ }
+ }
+ }
}
// MH1 needs this, but it breaks LSL1
- if (getVersion() >= 0x3000) {
- if (v->yPos < v->ySize)
- return 0;
- }
+// TODO: *NOT* in disassembly of AGI3 .149, why was this needed?
+// if (getVersion() >= 0x3000) {
+// if (screenObj->yPos < screenObj->ySize)
+// result = false;
+// }
- return 1;
+ if (!result) {
+ debugC(4, kDebugLevelSprites, "check position failed: x=%d, y=%d, h=%d, w=%d",
+ screenObj->xPos, screenObj->yPos, screenObj->xSize, screenObj->ySize);
+ }
+ return result;
}
/**
* Check if there's another object on the way
*/
-int AgiEngine::checkCollision(VtEntry *v) {
- VtEntry *u;
+bool AgiEngine::checkCollision(ScreenObjEntry *screenObj) {
+ ScreenObjEntry *checkObj;
- if (v->flags & fIgnoreObjects)
- return 0;
+ if (screenObj->flags & fIgnoreObjects)
+ return false;
- for (u = _game.viewTable; u < &_game.viewTable[MAX_VIEWTABLE]; u++) {
- if ((u->flags & (fAnimated | fDrawn)) != (fAnimated | fDrawn))
+ for (checkObj = _game.screenObjTable; checkObj < &_game.screenObjTable[SCREENOBJECTS_MAX]; checkObj++) {
+ if ((checkObj->flags & (fAnimated | fDrawn)) != (fAnimated | fDrawn))
continue;
- if (u->flags & fIgnoreObjects)
+ if (checkObj->flags & fIgnoreObjects)
continue;
// Same object, check next
- if (v->entry == u->entry)
+ if (screenObj->objectNr == checkObj->objectNr)
continue;
// No horizontal overlap, check next
- if (v->xPos + v->xSize < u->xPos || v->xPos > u->xPos + u->xSize)
+ if (screenObj->xPos + screenObj->xSize < checkObj->xPos || screenObj->xPos > checkObj->xPos + checkObj->xSize)
continue;
// Same y, return error!
- if (v->yPos == u->yPos) {
- debugC(4, kDebugLevelSprites, "check returns 1 (object %d)", v->entry);
- return 1;
+ if (screenObj->yPos == checkObj->yPos) {
+ debugC(4, kDebugLevelSprites, "check returns 1 (object %d)", screenObj->objectNr);
+ return true;
}
// Crossed the baseline, return error!
- if ((v->yPos > u->yPos && v->yPos2 < u->yPos2) ||
- (v->yPos < u->yPos && v->yPos2 > u->yPos2)) {
- debugC(4, kDebugLevelSprites, "check returns 1 (object %d)", v->entry);
- return 1;
+ if ((screenObj->yPos > checkObj->yPos && screenObj->yPos_prev < checkObj->yPos_prev) ||
+ (screenObj->yPos < checkObj->yPos && screenObj->yPos_prev > checkObj->yPos_prev)) {
+ debugC(4, kDebugLevelSprites, "check returns 1 (object %d)", screenObj->objectNr);
+ return true;
}
}
- return 0;
-
+ return false;
}
-int AgiEngine::checkPriority(VtEntry *v) {
- int i, trigger, water, pass, pri;
- uint8 *p0;
+bool AgiEngine::checkPriority(ScreenObjEntry *screenObj) {
+ bool touchedWater = false;
+ bool touchedTrigger = false;
+ bool touchedControl = true;
+ int16 curX;
+ int16 curY;
+ int16 celX;
+ byte screenPriority = 0;
- if (~v->flags & fFixedPriority) {
+ if (!(screenObj->flags & fFixedPriority)) {
// Priority bands
- v->priority = _game.priTable[v->yPos];
+ screenObj->priority = _gfx->priorityFromY(screenObj->yPos);
}
- trigger = 0;
- water = 0;
- pass = 1;
+ if (screenObj->priority != 0x0f) {
- if (v->priority == 0x0f) {
- // Check ego
- if (v->entry == 0) {
- setflag(fEgoTouchedP2, trigger ? true : false);
- setflag(fEgoWater, water ? true : false);
- }
-
- return pass;
- }
-
- water = 1;
-
- // Check if any picture is loaded before checking for priority below.
- // If no picture has been loaded, the priority buffer won't be initialized,
- // thus the check below will always fail. This case causes an infinite loop
- // in the fanmade game Nick's Quest (bug #3451122), as the game attempts to
- // draw a sprite (view 4, floating Nick) before it loads any picture. This
- // causes the checks below to always fail, and the engine keeps readjusting
- // the sprite's position in fixPosition() forever, as there is no valid
- // position to place it (the default visual and priority screen is set to
- // zero, i.e. unconditional black). To remedy this situation, we always
- // return true here if no picture has been loaded and no priority screen
- // has been set up.
- if (!_game._vm->_picture->isPictureLoaded()) {
- warning("checkPriority: no picture loaded");
- return pass;
- }
-
- p0 = &_game.sbuf16c[v->xPos + v->yPos * _WIDTH];
-
- for (i = 0; i < v->xSize; i++, p0++) {
- pri = *p0 >> 4;
-
- if (pri == 0) { // unconditional black. no go at all!
- pass = 0;
- break;
- }
+ touchedWater = true;
- if (pri == 3) // water surface
- continue;
+ curX = screenObj->xPos;
+ curY = screenObj->yPos;
- water = 0;
+ for (celX = 0; celX < screenObj->xSize; celX++, curX++) {
+ screenPriority = _gfx->getPriority(curX, curY);
- if (pri == 1) { // conditional blue
- if (v->flags & fIgnoreBlocks)
- continue;
+ if (screenPriority == 0) { // unconditional black. no go at all!
+ touchedControl = false;
+ break;
+ }
- debugC(4, kDebugLevelSprites, "Blocks observed!");
- pass = 0;
- break;
+ if (screenPriority != 3) { // not water surface
+ touchedWater = false;
+
+ if (screenPriority == 1) { // conditional blue
+ if (!(screenObj->flags & fIgnoreBlocks)) {
+ debugC(4, kDebugLevelSprites, "Blocks observed!");
+ touchedControl = false;
+ break;
+ }
+ } else if (screenPriority == 2) {
+ debugC(4, kDebugLevelSprites, "stepped on trigger");
+ if (!_debug.ignoretriggers)
+ touchedTrigger = true;
+ }
+ }
}
- if (pri == 2) { // trigger
- debugC(4, kDebugLevelSprites, "stepped on trigger");
- if (!_debug.ignoretriggers)
- trigger = 1;
+ if (touchedControl) {
+ if (!touchedWater) {
+ if (screenObj->flags & fOnWater)
+ touchedControl = false;
+ } else {
+ if (screenObj->flags & fOnLand)
+ touchedControl = false;
+ }
}
}
- if (pass) {
- if (!water && v->flags & fOnWater)
- pass = 0;
- if (water && v->flags & fOnLand)
- pass = 0;
- }
-
// Check ego
- if (v->entry == 0) {
- setflag(fEgoTouchedP2, trigger ? true : false);
- setflag(fEgoWater, water ? true : false);
+ if (screenObj->objectNr == 0) {
+ setFlag(VM_FLAG_EGO_TOUCHED_P2, touchedTrigger ? true : false);
+ setFlag(VM_FLAG_EGO_WATER, touchedWater ? true : false);
}
- return pass;
+ return touchedControl;
}
/*
@@ -188,91 +182,106 @@ int AgiEngine::checkPriority(VtEntry *v) {
* rules, otherwise the previous position will be kept.
*/
void AgiEngine::updatePosition() {
- VtEntry *v;
+ ScreenObjEntry *screenObj;
int x, y, oldX, oldY, border;
- _game.vars[vBorderCode] = 0;
- _game.vars[vBorderTouchEgo] = 0;
- _game.vars[vBorderTouchObj] = 0;
+ setVar(VM_VAR_BORDER_CODE, 0);
+ setVar(VM_VAR_BORDER_TOUCH_EGO, 0);
+ setVar(VM_VAR_BORDER_TOUCH_OBJECT, 0);
- for (v = _game.viewTable; v < &_game.viewTable[MAX_VIEWTABLE]; v++) {
- if ((v->flags & (fAnimated | fUpdate | fDrawn)) != (fAnimated | fUpdate | fDrawn)) {
+ for (screenObj = _game.screenObjTable; screenObj < &_game.screenObjTable[SCREENOBJECTS_MAX]; screenObj++) {
+ if ((screenObj->flags & (fAnimated | fUpdate | fDrawn)) != (fAnimated | fUpdate | fDrawn)) {
continue;
}
- if (v->stepTimeCount != 0) {
- if (--v->stepTimeCount != 0)
- continue;
+ if (screenObj->stepTimeCount > 1) {
+ screenObj->stepTimeCount--;
+ continue;
}
- v->stepTimeCount = v->stepTime;
+ screenObj->stepTimeCount = screenObj->stepTime;
- x = oldX = v->xPos;
- y = oldY = v->yPos;
+ x = oldX = screenObj->xPos;
+ y = oldY = screenObj->yPos;
// If object has moved, update its position
- if (~v->flags & fUpdatePos) {
+ if (!(screenObj->flags & fUpdatePos)) {
int dx[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 };
int dy[9] = { 0, -1, -1, 0, 1, 1, 1, 0, -1 };
- x += v->stepSize * dx[v->direction];
- y += v->stepSize * dy[v->direction];
+ x += screenObj->stepSize * dx[screenObj->direction];
+ y += screenObj->stepSize * dy[screenObj->direction];
}
// Now check if it touched the borders
border = 0;
// Check left/right borders
- if (x < 0) {
- x = 0;
- border = 4;
- } else if (x <= 0 && getVersion() == 0x3086) { // KQ4
- x = 0; // See Sarien bug #590462
- border = 4;
- } else if (v->entry == 0 && x == 0 && v->flags & fAdjEgoXY) {
- // Extra test to walk west clicking the mouse
- x = 0;
- border = 4;
- } else if (x + v->xSize > _WIDTH) {
- x = _WIDTH - v->xSize;
- border = 2;
+ if (getVersion() == 0x3086) {
+ // KQ4 interpreter does a different comparison on x
+ // The interpreter before (2.917) and after that (3.098) don't do them that way
+ // This difference is required for at least Sarien bug #192
+ // KQ4: room 135, hen moves from the center of the screen to the left border,
+ // but it doesn't disappear.
+ if (x <= 0) {
+ x = 0;
+ border = 4;
+ }
+ } else {
+ // regular comparison
+ if (x < 0) {
+ x = 0;
+ border = 4;
+ }
+ }
+
+// } else if (v->entry == 0 && x == 0 && v->flags & fAdjEgoXY) { // should not be required
+// // Extra test to walk west clicking the mouse
+// x = 0;
+// border = 4;
+
+ if (!border) {
+ if (x + screenObj->xSize > SCRIPT_WIDTH) {
+ x = SCRIPT_WIDTH - screenObj->xSize;
+ border = 2;
+ }
}
// Check top/bottom borders.
- if (y - v->ySize + 1 < 0) {
- y = v->ySize - 1;
+ if (y - screenObj->ySize < -1) {
+ y = screenObj->ySize - 1;
border = 1;
- } else if (y > _HEIGHT - 1) {
- y = _HEIGHT - 1;
+ } else if (y > SCRIPT_HEIGHT - 1) {
+ y = SCRIPT_HEIGHT - 1;
border = 3;
- } else if ((~v->flags & fIgnoreHorizon) && y <= _game.horizon) {
+ } else if ((!(screenObj->flags & fIgnoreHorizon)) && y <= _game.horizon) {
debugC(4, kDebugLevelSprites, "y = %d, horizon = %d", y, _game.horizon);
y = _game.horizon + 1;
border = 1;
}
// Test new position. rollback if test fails
- v->xPos = x;
- v->yPos = y;
- if (checkCollision(v) || !checkPriority(v)) {
- v->xPos = oldX;
- v->yPos = oldY;
+ screenObj->xPos = x;
+ screenObj->yPos = y;
+ if (checkCollision(screenObj) || !checkPriority(screenObj)) {
+ screenObj->xPos = oldX;
+ screenObj->yPos = oldY;
border = 0;
- fixPosition(v->entry);
+ fixPosition(screenObj->objectNr);
}
- if (border != 0) {
- if (isEgoView(v)) {
- _game.vars[vBorderTouchEgo] = border;
+ if (border) {
+ if (isEgoView(screenObj)) {
+ setVar(VM_VAR_BORDER_TOUCH_EGO, border);
} else {
- _game.vars[vBorderCode] = v->entry;
- _game.vars[vBorderTouchObj] = border;
+ setVar(VM_VAR_BORDER_CODE, screenObj->objectNr);
+ setVar(VM_VAR_BORDER_TOUCH_OBJECT, border);
}
- if (v->motion == kMotionMoveObj) {
- inDestination(v);
+ if (screenObj->motionType == kMotionMoveObj) {
+ motionMoveObjStop(screenObj);
}
}
- v->flags &= ~fUpdatePos;
+ screenObj->flags &= ~fUpdatePos;
}
}
@@ -285,42 +294,46 @@ void AgiEngine::updatePosition() {
*
* @param n view table entry number
*/
-void AgiEngine::fixPosition(int n) {
- VtEntry *v = &_game.viewTable[n];
+void AgiEngine::fixPosition(int16 screenObjNr) {
+ ScreenObjEntry *screenObj = &_game.screenObjTable[screenObjNr];
+ fixPosition(screenObj);
+}
+
+void AgiEngine::fixPosition(ScreenObjEntry *screenObj) {
int count, dir, size;
- debugC(4, kDebugLevelSprites, "adjusting view table entry #%d (%d,%d)", n, v->xPos, v->yPos);
+ debugC(4, kDebugLevelSprites, "adjusting view table entry #%d (%d,%d)", screenObj->objectNr, screenObj->xPos, screenObj->yPos);
// test horizon
- if ((~v->flags & fIgnoreHorizon) && v->yPos <= _game.horizon)
- v->yPos = _game.horizon + 1;
+ if ((!(screenObj->flags & fIgnoreHorizon)) && screenObj->yPos <= _game.horizon)
+ screenObj->yPos = _game.horizon + 1;
dir = 0;
count = size = 1;
- while (!checkPosition(v) || checkCollision(v) || !checkPriority(v)) {
+ while (!checkPosition(screenObj) || checkCollision(screenObj) || !checkPriority(screenObj)) {
switch (dir) {
- case 0: // west
- v->xPos--;
+ case 0: // west
+ screenObj->xPos--;
if (--count)
continue;
dir = 1;
break;
- case 1: // south
- v->yPos++;
+ case 1: // south
+ screenObj->yPos++;
if (--count)
continue;
dir = 2;
size++;
break;
- case 2: // east
- v->xPos++;
+ case 2: // east
+ screenObj->xPos++;
if (--count)
continue;
dir = 3;
break;
- case 3: // north
- v->yPos--;
+ case 3: // north
+ screenObj->yPos--;
if (--count)
continue;
dir = 0;
@@ -331,7 +344,7 @@ void AgiEngine::fixPosition(int n) {
count = size;
}
- debugC(4, kDebugLevelSprites, "view table entry #%d position adjusted to (%d,%d)", n, v->xPos, v->yPos);
+ debugC(4, kDebugLevelSprites, "view table entry #%d position adjusted to (%d,%d)", screenObj->objectNr, screenObj->xPos, screenObj->yPos);
}
} // End of namespace Agi
diff --git a/engines/agi/console.cpp b/engines/agi/console.cpp
index 6d7f9384cd..9a4a357b44 100644
--- a/engines/agi/console.cpp
+++ b/engines/agi/console.cpp
@@ -22,6 +22,7 @@
#include "agi/agi.h"
#include "agi/opcodes.h"
+#include "agi/graphics.h"
#include "agi/preagi.h"
#include "agi/preagi_mickey.h"
@@ -32,22 +33,28 @@ namespace Agi {
Console::Console(AgiEngine *vm) : GUI::Debugger() {
_vm = vm;
- registerCmd("debug", WRAP_METHOD(Console, Cmd_Debug));
- registerCmd("cont", WRAP_METHOD(Console, Cmd_Cont));
- registerCmd("agiver", WRAP_METHOD(Console, Cmd_Agiver));
- registerCmd("flags", WRAP_METHOD(Console, Cmd_Flags));
- registerCmd("logic0", WRAP_METHOD(Console, Cmd_Logic0));
- registerCmd("objs", WRAP_METHOD(Console, Cmd_Objs));
- registerCmd("runopcode", WRAP_METHOD(Console, Cmd_RunOpcode));
- registerCmd("opcode", WRAP_METHOD(Console, Cmd_Opcode));
- registerCmd("step", WRAP_METHOD(Console, Cmd_Step));
- registerCmd("trigger", WRAP_METHOD(Console, Cmd_Trigger));
- registerCmd("vars", WRAP_METHOD(Console, Cmd_Vars));
- registerCmd("setvar", WRAP_METHOD(Console, Cmd_SetVar));
- registerCmd("setflag", WRAP_METHOD(Console, Cmd_SetFlag));
- registerCmd("setobj", WRAP_METHOD(Console, Cmd_SetObj));
- registerCmd("room", WRAP_METHOD(Console, Cmd_Room));
- registerCmd("bt", WRAP_METHOD(Console, Cmd_BT));
+ registerCmd("debug", WRAP_METHOD(Console, Cmd_Debug));
+ registerCmd("cont", WRAP_METHOD(Console, Cmd_Cont));
+ registerCmd("agiver", WRAP_METHOD(Console, Cmd_Agiver));
+ registerCmd("version", WRAP_METHOD(Console, Cmd_Version));
+ registerCmd("flags", WRAP_METHOD(Console, Cmd_Flags));
+ registerCmd("logic0", WRAP_METHOD(Console, Cmd_Logic0));
+ registerCmd("objs", WRAP_METHOD(Console, Cmd_Objs));
+ registerCmd("runopcode", WRAP_METHOD(Console, Cmd_RunOpcode));
+ registerCmd("opcode", WRAP_METHOD(Console, Cmd_Opcode));
+ registerCmd("step", WRAP_METHOD(Console, Cmd_Step));
+ registerCmd("trigger", WRAP_METHOD(Console, Cmd_Trigger));
+ registerCmd("vars", WRAP_METHOD(Console, Cmd_Vars));
+ registerCmd("setvar", WRAP_METHOD(Console, Cmd_SetVar));
+ registerCmd("setflag", WRAP_METHOD(Console, Cmd_SetFlag));
+ registerCmd("setobj", WRAP_METHOD(Console, Cmd_SetObj));
+ registerCmd("room", WRAP_METHOD(Console, Cmd_Room));
+ registerCmd("bt", WRAP_METHOD(Console, Cmd_BT));
+ registerCmd("show_map", WRAP_METHOD(Console, Cmd_ShowMap));
+ registerCmd("screenobj", WRAP_METHOD(Console, Cmd_ScreenObj));
+ registerCmd("vmvars", WRAP_METHOD(Console, Cmd_VmVars));
+ registerCmd("vmflags", WRAP_METHOD(Console, Cmd_VmFlags));
+ registerCmd("disableautosave", WRAP_METHOD(Console, Cmd_DisableAutomaticSave));
}
bool Console::Cmd_SetVar(int argc, const char **argv) {
@@ -57,7 +64,7 @@ bool Console::Cmd_SetVar(int argc, const char **argv) {
}
int p1 = (int)atoi(argv[1]);
int p2 = (int)atoi(argv[2]);
- _vm->setvar(p1, p2);
+ _vm->setVar(p1, p2);
return true;
}
@@ -69,7 +76,7 @@ bool Console::Cmd_SetFlag(int argc, const char **argv) {
}
int p1 = (int)atoi(argv[1]);
int p2 = (int)atoi(argv[2]);
- _vm->setflag(p1, !!p2);
+ _vm->setFlag(p1, !!p2);
return true;
}
@@ -125,11 +132,154 @@ bool Console::Cmd_Agiver(int argc, const char **argv) {
maj = (ver >> 12) & 0xf;
min = ver & 0xfff;
+ debugPrintf("AGI version: ");
debugPrintf(maj <= 2 ? "%x.%03x\n" : "%x.002.%03x\n", maj, min);
return true;
}
+#define CONSOLE_VERSION_MAXLEN 10
+
+bool Console::Cmd_Version(int argc, const char **argv) {
+ AgiGame *game = &_vm->_game;
+ int scriptNr = 0;
+ int scriptTextCount = 0;
+ int scriptTextNr = 0;
+ const char *scriptTextPtr = NULL;
+ const char *wordScanPtr = NULL;
+ const char *wordStartPtr = NULL;
+ const char *versionStartPtr = NULL;
+ int wordLen = 0;
+ char curChar = 0;
+ int versionLen = 0;
+ bool wordFound = false;
+ bool versionFound = false;
+ char versionString[CONSOLE_VERSION_MAXLEN];
+ bool scriptLoadedByUs = false;
+
+ // Show AGI version
+ Cmd_Agiver(argc, argv);
+
+ // And now try to figure out the version of the game
+ // We do this by scanning through all script texts
+ // This is the best we can do about it. There is no special location for the game version number.
+ // There are multiple variations, like "ver. X.XX", "ver X.XX" and even "verion X.XX".
+ for (scriptNr = 0; scriptNr < MAX_DIRECTORY_ENTRIES; scriptNr++) {
+ if (game->dirLogic[scriptNr].offset != _EMPTY) {
+ // Script is supposed to exist?
+ scriptLoadedByUs = false;
+ if (!(game->dirLogic[scriptNr].flags & RES_LOADED)) {
+ // But not currently loaded? -> load it now
+ if (_vm->agiLoadResource(RESOURCETYPE_LOGIC, scriptNr) != errOK) {
+ // In case we can't load the source, skip it
+ continue;
+ }
+ scriptLoadedByUs = true;
+ }
+ // Script currently loaded
+ // Now scan all texts
+ scriptTextCount = game->logics[scriptNr].numTexts;
+ for (scriptTextNr = 0; scriptTextNr < scriptTextCount; scriptTextNr++) {
+ scriptTextPtr = game->logics[scriptNr].texts[scriptTextNr];
+
+ // Now scan this text for version information
+ wordScanPtr = scriptTextPtr;
+
+ do {
+ curChar = *wordScanPtr;
+
+ if ((curChar == 'V') || (curChar == 'v')) {
+ // "V" gefunden, ggf. beginning of version?
+ wordStartPtr = wordScanPtr;
+ wordFound = false;
+
+ do {
+ curChar = *wordScanPtr;
+ if (curChar == ' ') {
+ break;
+ }
+ wordScanPtr++;
+ } while (curChar);
+
+ if (curChar) {
+ // end of "version" found
+ wordLen = wordScanPtr - wordStartPtr;
+
+ if (wordLen >= 3) {
+ if (strncmp(wordStartPtr, "ver", wordLen) == 0)
+ wordFound = true;
+ if (strncmp(wordStartPtr, "Ver", wordLen) == 0)
+ wordFound = true;
+ }
+ if ((!wordFound) && (wordLen >= 4)) {
+ if (strncmp(wordStartPtr, "ver.", wordLen) == 0)
+ wordFound = true;
+ if (strncmp(wordStartPtr, "Ver.", wordLen) == 0)
+ wordFound = true;
+ }
+ if ((!versionFound) && (wordLen >= 7)) {
+ if (strncmp(wordStartPtr, "version", wordLen) == 0)
+ wordFound = true;
+ if (strncmp(wordStartPtr, "Version", wordLen) == 0)
+ wordFound = true;
+ if (strncmp(wordStartPtr, "VERSION", wordLen) == 0)
+ wordFound = true;
+ }
+
+ if (wordFound) {
+ // We found something interesting
+ //debugPrintf("%d: %s\n", scriptNr, scriptTextPtr);
+
+ wordScanPtr++; // skip space
+ versionStartPtr = wordScanPtr;
+ curChar = *wordScanPtr;
+ if ((curChar >= '0') && (curChar <= '9')) {
+ // Next word starts with a number
+ wordScanPtr++;
+ curChar = *wordScanPtr;
+ if (curChar == '.') {
+ // Followed by a point? then we assume that we found a version number
+ // Now we try to find the end of it
+ wordScanPtr++;
+ do {
+ curChar = *wordScanPtr;
+ if ((curChar == ' ') || (curChar == '\\') || (!curChar))
+ break; // space or potential new line or NUL? -> found the end
+ wordScanPtr++;
+ } while (1);
+
+ versionLen = wordScanPtr - versionStartPtr;
+ if (versionLen < CONSOLE_VERSION_MAXLEN) {
+ // Looks fine, now extract and show it
+ memcpy(versionString, versionStartPtr, versionLen);
+ versionString[versionLen] = 0;
+ debugPrintf("Scanned game version: %s\n", versionString);
+ versionFound = true;
+ }
+ }
+ }
+ }
+ }
+
+ // Seek back
+ wordScanPtr = wordStartPtr;
+ }
+ wordScanPtr++;
+ } while (curChar);
+ }
+
+ if (scriptLoadedByUs) {
+ _vm->agiUnloadResource(RESOURCETYPE_LOGIC, scriptNr);
+ }
+ }
+ }
+
+ if (!versionFound) {
+ debugPrintf("Scanned game version: [not found]\n");
+ }
+ return true;
+}
+
bool Console::Cmd_Flags(int argc, const char **argv) {
int i, j;
@@ -141,7 +291,7 @@ bool Console::Cmd_Flags(int argc, const char **argv) {
for (i = 0; i < 255;) {
debugPrintf("%3d ", i);
for (j = 0; j < 10; j++, i++) {
- debugPrintf("%c ", _vm->getflag(i) ? 'T' : 'F');
+ debugPrintf("%c ", _vm->getFlag(i) ? 'T' : 'F');
}
debugPrintf("\n");
}
@@ -154,7 +304,7 @@ bool Console::Cmd_Vars(int argc, const char **argv) {
for (i = 0; i < 255;) {
for (j = 0; j < 5; j++, i++) {
- debugPrintf("%03d:%3d ", i, _vm->getvar(i));
+ debugPrintf("%03d:%3d ", i, _vm->getVar(i));
}
debugPrintf("\n");
}
@@ -199,7 +349,7 @@ bool Console::Cmd_Trigger(int argc, const char **argv) {
debugPrintf("Usage: trigger on|off\n");
return true;
}
- _vm->_debug.ignoretriggers = strcmp (argv[1], "on");
+ _vm->_debug.ignoretriggers = strcmp(argv[1], "on");
return true;
}
@@ -236,13 +386,13 @@ bool Console::Cmd_Room(int argc, const char **argv) {
_vm->newRoom(strtoul(argv[1], NULL, 0));
}
- debugPrintf("Current room: %d\n", _vm->getvar(0));
+ debugPrintf("Current room: %d\n", _vm->getVar(0));
return true;
}
bool Console::Cmd_BT(int argc, const char **argv) {
- debugPrintf("Current script: %d\nStack depth: %d\n", _vm->_game.lognum, _vm->_game.execStack.size());
+ debugPrintf("Current script: %d\nStack depth: %d\n", _vm->_game.curLogicNr, _vm->_game.execStack.size());
uint8 *code = NULL;
uint8 op = 0;
@@ -268,6 +418,233 @@ bool Console::Cmd_BT(int argc, const char **argv) {
return true;
}
+bool Console::Cmd_ShowMap(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("Switches to one of the following screen maps\n");
+ debugPrintf("Usage: %s <screen map>\n", argv[0]);
+ debugPrintf("Screen maps:\n");
+ debugPrintf("- 0: visual map\n");
+ debugPrintf("- 1: priority map\n");
+ return true;
+ }
+
+ int map = atoi(argv[1]);
+
+ switch (map) {
+ case 0:
+ case 1:
+ _vm->_gfx->debugShowMap(map);
+ break;
+
+ default:
+ debugPrintf("Map %d is not available.\n", map);
+ return true;
+ }
+ return cmdExit(0, 0);
+}
+
+bool Console::Cmd_ScreenObj(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("Shows information about a specific screen object\n");
+ debugPrintf("Usage: %s <screenobj number>\n", argv[0]);
+ return true;
+ }
+
+ int16 screenObjNr = atoi(argv[1]);
+
+ if ((screenObjNr >= 0) && (screenObjNr < SCREENOBJECTS_MAX)) {
+ ScreenObjEntry *screenObj = &_vm->_game.screenObjTable[screenObjNr];
+
+ debugPrintf("Screen Object ID %d\n", screenObj->objectNr);
+ debugPrintf("current view: %d, loop: %d, cel: %d\n", screenObj->currentViewNr, screenObj->currentLoopNr, screenObj->currentCelNr);
+
+ // Figure out flags
+ Common::String flagsString;
+
+ if (screenObj->flags & fDrawn)
+ flagsString += "Drawn ";
+ if (screenObj->flags & fIgnoreBlocks)
+ flagsString += "IgnoreBlocks ";
+ if (screenObj->flags & fFixedPriority)
+ flagsString += "FixedPriority ";
+ if (screenObj->flags & fIgnoreHorizon)
+ flagsString += "IgnoreHorizon ";
+ if (screenObj->flags & fUpdate)
+ flagsString += "Update ";
+ if (screenObj->flags & fCycling)
+ flagsString += "Cycling ";
+ if (screenObj->flags & fAnimated)
+ flagsString += "Animated ";
+ if (screenObj->flags & fMotion)
+ flagsString += "Motion ";
+ if (screenObj->flags & fOnWater)
+ flagsString += "OnWater ";
+ if (screenObj->flags & fIgnoreObjects)
+ flagsString += "IgnoreObjects ";
+ if (screenObj->flags & fUpdatePos)
+ flagsString += "UpdatePos ";
+ if (screenObj->flags & fOnLand)
+ flagsString += "OnLand ";
+ if (screenObj->flags & fDontupdate)
+ flagsString += "DontUpdate ";
+ if (screenObj->flags & fFixLoop)
+ flagsString += "FixLoop ";
+ if (screenObj->flags & fDidntMove)
+ flagsString += "DidntMove ";
+ if (screenObj->flags & fAdjEgoXY)
+ flagsString += "AdjEgoXY ";
+
+ if (flagsString.size() == 0) {
+ flagsString += "*none*";
+ }
+
+ debugPrintf("flags: %s\n", flagsString.c_str());
+
+ debugPrintf("\n");
+ debugPrintf("xPos: %d, yPos: %d, xSize: %d, ySize: %d\n", screenObj->xPos, screenObj->yPos, screenObj->xSize, screenObj->ySize);
+ debugPrintf("previous: xPos: %d, yPos: %d, xSize: %d, ySize: %d\n", screenObj->xPos_prev, screenObj->yPos_prev, screenObj->xSize_prev, screenObj->ySize_prev);
+ debugPrintf("direction: %d, priority: %d\n", screenObj->direction, screenObj->priority);
+ debugPrintf("stepTime: %d, timeCount: %d, size: %d\n", screenObj->stepTime, screenObj->stepTimeCount, screenObj->stepSize);
+ debugPrintf("cycleTime: %d, timeCount: %d\n", screenObj->cycleTime, screenObj->cycleTimeCount);
+
+ switch (screenObj->motionType) {
+ case kMotionNormal:
+ debugPrintf("motion: normal\n");
+ break;
+ case kMotionWander:
+ debugPrintf("motion: wander\n");
+ debugPrintf("wanderCount: %d\n", screenObj->wander_count);
+ break;
+ case kMotionFollowEgo:
+ debugPrintf("motion: follow ego\n");
+ debugPrintf("stepSize: %d, flag: %x, count: %d", screenObj->follow_stepSize, screenObj->follow_flag, screenObj->follow_count);
+ break;
+ case kMotionMoveObj:
+ case kMotionEgo:
+ if (screenObj->motionType == kMotionMoveObj) {
+ debugPrintf("motion: move obj\n");
+ } else {
+ debugPrintf("motion: ego\n");
+ }
+ debugPrintf("x: %d, y: %d, stepSize: %d, flag: %x\n", screenObj->move_x, screenObj->move_y, screenObj->move_stepSize, screenObj->move_flag);
+ break;
+ }
+ }
+ return true;
+}
+
+bool Console::Cmd_VmVars(int argc, const char **argv) {
+ if (argc < 2) {
+ debugPrintf("Shows the content of a VM variable / sets it\n");
+ debugPrintf("Usage: %s <variable number> [<value>]\n", argv[0]);
+ return true;
+ }
+
+ int varNr = 0;
+ int newValue = 0;
+
+ if (!parseInteger(argv[1], varNr))
+ return true;
+
+ if ((varNr < 0) || (varNr > 255)) {
+ debugPrintf("invalid variable number\n");
+ return true;
+ }
+
+ if (argc < 3) {
+ // show contents
+ debugPrintf("variable %d == %d\n", varNr, _vm->getVar(varNr));
+ } else {
+ if (!parseInteger(argv[2], newValue))
+ return true;
+
+ _vm->setVar(varNr, newValue);
+
+ debugPrintf("value set.\n");
+ }
+ return true;
+}
+
+bool Console::Cmd_VmFlags(int argc, const char **argv) {
+ if (argc < 2) {
+ debugPrintf("Shows the content of a VM flag / sets it\n");
+ debugPrintf("Usage: %s <flag number> [<value>]\n", argv[0]);
+ return true;
+ }
+
+ int flagNr = 0;
+ int newFlagState = 0;
+
+ if (!parseInteger(argv[1], flagNr))
+ return true;
+
+ if ((flagNr < 0) || (flagNr > 255)) {
+ debugPrintf("invalid flag number\n");
+ return true;
+ }
+
+ if (argc < 3) {
+ // show contents
+ if (_vm->getFlag(flagNr)) {
+ debugPrintf("flag %d == set\n", flagNr);
+ } else {
+ debugPrintf("flag %d == not set\n", flagNr);
+ }
+ } else {
+ if (!parseInteger(argv[2], newFlagState))
+ return true;
+
+ if ((newFlagState != 0) && (newFlagState != 1)) {
+ debugPrintf("new state must bei either 0 or 1\n");
+ return true;
+ }
+
+ if (!newFlagState) {
+ _vm->setFlag(flagNr, false);
+ debugPrintf("flag %d reset.\n", flagNr);
+ } else {
+ _vm->setFlag(flagNr, true);
+ debugPrintf("flag %d set.\n", flagNr);
+ }
+ }
+ return true;
+}
+
+bool Console::Cmd_DisableAutomaticSave(int argc, const char **argv) {
+ if (!_vm->_game.automaticSave) {
+ debugPrintf("Automatic saving is currently not enabled\n");
+ return true;
+ }
+
+ _vm->_game.automaticSave = false;
+
+ debugPrintf("Automatic saving DISABLED!\n");
+ return true;
+}
+
+bool Console::parseInteger(const char *argument, int &result) {
+ char *endPtr = 0;
+ int idxLen = strlen(argument);
+ const char *lastChar = argument + idxLen - (idxLen == 0 ? 0 : 1);
+
+ if ((strncmp(argument, "0x", 2) == 0) || (*lastChar == 'h')) {
+ // hexadecimal number
+ result = strtol(argument, &endPtr, 16);
+ if ((*endPtr != 0) && (*endPtr != 'h')) {
+ debugPrintf("Invalid hexadecimal number '%s'\n", argument);
+ return false;
+ }
+ } else {
+ // decimal number
+ result = strtol(argument, &endPtr, 10);
+ if (*endPtr != 0) {
+ debugPrintf("Invalid decimal number '%s'\n", argument);
+ return false;
+ }
+ }
+ return true;
+}
+
MickeyConsole::MickeyConsole(MickeyEngine *mickey) : GUI::Debugger() {
_mickey = mickey;
diff --git a/engines/agi/console.h b/engines/agi/console.h
index 6e86067373..ccc17b31de 100644
--- a/engines/agi/console.h
+++ b/engines/agi/console.h
@@ -50,6 +50,7 @@ private:
bool Cmd_SetObj(int argc, const char **argv);
bool Cmd_RunOpcode(int argc, const char **argv);
bool Cmd_Agiver(int argc, const char **argv);
+ bool Cmd_Version(int argc, const char **argv);
bool Cmd_Flags(int argc, const char **argv);
bool Cmd_Vars(int argc, const char **argv);
bool Cmd_Objs(int argc, const char **argv);
@@ -61,6 +62,13 @@ private:
bool Cmd_Cont(int argc, const char **argv);
bool Cmd_Room(int argc, const char **argv);
bool Cmd_BT(int argc, const char **argv);
+ bool Cmd_ShowMap(int argc, const char **argv);
+ bool Cmd_ScreenObj(int argc, const char **argv);
+ bool Cmd_VmVars(int argc, const char **argv);
+ bool Cmd_VmFlags(int argc, const char **argv);
+ bool Cmd_DisableAutomaticSave(int argc, const char **argv);
+
+ bool parseInteger(const char *argument, int &result);
private:
AgiEngine *_vm;
diff --git a/engines/agi/cycle.cpp b/engines/agi/cycle.cpp
index 6b34605364..19aca6f2c4 100644
--- a/engines/agi/cycle.cpp
+++ b/engines/agi/cycle.cpp
@@ -20,11 +20,17 @@
*
*/
+#include "common/config-manager.h"
+
#include "agi/agi.h"
#include "agi/sprite.h"
#include "agi/graphics.h"
+#include "agi/inv.h"
+#include "agi/text.h"
#include "agi/keyboard.h"
#include "agi/menu.h"
+#include "agi/systemui.h"
+#include "agi/appleIIgs_timedelay_overwrite.h"
namespace Agi {
@@ -33,295 +39,286 @@ namespace Agi {
* This function is called when ego enters a new room.
* @param n room number
*/
-void AgiEngine::newRoom(int n) {
- VtEntry *v;
+void AgiEngine::newRoom(int16 newRoomNr) {
+ ScreenObjEntry *screenObj;
+ ScreenObjEntry *screenObjEgo = &_game.screenObjTable[SCREENOBJECTS_EGO_ENTRY];
int i;
- // Simulate slowww computer.
- // Many effects rely on it.
- pause(kPauseRoom);
+ // Loading trigger
+ artificialDelayTrigger_NewRoom(newRoomNr);
- debugC(4, kDebugLevelMain, "*** room %d ***", n);
+ debugC(4, kDebugLevelMain, "*** room %d ***", newRoomNr);
_sound->stopSound();
i = 0;
- for (v = _game.viewTable; v < &_game.viewTable[MAX_VIEWTABLE]; v++) {
- v->entry = i++;
- v->flags &= ~(fAnimated | fDrawn);
- v->flags |= fUpdate;
- v->stepTime = 1;
- v->stepTimeCount = 1;
- v->cycleTime = 1;
- v->cycleTimeCount = 1;
- v->stepSize = 1;
+ for (screenObj = _game.screenObjTable; screenObj < &_game.screenObjTable[SCREENOBJECTS_MAX]; screenObj++) {
+ screenObj->objectNr = i++;
+ screenObj->flags &= ~(fAnimated | fDrawn);
+ screenObj->flags |= fUpdate;
+ screenObj->stepTime = 1;
+ screenObj->stepTimeCount = 1;
+ screenObj->cycleTime = 1;
+ screenObj->cycleTimeCount = 1;
+ screenObj->stepSize = 1;
}
agiUnloadResources();
_game.playerControl = true;
_game.block.active = false;
_game.horizon = 36;
- _game.vars[vPrevRoom] = _game.vars[vCurRoom];
- _game.vars[vCurRoom] = n;
- _game.vars[vBorderTouchObj] = 0;
- _game.vars[vBorderCode] = 0;
- _game.vars[vEgoViewResource] = _game.viewTable[0].currentView;
+ setVar(VM_VAR_PREVIOUS_ROOM, getVar(VM_VAR_CURRENT_ROOM));
+ setVar(VM_VAR_CURRENT_ROOM, newRoomNr);
+ setVar(VM_VAR_BORDER_TOUCH_OBJECT, 0);
+ setVar(VM_VAR_BORDER_CODE, 0);
+ setVar(VM_VAR_EGO_VIEW_RESOURCE, screenObjEgo->currentViewNr);
- agiLoadResource(rLOGIC, n);
+ agiLoadResource(RESOURCETYPE_LOGIC, newRoomNr);
// Reposition ego in the new room
- switch (_game.vars[vBorderTouchEgo]) {
+ switch (getVar(VM_VAR_BORDER_TOUCH_EGO)) {
case 1:
- _game.viewTable[0].yPos = _HEIGHT - 1;
+ screenObjEgo->yPos = SCRIPT_HEIGHT - 1;
break;
case 2:
- _game.viewTable[0].xPos = 0;
+ screenObjEgo->xPos = 0;
break;
case 3:
- _game.viewTable[0].yPos = HORIZON + 1;
+ screenObjEgo->yPos = _game.horizon + 1;
break;
case 4:
- _game.viewTable[0].xPos = _WIDTH - _game.viewTable[0].xSize;
+ screenObjEgo->xPos = SCRIPT_WIDTH - screenObjEgo->xSize;
break;
}
- _game.vars[vBorderTouchEgo] = 0;
- setflag(fNewRoomExec, true);
+ uint16 agiVersion = getVersion();
+
+ if (agiVersion < 0x2000) {
+ warning("STUB: NewRoom(%d)", newRoomNr);
+
+ screenObjEgo->flags &= ~fDidntMove;
+ // animateObject(0);
+ agiLoadResource(RESOURCETYPE_VIEW, screenObjEgo->currentViewNr);
+ setView(screenObjEgo, screenObjEgo->currentViewNr);
- _game.exitAllLogics = true;
+ } else {
+ if (agiVersion >= 0x3000) {
+ // this was only done in AGI3
+ if (screenObjEgo->motionType == kMotionEgo) {
+ screenObjEgo->motionType = kMotionNormal;
+ setVar(VM_VAR_EGO_DIRECTION, 0);
+ }
+ }
- writeStatus();
- writePrompt();
+ setVar(VM_VAR_BORDER_TOUCH_EGO, 0);
+ setFlag(VM_FLAG_NEW_ROOM_EXEC, true);
+
+ _game.exitAllLogics = true;
+
+ _game._vm->_text->statusDraw();
+ _game._vm->_text->promptRedraw();
+ }
}
void AgiEngine::resetControllers() {
int i;
- for (i = 0; i < MAX_DIRS; i++) {
+ for (i = 0; i < MAX_CONTROLLERS; i++) {
_game.controllerOccured[i] = false;
}
}
void AgiEngine::interpretCycle() {
- int oldSound, oldScore;
+ ScreenObjEntry *screenObjEgo = &_game.screenObjTable[SCREENOBJECTS_EGO_ENTRY];
+ bool oldSound;
+ byte oldScore;
- if (_game.playerControl)
- _game.vars[vEgoDir] = _game.viewTable[0].direction;
+ if (!_game.playerControl)
+ setVar(VM_VAR_EGO_DIRECTION, screenObjEgo->direction);
else
- _game.viewTable[0].direction = _game.vars[vEgoDir];
+ screenObjEgo->direction = getVar(VM_VAR_EGO_DIRECTION);
checkAllMotions();
- oldScore = _game.vars[vScore];
- oldSound = getflag(fSoundOn);
+ oldScore = getVar(VM_VAR_SCORE);
+ oldSound = getFlag(VM_FLAG_SOUND_ON);
+
+ // Reset script heuristic here
+ resetGetVarSecondsHeuristic();
_game.exitAllLogics = false;
while (runLogic(0) == 0 && !(shouldQuit() || _restartGame)) {
- _game.vars[vWordNotFound] = 0;
- _game.vars[vBorderTouchObj] = 0;
- _game.vars[vBorderCode] = 0;
- oldScore = _game.vars[vScore];
- setflag(fEnteredCli, false);
+ setVar(VM_VAR_WORD_NOT_FOUND, 0);
+ setVar(VM_VAR_BORDER_TOUCH_OBJECT, 0);
+ setVar(VM_VAR_BORDER_CODE, 0);
+ oldScore = getVar(VM_VAR_SCORE);
+ setFlag(VM_FLAG_ENTERED_CLI, false);
_game.exitAllLogics = false;
+ _veryFirstInitialCycle = false;
+ artificialDelay_CycleDone();
resetControllers();
}
+ _veryFirstInitialCycle = false;
+ artificialDelay_CycleDone();
resetControllers();
- _game.viewTable[0].direction = _game.vars[vEgoDir];
+ screenObjEgo->direction = getVar(VM_VAR_EGO_DIRECTION);
- if (_game.vars[vScore] != oldScore || getflag(fSoundOn) != oldSound)
- writeStatus();
+ if (getVar(VM_VAR_SCORE) != oldScore || getFlag(VM_FLAG_SOUND_ON) != oldSound)
+ _game._vm->_text->statusDraw();
- _game.vars[vBorderTouchObj] = 0;
- _game.vars[vBorderCode] = 0;
- setflag(fNewRoomExec, false);
- setflag(fRestartGame, false);
- setflag(fRestoreJustRan, false);
+ setVar(VM_VAR_BORDER_TOUCH_OBJECT, 0);
+ setVar(VM_VAR_BORDER_CODE, 0);
+ setFlag(VM_FLAG_NEW_ROOM_EXEC, false);
+ setFlag(VM_FLAG_RESTART_GAME, false);
+ setFlag(VM_FLAG_RESTORE_JUST_RAN, false);
if (_game.gfxMode) {
- updateViewtable();
- _gfx->doUpdate();
+ updateScreenObjTable();
}
+ _gfx->updateScreen();
+ //_gfx->doUpdate();
}
-/**
- * Update AGI interpreter timer.
- */
-void AgiEngine::updateTimer() {
- _clockCount++;
- if (_clockCount <= TICK_SECONDS)
- return;
-
- _clockCount -= TICK_SECONDS;
-
- if (!_game.clockEnabled)
- return;
-
- setvar(vSeconds, getvar(vSeconds) + 1);
- if (getvar(vSeconds) < 60)
- return;
-
- setvar(vSeconds, 0);
- setvar(vMinutes, getvar(vMinutes) + 1);
- if (getvar(vMinutes) < 60)
- return;
-
- setvar(vMinutes, 0);
- setvar(vHours, getvar(vHours) + 1);
- if (getvar(vHours) < 24)
- return;
-
- setvar(vHours, 0);
- setvar(vDays, getvar(vDays) + 1);
-}
-
-void AgiEngine::newInputMode(InputMode mode) {
- if (mode == INPUT_MENU && !getflag(fMenusWork) && !(getFeatures() & GF_MENUS))
- return;
-
- _oldMode = _game.inputMode;
- _game.inputMode = mode;
-}
-
-void AgiEngine::oldInputMode() {
- _game.inputMode = _oldMode;
-}
-
-// If main_cycle returns false, don't process more events!
-int AgiEngine::mainCycle(bool onlyCheckForEvents) {
- unsigned int key, kascii;
- VtEntry *v = &_game.viewTable[0];
-
- if (!onlyCheckForEvents) {
- pollTimer();
- updateTimer();
- }
+// We return the current key, or 0 if no key was pressed
+uint16 AgiEngine::processAGIEvents() {
+ uint16 key;
+ ScreenObjEntry *screenObjEgo = &_game.screenObjTable[SCREENOBJECTS_EGO_ENTRY];
+ wait(10);
key = doPollKeyboard();
// In AGI Mouse emulation mode we must update the mouse-related
// vars in every interpreter cycle.
//
// We run AGIMOUSE always as a side effect
- //if (getFeatures() & GF_AGIMOUSE) {
- _game.vars[28] = _mouse.x / 2;
- _game.vars[29] = _mouse.y;
- //}
-
- if (key == KEY_STATUSLN) { // F11
- _debug.statusline = !_debug.statusline;
- writeStatus();
- key = 0;
+ setVar(VM_VAR_MOUSE_X, _mouse.pos.x / 2);
+ setVar(VM_VAR_MOUSE_Y, _mouse.pos.y);
+
+ if (!cycleInnerLoopIsActive()) {
+ // Click-to-walk mouse interface
+ if (_game.playerControl && (screenObjEgo->flags & fAdjEgoXY)) {
+ int toX = screenObjEgo->move_x;
+ int toY = screenObjEgo->move_y;
+
+ // AGI Mouse games use ego's sprite's bottom left corner for mouse walking target.
+ // Amiga games use ego's sprite's bottom center for mouse walking target.
+ // Atari ST and Apple II GS seem to use the bottom left
+ if (getPlatform() == Common::kPlatformAmiga)
+ toX -= (screenObjEgo->xSize / 2); // Center ego's sprite horizontally
+
+ // Adjust ego's sprite's mouse walking target position (These parameters are
+ // controlled with the adj.ego.move.to.x.y-command). Note that these values rely
+ // on the horizontal centering of the ego's sprite at least on the Amiga platform.
+ toX += _game.adjMouseX;
+ toY += _game.adjMouseY;
+
+ screenObjEgo->direction = getDirection(screenObjEgo->xPos, screenObjEgo->yPos, toX, toY, screenObjEgo->stepSize);
+
+ if (screenObjEgo->direction == 0)
+ inDestination(screenObjEgo);
+ }
}
- if (key == KEY_PRIORITY) { // F12
- _sprites->eraseBoth();
- _debug.priority = !_debug.priority;
- _picture->showPic();
- _sprites->blitBoth();
- _sprites->commitBoth();
- key = 0;
- }
+ handleMouseClicks(key);
- // Click-to-walk mouse interface
- if (_game.playerControl && (v->flags & fAdjEgoXY)) {
- int toX = v->parm1;
- int toY = v->parm2;
+ if (!cycleInnerLoopIsActive()) {
+ // no inner loop active at the moment, regular processing
- // AGI Mouse games use ego's sprite's bottom left corner for mouse walking target.
- // Amiga games use ego's sprite's bottom center for mouse walking target.
- // TODO: Check what Atari ST AGI and Apple IIGS AGI use for mouse walking target.
- if (getPlatform() == Common::kPlatformAmiga)
- toX -= (v->xSize / 2); // Center ego's sprite horizontally
+ if (key) {
+ if (!handleController(key)) {
+ if (key) {
+ // Only set VAR_KEY, when no controller/direction was detected
+ setVar(VM_VAR_KEY, key & 0xFF);
+ if (_text->promptIsEnabled()) {
+ _text->promptKeyPress(key);
+ }
+ }
+ }
+ }
- // Adjust ego's sprite's mouse walking target position (These parameters are
- // controlled with the adj.ego.move.to.x.y-command). Note that these values rely
- // on the horizontal centering of the ego's sprite at least on the Amiga platform.
- toX += _game.adjMouseX;
- toY += _game.adjMouseY;
+ if (_menu->delayedExecuteActive()) {
+ _menu->execute();
+ }
- v->direction = getDirection(v->xPos, v->yPos, toX, toY, v->stepSize);
+ } else {
+ // inner loop active
+ // call specific workers
+ switch (_game.cycleInnerLoopType) {
+ case CYCLE_INNERLOOP_GETSTRING: // loop called from TextMgr::stringEdit()
+ case CYCLE_INNERLOOP_GETNUMBER:
+ if (key) {
+ _text->stringKeyPress(key);
+ }
+ break;
- if (v->direction == 0)
- inDestination(v);
- }
+ case CYCLE_INNERLOOP_INVENTORY: // loop called from InventoryMgr::show()
+ if (key) {
+ _inventory->keyPress(key);
+ }
+ break;
- kascii = KEY_ASCII(key);
+ case CYCLE_INNERLOOP_MENU_VIA_KEYBOARD:
+ if (key) {
+ _menu->keyPress(key);
+ }
+ break;
- if (kascii)
- setvar(vKey, kascii);
+ case CYCLE_INNERLOOP_MENU_VIA_MOUSE:
+ _menu->mouseEvent(key);
+ break;
- bool restartProcessKey;
- do {
- restartProcessKey = false;
+ case CYCLE_INNERLOOP_SYSTEMUI_SELECTSAVEDGAMESLOT:
+ if (key) {
+ _systemUI->savedGameSlot_KeyPress(key);
+ }
+ break;
- switch (_game.inputMode) {
- case INPUT_NORMAL:
- if (!handleController(key)) {
- if (key == 0 || !_game.inputEnabled)
- break;
- handleKeys(key);
-
- // if ESC pressed, activate menu before
- // accept.input from the interpreter cycle
- // sets the input mode to normal again
- // (closes: #540856)
- if (key == KEY_ESCAPE) {
- key = 0;
- restartProcessKey = true;
- }
+ case CYCLE_INNERLOOP_SYSTEMUI_VERIFICATION:
+ _systemUI->askForVerificationKeyPress(key);
+ break;
- // commented out to close Sarien bug #438872
- //if (key)
- // _game.keypress = key;
+ case CYCLE_INNERLOOP_MESSAGEBOX:
+ if (key) {
+ _text->messageBox_KeyPress(key);
}
break;
- case INPUT_GETSTRING:
- handleController(key);
- handleGetstring(key);
- setvar(vKey, 0); // clear ENTER key
- break;
- case INPUT_MENU:
- _menu->keyhandler(key);
- _gfx->doUpdate();
- return false;
- case INPUT_NONE:
- handleController(key);
- if (key)
- _game.keypress = key;
+
+ default:
break;
}
- } while (restartProcessKey);
-
- if (!onlyCheckForEvents) {
- _gfx->doUpdate();
-
- if (_game.msgBoxTicks > 0)
- _game.msgBoxTicks--;
}
- return true;
+ _gfx->updateScreen();
+
+ return key;
}
int AgiEngine::playGame() {
int ec = errOK;
+ const AgiAppleIIgsDelayOverwriteGameEntry *appleIIgsDelayOverwrite = nullptr;
+ const AgiAppleIIgsDelayOverwriteRoomEntry *appleIIgsDelayRoomOverwrite = nullptr;
debugC(2, kDebugLevelMain, "initializing...");
debugC(2, kDebugLevelMain, "game version = 0x%x", getVersion());
_sound->stopSound();
- _gfx->clearScreen(0);
- _game.horizon = HORIZON;
+ // We need to do this accurately and reset the AGI priorityscreen to 4
+ // otherwise at least the fan game Nick's Quest will go into an endless
+ // loop, because the game draws views before it draws the first background picture.
+ // For further study see bug #3451122
+ _gfx->clear(0, 4);
+
+ _game.horizon = 36;
_game.playerControl = false;
- setflag(fLogicZeroFirsttime, true); // not in 2.917
- setflag(fNewRoomExec, true); // needed for MUMG and SQ2!
- setflag(fSoundOn, true); // enable sound
- setvar(vTimeDelay, 2); // "normal" speed
+ setFlag(VM_FLAG_LOGIC_ZERO_FIRST_TIME, true); // not in 2.917
+ setFlag(VM_FLAG_NEW_ROOM_EXEC, true); // needed for MUMG and SQ2!
+ setFlag(VM_FLAG_SOUND_ON, true); // enable sound
+ // do not set VM_VAR_TIME_DELAY, original AGI did not do it (in the data segment it was simply set to 0)
_game.gfxMode = true;
- _game.clockEnabled = true;
- _game.lineUserInput = 22;
+ _text->promptRow_Set(22);
// We run AGIMOUSE always as a side effect
//if (getFeatures() & GF_AGIMOUSE)
@@ -332,41 +329,106 @@ int AgiEngine::playGame() {
debug(0, "Running AGI script.\n");
- setflag(fEnteredCli, false);
- setflag(fSaidAcceptedInput, false);
- _game.vars[vWordNotFound] = 0;
- _game.vars[vKey] = 0;
+ setFlag(VM_FLAG_ENTERED_CLI, false);
+ setFlag(VM_FLAG_SAID_ACCEPTED_INPUT, false);
+ setVar(VM_VAR_WORD_NOT_FOUND, 0);
+ setVar(VM_VAR_KEY, 0);
debugC(2, kDebugLevelMain, "Entering main loop");
- bool firstLoop = !getflag(fRestartGame); // Do not restore on game restart
+ bool firstLoop = !getFlag(VM_FLAG_RESTART_GAME); // Do not restore on game restart
+
+ if (firstLoop) {
+ if (ConfMan.hasKey("save_slot")) {
+ // quick restore enabled
+ _game.automaticRestoreGame = true;
+ }
+ }
+
+ artificialDelay_Reset();
+
+ if (getPlatform() == Common::kPlatformApple2GS) {
+ // Look up, if there is a time delay overwrite table for the current game
+ appleIIgsDelayOverwrite = appleIIgsDelayOverwriteGameTable;
+ while (appleIIgsDelayOverwrite->gameId != GID_AGIDEMO) {
+ if (appleIIgsDelayOverwrite->gameId == getGameID())
+ break; // game found
+ appleIIgsDelayOverwrite++;
+ }
+ }
do {
+ processAGIEvents();
+
+ inGameTimerUpdate();
+
+ uint16 timeDelay = getVar(VM_VAR_TIME_DELAY);
+
+ if (getPlatform() == Common::kPlatformApple2GS) {
+ timeDelay++;
+ // It seems that either Apple IIgs ran very slowly or that the delay in its interpreter was not working as everywhere else
+ // Most games on that platform set the delay to 0, which means no delay in DOS
+ // Gold Rush! even "optimizes" itself when larger sprites are on the screen it sets TIME_DELAY to 0.
+ // Normally that game runs at TIME_DELAY 1.
+ // Maybe a script patch for this game would make sense.
+ // TODO: needs further investigation
+
+ int16 timeDelayOverwrite = -99;
+
+ // Now check, if we got a time delay overwrite entry for current room
+ if (appleIIgsDelayOverwrite->roomTable) {
+ byte curRoom = getVar(VM_VAR_CURRENT_ROOM);
+
+ appleIIgsDelayRoomOverwrite = appleIIgsDelayOverwrite->roomTable;
+ while (appleIIgsDelayRoomOverwrite->fromRoom >= 0) {
+ if ((appleIIgsDelayRoomOverwrite->fromRoom <= curRoom) && (appleIIgsDelayRoomOverwrite->toRoom >= curRoom)) {
+ if (appleIIgsDelayRoomOverwrite->onlyWhenPlayerNotInControl) {
+ if (_game.playerControl) {
+ // Player is actually currently in control? -> then skip this entry
+ appleIIgsDelayRoomOverwrite++;
+ continue;
+ }
+ }
+ timeDelayOverwrite = appleIIgsDelayRoomOverwrite->timeDelayOverwrite;
+ break;
+ }
+ appleIIgsDelayRoomOverwrite++;
+ }
+
+ if (timeDelayOverwrite == -99) {
+ // use default time delay in case no room specific one was found
+ timeDelayOverwrite = appleIIgsDelayOverwrite->defaultTimeDelayOverwrite;
+ }
+ } else {
+ timeDelayOverwrite = appleIIgsDelayOverwrite->defaultTimeDelayOverwrite;
+ }
- if (!mainCycle())
- continue;
+ if (timeDelayOverwrite >= 0) {
+ if (timeDelayOverwrite != timeDelay) {
+ // delayOverwrite is not the same as the delay taken from the scripts? overwrite it
+ //warning("AppleIIgs: time delay overwrite from %d to %d", timeDelay, timeDelayOverwrite);
- if (getvar(vTimeDelay) == 0 || (1 + _clockCount) % getvar(vTimeDelay) == 0) {
- if (!_game.hasPrompt && _game.inputMode == INPUT_NORMAL) {
- writePrompt();
- _game.hasPrompt = 1;
- } else if (_game.hasPrompt && _game.inputMode == INPUT_NONE) {
- writePrompt();
- _game.hasPrompt = 0;
+ setVar(VM_VAR_TIME_DELAY, timeDelayOverwrite - 1); // adjust for Apple IIgs
+ timeDelay = timeDelayOverwrite;
+ }
}
+ }
+
+ if (_passedPlayTimeCycles >= timeDelay) {
+ inGameTimerResetPassedCycles();
interpretCycle();
// Check if the user has asked to load a game from the command line
// or the launcher
- if (firstLoop) {
+ if (_game.automaticRestoreGame) {
+ _game.automaticRestoreGame = false;
checkQuickLoad();
- firstLoop = false;
}
- setflag(fEnteredCli, false);
- setflag(fSaidAcceptedInput, false);
- _game.vars[vWordNotFound] = 0;
- _game.vars[vKey] = 0;
+ setFlag(VM_FLAG_ENTERED_CLI, false);
+ setFlag(VM_FLAG_SAID_ACCEPTED_INPUT, false);
+ setVar(VM_VAR_WORD_NOT_FOUND, 0);
+ setVar(VM_VAR_KEY, 0);
}
if (shouldPerformAutoSave(_lastSaveTime)) {
@@ -392,66 +454,74 @@ int AgiEngine::runGame() {
break;
if (_restartGame) {
- setflag(fRestartGame, true);
- setvar(vTimeDelay, 2); // "normal" speed
+ setFlag(VM_FLAG_RESTART_GAME, true);
+ // do not set VM_VAR_TIME_DELAY, original AGI did not do it
+
+ // Reset in-game timer
+ inGameTimerReset();
+
_restartGame = false;
}
// Set computer type (v20 i.e. vComputer) and sound type
switch (getPlatform()) {
case Common::kPlatformAtariST:
- setvar(vComputer, kAgiComputerAtariST);
- setvar(vSoundgen, kAgiSoundPC);
+ setVar(VM_VAR_COMPUTER, kAgiComputerAtariST);
+ setVar(VM_VAR_SOUNDGENERATOR, kAgiSoundPC);
break;
case Common::kPlatformAmiga:
if (getFeatures() & GF_OLDAMIGAV20)
- setvar(vComputer, kAgiComputerAmigaOld);
+ setVar(VM_VAR_COMPUTER, kAgiComputerAmigaOld);
else
- setvar(vComputer, kAgiComputerAmiga);
- setvar(vSoundgen, kAgiSoundTandy);
+ setVar(VM_VAR_COMPUTER, kAgiComputerAmiga);
+ setVar(VM_VAR_SOUNDGENERATOR, kAgiSoundTandy);
break;
case Common::kPlatformApple2GS:
- setvar(vComputer, kAgiComputerApple2GS);
+ setVar(VM_VAR_COMPUTER, kAgiComputerApple2GS);
if (getFeatures() & GF_2GSOLDSOUND)
- setvar(vSoundgen, kAgiSound2GSOld);
+ setVar(VM_VAR_SOUNDGENERATOR, kAgiSound2GSOld);
else
- setvar(vSoundgen, kAgiSoundTandy);
+ setVar(VM_VAR_SOUNDGENERATOR, kAgiSoundTandy);
break;
case Common::kPlatformDOS:
default:
- setvar(vComputer, kAgiComputerPC);
- setvar(vSoundgen, kAgiSoundPC);
+ setVar(VM_VAR_COMPUTER, kAgiComputerPC);
+ setVar(VM_VAR_SOUNDGENERATOR, kAgiSoundPC);
break;
}
// Set monitor type (v26 i.e. vMonitor)
switch (_renderMode) {
case Common::kRenderCGA:
- setvar(vMonitor, kAgiMonitorCga);
+ setVar(VM_VAR_MONITOR, kAgiMonitorCga);
break;
- case Common::kRenderHercG:
case Common::kRenderHercA:
- setvar(vMonitor, kAgiMonitorHercules);
+ case Common::kRenderHercG:
+ // Set EGA for now. Some games place text differently, when this is set to kAgiMonitorHercules.
+ // Text placement was different for Hercules rendering (16x12 instead of 16x16). There also was
+ // not enough space left for the prompt at the bottom. This was caused by the Hercules resolution.
+ // We don't have this restriction and we also support the regular prompt for Hercules mode.
+ // In theory Sierra could have had special Hercules code inside their games.
+ // TODO: check this.
+ setVar(VM_VAR_MONITOR, kAgiMonitorEga);
break;
// Don't know if Amiga AGI games use a different value than kAgiMonitorEga
// for vMonitor so I just use kAgiMonitorEga for them (As was done before too).
case Common::kRenderAmiga:
- case Common::kRenderDefault:
+ case Common::kRenderApple2GS:
+ case Common::kRenderAtariST:
case Common::kRenderEGA:
+ case Common::kRenderVGA:
default:
- setvar(vMonitor, kAgiMonitorEga);
+ setVar(VM_VAR_MONITOR, kAgiMonitorEga);
break;
}
- setvar(vFreePages, 180); // Set amount of free memory to realistic value
- setvar(vMaxInputChars, 38);
- _game.inputMode = INPUT_NONE;
- _game.inputEnabled = false;
- _game.hasPrompt = 0;
+ setVar(VM_VAR_FREE_PAGES, 180); // Set amount of free memory to realistic value
+ setVar(VM_VAR_MAX_INPUT_CHARACTERS, 38);
+ _text->promptDisable();
- _game.state = STATE_RUNNING;
ec = playGame();
- _game.state = STATE_LOADED;
agiDeinit();
} while (_restartGame);
diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp
index 823ec7be66..9f66d78d80 100644
--- a/engines/agi/detection.cpp
+++ b/engines/agi/detection.cpp
@@ -171,19 +171,39 @@ static const ADExtraGuiOptionsMap optionsList[] = {
}
},
+ {
+ GAMEOPTION_USE_HERCULES_FONT,
+ {
+ _s("Use Hercules hires font"),
+ _s("Uses Hercules hires font, when font file is available."),
+ "herculesfont",
+ false
+ }
+ },
+
+ {
+ GAMEOPTION_COMMAND_PROMPT_WINDOW,
+ {
+ _s("Pause when entering commands"),
+ _s("Shows a command prompt window and pauses the game (like in SCI) instead of a real-time prompt."),
+ "commandpromptwindow",
+ false
+ }
+ },
+
AD_EXTRA_GUI_OPTIONS_TERMINATOR
};
using namespace Agi;
class AgiMetaEngine : public AdvancedMetaEngine {
- mutable Common::String _gameid;
- mutable Common::String _extra;
+ mutable Common::String _gameid;
+ mutable Common::String _extra;
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 {
@@ -205,20 +225,20 @@ public:
bool AgiMetaEngine::hasFeature(MetaEngineFeature f) const {
return
- (f == kSupportsListSaves) ||
- (f == kSupportsLoadingDuringStartup) ||
- (f == kSupportsDeleteSave) ||
- (f == kSavesSupportMetaInfo) ||
- (f == kSavesSupportThumbnail) ||
- (f == kSavesSupportCreationDate) ||
- (f == kSavesSupportPlayTime);
+ (f == kSupportsListSaves) ||
+ (f == kSupportsLoadingDuringStartup) ||
+ (f == kSupportsDeleteSave) ||
+ (f == kSavesSupportMetaInfo) ||
+ (f == kSavesSupportThumbnail) ||
+ (f == kSavesSupportCreationDate) ||
+ (f == kSavesSupportPlayTime);
}
bool AgiBase::hasFeature(EngineFeature f) const {
return
- (f == kSupportsRTL) ||
- (f == kSupportsLoadingDuringRuntime) ||
- (f == kSupportsSavingDuringRuntime);
+ (f == kSupportsRTL) ||
+ (f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsSavingDuringRuntime);
}
@@ -254,33 +274,52 @@ bool AgiMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameD
}
SaveStateList AgiMetaEngine::listSaves(const char *target) const {
- const uint32 AGIflag = MKTAG('A','G','I',':');
+ const uint32 AGIflag = MKTAG('A', 'G', 'I', ':');
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Common::StringArray filenames;
- char saveDesc[31];
Common::String pattern = target;
- pattern += ".???";
+ pattern += ".###";
filenames = saveFileMan->listSavefiles(pattern);
- sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
SaveStateList saveList;
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);
+ int slotNr = atoi(file->c_str() + file->size() - 3);
- if (slotNum >= 0 && slotNum <= 999) {
+ if (slotNr >= 0 && slotNr <= 999) {
Common::InSaveFile *in = saveFileMan->openForLoading(*file);
if (in) {
uint32 type = in->readUint32BE();
- if (type == AGIflag)
- in->read(saveDesc, 31);
- saveList.push_back(SaveStateDescriptor(slotNum, saveDesc));
+ char description[31];
+
+ if (type == AGIflag) {
+ uint16 descriptionPos = 0;
+
+ in->read(description, 31);
+
+ // Security-check, if saveDescription has a terminating NUL
+ while (description[descriptionPos]) {
+ descriptionPos++;
+ if (descriptionPos >= sizeof(description))
+ break;
+ }
+ if (descriptionPos >= sizeof(description)) {
+ strcpy(description, "[broken saved game]");
+ }
+ } else {
+ strcpy(description, "[not an AGI saved game]");
+ }
+
delete in;
+
+ saveList.push_back(SaveStateDescriptor(slotNr, description));
}
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
@@ -291,9 +330,9 @@ void AgiMetaEngine::removeSaveState(const char *target, int slot) const {
g_system->getSavefileManager()->removeSavefile(fileName);
}
-SaveStateDescriptor AgiMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
- const uint32 AGIflag = MKTAG('A','G','I',':');
- Common::String fileName = Common::String::format("%s.%03d", target, slot);
+SaveStateDescriptor AgiMetaEngine::querySaveMetaInfos(const char *target, int slotNr) const {
+ const uint32 AGIflag = MKTAG('A', 'G', 'I', ':');
+ Common::String fileName = Common::String::format("%s.%03d", target, slotNr);
Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(fileName);
@@ -303,49 +342,76 @@ SaveStateDescriptor AgiMetaEngine::querySaveMetaInfos(const char *target, int sl
return SaveStateDescriptor();
}
- char name[32];
- in->read(name, 31);
+ char description[31];
+ uint16 descriptionPos = 0;
+
+ in->read(description, 31);
+
+ while (description[descriptionPos]) {
+ descriptionPos++;
+ if (descriptionPos >= sizeof(description))
+ break;
+ }
+ if (descriptionPos >= sizeof(description)) {
+ // broken description, ignore it
+ delete in;
+
+ SaveStateDescriptor descriptor(slotNr, "[broken saved game]");
+ return descriptor;
+ }
- SaveStateDescriptor desc(slot, name);
+ SaveStateDescriptor descriptor(slotNr, description);
// Do not allow save slot 0 (used for auto-saving) to be deleted or
// overwritten.
- desc.setDeletableFlag(slot != 0);
- desc.setWriteProtectedFlag(slot == 0);
+ if (slotNr == 0) {
+ descriptor.setWriteProtectedFlag(true);
+ descriptor.setDeletableFlag(false);
+ } else {
+ descriptor.setWriteProtectedFlag(false);
+ descriptor.setDeletableFlag(true);
+ }
char saveVersion = in->readByte();
if (saveVersion >= 4) {
Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*in);
- desc.setThumbnail(thumbnail);
+ descriptor.setThumbnail(thumbnail);
uint32 saveDate = in->readUint32BE();
uint16 saveTime = in->readUint16BE();
+ if (saveVersion >= 9) {
+ in->readByte(); // skip over seconds of saveTime (not needed here)
+ }
if (saveVersion >= 6) {
uint32 playTime = in->readUint32BE();
- desc.setPlayTime(playTime * 1000);
+ descriptor.setPlayTime(playTime * 1000);
}
int day = (saveDate >> 24) & 0xFF;
int month = (saveDate >> 16) & 0xFF;
int year = saveDate & 0xFFFF;
- desc.setSaveDate(year, month, day);
+ descriptor.setSaveDate(year, month, day);
int hour = (saveTime >> 8) & 0xFF;
int minutes = saveTime & 0xFF;
- desc.setSaveTime(hour, minutes);
+ descriptor.setSaveTime(hour, minutes);
}
-
delete in;
- return desc;
+ return descriptor;
+
} else {
SaveStateDescriptor emptySave;
// Do not allow save slot 0 (used for auto-saving) to be overwritten.
- emptySave.setWriteProtectedFlag(slot == 0);
+ if (slotNr == 0) {
+ emptySave.setWriteProtectedFlag(true);
+ } else {
+ emptySave.setWriteProtectedFlag(false);
+ }
return emptySave;
}
}
@@ -389,9 +455,9 @@ const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXX
}
if (allFiles.contains("logdir") && allFiles.contains("object") &&
- allFiles.contains("picdir") && allFiles.contains("snddir") &&
- allFiles.contains("viewdir") && allFiles.contains("vol.0") &&
- allFiles.contains("words.tok")) { // Check for v2
+ allFiles.contains("picdir") && allFiles.contains("snddir") &&
+ allFiles.contains("viewdir") && allFiles.contains("vol.0") &&
+ allFiles.contains("words.tok")) { // Check for v2
// The default AGI interpreter version 0x2917 is okay for v2 games
// so we don't have to change it here.
@@ -423,7 +489,7 @@ const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXX
strncpy(name, f->_key.c_str(), MIN((uint)8, f->_key.size() > 5 ? f->_key.size() - 5 : f->_key.size()));
if (allFiles.contains("object") && allFiles.contains("words.tok") &&
- allFiles.contains(Common::String(name) + "dir")) {
+ allFiles.contains(Common::String(name) + "dir")) {
matchedUsingFilenames = true;
description = "Unknown v3 Game";
g_fallbackDesc.version = 0x3149; // Set the default AGI version for an AGI v3 game
@@ -501,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";
@@ -528,14 +594,39 @@ const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXX
namespace Agi {
bool AgiBase::canLoadGameStateCurrently() {
- return (!(getGameType() == GType_PreAGI) && getflag(fMenusWork) && !_noSaveLoadAllowed);
+ if (!(getGameType() == GType_PreAGI)) {
+ if (getFlag(VM_FLAG_MENUS_ACCESSIBLE)) {
+ if (!_noSaveLoadAllowed) {
+ if (!cycleInnerLoopIsActive()) {
+ // We can't allow to restore a game, while inner loop is active
+ // For example Mixed Up Mother Goose has an endless loop for user name input
+ // Which means even if we abort the inner loop, the game would keep on calling
+ // GetString() until something is entered. And this would of course also happen
+ // right after restoring a saved game.
+ return true;
+ }
+ }
+ }
+ }
+ return false;
}
bool AgiBase::canSaveGameStateCurrently() {
if (getGameID() == GID_BC) // Technically in Black Cauldron we may save anytime
return true;
- return (!(getGameType() == GType_PreAGI) && getflag(fMenusWork) && !_noSaveLoadAllowed && _game.inputEnabled);
+ if (!(getGameType() == GType_PreAGI)) {
+ if (getFlag(VM_FLAG_MENUS_ACCESSIBLE)) {
+ if (!_noSaveLoadAllowed) {
+ if (!cycleInnerLoopIsActive()) {
+ if (promptIsEnabled()) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
}
int AgiEngine::agiDetectGame() {
diff --git a/engines/agi/detection_tables.h b/engines/agi/detection_tables.h
index af3d93288e..0938e9d4d6 100644
--- a/engines/agi/detection_tables.h
+++ b/engines/agi/detection_tables.h
@@ -24,22 +24,24 @@ namespace Agi {
#define GAMEOPTION_ORIGINAL_SAVELOAD GUIO_GAMEOPTIONS1
#define GAMEOPTION_AMIGA_ALTERNATIVE_PALETTE GUIO_GAMEOPTIONS2
-#define GAMEOPTION_DISABLE_MOUSE GUIO_GAMEOPTIONS3
+#define GAMEOPTION_DISABLE_MOUSE GUIO_GAMEOPTIONS3
+#define GAMEOPTION_USE_HERCULES_FONT GUIO_GAMEOPTIONS4
+#define GAMEOPTION_COMMAND_PROMPT_WINDOW GUIO_GAMEOPTIONS5
// TODO: properly implement GAMEOPTIONs
-#define GAMEOPTIONS_DEFAULT GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD,GAMEOPTION_DISABLE_MOUSE)
-#define GAMEOPTIONS_AMIGA GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD,GAMEOPTION_AMIGA_ALTERNATIVE_PALETTE)
-#define GAMEOPTIONS_FANMADE_MOUSE GUIO1(GAMEOPTION_ORIGINAL_SAVELOAD)
+#define GAMEOPTIONS_DEFAULT GUIO4(GAMEOPTION_ORIGINAL_SAVELOAD,GAMEOPTION_DISABLE_MOUSE,GAMEOPTION_USE_HERCULES_FONT,GAMEOPTION_COMMAND_PROMPT_WINDOW)
+#define GAMEOPTIONS_AMIGA GUIO4(GAMEOPTION_ORIGINAL_SAVELOAD,GAMEOPTION_AMIGA_ALTERNATIVE_PALETTE,GAMEOPTION_USE_HERCULES_FONT,GAMEOPTION_COMMAND_PROMPT_WINDOW)
+#define GAMEOPTIONS_FANMADE_MOUSE GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD,GAMEOPTION_USE_HERCULES_FONT,GAMEOPTION_COMMAND_PROMPT_WINDOW)
#define GAME_LVFPN(id,extra,fname,md5,size,lang,ver,features,gid,platform,interp,guioptions) { \
{ \
id, \
extra, \
- AD_ENTRY1s(fname,md5,size), \
+ AD_ENTRY1s(fname,md5,size), \
lang, \
platform, \
- ADGF_NO_FLAGS, \
- guioptions \
+ ADGF_NO_FLAGS, \
+ guioptions \
}, \
gid, \
interp, \
@@ -51,11 +53,11 @@ namespace Agi {
{ \
id, \
name, \
- AD_ENTRY1s(fname,md5,size), \
+ AD_ENTRY1s(fname,md5,size), \
lang, \
platform, \
- ADGF_USEEXTRAASTITLE, \
- guioptions \
+ ADGF_USEEXTRAASTITLE, \
+ guioptions \
}, \
gid, \
interp, \
@@ -238,7 +240,7 @@ static const AGIGameDescription gameDescriptions[] = {
// Menus not tested
GAME_PS("ddp", "1.0C 1986-06-09", "550971d196f65190a5c760d2479406ef", 132, 0x2272, GID_DDP, Common::kPlatformDOS),
- // Gold Rush! (Amiga) 1.01 1/13/89 aka 2.05 3/9/89 # 2.316
+ // Gold Rush! (Amiga) 1.01 1/13/89 aka 2.05 3/9/89 # 2.316
GAME3_PSO("goldrush", "1.01 1989-01-13 aka 2.05 1989-03-09", "dirs", "a1d4de3e75c2688c1e2ca2634ffc3bd8", 2399, 0x3149, 0, GID_GOLDRUSH, Common::kPlatformAmiga, GAMEOPTIONS_AMIGA),
// Gold Rush! (Apple IIgs) 1.0M 2/28/89 (CE) aka 2.01 12/22/88
@@ -285,7 +287,7 @@ static const AGIGameDescription gameDescriptions[] = {
// Gold Rush! (CoCo3 360k/720k) [AGI 2.072]
GAME_PS("goldrush", "updated", "c49bf56bf91e31a4601a604e51ef8bfb", 744, 0x2440, GID_GOLDRUSH, Common::kPlatformCoCo3),
- // King's Quest 1 (Amiga) 1.0U # 2.082
+ // King's Quest 1 (Amiga) 1.0U # 2.082
// The original game did not have menus, they are enabled under ScummVM
GAME_FPO("kq1", "1.0U 1986", "246c695324f1c514aee2b904fa352fad", 0x2440, GF_MENUS, GID_KQ1, Common::kPlatformAmiga, GAMEOPTIONS_AMIGA),
@@ -354,7 +356,7 @@ static const AGIGameDescription gameDescriptions[] = {
// King's Quest 3 (IIgs) 2.0A 8/28/88 (CE)
GAME_P("kq3", "2.0A 1988-08-28 (CE)", "ac30b7ca5a089b5e642fbcdcbe872c12", 0x2917, GID_KQ3, Common::kPlatformApple2GS),
- // King's Quest 3 (Amiga) 2.15 11/15/89 # 2.333
+ // King's Quest 3 (Amiga) 2.15 11/15/89 # 2.333
// Original pauses with ESC, has menus accessible with mouse.
// ver = 0x3086 -> menus accessible with ESC or mouse, bug #2835581 (KQ3: Game Crash When Leaving Tavern as Fly).
// ver = 0x3149 -> menus accessible with mouse, ESC pauses game, bug #2835581 disappears.
@@ -422,7 +424,7 @@ static const AGIGameDescription gameDescriptions[] = {
// Leisure Suit Larry 1 (ST) 1.04 6/18/87
GAME_P("lsl1", "1.04 1987-06-18", "8b579f8673fe9448c2538f5ed9887cf0", 0x2440, GID_LSL1, Common::kPlatformAtariST),
- // Leisure Suit Larry 1 (Amiga) 1.05 6/26/87 # x.yyy
+ // Leisure Suit Larry 1 (Amiga) 1.05 6/26/87 # x.yyy
GAME_PO("lsl1", "1.05 1987-06-26", "3f5d26d8834ca49c147fb60936869d56", 0x2440, GID_LSL1, Common::kPlatformAmiga, GAMEOPTIONS_AMIGA),
// Leisure Suit Larry 1 (IIgs) 1.0E
@@ -459,7 +461,7 @@ static const AGIGameDescription gameDescriptions[] = {
// Manhunter SF (ST) 1.0 7/29/89
GAME3_P("mh2", "1.0 1989-07-29", "mh2dir", "5e3581495708b952fea24438a6c7e040", 0x3149, 0, GID_MH1, Common::kPlatformAtariST),
- // Manhunter SF (Amiga) 3.06 8/17/89 # 2.333
+ // Manhunter SF (Amiga) 3.06 8/17/89 # 2.333
GAME3_PSO("mh2", "3.06 1989-08-17", "dirs", "b412e8a126368b76696696f7632d4c16", 2573, 0x3086, GF_OLDAMIGAV20, GID_MH2, Common::kPlatformAmiga, GAMEOPTIONS_AMIGA),
// Manhunter SF (PC 5.25") 3.03 8/17/89 [AGI 3.002.149]
@@ -503,7 +505,7 @@ static const AGIGameDescription gameDescriptions[] = {
// Police Quest 1 (IIgs) 2.0B-88421
GAME_P("pq1", "2.0B 1988-04-21", "e7c175918372336461e3811d594f482f", 0x2917, GID_PQ1, Common::kPlatformApple2GS),
- // Police Quest 1 (Amiga) 2.0B 2/22/89 # 2.310
+ // Police Quest 1 (Amiga) 2.0B 2/22/89 # 2.310
GAME3_PSO("pq1", "2.0B 1989-02-22", "dirs", "cfa93e5f2aa7378bddd10ad6746a2ffb", 1613, 0x3149, 0, GID_PQ1, Common::kPlatformAmiga, GAMEOPTIONS_AMIGA),
// Police Quest 1 (IIgs) 2.0A-88318
@@ -540,7 +542,7 @@ static const AGIGameDescription gameDescriptions[] = {
// The original game did not have menus, they are enabled under ScummVM
GAME_FP("sq1", "1.1A 720kb", "0a92b1be7daf3bb98caad3f849868aeb", 0x2272, GF_MENUS, GID_SQ1, Common::kPlatformDOS),
- // Space Quest 1 (Amiga) 1.2 # 2.082
+ // Space Quest 1 (Amiga) 1.2 # 2.082
// The original game did not have menus, they are enabled under ScummVM
GAME_FPO("sq1", "1.2 1986", "0b216d931e95750f1f4837d6a4b821e5", 0x2440, GF_MENUS | GF_OLDAMIGAV20, GID_SQ1, Common::kPlatformAmiga, GAMEOPTIONS_AMIGA),
@@ -573,7 +575,14 @@ static const AGIGameDescription gameDescriptions[] = {
GAME("sq2", "2.0D 1988-03-14 3.5\"", "85390bde8958c39830e1adbe9fff87f3", 0x2936, GID_SQ2),
// Space Quest 2 (IIgs) 2.0A 7/25/88 (CE)
- GAME_P("sq2", "2.0A 1988-07-25 (CE)", "5dfdac98dd3c01fcfb166529f917e911", 0x2936, GID_SQ2, Common::kPlatformApple2GS),
+ // We have to see this as AGI < 2.936, because otherwise a set.pri.base call would somewhat break
+ // priority in SQ2, when entering Vohaul's vault.
+ // The Apple IIgs AGI included with SQ2 is the same as the one included with KQ3.
+ // We currently consider KQ3 IIgs to be a 2.917-equivalent.
+ // The SQ2 IIgs AGI definitely has 177 kernel functions, but it seems that Sierra shuffled the last few around / added a few extras at the end.
+ // For KQ3 set.pri.base is called with parameters that seem to be sound resources, which means
+ // set.pri.base was possibly discard.sound. For KQ4 onwards it seems this was cleaned up.
+ GAME_P("sq2", "2.0A 1988-07-25 (CE)", "5dfdac98dd3c01fcfb166529f917e911", 0x2917, GID_SQ2, Common::kPlatformApple2GS),
{
// Space Quest 2 (Amiga) 2.0F
@@ -726,10 +735,10 @@ static const AGIGameDescription gameDescriptions[] = {
FANMADE("Good Man (demo v3.41)", "3facd8a8f856b7b6e0f6c3200274d88c"),
GAME_LVFPNF("agi-fanmade", "Groza (russian) [AGDS sample]", "logdir", "421da3a18004122a966d64ab6bd86d2e", -1,
- Common::RU_RUS, 0x2440, GF_AGDS, GID_FANMADE, Common::kPlatformDOS,GType_V2,GAMEOPTIONS_DEFAULT),
+ Common::RU_RUS, 0x2440, GF_AGDS, GID_FANMADE, Common::kPlatformDOS, GType_V2, GAMEOPTIONS_DEFAULT),
GAME_LVFPNF("agi-fanmade", "Get Outta Space Quest", "logdir", "aaea5b4a348acb669d13b0e6f22d4dc9", -1,
- Common::EN_ANY, 0x2440, GF_FANMADE, GID_GETOUTTASQ, Common::kPlatformDOS,GType_V2,GAMEOPTIONS_DEFAULT),
+ Common::EN_ANY, 0x2440, GF_FANMADE, GID_GETOUTTASQ, Common::kPlatformDOS, GType_V2, GAMEOPTIONS_DEFAULT),
FANMADE_FO("Half-Death - Terror At White-Mesa", "b62c05d0ace878261392073f57ae788c", GF_AGIMOUSE, GAMEOPTIONS_FANMADE_MOUSE),
FANMADE("Hank's Quest (v1.0 English) - Victim of Society", "64c15b3d0483d17888129100dc5af213"),
@@ -801,7 +810,7 @@ static const AGIGameDescription gameDescriptions[] = {
FANMADE("Residence 44 Quest (English v0.99)", "fe507851fddc863d540f2bec67cc67fd"),
FANMADE("Residence 44 Quest (English v1.0a)", "f99e3f69dc8c77a45399da9472ef5801"),
FANMADE("SQ2Eye (v0.3)", "2be2519401d38ad9ce8f43b948d093a3"),
- // FANMADE("SQ2Eye (v0.4)", "2be2519401d38ad9ce8f43b948d093a3"),
+ //FANMADE("SQ2Eye (v0.4)", "2be2519401d38ad9ce8f43b948d093a3"),
FANMADE("SQ2Eye (v0.41)", "f0e82c55f10eb3542d7cd96c107ae113"),
FANMADE("SQ2Eye (v0.42)", "d7beae55f6328ef8b2da47b1aafea40c"),
FANMADE("SQ2Eye (v0.43)", "2a895f06e45de153bb4b77c982009e06"),
@@ -849,6 +858,7 @@ static const AGIGameDescription gameDescriptions[] = {
FANMADE("Tex McPhilip 2 - Road To Divinity (v1.5)", "7387e8df854440bc26620ca0ea43af9a"),
FANMADE("Tex McPhilip 3 - A Destiny of Sin (Demo v0.25)", "992d12031a486ad84e592ff5d7c9d782"),
FANMADE("The 13th Disciple (v1.00)", "887719ad59afce9a41ec057dbb73ad73"),
+ FANMADE("The 13th Disciple (v1.01)", "58e3ec1b9ac1a79901c472aaa59db832"),
FANMADE("The Adventures of a Crazed Hermit", "6e3086cbb794d3299a9c5a9792295511"),
FANMADE("The Gourd of the Beans", "246f4d94946afb547482d44a53616d06"),
FANMADE("The Grateful Dead", "c2146631afacf8cb455ce24f3d2d46e7"),
diff --git a/engines/agi/font.cpp b/engines/agi/font.cpp
new file mode 100644
index 0000000000..f9605e4a3d
--- /dev/null
+++ b/engines/agi/font.cpp
@@ -0,0 +1,1296 @@
+/* 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 "agi/agi.h"
+#include "agi/font.h"
+#include "agi/text.h"
+
+namespace Agi {
+
+GfxFont::GfxFont(AgiBase *vm) {
+ _vm = vm;
+
+ _fontData = nullptr;
+ _fontDataAllocated = nullptr;
+ _fontIsHires = false;
+}
+
+GfxFont::~GfxFont() {
+ free(_fontDataAllocated);
+}
+
+// Arrow to the right character, used for original saved game dialogs
+// Needs to get patched into at least the Apple IIgs font, because the font didn't support
+// that character and original AGI on Apple IIgs used Apple II menus for saving/restoring.
+static const uint8 fontData_ArrowRightCharacter[8] = {
+ 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00,
+};
+
+// topaz data, same as in engines/parallaction/staticres.cpp
+// seems to have been recreated and is not the original amiga font
+static const uint8 fontData_AmigaPseudoTopaz[2600] = {
+ 0x00, 0x00, 0x03, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x79, 0x00, 0x00, 0x03, 0xe9, 0x00, 0x00, 0x02, 0x79,
+ 0x70, 0xff, 0x4e, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x00, 0x1a, 0x0f, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x45, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x09, 0x74, 0x00, 0x08,
+ 0x00, 0x40, 0x00, 0x08, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x20, 0xff, 0x00, 0x00, 0x00, 0x6e,
+ 0x00, 0xbe, 0x00, 0x00, 0x06, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+ 0x6c, 0x6c, 0x18, 0x00, 0x38, 0x18, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x3c, 0x18,
+ 0x3c, 0x3c, 0x1c, 0x7e, 0x1c, 0x7e, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x7c, 0x3c,
+ 0x7c, 0x1e, 0x78, 0x7e, 0x7e, 0x3c, 0x66, 0x3c, 0x06, 0xc6, 0x60, 0xc6, 0xc6, 0x3c, 0x7c, 0x78,
+ 0x7c, 0x3c, 0x7e, 0x66, 0x66, 0xc6, 0xc3, 0xc3, 0xfe, 0x3c, 0xc0, 0x3c, 0x10, 0x00, 0x18, 0x00,
+ 0x60, 0x00, 0x06, 0x00, 0x1c, 0x00, 0x60, 0x18, 0x0c, 0x60, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x18, 0x70, 0x72, 0x0f, 0x00, 0x18,
+ 0x00, 0x1c, 0x42, 0xc3, 0x18, 0x3c, 0x66, 0x7e, 0x1c, 0x00, 0x3e, 0x7e, 0x7e, 0x3c, 0x18, 0x78,
+ 0x78, 0x18, 0x00, 0x3e, 0x00, 0x00, 0x30, 0x38, 0x00, 0x40, 0x40, 0xc0, 0x18, 0x3c, 0x3c, 0x7e,
+ 0x06, 0x66, 0x18, 0x7e, 0x7e, 0x36, 0x0c, 0x0c, 0x18, 0x3c, 0xc6, 0x3c, 0x60, 0x76, 0x18, 0x00,
+ 0x0c, 0x7e, 0x71, 0x66, 0x00, 0x66, 0x60, 0x0e, 0x7e, 0x66, 0x18, 0x6e, 0x3c, 0x00, 0x18, 0x7e,
+ 0x06, 0x66, 0x18, 0x00, 0x7e, 0x34, 0x0c, 0x0c, 0x18, 0x0c, 0x60, 0x00, 0x18, 0x3c, 0x0c, 0x00,
+ 0x0c, 0x00, 0x71, 0x00, 0x00, 0x00, 0x18, 0x0c, 0x7e, 0x00, 0x18, 0x3c, 0x00, 0x18, 0x6c, 0x6c,
+ 0x3e, 0x66, 0x6c, 0x18, 0x18, 0x18, 0x66, 0x18, 0x00, 0x00, 0x00, 0x06, 0x66, 0x38, 0x66, 0x66,
+ 0x3c, 0x60, 0x30, 0x06, 0x66, 0x66, 0x18, 0x18, 0x06, 0x00, 0x60, 0x66, 0xc6, 0x66, 0x66, 0x30,
+ 0x6c, 0x60, 0x60, 0x66, 0x66, 0x18, 0x06, 0xcc, 0x60, 0xee, 0xe6, 0x66, 0x66, 0xcc, 0x66, 0x66,
+ 0x18, 0x66, 0x66, 0xc6, 0x66, 0x66, 0x0c, 0x30, 0x60, 0x0c, 0x38, 0x00, 0x18, 0x00, 0x60, 0x00,
+ 0x06, 0x00, 0x30, 0x00, 0x60, 0x00, 0x00, 0x60, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x9c, 0x3c, 0x7e, 0x00, 0x0c, 0x36,
+ 0x3c, 0x66, 0x18, 0x60, 0x66, 0x81, 0x24, 0x33, 0x06, 0x81, 0x00, 0x66, 0x18, 0x0c, 0x0c, 0x30,
+ 0x00, 0x7a, 0x00, 0x00, 0x70, 0x44, 0xcc, 0xc6, 0xc6, 0x23, 0x00, 0x66, 0x18, 0x00, 0x1c, 0x00,
+ 0x24, 0x60, 0x00, 0x1c, 0x18, 0x18, 0x00, 0x66, 0xcc, 0x00, 0x60, 0x3c, 0x30, 0xc6, 0x18, 0x00,
+ 0x8e, 0x00, 0xc6, 0x66, 0x60, 0x38, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x0c, 0x00,
+ 0x24, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x18, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x7e,
+ 0x8e, 0x66, 0x18, 0x00, 0x18, 0x18, 0x00, 0x66, 0x00, 0x18, 0x00, 0x18, 0x00, 0xfe, 0x60, 0xac,
+ 0x68, 0x30, 0x30, 0x0c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x6e, 0x78, 0x06, 0x06, 0x6c, 0x7c,
+ 0x60, 0x06, 0x66, 0x66, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x06, 0xde, 0x66, 0x66, 0x60, 0x66, 0x60,
+ 0x60, 0x60, 0x66, 0x18, 0x06, 0xd8, 0x60, 0xfe, 0xf6, 0x66, 0x66, 0xcc, 0x66, 0x70, 0x18, 0x66,
+ 0x66, 0xc6, 0x3c, 0x3c, 0x18, 0x30, 0x30, 0x0c, 0x6c, 0x00, 0x0c, 0x3c, 0x7c, 0x3c, 0x3e, 0x3c,
+ 0x7c, 0x3e, 0x7c, 0x18, 0x0c, 0x66, 0x18, 0xec, 0x7c, 0x3c, 0x7c, 0x3e, 0x7c, 0x3c, 0x7c, 0x66,
+ 0x66, 0xc6, 0xc6, 0x66, 0x7e, 0x18, 0x18, 0x18, 0x00, 0xf0, 0x66, 0x18, 0x3e, 0x30, 0x66, 0x3c,
+ 0x18, 0x3c, 0x00, 0x9d, 0x44, 0x66, 0x00, 0xb9, 0x00, 0x3c, 0x7e, 0x18, 0x18, 0x60, 0x66, 0x7a,
+ 0x18, 0x00, 0x30, 0x44, 0x66, 0x4c, 0x4c, 0x66, 0x18, 0x66, 0x18, 0x3c, 0x3c, 0x3c, 0x3c, 0x60,
+ 0x7e, 0x3c, 0x7e, 0x7e, 0x7e, 0x60, 0xd8, 0x3c, 0x60, 0x66, 0xc6, 0xe6, 0x3c, 0x3c, 0x3c, 0x3c,
+ 0x6c, 0x66, 0x6c, 0x66, 0x66, 0x66, 0x7e, 0x7e, 0x66, 0x3c, 0x18, 0x3c, 0x18, 0x3c, 0x3c, 0x3c,
+ 0x3c, 0x18, 0x3c, 0x7e, 0x3c, 0x3e, 0x6c, 0x00, 0x18, 0x3c, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x66, 0x1e, 0x3c, 0x66, 0x00, 0x7e, 0x7e, 0x00, 0x18, 0x00, 0x6c, 0x3c, 0xd8, 0x76, 0x00,
+ 0x30, 0x0c, 0xff, 0x7e, 0x00, 0x7e, 0x00, 0x18, 0x7e, 0x18, 0x0c, 0x1c, 0xcc, 0x06, 0x7c, 0x0c,
+ 0x3c, 0x3e, 0x00, 0x00, 0x60, 0x00, 0x06, 0x0c, 0xd6, 0x7e, 0x7c, 0x60, 0x66, 0x78, 0x78, 0x6e,
+ 0x7e, 0x18, 0x06, 0xf0, 0x60, 0xd6, 0xde, 0x66, 0x7c, 0xcc, 0x7c, 0x3c, 0x18, 0x66, 0x66, 0xd6,
+ 0x18, 0x18, 0x30, 0x30, 0x18, 0x0c, 0xc6, 0x00, 0x00, 0x06, 0x66, 0x60, 0x66, 0x66, 0x30, 0x66,
+ 0x66, 0x18, 0x0c, 0x6c, 0x18, 0xfe, 0x66, 0x66, 0x66, 0x66, 0x66, 0x60, 0x30, 0x66, 0x66, 0xc6,
+ 0x6c, 0x66, 0x0c, 0x70, 0x18, 0x0e, 0x00, 0xc3, 0x66, 0x18, 0x6c, 0x78, 0x3c, 0x18, 0x00, 0x66,
+ 0x00, 0xb1, 0x3c, 0xcc, 0x00, 0xa5, 0x00, 0x00, 0x18, 0x30, 0x0c, 0x00, 0x66, 0x3a, 0x18, 0x00,
+ 0x30, 0x38, 0x33, 0x58, 0x58, 0x2c, 0x30, 0x7e, 0x18, 0x66, 0x66, 0x66, 0x66, 0x78, 0x60, 0x66,
+ 0x60, 0x4c, 0x60, 0x6e, 0xf0, 0x18, 0x60, 0x30, 0xe6, 0xf6, 0x66, 0x66, 0x66, 0x66, 0x38, 0x66,
+ 0x70, 0x30, 0x66, 0x66, 0x4c, 0x4c, 0x6c, 0x06, 0x18, 0x06, 0x3c, 0x06, 0x06, 0x66, 0x66, 0x3c,
+ 0x66, 0x0c, 0x66, 0x66, 0x78, 0x18, 0x18, 0x60, 0x7c, 0x66, 0x3c, 0x3c, 0x3c, 0x3c, 0x7e, 0x66,
+ 0x78, 0x60, 0x66, 0x66, 0x0c, 0x0c, 0x00, 0x18, 0x00, 0xfe, 0x06, 0x36, 0xdc, 0x00, 0x30, 0x0c,
+ 0x3c, 0x18, 0x00, 0x00, 0x00, 0x30, 0x76, 0x18, 0x18, 0x06, 0xfe, 0x06, 0x66, 0x18, 0x66, 0x06,
+ 0x00, 0x00, 0x18, 0x7e, 0x18, 0x18, 0xde, 0x66, 0x66, 0x60, 0x66, 0x60, 0x60, 0x66, 0x66, 0x18,
+ 0x06, 0xd8, 0x60, 0xc6, 0xce, 0x66, 0x60, 0xcc, 0x6c, 0x0e, 0x18, 0x66, 0x3c, 0xfe, 0x3c, 0x18,
+ 0x60, 0x30, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x3e, 0x66, 0x60, 0x66, 0x7e, 0x30, 0x66, 0x66, 0x18,
+ 0x0c, 0x78, 0x18, 0xd6, 0x66, 0x66, 0x66, 0x66, 0x60, 0x3c, 0x30, 0x66, 0x66, 0xd6, 0x38, 0x66,
+ 0x18, 0x18, 0x18, 0x18, 0x00, 0x0f, 0x66, 0x18, 0x3e, 0x30, 0x42, 0x3c, 0x18, 0x3c, 0x00, 0x9d,
+ 0x00, 0x66, 0x00, 0xb9, 0x00, 0x00, 0x18, 0x7c, 0x78, 0x00, 0x66, 0x0a, 0x00, 0x00, 0x30, 0x00,
+ 0x66, 0x32, 0x3e, 0xd9, 0x60, 0x66, 0x18, 0x7e, 0x40, 0x7e, 0x7e, 0x60, 0x78, 0x40, 0x78, 0x18,
+ 0x78, 0x66, 0xd8, 0x18, 0x60, 0x0c, 0xf6, 0xde, 0x66, 0x66, 0x66, 0x66, 0x6c, 0x66, 0xe0, 0x0c,
+ 0x66, 0x66, 0x18, 0x18, 0x66, 0x3e, 0x18, 0x3e, 0x60, 0x3e, 0x3e, 0x7e, 0x7e, 0x60, 0x7e, 0x18,
+ 0x7e, 0x66, 0x6c, 0x18, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x18, 0x3c,
+ 0x66, 0x66, 0x18, 0x18, 0x00, 0x00, 0x00, 0x6c, 0x7c, 0x6a, 0xce, 0x00, 0x18, 0x18, 0x66, 0x18,
+ 0x18, 0x00, 0x18, 0x60, 0x66, 0x18, 0x30, 0x66, 0x0c, 0x66, 0x66, 0x18, 0x66, 0x0c, 0x18, 0x18,
+ 0x06, 0x00, 0x60, 0x00, 0xc0, 0x66, 0x66, 0x30, 0x6c, 0x60, 0x60, 0x66, 0x66, 0x18, 0x66, 0xcc,
+ 0x60, 0xc6, 0xc6, 0x66, 0x60, 0xdc, 0x66, 0x66, 0x18, 0x66, 0x3c, 0xee, 0x66, 0x18, 0xc0, 0x30,
+ 0x06, 0x0c, 0x00, 0x00, 0x00, 0x66, 0x66, 0x60, 0x66, 0x60, 0x30, 0x3e, 0x66, 0x18, 0x0c, 0x6c,
+ 0x18, 0xc6, 0x66, 0x66, 0x7c, 0x3e, 0x60, 0x06, 0x30, 0x66, 0x3c, 0xfe, 0x6c, 0x3c, 0x30, 0x18,
+ 0x18, 0x18, 0x00, 0x3c, 0x66, 0x18, 0x0c, 0x30, 0x00, 0x18, 0x18, 0x06, 0x00, 0x81, 0x7e, 0x33,
+ 0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x0a, 0x00, 0x00, 0x00, 0x7c, 0xcc, 0x66,
+ 0x62, 0x33, 0x66, 0x66, 0x18, 0x66, 0x66, 0x66, 0x66, 0x60, 0x60, 0x66, 0x60, 0x32, 0x60, 0x3e,
+ 0xcc, 0x18, 0x7e, 0x66, 0xde, 0xce, 0x66, 0x66, 0x66, 0x66, 0xc6, 0x66, 0x60, 0x66, 0x66, 0x66,
+ 0x32, 0x32, 0x66, 0x66, 0x18, 0x66, 0x60, 0x66, 0x66, 0x60, 0x60, 0x60, 0x60, 0x30, 0x60, 0x3e,
+ 0x66, 0x18, 0x18, 0x06, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x18, 0x66, 0x18, 0x06, 0x66, 0x66,
+ 0x30, 0x30, 0x00, 0x18, 0x00, 0x6c, 0x18, 0xcc, 0x7b, 0x00, 0x0c, 0x30, 0x00, 0x00, 0x18, 0x00,
+ 0x18, 0xc0, 0x3c, 0x18, 0x7e, 0x3c, 0x0c, 0x3c, 0x3c, 0x18, 0x3c, 0x38, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x18, 0x78, 0x66, 0x7c, 0x1e, 0x78, 0x7e, 0x60, 0x3e, 0x66, 0x3c, 0x3c, 0xc6, 0x7e, 0xc6,
+ 0xc6, 0x3c, 0x60, 0x7e, 0x66, 0x3c, 0x18, 0x3c, 0x18, 0xc6, 0xc3, 0x18, 0xfe, 0x3c, 0x03, 0x3c,
+ 0x00, 0x00, 0x00, 0x3e, 0x7c, 0x3c, 0x3e, 0x3c, 0x30, 0x06, 0x66, 0x0c, 0x0c, 0x66, 0x0c, 0xc6,
+ 0x66, 0x3c, 0x60, 0x06, 0x60, 0x7c, 0x1c, 0x3e, 0x18, 0x6c, 0xc6, 0x18, 0x7e, 0x0e, 0x18, 0x70,
+ 0x00, 0xf0, 0x7e, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x3c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x81,
+ 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7f, 0x0a, 0x00, 0x18, 0x00, 0x00, 0x00, 0xcf, 0xc4, 0x67,
+ 0x3c, 0x67, 0x3e, 0x66, 0x3c, 0x66, 0x66, 0x7f, 0x7e, 0x3c, 0x7e, 0x7e, 0x7e, 0x18, 0x30, 0x3c,
+ 0x18, 0x3c, 0xce, 0x18, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x3f, 0x7e, 0x3c, 0x3c, 0x3c, 0x7e, 0x7e,
+ 0x6c, 0x3f, 0x1e, 0x3e, 0x3c, 0x3e, 0x3e, 0x3c, 0x3c, 0x3c, 0x3c, 0x7e, 0x3c, 0x06, 0x18, 0x0c,
+ 0x0c, 0x7c, 0x66, 0x18, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x3f, 0x0c, 0x7c, 0x3e, 0x3e, 0x7e, 0x7e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x0e, 0x01, 0x00, 0x03,
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0x00, 0x30, 0x00,
+ 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x03,
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x00, 0x18, 0x00,
+ 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x10, 0x00, 0x08, 0x00, 0x18, 0x00, 0x08, 0x00, 0x20,
+ 0x00, 0x08, 0x00, 0x28, 0x00, 0x08, 0x00, 0x30, 0x00, 0x08, 0x00, 0x38, 0x00, 0x08, 0x00, 0x40,
+ 0x00, 0x08, 0x00, 0x48, 0x00, 0x08, 0x00, 0x50, 0x00, 0x08, 0x00, 0x58, 0x00, 0x08, 0x00, 0x60,
+ 0x00, 0x08, 0x00, 0x68, 0x00, 0x08, 0x00, 0x70, 0x00, 0x08, 0x00, 0x78, 0x00, 0x08, 0x00, 0x80,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x08, 0x00, 0x90, 0x00, 0x08, 0x00, 0x98, 0x00, 0x08, 0x00, 0xa0,
+ 0x00, 0x08, 0x00, 0xa8, 0x00, 0x08, 0x00, 0xb0, 0x00, 0x08, 0x00, 0xb8, 0x00, 0x08, 0x00, 0xc0,
+ 0x00, 0x08, 0x00, 0xc8, 0x00, 0x08, 0x00, 0xd0, 0x00, 0x08, 0x00, 0xd8, 0x00, 0x08, 0x00, 0xe0,
+ 0x00, 0x08, 0x00, 0xe8, 0x00, 0x08, 0x00, 0xf0, 0x00, 0x08, 0x00, 0xf8, 0x00, 0x08, 0x01, 0x00,
+ 0x00, 0x08, 0x01, 0x08, 0x00, 0x08, 0x01, 0x10, 0x00, 0x08, 0x01, 0x18, 0x00, 0x08, 0x01, 0x20,
+ 0x00, 0x08, 0x01, 0x28, 0x00, 0x08, 0x01, 0x30, 0x00, 0x08, 0x01, 0x38, 0x00, 0x08, 0x01, 0x40,
+ 0x00, 0x08, 0x01, 0x48, 0x00, 0x08, 0x01, 0x50, 0x00, 0x08, 0x01, 0x58, 0x00, 0x08, 0x01, 0x60,
+ 0x00, 0x08, 0x01, 0x68, 0x00, 0x08, 0x01, 0x70, 0x00, 0x08, 0x01, 0x78, 0x00, 0x08, 0x01, 0x80,
+ 0x00, 0x08, 0x01, 0x88, 0x00, 0x08, 0x01, 0x90, 0x00, 0x08, 0x01, 0x98, 0x00, 0x08, 0x01, 0xa0,
+ 0x00, 0x08, 0x01, 0xa8, 0x00, 0x08, 0x01, 0xb0, 0x00, 0x08, 0x01, 0xb8, 0x00, 0x08, 0x01, 0xc0,
+ 0x00, 0x08, 0x01, 0xc8, 0x00, 0x08, 0x01, 0xd0, 0x00, 0x08, 0x01, 0xd8, 0x00, 0x08, 0x01, 0xe0,
+ 0x00, 0x08, 0x01, 0xe8, 0x00, 0x08, 0x01, 0xf0, 0x00, 0x08, 0x01, 0xf8, 0x00, 0x08, 0x02, 0x00,
+ 0x00, 0x08, 0x02, 0x08, 0x00, 0x08, 0x02, 0x10, 0x00, 0x08, 0x02, 0x18, 0x00, 0x08, 0x02, 0x20,
+ 0x00, 0x08, 0x02, 0x28, 0x00, 0x08, 0x02, 0x30, 0x00, 0x08, 0x02, 0x38, 0x00, 0x08, 0x02, 0x40,
+ 0x00, 0x08, 0x02, 0x48, 0x00, 0x08, 0x02, 0x50, 0x00, 0x08, 0x02, 0x58, 0x00, 0x08, 0x02, 0x60,
+ 0x00, 0x08, 0x02, 0x68, 0x00, 0x08, 0x02, 0x70, 0x00, 0x08, 0x02, 0x78, 0x00, 0x08, 0x02, 0x80,
+ 0x00, 0x08, 0x02, 0x88, 0x00, 0x08, 0x02, 0x90, 0x00, 0x08, 0x02, 0x98, 0x00, 0x08, 0x02, 0xa0,
+ 0x00, 0x08, 0x02, 0xa8, 0x00, 0x08, 0x02, 0xb0, 0x00, 0x08, 0x02, 0xb8, 0x00, 0x08, 0x02, 0xc0,
+ 0x00, 0x08, 0x02, 0xc8, 0x00, 0x08, 0x02, 0xd0, 0x00, 0x08, 0x02, 0xd8, 0x00, 0x08, 0x02, 0xe0,
+ 0x00, 0x08, 0x02, 0xe8, 0x00, 0x08, 0x02, 0xf0, 0x00, 0x08, 0x02, 0xf8, 0x00, 0x08, 0x03, 0x00,
+ 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+ 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+ 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+ 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+ 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+ 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+ 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+ 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x08, 0x03, 0x08, 0x00, 0x08, 0x03, 0x10, 0x00, 0x08, 0x03, 0x18, 0x00, 0x08, 0x03, 0x20,
+ 0x00, 0x08, 0x03, 0x28, 0x00, 0x08, 0x03, 0x30, 0x00, 0x08, 0x03, 0x38, 0x00, 0x08, 0x03, 0x40,
+ 0x00, 0x08, 0x03, 0x48, 0x00, 0x08, 0x03, 0x50, 0x00, 0x08, 0x03, 0x58, 0x00, 0x08, 0x03, 0x60,
+ 0x00, 0x08, 0x00, 0x68, 0x00, 0x08, 0x03, 0x68, 0x00, 0x08, 0x03, 0x70, 0x00, 0x08, 0x03, 0x78,
+ 0x00, 0x08, 0x03, 0x80, 0x00, 0x08, 0x03, 0x88, 0x00, 0x08, 0x03, 0x90, 0x00, 0x08, 0x03, 0x98,
+ 0x00, 0x08, 0x03, 0xa0, 0x00, 0x08, 0x03, 0xa8, 0x00, 0x08, 0x03, 0xb0, 0x00, 0x08, 0x03, 0xb8,
+ 0x00, 0x08, 0x03, 0xc0, 0x00, 0x08, 0x03, 0xc8, 0x00, 0x08, 0x03, 0xd0, 0x00, 0x08, 0x03, 0xd8,
+ 0x00, 0x08, 0x03, 0xe0, 0x00, 0x08, 0x03, 0xe8, 0x00, 0x08, 0x03, 0xf0, 0x00, 0x08, 0x03, 0xf8,
+ 0x00, 0x08, 0x04, 0x00, 0x00, 0x08, 0x04, 0x08, 0x00, 0x08, 0x04, 0x10, 0x00, 0x08, 0x04, 0x18,
+ 0x00, 0x08, 0x04, 0x20, 0x00, 0x08, 0x04, 0x28, 0x00, 0x08, 0x04, 0x30, 0x00, 0x08, 0x04, 0x38,
+ 0x00, 0x08, 0x04, 0x40, 0x00, 0x08, 0x04, 0x48, 0x00, 0x08, 0x04, 0x50, 0x00, 0x08, 0x04, 0x58,
+ 0x00, 0x08, 0x04, 0x60, 0x00, 0x08, 0x04, 0x68, 0x00, 0x08, 0x04, 0x70, 0x00, 0x08, 0x04, 0x78,
+ 0x00, 0x08, 0x04, 0x80, 0x00, 0x08, 0x04, 0x88, 0x00, 0x08, 0x04, 0x90, 0x00, 0x08, 0x04, 0x98,
+ 0x00, 0x08, 0x04, 0xa0, 0x00, 0x08, 0x04, 0xa8, 0x00, 0x08, 0x04, 0xb0, 0x00, 0x08, 0x04, 0xb8,
+ 0x00, 0x08, 0x04, 0xc0, 0x00, 0x08, 0x04, 0xc8, 0x00, 0x08, 0x04, 0xd0, 0x00, 0x08, 0x04, 0xd8,
+ 0x00, 0x08, 0x04, 0xe0, 0x00, 0x08, 0x04, 0xe8, 0x00, 0x08, 0x04, 0xf0, 0x00, 0x08, 0x04, 0xf8,
+ 0x00, 0x08, 0x05, 0x00, 0x00, 0x08, 0x05, 0x08, 0x00, 0x08, 0x05, 0x10, 0x00, 0x08, 0x05, 0x18,
+ 0x00, 0x08, 0x05, 0x20, 0x00, 0x08, 0x05, 0x28, 0x00, 0x08, 0x05, 0x30, 0x00, 0x08, 0x05, 0x38,
+ 0x00, 0x08, 0x05, 0x40, 0x00, 0x08, 0x05, 0x48, 0x00, 0x08, 0x05, 0x50, 0x00, 0x08, 0x05, 0x58,
+ 0x00, 0x08, 0x05, 0x60, 0x00, 0x08, 0x05, 0x68, 0x00, 0x08, 0x05, 0x70, 0x00, 0x08, 0x05, 0x78,
+ 0x00, 0x08, 0x05, 0x80, 0x00, 0x08, 0x05, 0x88, 0x00, 0x08, 0x05, 0x90, 0x00, 0x08, 0x05, 0x98,
+ 0x00, 0x08, 0x05, 0xa0, 0x00, 0x08, 0x05, 0xa8, 0x00, 0x08, 0x05, 0xb0, 0x00, 0x08, 0x05, 0xb8,
+ 0x00, 0x08, 0x05, 0xc0, 0x00, 0x08, 0x05, 0xc8, 0x00, 0x08, 0x05, 0xd0, 0x00, 0x08, 0x05, 0xd8,
+ 0x00, 0x08, 0x05, 0xe0, 0x00, 0x08, 0x05, 0xe8, 0x00, 0x08, 0x00, 0x38, 0x00, 0x08, 0x03, 0x00,
+ 0x00, 0x08, 0x03, 0x00, 0x00, 0x00, 0x03, 0xec, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x62,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf2
+};
+
+// 8x8 font patterns
+
+// this is basically the standard PC BIOS font, taken from Dos-Box, with a few modifications
+static const uint8 fontData_PCBIOS[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E,
+ 0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E,
+ 0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00,
+ 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00,
+ 0x38, 0x7C, 0x38, 0xFE, 0xFE, 0x7C, 0x38, 0x7C,
+ 0x10, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x7C,
+ 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00,
+ 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF,
+ 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00,
+ 0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF,
+ 0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78,
+ 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18,
+ 0x08, 0x0C, 0x0A, 0x0A, 0x08, 0x78, 0xF0, 0x00, // 0x0D changed
+ 0x18, 0x14, 0x1A, 0x16, 0x72, 0xE2, 0x0E, 0x1C, // 0x0E changed
+ 0x10, 0x54, 0x38, 0xEE, 0x38, 0x54, 0x10, 0x00, // 0x0F changed
+ //0x3F, 0x33, 0x3F, 0x30, 0x30, 0x70, 0xF0, 0xE0, // 0x0D original
+ //0x7F, 0x63, 0x7F, 0x63, 0x63, 0x67, 0xE6, 0xC0, // 0x0E original
+ //0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99, // 0x0F original
+ 0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00,
+ 0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00,
+ 0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x00, // 0x12 changed
+ //0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18, // 0x12 original
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
+ 0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x00, // 0x14 changed
+ 0x1C, 0x22, 0x38, 0x44, 0x44, 0x38, 0x88, 0x70, // 0x14 changed
+ //0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x00, // 0x14 original
+ //0x3E, 0x63, 0x38, 0x6C, 0x6C, 0x38, 0xCC, 0x78, // 0x15 original
+ 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00,
+ 0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x7E, // 0x17 changed
+ 0x18, 0x3C, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x00, // 0x18 changed
+ 0x18, 0x18, 0x18, 0x18, 0x5A, 0x3C, 0x18, 0x00, // 0x19 changed
+ //0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0xFF, // 0x17 original
+ //0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00, // 0x18 original
+ //0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, // 0x19 original
+ 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00,
+ 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00,
+ 0x00, 0x24, 0x42, 0xFF, 0x42, 0x24, 0x00, 0x00, // 0x1D changed
+ 0x00, 0x10, 0x38, 0x7C, 0xFE, 0xFE, 0x00, 0x00, // 0x1E changed
+ 0x00, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, // 0x1F changed
+ //0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00, // 0x1D original
+ //0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, 0x00, // 0x1E original
+ //0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00, // 0x1F original
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20
+ 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
+ 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00,
+ 0x30, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x30, 0x00,
+ 0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00,
+ 0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00,
+ 0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
+ 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
+ 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,
+ 0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
+ 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
+ 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00,
+ 0x7C, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0x7C, 0x00, // 0x30
+ 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00,
+ 0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00,
+ 0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00,
+ 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00,
+ 0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00,
+ 0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00,
+ 0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00,
+ 0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00,
+ 0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00,
+ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
+ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
+ 0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00,
+ 0x00, 0x00, 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x00,
+ 0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00,
+ 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00,
+ 0x7C, 0xC6, 0xDE, 0xDE, 0xDE, 0xC0, 0x78, 0x00, // 0x40
+ 0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00,
+ 0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00,
+ 0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00,
+ 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00,
+ 0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00,
+ 0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00,
+ 0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3E, 0x00,
+ 0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00,
+ 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00,
+ 0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00,
+ 0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00,
+ 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
+ 0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00,
+ 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00,
+ 0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, // 0x50
+ 0x78, 0xCC, 0xCC, 0xCC, 0xDC, 0x78, 0x1C, 0x00,
+ 0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00,
+ 0x78, 0xCC, 0xE0, 0x70, 0x1C, 0xCC, 0x78, 0x00,
+ 0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00,
+ 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
+ 0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00,
+ 0xC6, 0xC6, 0x6C, 0x38, 0x38, 0x6C, 0xC6, 0x00,
+ 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00,
+ 0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00,
+ 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
+ 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00,
+ 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
+ 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60
+ 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00,
+ 0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xDC, 0x00,
+ 0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00,
+ 0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00,
+ 0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
+ 0x38, 0x6C, 0x60, 0xF0, 0x60, 0x60, 0xF0, 0x00,
+ 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
+ 0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00,
+ 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x0C, 0x00, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78,
+ 0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00,
+ 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
+ 0x00, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00,
+ 0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00,
+ 0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0, // 0x70
+ 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E,
+ 0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0xF0, 0x00,
+ 0x00, 0x00, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x00,
+ 0x10, 0x30, 0x7C, 0x30, 0x30, 0x34, 0x18, 0x00,
+ 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00,
+ 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
+ 0x00, 0x00, 0xC6, 0xD6, 0xFE, 0xFE, 0x6C, 0x00,
+ 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00,
+ 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
+ 0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00,
+ 0x1C, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x1C, 0x00,
+ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
+ 0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00,
+ 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00,
+ 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x18, 0x0C, 0x78, // 0x80
+ 0x00, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
+ 0x1C, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
+ 0x7E, 0xC3, 0x3C, 0x06, 0x3E, 0x66, 0x3F, 0x00,
+ 0xCC, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
+ 0xE0, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
+ 0x30, 0x30, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
+ 0x00, 0x00, 0x78, 0xC0, 0xC0, 0x78, 0x0C, 0x38,
+ 0x7E, 0xC3, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
+ 0xCC, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
+ 0xE0, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
+ 0xCC, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x7C, 0xC6, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00,
+ 0xE0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0xC6, 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00,
+ 0x30, 0x30, 0x00, 0x78, 0xCC, 0xFC, 0xCC, 0x00,
+ 0x1C, 0x00, 0xFC, 0x60, 0x78, 0x60, 0xFC, 0x00,
+ 0x00, 0x00, 0x7F, 0x0C, 0x7F, 0xCC, 0x7F, 0x00,
+ 0x3E, 0x6C, 0xCC, 0xFE, 0xCC, 0xCC, 0xCE, 0x00,
+ 0x78, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
+ 0x00, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
+ 0x00, 0xE0, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
+ 0x78, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
+ 0x00, 0xE0, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
+ 0x00, 0xCC, 0x00, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
+ 0xC3, 0x18, 0x3C, 0x66, 0x66, 0x3C, 0x18, 0x00,
+ 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00,
+ 0x18, 0x18, 0x7E, 0xC0, 0xC0, 0x7E, 0x18, 0x18,
+ 0x38, 0x6C, 0x64, 0xF0, 0x60, 0xE6, 0xFC, 0x00,
+ 0xCC, 0xCC, 0x78, 0xFC, 0x30, 0xFC, 0x30, 0x30,
+ 0xF8, 0xCC, 0xCC, 0xFA, 0xC6, 0xCF, 0xC6, 0xC7,
+ 0x0E, 0x1B, 0x18, 0x3C, 0x18, 0x18, 0xD8, 0x70,
+ 0x1C, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
+ 0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x00, 0x1C, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
+ 0x00, 0x1C, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
+ 0x00, 0xF8, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0x00,
+ 0xFC, 0x00, 0xCC, 0xEC, 0xFC, 0xDC, 0xCC, 0x00,
+ 0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00, 0x00,
+ 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x7C, 0x00, 0x00,
+ 0x30, 0x00, 0x30, 0x60, 0xC0, 0xCC, 0x78, 0x00,
+ 0x00, 0x00, 0x00, 0xFC, 0xC0, 0xC0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xFC, 0x0C, 0x0C, 0x00, 0x00,
+ 0xC3, 0xC6, 0xCC, 0xDE, 0x33, 0x66, 0xCC, 0x0F,
+ 0xC3, 0xC6, 0xCC, 0xDB, 0x37, 0x6F, 0xCF, 0x03,
+ 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00,
+ 0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00,
+ 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,
+ 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
+ 0xDB, 0x77, 0xDB, 0xEE, 0xDB, 0x77, 0xDB, 0xEE,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xDC, 0xC8, 0xDC, 0x76, 0x00,
+ 0x00, 0x78, 0xCC, 0xF8, 0xCC, 0xF8, 0xC0, 0xC0,
+ 0x00, 0xFC, 0xCC, 0xC0, 0xC0, 0xC0, 0xC0, 0x00,
+ 0x00, 0xFE, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00,
+ 0xFC, 0xCC, 0x60, 0x30, 0x60, 0xCC, 0xFC, 0x00,
+ 0x00, 0x00, 0x7E, 0xD8, 0xD8, 0xD8, 0x70, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0xC0,
+ 0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0xFC, 0x30, 0x78, 0xCC, 0xCC, 0x78, 0x30, 0xFC,
+ 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x6C, 0x38, 0x00,
+ 0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x6C, 0xEE, 0x00,
+ 0x1C, 0x30, 0x18, 0x7C, 0xCC, 0xCC, 0x78, 0x00,
+ 0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x00, 0x00,
+ 0x06, 0x0C, 0x7E, 0xDB, 0xDB, 0x7E, 0x60, 0xC0,
+ 0x38, 0x60, 0xC0, 0xF8, 0xC0, 0x60, 0x38, 0x00,
+ 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x00,
+ 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0x00,
+ 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0xFC, 0x00,
+ 0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xFC, 0x00,
+ 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xFC, 0x00,
+ 0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70,
+ 0x30, 0x30, 0x00, 0xFC, 0x00, 0x30, 0x30, 0x00,
+ 0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00,
+ 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x0F, 0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x3C, 0x1C,
+ 0x78, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00,
+ 0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// Extended set (0x80-0xFF) for Russian versions of games
+static const uint8 fontData_ExtendedRussian[] = {
+ 0x1E, 0x36, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00, // 0x80
+ 0x7C, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
+ 0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00,
+ 0x7E, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00,
+ 0x38, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
+ 0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00,
+ 0xDB, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0xDB, 0x00,
+ 0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00,
+ 0x66, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
+ 0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
+ 0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00,
+ 0x1E, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
+ 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
+ 0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00,
+ 0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00,
+ 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
+ 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x00,
+ 0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00,
+ 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x66, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00,
+ 0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x18, 0x18, 0x00,
+ 0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
+ 0x66, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00,
+ 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
+ 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
+ 0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
+ 0xC6, 0xC6, 0xC6, 0xF6, 0xDE, 0xDE, 0xF6, 0x00,
+ 0x60, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
+ 0x78, 0x8C, 0x06, 0x3E, 0x06, 0x8C, 0x78, 0x00,
+ 0xCE, 0xDB, 0xDB, 0xFB, 0xDB, 0xDB, 0xCE, 0x00,
+ 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x00,
+ 0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3A, 0x00,
+ 0x00, 0x3C, 0x60, 0x3C, 0x66, 0x66, 0x3C, 0x00,
+ 0x00, 0x00, 0x7C, 0x66, 0x7C, 0x66, 0x7C, 0x00,
+ 0x00, 0x00, 0x7E, 0x60, 0x60, 0x60, 0x60, 0x00,
+ 0x00, 0x00, 0x3C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
+ 0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
+ 0x00, 0x00, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0x00,
+ 0x00, 0x00, 0x3C, 0x66, 0x0C, 0x66, 0x3C, 0x00,
+ 0x00, 0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
+ 0x00, 0x18, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
+ 0x00, 0x00, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00,
+ 0x00, 0x00, 0x1E, 0x36, 0x66, 0x66, 0x66, 0x00,
+ 0x00, 0x00, 0xC6, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00,
+ 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00,
+ 0x00, 0x00, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00,
+ 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+ 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
+ 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00,
+ 0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00,
+ 0x00, 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x7C, 0x00,
+ 0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x18, 0x00,
+ 0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
+ 0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x00,
+ 0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
+ 0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
+ 0x00, 0x00, 0xE0, 0x60, 0x7C, 0x66, 0x7C, 0x00,
+ 0x00, 0x00, 0xC6, 0xC6, 0xF6, 0xDE, 0xF6, 0x00,
+ 0x00, 0x00, 0x60, 0x60, 0x7C, 0x66, 0x7C, 0x00,
+ 0x00, 0x00, 0x7C, 0x06, 0x3E, 0x06, 0x7C, 0x00,
+ 0x00, 0x00, 0xCE, 0xDB, 0xFB, 0xDB, 0xCE, 0x00,
+ 0x00, 0x00, 0x3E, 0x66, 0x3E, 0x36, 0x66, 0x00,
+ 0x00, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00,
+ 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x7C, 0x00,
+ 0x00, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30,
+ 0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C,
+ 0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70,
+ 0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18,
+ 0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00,
+ 0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00,
+ 0x03, 0x02, 0x06, 0x04, 0xCC, 0x68, 0x38, 0x10,
+ 0x3C, 0x42, 0x99, 0xA1, 0xA1, 0x99, 0x42, 0x3C,
+ 0x30, 0x48, 0x10, 0x20, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x7E, 0x00
+};
+
+void GfxFont::init() {
+ if (ConfMan.getBool("herculesfont")) {
+ // User wants, that we use Hercules hires font, try to load it
+ loadFontHercules();
+ } else {
+ switch (_vm->_renderMode) {
+ case Common::kRenderHercA:
+ case Common::kRenderHercG:
+ // Render mode is Hercules, we try to load Hercules hires font
+ loadFontHercules();
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!_fontData) {
+ switch (_vm->_renderMode) {
+ case Common::kRenderAmiga:
+ // Try user-file first, if that fails use our internal inaccurate topaz font
+ loadFontScummVMFile("agi-font-amiga.bin");
+ if (!_fontData) {
+ loadFontAmigaPseudoTopaz();
+ }
+ break;
+ case Common::kRenderApple2GS:
+ // Special font, stored in file AGIFONT
+ loadFontAppleIIgs();
+ break;
+ case Common::kRenderAtariST:
+ // TODO: Atari ST uses another font
+ // Seems to be the standard Atari ST 8x8 system font
+ loadFontScummVMFile("agi-font-atarist.bin");
+ if (!_fontData) {
+ loadFontAtariST("agi-font-atarist-system.fnt");
+ if (!_fontData) {
+ // TODO: in case we find a recreation of the font, add it in here
+ }
+ }
+ break;
+ case Common::kRenderHercA:
+ case Common::kRenderHercG:
+ case Common::kRenderCGA:
+ case Common::kRenderEGA:
+ case Common::kRenderVGA:
+ switch (_vm->getGameID()) {
+ case GID_MICKEY:
+ // load mickey mouse font from interpreter file
+ loadFontMickey();
+ break;
+ default:
+ loadFontScummVMFile("agi-font-dos.bin");
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (!_fontData) {
+ // no font assigned?
+ // use regular PC-BIOS font (taken from Dos-Box with a few modifications)
+ _fontData = fontData_PCBIOS;
+ debug("AGI: Using PC-BIOS font");
+ }
+ }
+
+ if (_vm->getLanguage() == Common::RU_RUS) {
+ // Russian versions need special extended set
+ overwriteExtendedWithRussianSet();
+ }
+}
+
+const byte *GfxFont::getFontData() {
+ assert(_fontData);
+ return _fontData;
+}
+
+bool GfxFont::isFontHires() {
+ return _fontIsHires;
+}
+
+void GfxFont::overwriteSaveRestoreDialogCharacter() {
+ // overwrite character 0x1A with the standard Sierra arrow to the right character
+ // required for the original save/restore dialogs
+ memcpy(_fontDataAllocated + (0x1A * 8), fontData_ArrowRightCharacter, sizeof(fontData_ArrowRightCharacter));
+}
+
+// Overwrite extended character set (0x80-0xFF) with Russian characters
+void GfxFont::overwriteExtendedWithRussianSet() {
+ if (_fontIsHires) {
+ // TODO: Implement overwriting hires font characters too
+ return;
+ }
+
+ if (!_fontDataAllocated) {
+ // nothing allocated, we need to allocate space ourselves to be able to modify an internal font
+ _fontDataAllocated = (uint8 *)calloc(256, 8);
+ memcpy(_fontDataAllocated, _fontData, 128 * 8); // copy ASCII set over
+ _fontData = _fontDataAllocated;
+ }
+ // Overwrite extended set with Russian characters
+ memcpy(_fontDataAllocated + (128 * 8), fontData_ExtendedRussian, 128 * 8);
+
+ debug("AGI: Using Russian extended font set");
+}
+
+// This code loads a ScummVM-specific user-supplied binary font file
+// It's assumed that it's a plain binary file, that contains 256 characters. 8 bytes per character.
+// 8x8 pixels per character. File size 2048 bytes.
+//
+// Currently used for:
+// Atari ST - "agi-font-atarist.bin" -> should be the Atari ST 8x8 system font
+// Amiga - "agi-font-amiga.bin" -> should be the Amiga 8x8 Topaz font
+// DOS - "agi-font-dos.bin"
+void GfxFont::loadFontScummVMFile(Common::String fontFilename) {
+ Common::File fontFile;
+ int32 fontFileSize = 0;
+
+ if (!fontFile.open(fontFilename)) {
+ // Continue, if file not found
+ // These ScummVM font files are totally optional, so don't show a warning
+ return;
+ }
+
+ fontFileSize = fontFile.size();
+ if (fontFileSize != (256 * 8)) {
+ // unexpected file size
+ fontFile.close();
+ warning("Fontfile '%s': unexpected file size", fontFilename.c_str());
+ return;
+ }
+
+ // allocate space for font bitmap data
+ _fontDataAllocated = (uint8 *)calloc(256, 8);
+ _fontData = _fontDataAllocated;
+
+ // read font data, is already in the format that we need (plain bitmap 8x8)
+ fontFile.read(_fontDataAllocated, 256 * 8);
+ fontFile.close();
+
+ overwriteSaveRestoreDialogCharacter();
+
+ debug("AGI: Using user-supplied font");
+}
+
+// We load the Mickey Mouse font from MICKEY.EXE
+void GfxFont::loadFontMickey() {
+ Common::File interpreterFile;
+ int32 interpreterFileSize = 0;
+ byte *fontData = nullptr;
+
+ if (!interpreterFile.open("mickey.exe")) {
+ // Continue, if file not found
+ warning("Could not open file 'mickey.exe' for Mickey Mouse font");
+ return;
+ }
+
+ interpreterFileSize = interpreterFile.size();
+ if (interpreterFileSize != 55136) {
+ // unexpected file size
+ interpreterFile.close();
+ warning("File 'mickey.exe': unexpected file size");
+ return;
+ }
+ interpreterFile.seek(32476); // offset of font data
+
+ // allocate space for font bitmap data
+ fontData = (uint8 *)calloc(256, 8);
+ _fontData = fontData;
+ _fontDataAllocated = fontData;
+
+ // read font data, is already in the format that we need (plain bitmap 8x8)
+ interpreterFile.read(fontData, 256 * 8);
+ interpreterFile.close();
+
+ debug("AGI: Using Mickey Mouse font");
+}
+
+// we create a bitmap out of the topaz data used in parallaction (which is normally found in staticres.cpp)
+// it's a recreation of the Amiga Topaz font but not really accurate
+void GfxFont::loadFontAmigaPseudoTopaz() {
+ const byte *topazStart = fontData_AmigaPseudoTopaz + 32;
+ const byte *topazHeader = topazStart + 78;
+ const byte *topazData = nullptr;
+ const byte *topazLocations = nullptr;
+ byte *fontData = nullptr;
+ uint16 topazHeight = 0;
+ uint16 topazWidth = 0;
+ uint16 topazModulo = 0;
+ uint32 topazDataOffset = 0;
+ uint32 topazLocationOffset = 0;
+ byte topazLowChar = 0;
+ byte topazHighChar = 0;
+ uint16 topazTotalChars = 0;
+ uint16 topazBitLength = 0;
+ uint16 topazBitOffset = 0;
+ uint16 topazByteOffset = 0;
+
+ // allocate space for font bitmap data
+ fontData = (uint8 *)calloc(256, 8);
+ _fontData = fontData;
+ _fontDataAllocated = fontData;
+
+ topazHeight = READ_BE_UINT16(topazHeader + 0);
+ topazWidth = READ_BE_UINT16(topazHeader + 4);
+
+ // we expect 8x8
+ assert(topazHeight == 8);
+ assert(topazWidth == 8);
+
+ topazLowChar = topazHeader[12];
+ topazHighChar = topazHeader[13];
+ topazTotalChars = topazHighChar - topazLowChar + 1;
+ topazDataOffset = READ_BE_UINT32(topazHeader + 14);
+ topazModulo = READ_BE_UINT16(topazHeader + 18);
+ topazLocationOffset = READ_BE_UINT32(topazHeader + 20);
+
+ // Security checks
+ assert(topazLowChar == ' ');
+ assert(topazHighChar == 0xFF);
+
+ // copy first 32 PC-BIOS characters over
+ memcpy(fontData, fontData_PCBIOS, FONT_DISPLAY_WIDTH * 32);
+ fontData += FONT_DISPLAY_WIDTH * 32;
+
+ // now actually convert from topaz data
+ topazData = topazStart + topazDataOffset;
+ topazLocations = topazStart + topazLocationOffset;
+
+ for (uint16 curChar = 0; curChar < topazTotalChars; curChar++) {
+ topazBitOffset = READ_BE_UINT16(topazLocations + (curChar * 4) + 0);
+ topazBitLength = READ_BE_UINT16(topazLocations + (curChar * 4) + 2);
+
+ if (topazBitLength == 8) {
+ assert((topazBitOffset & 7) == 0);
+
+ topazByteOffset = topazBitOffset >> 3;
+
+ // Security check, although we are working on static const data from within ScummVM
+ uint maxOffset = (topazByteOffset + ((topazHeight - 1) * topazModulo));
+ assert(maxOffset < sizeof(fontData_AmigaPseudoTopaz));
+
+ for (uint16 curHeight = 0; curHeight < topazHeight; curHeight++) {
+ *fontData = topazData[topazByteOffset];
+ fontData++;
+ topazByteOffset += topazModulo;
+ }
+ } else {
+ memset(fontData, 0, 8);
+ fontData += 8;
+ }
+ }
+
+ debug("AGI: Using recreation of Amiga Topaz font");
+}
+
+void GfxFont::loadFontAppleIIgs() {
+ Common::File fontFile;
+ uint16 headerIIgs_OffsetMacHeader = 0;
+ uint16 headerIIgs_Version = 0;
+ uint16 macRecord_FirstChar = 0;
+ uint16 macRecord_LastChar = 0;
+ int16 macRecord_MaxKern = 0;
+ uint16 macRecord_RectHeight = 0;
+ uint16 macRecord_StrikeWidth = 0;
+ uint16 strikeDataLen = 0;
+ byte *strikeDataPtr = nullptr;
+ uint16 actualCharacterCount = 0;
+ uint16 totalCharacterCount = 0;
+ uint16 *locationTablePtr = nullptr;
+ uint16 *offsetWidthTablePtr = nullptr;
+
+ uint16 curCharNr = 0;
+ uint16 curRow = 0;
+ uint16 curLocation = 0;
+ uint16 curLocationBytes = 0;
+ uint16 curLocationBits = 0;
+ uint16 curCharOffsetWidth = 0;
+ uint16 curCharOffset = 0;
+ uint16 curCharWidth = 0;
+ uint16 curStrikeWidth = 0;
+
+ uint16 curPixelNr = 0;
+ uint16 curBitMask = 0;
+ int16 positionAdjust = 0;
+ byte curByte = 0;
+ byte fontByte = 0;
+
+ uint16 strikeRowOffset = 0;
+ uint16 strikeCurOffset = 0;
+
+ byte *fontData = nullptr;
+
+ if (!fontFile.open("agifont")) {
+ // Continue,
+ // This also happens when the user selected Apple IIgs as render for the palette for non-AppleIIgs games
+ warning("Could not open file 'agifont' for Apple IIgs font");
+ return;
+ }
+
+ // Apple IIgs header
+ headerIIgs_OffsetMacHeader = fontFile.readUint16LE();
+ fontFile.skip(2); // font family
+ fontFile.skip(2); // font style
+ fontFile.skip(2); // point size
+ headerIIgs_Version = fontFile.readUint16LE();
+ fontFile.skip(2); // bounds type
+ // end of Apple IIgs header
+ // Macintosh font record
+ fontFile.skip(2); // font type
+ macRecord_FirstChar = fontFile.readUint16LE();
+ macRecord_LastChar = fontFile.readUint16LE();
+ fontFile.skip(2); // max width
+ macRecord_MaxKern = fontFile.readSint16LE();
+ fontFile.skip(2); // negative descent
+ fontFile.skip(2); // rect width
+ macRecord_RectHeight = fontFile.readUint16LE();
+ fontFile.skip(2); // low word ptr table
+ fontFile.skip(2); // font ascent
+ fontFile.skip(2); // font descent
+ fontFile.skip(2); // leading
+ macRecord_StrikeWidth = fontFile.readUint16LE();
+
+ // security-checks
+ if (headerIIgs_OffsetMacHeader != 6)
+ error("AppleIIgs-font: unexpected header");
+ if (headerIIgs_Version != 0x0101)
+ error("AppleIIgs-font: not a 1.1 font");
+ if ((macRecord_FirstChar != 0) || (macRecord_LastChar != 255))
+ error("AppleIIgs-font: unexpected characters");
+ if (macRecord_RectHeight != 8)
+ error("AppleIIgs-font: expected 8x8 font");
+
+ // Calculate table sizes
+ strikeDataLen = macRecord_StrikeWidth * macRecord_RectHeight * 2;
+ actualCharacterCount = (macRecord_LastChar - macRecord_FirstChar + 1);
+ totalCharacterCount = actualCharacterCount + 2; // replacement-char + extra character
+
+ // Allocate memory for tables
+ strikeDataPtr = (byte *)calloc(strikeDataLen, 1);
+ locationTablePtr = (uint16 *)calloc(totalCharacterCount, 2); // 1 word per character
+ offsetWidthTablePtr = (uint16 *)calloc(totalCharacterCount, 2); // ditto
+
+ // read tables
+ fontFile.read(strikeDataPtr, strikeDataLen);
+ for (curCharNr = 0; curCharNr < totalCharacterCount; curCharNr++) {
+ locationTablePtr[curCharNr] = fontFile.readUint16LE();
+ }
+ for (curCharNr = 0; curCharNr < totalCharacterCount; curCharNr++) {
+ offsetWidthTablePtr[curCharNr] = fontFile.readUint16LE();
+ }
+ fontFile.close();
+
+ // allocate space for font bitmap data
+ fontData = (uint8 *)calloc(256, 8);
+ _fontData = fontData;
+ _fontDataAllocated = fontData;
+
+ // extract font bitmap data
+ for (curCharNr = 0; curCharNr < actualCharacterCount; curCharNr++) {
+ curCharOffsetWidth = offsetWidthTablePtr[curCharNr];
+ curLocation = locationTablePtr[curCharNr];
+ if (curCharOffsetWidth == 0xFFFF) {
+ // character does not exist in font, use replacement character instead
+ curCharOffsetWidth = offsetWidthTablePtr[actualCharacterCount];
+ curLocation = locationTablePtr[actualCharacterCount];
+ curStrikeWidth = locationTablePtr[actualCharacterCount + 1] - curLocation;
+ } else {
+ curStrikeWidth = locationTablePtr[curCharNr + 1] - curLocation;
+ }
+
+ // Figure out bytes + bits location
+ curLocationBytes = curLocation >> 3;
+ curLocationBits = curLocation & 0x0007;
+ curCharWidth = curCharOffsetWidth & 0x00FF; // isolate width
+ curCharOffset = curCharOffsetWidth >> 8; // isolate offset
+
+ if (!curCharWidth) {
+ fontData += 8; // skip over this character
+ continue;
+ }
+
+ if (curCharWidth != 8) {
+ if (curCharNr != 0x3B)
+ error("AppleIIgs-font: expected 8x8 font");
+ }
+
+ // Get all rows of the current character
+ strikeRowOffset = 0;
+ for (curRow = 0; curRow < macRecord_RectHeight; curRow++) {
+ strikeCurOffset = strikeRowOffset + curLocationBytes;
+
+ // Copy over bits
+ fontByte = 0;
+ curByte = strikeDataPtr[strikeCurOffset];
+ curBitMask = 0x80 >> curLocationBits;
+
+ for (curPixelNr = 0; curPixelNr < curStrikeWidth; curPixelNr++) {
+ fontByte = fontByte << 1;
+ if (curByte & curBitMask) {
+ fontByte |= 0x01;
+ }
+ curBitMask = curBitMask >> 1;
+ if (!curBitMask) {
+ curByte = strikeDataPtr[strikeCurOffset + 1];
+ curBitMask = 0x80;
+ }
+ }
+
+ // adjust, so that it's aligned to the left (starting at 0x80 bit)
+ fontByte = fontByte << (8 - curStrikeWidth);
+
+ // now adjust according to offset + MaxKern
+ positionAdjust = macRecord_MaxKern + curCharOffset;
+
+ // adjust may be negative for space, or 8 for "empty" characters
+ if (positionAdjust > 8)
+ error("AppleIIgs-font: invalid character spacing");
+
+ if (positionAdjust < 0) {
+ // negative adjust strangely happens for empty characters like space
+ if (curStrikeWidth)
+ error("AppleIIgs-font: invalid character spacing");
+ }
+
+ if (positionAdjust > 0) {
+ // move the amount of pixels to the right
+ fontByte = fontByte >> positionAdjust;
+ }
+
+ *fontData = fontByte;
+ fontData++;
+
+ strikeRowOffset += macRecord_StrikeWidth * 2;
+ }
+ }
+
+ free(offsetWidthTablePtr);
+ free(locationTablePtr);
+ free(strikeDataPtr);
+
+ overwriteSaveRestoreDialogCharacter();
+
+ debug("AGI: Using Apple IIgs font");
+}
+
+// Loads Atari ST font file
+// It's found inside Atari ST ROMs. Just search for "8x8 system font". Font starts 4 bytes before that.
+void GfxFont::loadFontAtariST(Common::String fontFilename) {
+ Common::File fontFile;
+ uint16 header_FirstChar = 0;
+ uint16 header_LastChar = 0;
+ uint16 header_MaxWidth = 0;
+ uint16 header_MaxHeight = 0;
+ uint16 header_Flags = 0;
+ //uint32 header_OffsetOfCharOffsets = 0;
+ //uint32 header_OffsetOfFontData = 0;
+ uint16 header_FormWidth = 0;
+ uint16 header_FormHeight = 0;
+ uint16 totalCharacterCount = 0;
+ uint16 *charOffsetTablePtr = nullptr;
+ byte *rawDataTablePtr = nullptr;
+
+ uint16 curCharNr = 0;
+ uint16 curCharRawOffset = 0;
+ uint16 curCharDestOffset = 0;
+ uint16 curRow = 0;
+
+ byte *fontData = nullptr;
+
+ if (!fontFile.open(fontFilename)) {
+ // Continue, if file not found
+ warning("Could not open file 'agi-font-atarist-system.bin' for Atari ST 8x8 system font");
+ return;
+ }
+
+ // Atari ST font header
+ fontFile.skip(2); // face identifier
+ fontFile.skip(2); // point size
+ fontFile.skip(32); // font name
+ header_FirstChar = fontFile.readUint16BE();
+ header_LastChar = fontFile.readUint16BE();
+ fontFile.skip(10); // aligntment of cells
+ header_MaxWidth = fontFile.readUint16BE();
+ header_MaxHeight = fontFile.readUint16BE();
+ fontFile.skip(2); // left offset cel
+ fontFile.skip(2); // right offset cel
+ fontFile.skip(2); // number of pixels to thicken pixels
+ fontFile.skip(2); // underline width
+ fontFile.skip(2); // lightening mask
+ fontFile.skip(2); // skewing mask
+ header_Flags = fontFile.readUint16BE();
+ // bit 0 - default system font
+ // bit 1 - horizontal offset table (not supported)
+ // bit 2 - byte orientation word is high->low
+ // bit 3 - mono spaced font
+ fontFile.skip(4); // horizontal table offset
+ fontFile.skip(4); // header_OffsetOfCharOffsets = fontFile.readUint32BE();
+ fontFile.skip(4); // header_OffsetOfFontData = fontFile.readUint32BE();
+ header_FormWidth = fontFile.readUint16BE();
+ header_FormHeight = fontFile.readUint16BE();
+ fontFile.skip(4); // pointer to next font
+
+ totalCharacterCount = header_LastChar - header_FirstChar + 1;
+
+ // security-checks
+ if (header_MaxWidth > 8)
+ error("AtariST-font: not a 8x8 font");
+ if (header_MaxHeight != 8)
+ error("AtariST-font: not a 8x8 font");
+ if (header_FormHeight != 8)
+ error("AtariST-font: not a 8x8 font");
+ if ((header_FirstChar != 0) || (header_LastChar != 255))
+ error("AtariST-font: unexpected characters");
+ if (header_FormWidth != totalCharacterCount)
+ error("AtariST-font: header inconsistency");
+ if (!(header_Flags & 0x04))
+ error("AtariST-font: font data not in high->low order");
+ if (!(header_Flags & 0x08))
+ error("AtariST-font: not a mono-spaced font");
+
+ // Now we should normally use the offsets, but they don't make sense to me
+ // So I just read the data directly. For the 8x8 system font that works
+ fontFile.skip(2); // extra bytes
+
+ // Allocate memory for tables
+ charOffsetTablePtr = (uint16 *)calloc(totalCharacterCount, 2); // 1 word per character
+ rawDataTablePtr = (byte *)calloc(header_FormWidth, header_FormHeight);
+
+ // Char-Offset Table (2 * total number of characters)
+ for (curCharNr = 0; curCharNr < totalCharacterCount; curCharNr++) {
+ charOffsetTablePtr[curCharNr] = fontFile.readUint16BE();
+ }
+
+ // Followed by actual font data
+ // Attention: Atari ST fonts contain every same row of all characters after each other.
+ // So it's basically like this:
+ // [character data of first row of first character]
+ // [character data of first row of second character]
+ // ...
+ // [character data of first row of last character]
+ // [character data of second row of first character]
+ fontFile.skip(2); // extra bytes
+ fontFile.read(rawDataTablePtr, header_FormWidth * header_FormHeight);
+ fontFile.close();
+
+ // allocate space for font bitmap data
+ fontData = (uint8 *)calloc(256, 8);
+ _fontData = fontData;
+ _fontDataAllocated = fontData;
+
+ // extract font bitmap data
+ for (curCharNr = 0; curCharNr < totalCharacterCount; curCharNr++) {
+ // Figure out base offset from char offset table
+ curCharRawOffset = charOffsetTablePtr[curCharNr] >> 3;
+ curCharDestOffset = curCharNr * 8; // destination offset into our font data
+
+ // now copy over every row of the character
+ for (curRow = 0; curRow < header_FormHeight; curRow++) {
+ fontData[curCharDestOffset] = rawDataTablePtr[curCharRawOffset];
+ curCharDestOffset++;
+ curCharRawOffset += header_FormWidth;
+ }
+ }
+
+ free(rawDataTablePtr);
+ free(charOffsetTablePtr);
+
+ overwriteSaveRestoreDialogCharacter();
+
+ debug("AGI: Using Atari ST 8x8 system font");
+}
+
+// Loads a Sierra Hercules font file
+void GfxFont::loadFontHercules() {
+ Common::File fontFile;
+ int32 fontFileSize = 0;
+ byte *fontData = nullptr;
+ byte *rawData = nullptr;
+
+ uint16 rawDataPos = 0;
+ uint16 curCharNr = 0;
+ uint16 curCharLine = 0;
+
+ if (fontFile.open("hgc_font")) {
+ // hgc_font file found, this is interleaved font data 16x12, should be 3072 bytes
+ // 24 bytes per character, 128 characters
+ fontFileSize = fontFile.size();
+ if (fontFileSize == (128 * 24)) {
+ // size seems to be fine
+ fontData = (uint8 *)calloc(256, 32);
+ _fontDataAllocated = fontData;
+
+ rawData = (byte *)calloc(128, 24);
+ fontFile.read(rawData, 128 * 24);
+
+ // convert interleaved 16x12 -> non-interleaved 16x16
+ for (curCharNr = 0; curCharNr < 128; curCharNr++) {
+ fontData += 4; // skip the first 2 lines
+ for (curCharLine = 0; curCharLine < 6; curCharLine++) {
+ fontData[0] = rawData[rawDataPos + 2 + 0];
+ fontData[1] = rawData[rawDataPos + 2 + 1];
+ fontData[2] = rawData[rawDataPos + 0 + 0];
+ fontData[3] = rawData[rawDataPos + 0 + 1];
+ rawDataPos += 4;
+ fontData += 4;
+ }
+ fontData += 4; // skip the last 2 lines
+ }
+
+ free(rawData);
+ } else {
+ warning("Fontfile 'hgc_font': unexpected file size");
+ }
+ fontFile.close();
+
+ }
+
+ // It seems hgc_graf.ovl holds a low-res font. It makes no real sense to use it.
+ // This was only done to AGI3 games and those rendered differently (2 pixel lines -> 3 pixel lines instead of 4)
+ // User could copy hgc_font from another AGI game over to get the hires font working.
+#if 0
+ if (!_fontDataAllocated) {
+ if (fontFile.open("hgc_graf.ovl")) {
+ // hgc_graf.ovl file found, this is font data + code. non-interleaved font data, should be 3075 bytes
+ // 16 bytes per character, 128 characters, 2048 bytes of font data, starting offset 21
+ fontFileSize = fontFile.size();
+ if (fontFileSize == 3075) {
+ // size seems to be fine
+ fontData = (uint8 *)calloc(256, 32);
+ _fontDataAllocated = fontData;
+
+ fontFile.seek(21);
+ rawData = (byte *)calloc(128, 16);
+ fontFile.read(rawData, 128 * 16);
+
+ // repeat every line 2 times to get 16x16 pixels
+ for (curCharNr = 0; curCharNr < 128; curCharNr++) {
+ for (curCharLine = 0; curCharLine < 8; curCharLine++) {
+ fontData[0] = rawData[rawDataPos + 0];
+ fontData[1] = rawData[rawDataPos + 1];
+ fontData[2] = rawData[rawDataPos + 0];
+ fontData[3] = rawData[rawDataPos + 1];
+ rawDataPos += 2;
+ fontData += 4;
+ }
+ }
+
+ free(rawData);
+
+ } else {
+ warning("Fontfile 'hgc_graf.ovl': unexpected file size");
+ }
+ fontFile.close();
+ }
+ }
+#endif
+
+ if (_fontDataAllocated) {
+ // font loaded
+ _fontData = _fontDataAllocated;
+ _fontIsHires = true;
+
+ debug("AGI: Using Hercules hires font");
+
+ } else {
+ // Continue, if no file was not found
+ warning("Could not open/use file 'hgc_font' for Hercules hires font");
+ }
+}
+
+} // End of namespace Agi
diff --git a/engines/agi/font.h b/engines/agi/font.h
index 0e6b15f06b..485b139858 100644
--- a/engines/agi/font.h
+++ b/engines/agi/font.h
@@ -25,1043 +25,33 @@
namespace Agi {
-// 8x8 font patterns
-static const uint8 fontData_Sierra[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x7E, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E, // cursor hollow
- 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, // cursor solid
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cursor empty
- 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00,
- 0x3C, 0x3C, 0x18, 0xFF, 0xE7, 0x18, 0x3C, 0x00,
- 0x10, 0x38, 0x7C, 0xFE, 0xEE, 0x10, 0x38, 0x00,
- 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00,
- 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF,
- 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // \n
- 0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78,
- 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18,
- 0x08, 0x0C, 0x0A, 0x0A, 0x08, 0x78, 0xF0, 0x00,
- 0x18, 0x14, 0x1A, 0x16, 0x72, 0xE2, 0x0E, 0x1C,
- 0x10, 0x54, 0x38, 0xEE, 0x38, 0x54, 0x10, 0x00,
- 0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00,
- 0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00,
- 0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x00,
- 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
- 0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x00,
- 0x1C, 0x22, 0x38, 0x44, 0x44, 0x38, 0x88, 0x70,
- 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00,
- 0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x7E,
- 0x18, 0x3C, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x00,
- 0x18, 0x18, 0x18, 0x18, 0x5A, 0x3C, 0x18, 0x00,
- 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00,
- 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00,
- 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00,
- 0x00, 0x24, 0x42, 0xFF, 0x42, 0x24, 0x00, 0x00,
- 0x00, 0x10, 0x38, 0x7C, 0xFE, 0xFE, 0x00, 0x00,
- 0x00, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00,
- // original sierra font starts here
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20 Space
- 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
- 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00,
- 0x30, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x30, 0x00,
- 0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00,
- 0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00,
- 0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
- 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
- 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,
- 0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
- 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
- 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00,
- 0x7C, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0x7C, 0x00, // 0x30
- 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00,
- 0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00,
- 0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00,
- 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00,
- 0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00,
- 0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00,
- 0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00,
- 0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00,
- 0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00,
- 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
- 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
- 0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00,
- 0x00, 0x00, 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x00,
- 0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00,
- 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00,
- 0x7C, 0xC6, 0xDE, 0xDE, 0xDE, 0xC0, 0x78, 0x00, // 0x40
- 0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00,
- 0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00,
- 0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00,
- 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00,
- 0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00,
- 0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00,
- 0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3E, 0x00,
- 0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00,
- 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
- 0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00,
- 0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00,
- 0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00,
- 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
- 0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00,
- 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00,
- 0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, // 0x50
- 0x78, 0xCC, 0xCC, 0xCC, 0xDC, 0x78, 0x1C, 0x00,
- 0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00,
- 0x78, 0xCC, 0xE0, 0x70, 0x1C, 0xCC, 0x78, 0x00,
- 0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
- 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00,
- 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
- 0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00,
- 0xC6, 0xC6, 0x6C, 0x38, 0x38, 0x6C, 0xC6, 0x00,
- 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00,
- 0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00,
- 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
- 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00,
- 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
- 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
- 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60
- 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00,
- 0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xDC, 0x00,
- 0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00,
- 0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00,
- 0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
- 0x38, 0x6C, 0x60, 0xF0, 0x60, 0x60, 0xF0, 0x00,
- 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
- 0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00,
- 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
- 0x0C, 0x00, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78,
- 0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00,
- 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
- 0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
- 0x00, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00,
- 0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00,
- 0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0, // 0x70
- 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E,
- 0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0xF0, 0x00,
- 0x00, 0x00, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x00,
- 0x10, 0x30, 0x7C, 0x30, 0x30, 0x34, 0x18, 0x00,
- 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00,
- 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
- 0x00, 0x00, 0xC6, 0xD6, 0xFE, 0xFE, 0x6C, 0x00,
- 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00,
- 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
- 0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00,
- 0x1C, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x1C, 0x00,
- 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
- 0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00,
- 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- // custom font starting here at 0x80
- 0x1E, 0x36, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00, // 0x80
- 0x7C, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
- 0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00,
- 0x7E, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00,
- 0x38, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
- 0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00,
- 0xDB, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0xDB, 0x00,
- 0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00,
- 0x66, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
- 0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
- 0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00,
- 0x1E, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
- 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
- 0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00,
- 0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00,
- 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
- 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x00,
- 0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00,
- 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
- 0x66, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00,
- 0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x18, 0x18, 0x00,
- 0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00,
- 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
- 0x66, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00,
- 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
- 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
- 0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
- 0xC6, 0xC6, 0xC6, 0xF6, 0xDE, 0xDE, 0xF6, 0x00,
- 0x60, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
- 0x78, 0x8C, 0x06, 0x3E, 0x06, 0x8C, 0x78, 0x00,
- 0xCE, 0xDB, 0xDB, 0xFB, 0xDB, 0xDB, 0xCE, 0x00,
- 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x00,
- 0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3A, 0x00,
- 0x00, 0x3C, 0x60, 0x3C, 0x66, 0x66, 0x3C, 0x00,
- 0x00, 0x00, 0x7C, 0x66, 0x7C, 0x66, 0x7C, 0x00,
- 0x00, 0x00, 0x7E, 0x60, 0x60, 0x60, 0x60, 0x00,
- 0x00, 0x00, 0x3C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
- 0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
- 0x00, 0x00, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0x00,
- 0x00, 0x00, 0x3C, 0x66, 0x0C, 0x66, 0x3C, 0x00,
- 0x00, 0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
- 0x00, 0x18, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
- 0x00, 0x00, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00,
- 0x00, 0x00, 0x1E, 0x36, 0x66, 0x66, 0x66, 0x00,
- 0x00, 0x00, 0xC6, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
- 0x00, 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00,
- 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00,
- 0x00, 0x00, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00,
- 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
- 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
- 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
- 0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36,
- 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36,
- 0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
- 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
- 0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
- 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00,
- 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00,
- 0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
- 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
- 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
- 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36,
- 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
- 0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
- 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
- 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
- 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
- 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00, 0x00,
- 0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
- 0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36,
- 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
- 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
- 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00,
- 0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00,
- 0x00, 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00,
- 0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x7C, 0x00,
- 0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x18, 0x00,
- 0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00,
- 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
- 0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x00,
- 0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
- 0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
- 0x00, 0x00, 0xE0, 0x60, 0x7C, 0x66, 0x7C, 0x00,
- 0x00, 0x00, 0xC6, 0xC6, 0xF6, 0xDE, 0xF6, 0x00,
- 0x00, 0x00, 0x60, 0x60, 0x7C, 0x66, 0x7C, 0x00,
- 0x00, 0x00, 0x7C, 0x06, 0x3E, 0x06, 0x7C, 0x00,
- 0x00, 0x00, 0xCE, 0xDB, 0xFB, 0xDB, 0xCE, 0x00,
- 0x00, 0x00, 0x3E, 0x66, 0x3E, 0x36, 0x66, 0x00,
- 0x00, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00,
- 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x7C, 0x00,
- 0x00, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30,
- 0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C,
- 0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70,
- 0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18,
- 0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00,
- 0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00,
- 0x03, 0x02, 0x06, 0x04, 0xCC, 0x68, 0x38, 0x10,
- 0x3C, 0x42, 0x99, 0xA1, 0xA1, 0x99, 0x42, 0x3C,
- 0x30, 0x48, 0x10, 0x20, 0x78, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x7E, 0x00
-};
-
-static const uint8 fontData_FanGames[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x7E, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E, /* cursor hollow */
- 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, /* cursor solid */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* cursor empty */
- 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00,
- 0x3C, 0x3C, 0x18, 0xFF, 0xE7, 0x18, 0x3C, 0x00,
- 0x10, 0x38, 0x7C, 0xFE, 0xEE, 0x10, 0x38, 0x00,
- 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00,
- 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF,
- 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* \n */
- 0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78,
- 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18,
- 0x08, 0x0C, 0x0A, 0x0A, 0x08, 0x78, 0xF0, 0x00,
- 0x18, 0x14, 0x1A, 0x16, 0x72, 0xE2, 0x0E, 0x1C,
- 0x10, 0x54, 0x38, 0xEE, 0x38, 0x54, 0x10, 0x00,
- 0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00,
- 0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00,
- 0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x00,
- 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
- 0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x00,
- 0x1C, 0x22, 0x38, 0x44, 0x44, 0x38, 0x88, 0x70,
- 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00,
- 0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x7E,
- 0x18, 0x3C, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x00,
- 0x18, 0x18, 0x18, 0x18, 0x5A, 0x3C, 0x18, 0x00,
- 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00,
- 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00,
- 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00,
- 0x00, 0x24, 0x42, 0xFF, 0x42, 0x24, 0x00, 0x00,
- 0x00, 0x10, 0x38, 0x7C, 0xFE, 0xFE, 0x00, 0x00,
- 0x00, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00,
- 0x6C, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00,
- 0x10, 0x7C, 0xD0, 0x7C, 0x16, 0xFC, 0x10, 0x00,
- 0x00, 0x66, 0xAC, 0xD8, 0x36, 0x6A, 0xCC, 0x00,
- 0x38, 0x4C, 0x38, 0x78, 0xCE, 0xCC, 0x7A, 0x00,
- 0x30, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
- 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
- 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,
- 0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20,
- 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00,
- 0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x00,
- 0x7C, 0xCE, 0xDE, 0xF6, 0xE6, 0xE6, 0x7C, 0x00,
- 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x7E, 0x00,
- 0x7C, 0xC6, 0x06, 0x1C, 0x70, 0xC6, 0xFE, 0x00,
- 0x7C, 0xC6, 0x06, 0x3C, 0x06, 0xC6, 0x7C, 0x00,
- 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00,
- 0xFE, 0xC0, 0xFC, 0x06, 0x06, 0xC6, 0x7C, 0x00,
- 0x7C, 0xC6, 0xC0, 0xFC, 0xC6, 0xC6, 0x7C, 0x00,
- 0xFE, 0xC6, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00,
- 0x7C, 0xC6, 0xC6, 0x7C, 0xC6, 0xC6, 0x7C, 0x00,
- 0x7C, 0xC6, 0xC6, 0x7E, 0x06, 0xC6, 0x7C, 0x00,
- 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,
- 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20,
- 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00,
- 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00,
- 0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00,
- 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00,
- 0x7C, 0x82, 0x9E, 0xA6, 0x9E, 0x80, 0x7C, 0x00,
- 0x7C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00,
- 0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00,
- 0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C, 0x00,
- 0xFC, 0x66, 0x66, 0x66, 0x66, 0x66, 0xFC, 0x00,
- 0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00,
- 0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00,
- 0x7C, 0xC6, 0xC6, 0xC0, 0xCE, 0xC6, 0x7E, 0x00,
- 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00,
- 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00,
- 0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00,
- 0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00,
- 0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00,
- 0x82, 0xC6, 0xEE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
- 0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00,
- 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00,
- 0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00,
- 0x7C, 0xC6, 0xC6, 0xC6, 0xD6, 0xDE, 0x7C, 0x06,
- 0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xE6, 0x00,
- 0x7C, 0xC6, 0xC0, 0x7C, 0x06, 0xC6, 0x7C, 0x00,
- 0x7E, 0x5A, 0x5A, 0x18, 0x18, 0x18, 0x3C, 0x00,
- 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00,
- 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00,
- 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x82, 0x00,
- 0xC6, 0x6C, 0x38, 0x38, 0x38, 0x6C, 0xC6, 0x00,
- 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x3C, 0x00,
- 0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00,
- 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
- 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00,
- 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
- 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
- 0x30, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00,
- 0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
- 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC6, 0x7C, 0x00,
- 0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00,
- 0x00, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0x7C, 0x00,
- 0x1C, 0x36, 0x30, 0x78, 0x30, 0x30, 0x78, 0x00,
- 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x78,
- 0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00,
- 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00,
- 0x00, 0x0C, 0x00, 0x1C, 0x0C, 0x0C, 0xCC, 0x78,
- 0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00,
- 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00,
- 0x00, 0x00, 0xCC, 0xFE, 0xD6, 0xD6, 0xD6, 0x00,
- 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x00,
- 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00,
- 0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0,
- 0x00, 0x00, 0x7C, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E,
- 0x00, 0x00, 0xDE, 0x76, 0x60, 0x60, 0xF0, 0x00,
- 0x00, 0x00, 0x7C, 0xC0, 0x7C, 0x06, 0x7C, 0x00,
- 0x10, 0x30, 0xFC, 0x30, 0x30, 0x34, 0x18, 0x00,
- 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00,
- 0x00, 0x00, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00,
- 0x00, 0x00, 0xC6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00,
- 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00,
- 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
- 0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00,
- 0x0E, 0x18, 0x18, 0x30, 0x18, 0x18, 0x0E, 0x00,
- 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
- 0xE0, 0x30, 0x30, 0x18, 0x30, 0x30, 0xE0, 0x00,
- 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /*replacement 0x7F */
- 0x1E, 0x36, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00,
- 0x7C, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
- 0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00,
- 0x7E, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00,
- 0x38, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
- 0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00,
- 0xDB, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0xDB, 0x00,
- 0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00,
- 0x66, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
- 0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
- 0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00,
- 0x1E, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
- 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
- 0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00,
- 0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00,
- 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
- 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x00,
- 0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00,
- 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
- 0x66, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00,
- 0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x18, 0x18, 0x00,
- 0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00,
- 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
- 0x66, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00,
- 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
- 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
- 0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
- 0xC6, 0xC6, 0xC6, 0xF6, 0xDE, 0xDE, 0xF6, 0x00,
- 0x60, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
- 0x78, 0x8C, 0x06, 0x3E, 0x06, 0x8C, 0x78, 0x00,
- 0xCE, 0xDB, 0xDB, 0xFB, 0xDB, 0xDB, 0xCE, 0x00,
- 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x00,
- 0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3A, 0x00,
- 0x00, 0x3C, 0x60, 0x3C, 0x66, 0x66, 0x3C, 0x00,
- 0x00, 0x00, 0x7C, 0x66, 0x7C, 0x66, 0x7C, 0x00,
- 0x00, 0x00, 0x7E, 0x60, 0x60, 0x60, 0x60, 0x00,
- 0x00, 0x00, 0x3C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
- 0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
- 0x00, 0x00, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0x00,
- 0x00, 0x00, 0x3C, 0x66, 0x0C, 0x66, 0x3C, 0x00,
- 0x00, 0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
- 0x00, 0x18, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
- 0x00, 0x00, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00,
- 0x00, 0x00, 0x1E, 0x36, 0x66, 0x66, 0x66, 0x00,
- 0x00, 0x00, 0xC6, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
- 0x00, 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00,
- 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00,
- 0x00, 0x00, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00,
- 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
- 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
- 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
- 0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36,
- 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36,
- 0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
- 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
- 0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
- 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00,
- 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00,
- 0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
- 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
- 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
- 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36,
- 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
- 0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
- 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
- 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
- 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
- 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00, 0x00,
- 0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
- 0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36,
- 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
- 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
- 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00,
- 0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00,
- 0x00, 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00,
- 0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x7C, 0x00,
- 0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x18, 0x00,
- 0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00,
- 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
- 0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x00,
- 0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
- 0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
- 0x00, 0x00, 0xE0, 0x60, 0x7C, 0x66, 0x7C, 0x00,
- 0x00, 0x00, 0xC6, 0xC6, 0xF6, 0xDE, 0xF6, 0x00,
- 0x00, 0x00, 0x60, 0x60, 0x7C, 0x66, 0x7C, 0x00,
- 0x00, 0x00, 0x7C, 0x06, 0x3E, 0x06, 0x7C, 0x00,
- 0x00, 0x00, 0xCE, 0xDB, 0xFB, 0xDB, 0xCE, 0x00,
- 0x00, 0x00, 0x3E, 0x66, 0x3E, 0x36, 0x66, 0x00,
- 0x00, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00,
- 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x7C, 0x00,
- 0x00, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30,
- 0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C,
- 0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70,
- 0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18,
- 0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00,
- 0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00,
- 0x03, 0x02, 0x06, 0x04, 0xCC, 0x68, 0x38, 0x10,
- 0x3C, 0x42, 0x99, 0xA1, 0xA1, 0x99, 0x42, 0x3C,
- 0x30, 0x48, 0x10, 0x20, 0x78, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x7E, 0x00
-};
-
-static const uint8 fontData_Mickey[] = {
- 0x00, 0x36, 0x7F, 0x7F, 0x3E, 0x1C, 0x08, 0x00,
- 0x00, 0x00, 0x3F, 0x20, 0x2F, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0x2F, 0x20, 0x2F, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0x2F, 0x20, 0x3F, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xFF, 0x00, 0xEF, 0x28, 0x28, 0x28,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x28, 0x28, 0xEF, 0x00, 0xEF, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0xEF, 0x00, 0xFF, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xF8, 0x08, 0xE8, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0xE8, 0x08, 0xE8, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0xE8, 0x08, 0xF8, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x10, 0x10, 0x10,
- 0x10, 0x10, 0xFF, 0x00, 0xFF, 0x10, 0x10, 0x10,
- 0x10, 0x10, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0x10, 0x10, 0x10, 0xFF, 0x10, 0x10, 0x10, 0x10,
- 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
- 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
- 0x18, 0x18, 0x18, 0x1F, 0x1F, 0x00, 0x00, 0x00,
- 0x78, 0x60, 0x78, 0x60, 0x7E, 0x18, 0x1E, 0x00,
- 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x00,
- 0x00, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00,
- 0x00, 0x18, 0x30, 0x7E, 0x30, 0x18, 0x00, 0x00,
- 0x00, 0x18, 0x0C, 0x7E, 0x0C, 0x18, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00,
- 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x66, 0xFF, 0x66, 0x66, 0xFF, 0x66, 0x00,
- 0x18, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x18, 0x00,
- 0x00, 0x66, 0x6C, 0x18, 0x30, 0x66, 0x46, 0x00,
- 0x1C, 0x36, 0x1C, 0x38, 0x6F, 0x66, 0x3B, 0x00,
- 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x0E, 0x1C, 0x18, 0x18, 0x18, 0x1C, 0x0E, 0x00,
- 0x70, 0x38, 0x18, 0x18, 0x18, 0x38, 0x70, 0x00,
- 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,
- 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30,
- 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00,
- 0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00,
- 0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x3C, 0x00,
- 0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00,
- 0x3C, 0x66, 0x06, 0x0C, 0x18, 0x30, 0x7E, 0x00,
- 0x7E, 0x0C, 0x18, 0x0C, 0x06, 0x66, 0x3C, 0x00,
- 0x0C, 0x1C, 0x3C, 0x6C, 0x6C, 0x7E, 0x0C, 0x00,
- 0x7E, 0x60, 0x7C, 0x06, 0x06, 0x66, 0x3C, 0x00,
- 0x3C, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x3C, 0x00,
- 0x7E, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00,
- 0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00,
- 0x3C, 0x66, 0x66, 0x3E, 0x06, 0x0C, 0x38, 0x00,
- 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00,
- 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30,
- 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00,
- 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00,
- 0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00,
- 0x3C, 0x66, 0x04, 0x0C, 0x18, 0x00, 0x18, 0x00,
- 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x18, 0x3C, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00,
- 0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00,
- 0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00,
- 0x78, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0x78, 0x00,
- 0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00,
- 0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x60, 0x00,
- 0x3E, 0x60, 0x60, 0x6E, 0x66, 0x66, 0x3E, 0x00,
- 0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00,
- 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00,
- 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x3C, 0x00,
- 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0x66, 0x00,
- 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x00,
- 0x63, 0x77, 0x7F, 0x6B, 0x63, 0x63, 0x63, 0x00,
- 0x66, 0x76, 0x7E, 0x7E, 0x6E, 0x66, 0x66, 0x00,
- 0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00,
- 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x00,
- 0x3C, 0x66, 0x66, 0x66, 0x66, 0x6C, 0x36, 0x00,
- 0x7C, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0x66, 0x00,
- 0x3C, 0x60, 0x60, 0x3C, 0x06, 0x06, 0x3C, 0x00,
- 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
- 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x00,
- 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00,
- 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00,
- 0x66, 0x66, 0x3C, 0x3C, 0x66, 0x66, 0x66, 0x00,
- 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00,
- 0x7E, 0x0C, 0x18, 0x30, 0x60, 0x60, 0x7E, 0x00,
- 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00,
- 0x00, 0x40, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00,
- 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
- 0x00, 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00,
- 0x00, 0x18, 0x3C, 0x7E, 0x7E, 0x3C, 0x18, 0x00,
- 0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00,
- 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x00,
- 0x00, 0x00, 0x3C, 0x60, 0x60, 0x60, 0x3C, 0x00,
- 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x00,
- 0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
- 0x0E, 0x18, 0x18, 0x3E, 0x18, 0x18, 0x18, 0x00,
- 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x7C,
- 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00,
- 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00,
- 0x06, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x3C,
- 0x60, 0x60, 0x6C, 0x78, 0x6C, 0x66, 0x66, 0x00,
- 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00,
- 0x00, 0x00, 0x66, 0x7F, 0x7F, 0x6B, 0x63, 0x00,
- 0x00, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00,
- 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00,
- 0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60,
- 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x06,
- 0x00, 0x00, 0x7C, 0x66, 0x60, 0x60, 0x60, 0x00,
- 0x00, 0x00, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x00,
- 0x18, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x0E, 0x00,
- 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00,
- 0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00,
- 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x3E, 0x36, 0x00,
- 0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00,
- 0x00, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x0C, 0x78,
- 0x00, 0x00, 0x7E, 0x0C, 0x18, 0x30, 0x7E, 0x00,
- 0x00, 0x18, 0x3C, 0x7E, 0x7E, 0x18, 0x3C, 0x00,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x00, 0x7E, 0x78, 0x7C, 0x6E, 0x66, 0x06, 0x00,
- 0x08, 0x18, 0x38, 0x78, 0x38, 0x18, 0x08, 0x00,
- 0x10, 0x18, 0x1C, 0x1E, 0x1C, 0x18, 0x10, 0x00,
- 0xFF, 0xC9, 0x80, 0x80, 0xC1, 0xE3, 0xF7, 0xFF,
- 0xFF, 0xFF, 0xC0, 0xDF, 0xD0, 0xD7, 0xD7, 0xD7,
- 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7,
- 0xD7, 0xD7, 0xD0, 0xDF, 0xD0, 0xD7, 0xD7, 0xD7,
- 0xD7, 0xD7, 0xD0, 0xDF, 0xC0, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0x00, 0xFF, 0x10, 0xD7, 0xD7, 0xD7,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xD7, 0xD7, 0x10, 0xFF, 0x10, 0xD7, 0xD7, 0xD7,
- 0xD7, 0xD7, 0x10, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0x07, 0xF7, 0x17, 0xD7, 0xD7, 0xD7,
- 0xD7, 0xD7, 0x17, 0xF7, 0x17, 0xD7, 0xD7, 0xD7,
- 0xD7, 0xD7, 0x17, 0xF7, 0x07, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xEF, 0xEF, 0xEF,
- 0xEF, 0xEF, 0x00, 0xFF, 0x00, 0xEF, 0xEF, 0xEF,
- 0xEF, 0xEF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xEF, 0xEF, 0xEF, 0x00, 0xEF, 0xEF, 0xEF, 0xEF,
- 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF,
- 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
- 0x18, 0x18, 0x18, 0x1F, 0x1F, 0x00, 0x00, 0x00,
- 0x78, 0x60, 0x78, 0x60, 0x7E, 0x18, 0x1E, 0x00,
- 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x00,
- 0x00, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00,
- 0x00, 0x18, 0x30, 0x7E, 0x30, 0x18, 0x00, 0x00,
- 0x00, 0x18, 0x0C, 0x7E, 0x0C, 0x18, 0x00, 0x00,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xE7, 0xE7, 0xE7, 0xE7, 0xFF, 0xE7, 0xE7, 0xFF,
- 0x99, 0x99, 0x99, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0x99, 0x00, 0x99, 0x99, 0x00, 0x99, 0xFF,
- 0xE7, 0xC1, 0x9F, 0xC3, 0xF9, 0x83, 0xE7, 0xFF,
- 0xFF, 0x99, 0x93, 0xE7, 0xCF, 0x99, 0xB9, 0xFF,
- 0xE3, 0xC9, 0xE3, 0xC7, 0x90, 0x99, 0xC4, 0xFF,
- 0xE7, 0xE7, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xF1, 0xE3, 0xE7, 0xE7, 0xE7, 0xE3, 0xF1, 0xFF,
- 0x8F, 0xC7, 0xE7, 0xE7, 0xE7, 0xC7, 0x8F, 0xFF,
- 0xFF, 0x99, 0xC3, 0x00, 0xC3, 0x99, 0xFF, 0xFF,
- 0xFF, 0xE7, 0xE7, 0x81, 0xE7, 0xE7, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xE7, 0xCF,
- 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xE7, 0xFF,
- 0xFD, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0xBF, 0xFF,
- 0xC3, 0x99, 0x91, 0x81, 0x89, 0x99, 0xC3, 0xFF,
- 0xE7, 0xC7, 0xE7, 0xE7, 0xE7, 0xE7, 0x81, 0xFF,
- 0xC3, 0x99, 0xF9, 0xF3, 0xE7, 0xCF, 0x81, 0xFF,
- 0x81, 0xF3, 0xE7, 0xF3, 0xF9, 0x99, 0xC3, 0xFF,
- 0xF3, 0xE3, 0xC3, 0x93, 0x93, 0x81, 0xF3, 0xFF,
- 0x81, 0x9F, 0x83, 0xF9, 0xF9, 0x99, 0xC3, 0xFF,
- 0xC3, 0x9F, 0x9F, 0x83, 0x99, 0x99, 0xC3, 0xFF,
- 0x81, 0xF9, 0xF3, 0xE7, 0xCF, 0xCF, 0xCF, 0xFF,
- 0xC3, 0x99, 0x99, 0xC3, 0x99, 0x99, 0xC3, 0xFF,
- 0xC3, 0x99, 0x99, 0xC1, 0xF9, 0xF3, 0xC7, 0xFF,
- 0xFF, 0xE7, 0xE7, 0xFF, 0xFF, 0xE7, 0xE7, 0xFF,
- 0xFF, 0xE7, 0xE7, 0xFF, 0xFF, 0xE7, 0xE7, 0xCF,
- 0xF9, 0xF3, 0xE7, 0xCF, 0xE7, 0xF3, 0xF9, 0xFF,
- 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0x81, 0xFF, 0xFF,
- 0x9F, 0xCF, 0xE7, 0xF3, 0xE7, 0xCF, 0x9F, 0xFF,
- 0xC3, 0x99, 0xFB, 0xF3, 0xE7, 0xFF, 0xE7, 0xFF,
- 0xC3, 0x99, 0x99, 0x91, 0x91, 0x9F, 0xC1, 0xFF,
- 0xE7, 0xC3, 0x99, 0x99, 0x81, 0x99, 0x99, 0xFF,
- 0x83, 0x99, 0x99, 0x83, 0x99, 0x99, 0x83, 0xFF,
- 0xC3, 0x99, 0x9F, 0x9F, 0x9F, 0x99, 0xC3, 0xFF,
- 0x87, 0x93, 0x99, 0x99, 0x99, 0x93, 0x87, 0xFF,
- 0x81, 0x9F, 0x9F, 0x83, 0x9F, 0x9F, 0x81, 0xFF,
- 0x81, 0x9F, 0x9F, 0x83, 0x9F, 0x9F, 0x9F, 0xFF,
- 0xC1, 0x9F, 0x9F, 0x91, 0x99, 0x99, 0xC1, 0xFF,
- 0x99, 0x99, 0x99, 0x81, 0x99, 0x99, 0x99, 0xFF,
- 0x81, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0x81, 0xFF,
- 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0x99, 0xC3, 0xFF,
- 0x99, 0x93, 0x87, 0x87, 0x93, 0x99, 0x99, 0xFF,
- 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x81, 0xFF,
- 0x9C, 0x88, 0x80, 0x94, 0x9C, 0x9C, 0x9C, 0xFF,
- 0x99, 0x89, 0x81, 0x81, 0x91, 0x99, 0x99, 0xFF,
- 0xC3, 0x99, 0x99, 0x99, 0x99, 0x99, 0xC3, 0xFF,
- 0x83, 0x99, 0x99, 0x99, 0x83, 0x9F, 0x9F, 0xFF,
- 0xC3, 0x99, 0x99, 0x99, 0x99, 0x93, 0xC9, 0xFF,
- 0x83, 0x99, 0x99, 0x83, 0x93, 0x99, 0x99, 0xFF,
- 0xC3, 0x9F, 0x9F, 0xC3, 0xF9, 0xF9, 0xC3, 0xFF,
- 0x81, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xFF,
- 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x81, 0xFF,
- 0x99, 0x99, 0x99, 0x99, 0x99, 0xC3, 0xE7, 0xFF,
- 0x9C, 0x9C, 0x9C, 0x94, 0x80, 0x88, 0x9C, 0xFF,
- 0x99, 0x99, 0xC3, 0xC3, 0x99, 0x99, 0x99, 0xFF,
- 0x99, 0x99, 0x99, 0xC3, 0xE7, 0xE7, 0xE7, 0xFF,
- 0x81, 0xF3, 0xE7, 0xCF, 0x9F, 0x9F, 0x81, 0xFF,
- 0xE1, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE1, 0xFF,
- 0xFF, 0xBF, 0x9F, 0xCF, 0xE7, 0xF3, 0xF9, 0xFF,
- 0x87, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0x87, 0xFF,
- 0xFF, 0xF7, 0xE3, 0xC9, 0x9C, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF,
- 0x00, 0x18, 0x3C, 0x7E, 0x7E, 0x3C, 0x18, 0x00,
- 0xFF, 0xFF, 0xC3, 0xF9, 0xC1, 0x99, 0xC1, 0xFF,
- 0x9F, 0x9F, 0x83, 0x99, 0x99, 0x99, 0x83, 0xFF,
- 0xFF, 0xFF, 0xC3, 0x9F, 0x9F, 0x9F, 0xC3, 0xFF,
- 0xF9, 0xF9, 0xC1, 0x99, 0x99, 0x99, 0xC1, 0xFF,
- 0xFF, 0xFF, 0xC3, 0x99, 0x81, 0x9F, 0xC3, 0xFF,
- 0xF1, 0xE7, 0xE7, 0xC1, 0xE7, 0xE7, 0xE7, 0xFF,
- 0xFF, 0xFF, 0xC1, 0x99, 0x99, 0xC1, 0xF9, 0x83,
- 0x9F, 0x9F, 0x83, 0x99, 0x99, 0x99, 0x99, 0xFF,
- 0xE7, 0xFF, 0xC7, 0xE7, 0xE7, 0xE7, 0xC3, 0xFF,
- 0xF9, 0xFF, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xC3,
- 0x9F, 0x9F, 0x93, 0x87, 0x93, 0x99, 0x99, 0xFF,
- 0xC7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xC3, 0xFF,
- 0xFF, 0xFF, 0x99, 0x80, 0x80, 0x94, 0x9C, 0xFF,
- 0xFF, 0xFF, 0x83, 0x99, 0x99, 0x99, 0x99, 0xFF,
- 0xFF, 0xFF, 0xC3, 0x99, 0x99, 0x99, 0xC3, 0xFF,
- 0xFF, 0xFF, 0x83, 0x99, 0x99, 0x83, 0x9F, 0x9F,
- 0xFF, 0xFF, 0xC1, 0x99, 0x99, 0xC1, 0xF9, 0xF9,
- 0xFF, 0xFF, 0x83, 0x99, 0x9F, 0x9F, 0x9F, 0xFF,
- 0xFF, 0xFF, 0xC1, 0x9F, 0xC3, 0xF9, 0x83, 0xFF,
- 0xE7, 0xE7, 0x81, 0xE7, 0xE7, 0xE7, 0xF1, 0xFF,
- 0xFF, 0xFF, 0x99, 0x99, 0x99, 0x99, 0xC1, 0xFF,
- 0xFF, 0xFF, 0x99, 0x99, 0x99, 0xC3, 0xE7, 0xFF,
- 0xFF, 0xFF, 0x9C, 0x94, 0x80, 0xC1, 0xC9, 0xFF,
- 0xFF, 0xFF, 0x99, 0xC3, 0xE7, 0xC3, 0x99, 0xFF,
- 0xFF, 0xFF, 0x99, 0x99, 0x99, 0xC1, 0xF3, 0x87,
- 0xFF, 0xFF, 0x81, 0xF3, 0xE7, 0xCF, 0x81, 0xFF,
- 0x00, 0x18, 0x3C, 0x7E, 0x7E, 0x18, 0x3C, 0x00,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x00, 0x7E, 0x78, 0x7C, 0x6E, 0x66, 0x06, 0x00,
- 0x08, 0x18, 0x38, 0x78, 0x38, 0x18, 0x08, 0x00,
- 0x10, 0x18, 0x1C, 0x1E, 0x1C, 0x18, 0x10, 0x00,
-};
-
-static const uint8 fontData_IBM[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E,
- 0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E,
- 0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00,
- 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00,
- 0x38, 0x7C, 0x38, 0xFE, 0xFE, 0x7C, 0x38, 0x7C,
- 0x10, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x7C,
- 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00,
- 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF,
- 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00,
- 0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF,
- 0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78,
- 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18,
- 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x70, 0xF0, 0xE0,
- 0x7F, 0x63, 0x7F, 0x63, 0x63, 0x67, 0xE6, 0xC0,
- 0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99,
- 0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00,
- 0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00,
- 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18,
- 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
- 0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x00,
- 0x3E, 0x63, 0x38, 0x6C, 0x6C, 0x38, 0xCC, 0x78,
- 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00,
- 0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0xFF,
- 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00,
- 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00,
- 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00,
- 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00,
- 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00,
- 0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00,
- 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, 0x00,
- 0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
- 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00,
- 0x30, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x30, 0x00,
- 0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00,
- 0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00,
- 0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
- 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
- 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,
- 0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
- 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
- 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00,
- 0x7C, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0x7C, 0x00,
- 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00,
- 0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00,
- 0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00,
- 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00,
- 0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00,
- 0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00,
- 0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00,
- 0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00,
- 0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00,
- 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
- 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
- 0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00,
- 0x00, 0x00, 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x00,
- 0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00,
- 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00,
- 0x7C, 0xC6, 0xDE, 0xDE, 0xDE, 0xC0, 0x78, 0x00,
- 0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00,
- 0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00,
- 0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00,
- 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00,
- 0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00,
- 0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00,
- 0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3E, 0x00,
- 0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00,
- 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
- 0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00,
- 0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00,
- 0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00,
- 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
- 0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00,
- 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00,
- 0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00,
- 0x78, 0xCC, 0xCC, 0xCC, 0xDC, 0x78, 0x1C, 0x00,
- 0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00,
- 0x78, 0xCC, 0xE0, 0x70, 0x1C, 0xCC, 0x78, 0x00,
- 0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
- 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00,
- 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
- 0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00,
- 0xC6, 0xC6, 0x6C, 0x38, 0x38, 0x6C, 0xC6, 0x00,
- 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00,
- 0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00,
- 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
- 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00,
- 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
- 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
- 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00,
- 0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xDC, 0x00,
- 0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00,
- 0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00,
- 0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
- 0x38, 0x6C, 0x60, 0xF0, 0x60, 0x60, 0xF0, 0x00,
- 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
- 0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00,
- 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
- 0x0C, 0x00, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78,
- 0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00,
- 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
- 0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
- 0x00, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00,
- 0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00,
- 0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0,
- 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E,
- 0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0xF0, 0x00,
- 0x00, 0x00, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x00,
- 0x10, 0x30, 0x7C, 0x30, 0x30, 0x34, 0x18, 0x00,
- 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00,
- 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
- 0x00, 0x00, 0xC6, 0xD6, 0xFE, 0xFE, 0x6C, 0x00,
- 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00,
- 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
- 0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00,
- 0x1C, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x1C, 0x00,
- 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
- 0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00,
- 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00,
- 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x18, 0x0C, 0x78,
- 0x00, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
- 0x1C, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
- 0x7E, 0xC3, 0x3C, 0x06, 0x3E, 0x66, 0x3F, 0x00,
- 0xCC, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
- 0xE0, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
- 0x30, 0x30, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
- 0x00, 0x00, 0x78, 0xC0, 0xC0, 0x78, 0x0C, 0x38,
- 0x7E, 0xC3, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
- 0xCC, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
- 0xE0, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
- 0xCC, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
- 0x7C, 0xC6, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00,
- 0xE0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
- 0xC6, 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00,
- 0x30, 0x30, 0x00, 0x78, 0xCC, 0xFC, 0xCC, 0x00,
- 0x1C, 0x00, 0xFC, 0x60, 0x78, 0x60, 0xFC, 0x00,
- 0x00, 0x00, 0x7F, 0x0C, 0x7F, 0xCC, 0x7F, 0x00,
- 0x3E, 0x6C, 0xCC, 0xFE, 0xCC, 0xCC, 0xCE, 0x00,
- 0x78, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
- 0x00, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
- 0x00, 0xE0, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
- 0x78, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
- 0x00, 0xE0, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
- 0x00, 0xCC, 0x00, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
- 0xC3, 0x18, 0x3C, 0x66, 0x66, 0x3C, 0x18, 0x00,
- 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00,
- 0x18, 0x18, 0x7E, 0xC0, 0xC0, 0x7E, 0x18, 0x18,
- 0x38, 0x6C, 0x64, 0xF0, 0x60, 0xE6, 0xFC, 0x00,
- 0xCC, 0xCC, 0x78, 0xFC, 0x30, 0xFC, 0x30, 0x30,
- 0xF8, 0xCC, 0xCC, 0xFA, 0xC6, 0xCF, 0xC6, 0xC7,
- 0x0E, 0x1B, 0x18, 0x3C, 0x18, 0x18, 0xD8, 0x70,
- 0x1C, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
- 0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
- 0x00, 0x1C, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
- 0x00, 0x1C, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
- 0x00, 0xF8, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0x00,
- 0xFC, 0x00, 0xCC, 0xEC, 0xFC, 0xDC, 0xCC, 0x00,
- 0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00, 0x00,
- 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x7C, 0x00, 0x00,
- 0x30, 0x00, 0x30, 0x60, 0xC0, 0xCC, 0x78, 0x00,
- 0x00, 0x00, 0x00, 0xFC, 0xC0, 0xC0, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xFC, 0x0C, 0x0C, 0x00, 0x00,
- 0xC3, 0xC6, 0xCC, 0xDE, 0x33, 0x66, 0xCC, 0x0F,
- 0xC3, 0xC6, 0xCC, 0xDB, 0x37, 0x6F, 0xCF, 0x03,
- 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
- 0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00,
- 0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00,
- 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,
- 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
- 0xDB, 0x77, 0xDB, 0xEE, 0xDB, 0x77, 0xDB, 0xEE,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18,
- 0x36, 0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36,
- 0x00, 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36,
- 0x00, 0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18,
- 0x36, 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
- 0x00, 0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00,
- 0x36, 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00,
- 0x18, 0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00,
- 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18,
- 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
- 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18,
- 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36,
- 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00,
- 0x36, 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36,
- 0x18, 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00,
- 0x36, 0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18,
- 0x00, 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00,
- 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18,
- 0x00, 0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36,
- 0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
- 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x76, 0xDC, 0xC8, 0xDC, 0x76, 0x00,
- 0x00, 0x78, 0xCC, 0xF8, 0xCC, 0xF8, 0xC0, 0xC0,
- 0x00, 0xFC, 0xCC, 0xC0, 0xC0, 0xC0, 0xC0, 0x00,
- 0x00, 0xFE, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00,
- 0xFC, 0xCC, 0x60, 0x30, 0x60, 0xCC, 0xFC, 0x00,
- 0x00, 0x00, 0x7E, 0xD8, 0xD8, 0xD8, 0x70, 0x00,
- 0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0xC0,
- 0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x00,
- 0xFC, 0x30, 0x78, 0xCC, 0xCC, 0x78, 0x30, 0xFC,
- 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x6C, 0x38, 0x00,
- 0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x6C, 0xEE, 0x00,
- 0x1C, 0x30, 0x18, 0x7C, 0xCC, 0xCC, 0x78, 0x00,
- 0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x00, 0x00,
- 0x06, 0x0C, 0x7E, 0xDB, 0xDB, 0x7E, 0x60, 0xC0,
- 0x38, 0x60, 0xC0, 0xF8, 0xC0, 0x60, 0x38, 0x00,
- 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x00,
- 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0x00,
- 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0xFC, 0x00,
- 0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xFC, 0x00,
- 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xFC, 0x00,
- 0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70,
- 0x30, 0x30, 0x00, 0xFC, 0x00, 0x30, 0x30, 0x00,
- 0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00,
- 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
- 0x0F, 0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x3C, 0x1C,
- 0x78, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00,
- 0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+class GfxFont {
+public:
+ GfxFont(AgiBase *vm);
+ ~GfxFont();
+
+private:
+ AgiBase *_vm;
+
+public:
+ void init();
+ const byte *getFontData();
+ bool isFontHires();
+
+private:
+ void overwriteSaveRestoreDialogCharacter();
+ void overwriteExtendedWithRussianSet();
+
+ void loadFontScummVMFile(Common::String fontFilename);
+ void loadFontMickey();
+ void loadFontAmigaPseudoTopaz();
+ void loadFontAppleIIgs();
+ void loadFontAtariST(Common::String fontFilename);
+ void loadFontHercules();
+
+ const uint8 *_fontData; // pointer to the currently used font
+ uint8 *_fontDataAllocated;
+ bool _fontIsHires;
};
} // End of namespace Agi
diff --git a/engines/agi/global.cpp b/engines/agi/global.cpp
index 7d55316d7b..6f83f02a4e 100644
--- a/engines/agi/global.cpp
+++ b/engines/agi/global.cpp
@@ -20,45 +20,309 @@
*
*/
+#include "common/config-manager.h"
+#include "audio/mixer.h"
+
#include "agi/agi.h"
+#include "agi/graphics.h"
namespace Agi {
-int AgiBase::getflag(int n) {
- uint8 *set = (uint8 *)&_game.flags;
+bool AgiBase::getFlag(int16 flagNr) {
+ uint8 *flagPtr = _game.flags;
- set += n >> 3;
- return (*set & (1 << (n & 0x07))) != 0;
+ flagPtr += flagNr >> 3;
+ return (*flagPtr & (1 << (flagNr & 0x07))) != 0;
}
-void AgiBase::setflag(int n, int v) {
- uint8 *set = (uint8 *)&_game.flags;
+void AgiBase::setFlag(int16 flagNr, bool newState) {
+ uint8 *flagPtr = _game.flags;
- set += n >> 3;
- if (v)
- *set |= 1 << (n & 0x07); // set bit
+ flagPtr += flagNr >> 3;
+ if (newState)
+ *flagPtr |= 1 << (flagNr & 0x07); // set bit
else
- *set &= ~(1 << (n & 0x07)); // clear bit
+ *flagPtr &= ~(1 << (flagNr & 0x07)); // clear bit
+}
+
+void AgiBase::flipFlag(int16 flagNr) {
+ uint8 *flagPtr = _game.flags;
+
+ flagPtr += flagNr >> 3;
+ *flagPtr ^= 1 << (flagNr & 0x07); // flip bit
+}
+
+void AgiEngine::setVar(int16 varNr, byte newValue) {
+ _game.vars[varNr] = newValue;
+
+ switch (varNr) {
+ case VM_VAR_SECONDS:
+ setVarSecondsTrigger(newValue);
+ break;
+ case VM_VAR_VOLUME:
+ setVolumeViaScripts(newValue);
+ break;
+ }
}
-void AgiBase::flipflag(int n) {
- uint8 *set = (uint8 *)&_game.flags;
+byte AgiEngine::getVar(int16 varNr) {
+ switch (varNr) {
+ case VM_VAR_SECONDS:
+ getVarSecondsHeuristicTrigger();
+ // is supposed to fall through
+ case VM_VAR_MINUTES:
+ case VM_VAR_HOURS:
+ case VM_VAR_DAYS:
+ // Timer Update is necessary in here, because of at least Manhunter 1 script 153
+ // Sierra AGI updated the timer via a timer procedure
+ inGameTimerUpdate();
+ break;
+ default:
+ break;
+ }
+ return _game.vars[varNr];
+}
+
+// sets volume based on script value
+// 0 - maximum volume
+// 15 - mute
+void AgiEngine::setVolumeViaScripts(byte newVolume) {
+ newVolume = CLIP<byte>(newVolume, 0, 15);
+
+ if (_veryFirstInitialCycle) {
+ // WORKAROUND:
+ // The very first cycle is currently running and volume got changed
+ // This is surely the initial value. For plenty of fan games, a default of 15 is set
+ // Which actually means "mute" in AGI, but AGI on PC used PC speaker, which did not use
+ // volume setting. We do. So we detect such a situation and set a flag, so that the
+ // volume will get interpreted "correctly" for those fan games.
+ // Note: not all fan games are broken in that regard!
+ // See bug #7035
+ if (getFeatures() & GF_FANMADE) {
+ // We only check for fan games, Sierra always did it properly of course
+ if (newVolume == 15) {
+ // Volume gets set to mute at the start?
+ // Probably broken fan game detected, set flag
+ debug("Broken volume in fan game detected, enabling workaround");
+ _setVolumeBrokenFangame = true;
+ }
+ }
+ }
+
+ if (!_setVolumeBrokenFangame) {
+ // In AGI 15 is mute, 0 is loudest
+ // Some fan games set this incorrectly as 15 for loudest, 0 for mute
+ newVolume = 15 - newVolume; // turn volume around
+ }
+
+ int scummVMVolume = newVolume * Audio::Mixer::kMaxMixerVolume / 15;
+ bool scummVMMute = false;
+
+ // Set ScummVM setting
+ // We do not set "mute". In case "mute" is set, we will not apply the scripts wishes
+ ConfMan.setInt("music_volume", scummVMVolume);
+ ConfMan.setInt("sfx_volume", scummVMVolume);
+
+ if (ConfMan.hasKey("mute"))
+ scummVMMute = ConfMan.getBool("mute");
+
+ if (!scummVMMute) {
+ // Also change volume directly
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, scummVMVolume);
+ _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, scummVMVolume);
+ }
+}
+
+void AgiEngine::setVolumeViaSystemSetting() {
+ int scummVMVolumeMusic = ConfMan.getInt("music_volume");
+ int scummVMVolumeSfx = ConfMan.getInt("sfx_volume");
+ bool scummVMMute = false;
+ int internalVolume = 0;
+
+ if (ConfMan.hasKey("mute"))
+ scummVMMute = ConfMan.getBool("mute");
+
+ // Clip user system setting
+ scummVMVolumeMusic = CLIP<int>(scummVMVolumeMusic, 0, Audio::Mixer::kMaxMixerVolume);
+ scummVMVolumeSfx = CLIP<int>(scummVMVolumeSfx, 0, Audio::Mixer::kMaxMixerVolume);
+
+ if (scummVMMute) {
+ scummVMVolumeMusic = 0;
+ scummVMVolumeSfx = 0;
+ }
+
+ // Now actually set it
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, scummVMVolumeMusic);
+ _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, scummVMVolumeSfx);
+
+ // Take lowest volume to the scripts
+ if (scummVMVolumeMusic < scummVMVolumeSfx) {
+ internalVolume = scummVMVolumeMusic;
+ } else {
+ internalVolume = scummVMVolumeSfx;
+ }
+ // Change it to 0-15 range
+ internalVolume = (internalVolume + 1) * 15 / Audio::Mixer::kMaxMixerVolume;
+ // Reverse it
+ internalVolume = 15 - internalVolume;
+ // Put it into the VM variable. Directly set it, otherwise it would call a volume set call
+ _game.vars[VM_VAR_VOLUME] = internalVolume;
+}
- set += n >> 3;
- *set ^= 1 << (n & 0x07); // flip bit
+void AgiEngine::resetGetVarSecondsHeuristic() {
+ _getVarSecondsHeuristicLastInstructionCounter = 0;
+ _getVarSecondsHeuristicCounter = 0;
}
-void AgiEngine::setvar(int var, int val) {
- _game.vars[var] = val;
+// Called, when the scripts read VM_VAR_SECONDS
+void AgiEngine::getVarSecondsHeuristicTrigger() {
+ uint32 counterDifference = _instructionCounter - _getVarSecondsHeuristicLastInstructionCounter;
+
+ if (counterDifference <= 3) {
+ // Seconds were read within 3 instructions
+ _getVarSecondsHeuristicCounter++;
+ if (_getVarSecondsHeuristicCounter > 20) {
+ // More than 20 times in a row? This really seems to be an inner loop waiting for seconds to change
+ // This happens in at least:
+ // Police Quest 1 - Poker game (room 75, responsible script 81)
- if (var == vVolume) {
- _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, val * 17);
- _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, val * 17);
+ // Wait a few milliseconds, get events and update screen
+ // We MUST NOT process AGI events in here
+ wait(10);
+ processScummVMEvents();
+ _gfx->updateScreen();
+
+ _getVarSecondsHeuristicCounter = 0;
+ }
+ } else {
+ _getVarSecondsHeuristicCounter = 0;
}
+ _getVarSecondsHeuristicLastInstructionCounter = _instructionCounter;
+}
+
+// In-Game timer, used for timer VM Variables
+void AgiEngine::inGameTimerReset(uint32 newPlayTime) {
+ _lastUsedPlayTimeInCycles = newPlayTime / 50;
+ _lastUsedPlayTimeInSeconds = newPlayTime / 1000;
+ _playTimeInSecondsAdjust = 0; // no adjust for now
+ setTotalPlayTime(newPlayTime);
+ inGameTimerResetPassedCycles();
+}
+void AgiEngine::inGameTimerResetPassedCycles() {
+ _passedPlayTimeCycles = 0;
+}
+void AgiEngine::inGameTimerPause() {
+ pauseEngine(true);
+}
+void AgiEngine::inGameTimerResume() {
+ pauseEngine(false);
}
+uint32 AgiEngine::inGameTimerGet() {
+ return getTotalPlayTime();
+}
+uint32 AgiEngine::inGameTimerGetPassedCycles() {
+ return _passedPlayTimeCycles;
+}
+
+// Seconds got set by the game
+// This happens in Mixed Up Mother Goose. The game syncs the songs to VM_VAR_SECONDS, but instead
+// of only reading them, it sets it to 0 and then checks if it reached a certain second.
+// The original interpreter didn't reset the internal cycles counter. Which means the timing was never accurate,
+// because the cycles counter may just overflow right after setting the seconds, which means a second
+// increase almost immediately happened. We even fix this issue by adjusting for it.
+void AgiEngine::setVarSecondsTrigger(byte newSeconds) {
+ // Adjust in game timer, so that VM timer variables are accurate
+ inGameTimerUpdate();
+
+ // Adjust VM seconds again
+ _game.vars[VM_VAR_SECONDS] = newSeconds;
+
+ // Calculate milliseconds adjust (see comment above)
+ uint32 curPlayTimeMilliseconds = inGameTimerGet();
+ _playTimeInSecondsAdjust = curPlayTimeMilliseconds % 1000;
+}
+
+// This is called, when one of the timer variables is read
+// We calculate the latest variables, according to current official playtime
+// This is also called in the main loop, because the game needs to be sync'd to 20 cycles per second
+void AgiEngine::inGameTimerUpdate() {
+ uint32 curPlayTimeMilliseconds = inGameTimerGet();
+ uint32 curPlayTimeCycles = curPlayTimeMilliseconds / 50;
+
+ if (curPlayTimeCycles == _lastUsedPlayTimeInCycles) {
+ // No difference, skip updating
+ return;
+ }
+
+ // Increase passed cycles accordingly
+ int32 playTimeCycleDelta = curPlayTimeCycles - _lastUsedPlayTimeInCycles;
+ if (playTimeCycleDelta > 0) {
+ _passedPlayTimeCycles += playTimeCycleDelta;
+ }
+ _lastUsedPlayTimeInCycles = curPlayTimeCycles;
+
+ // Now calculate current play time in seconds
+ if (_playTimeInSecondsAdjust) {
+ // Apply adjust from setVarSecondsTrigger()
+ if (curPlayTimeMilliseconds >= _playTimeInSecondsAdjust) {
+ curPlayTimeMilliseconds -= _playTimeInSecondsAdjust;
+ } else {
+ curPlayTimeMilliseconds = 0;
+ }
+ }
+ uint32 curPlayTimeSeconds = curPlayTimeMilliseconds / 1000;
+
+ if (curPlayTimeSeconds == _lastUsedPlayTimeInSeconds) {
+ // No difference, skip updating
+ return;
+ }
+
+ int32 playTimeSecondsDelta = curPlayTimeSeconds - _lastUsedPlayTimeInSeconds;
+
+ if (playTimeSecondsDelta > 0) {
+ // Read and write to VM vars directly to avoid endless loop
+ uint32 secondsLeft = playTimeSecondsDelta;
+ byte curSeconds = _game.vars[VM_VAR_SECONDS];
+ byte curMinutes = _game.vars[VM_VAR_MINUTES];
+ byte curHours = _game.vars[VM_VAR_HOURS];
+ byte curDays = _game.vars[VM_VAR_DAYS];
+
+ // Add delta to VM variables
+ if (secondsLeft >= 86400) {
+ curDays += secondsLeft / 86400;
+ secondsLeft = secondsLeft % 86400;
+ }
+ if (secondsLeft >= 3600) {
+ curHours += secondsLeft / 3600;
+ secondsLeft = secondsLeft % 3600;
+ }
+ if (secondsLeft >= 60) {
+ curMinutes += secondsLeft / 60;
+ secondsLeft = secondsLeft % 60;
+ }
+ curSeconds += secondsLeft;
+
+ while (curSeconds > 59) {
+ curSeconds -= 60;
+ curMinutes++;
+ }
+ while (curMinutes > 59) {
+ curMinutes -= 60;
+ curHours++;
+ }
+ while (curHours > 23) {
+ curHours -= 24;
+ curDays++;
+ }
+
+ // directly set them
+ _game.vars[VM_VAR_SECONDS] = curSeconds;
+ _game.vars[VM_VAR_MINUTES] = curMinutes;
+ _game.vars[VM_VAR_HOURS] = curHours;
+ _game.vars[VM_VAR_DAYS] = curDays;
+ }
-int AgiEngine::getvar(int var) {
- return _game.vars[var];
+ _lastUsedPlayTimeInSeconds = curPlayTimeSeconds;
}
void AgiEngine::decrypt(uint8 *mem, int len) {
@@ -66,7 +330,7 @@ void AgiEngine::decrypt(uint8 *mem, int len) {
int i;
key = (getFeatures() & GF_AGDS) ? (const uint8 *)CRYPT_KEY_AGDS
- : (const uint8 *)CRYPT_KEY_SIERRA;
+ : (const uint8 *)CRYPT_KEY_SIERRA;
for (i = 0; i < len; i++)
*(mem + i) ^= *(key + (i % 11));
diff --git a/engines/agi/graphics.cpp b/engines/agi/graphics.cpp
index c5cede71ef..3b1b99f458 100644
--- a/engines/agi/graphics.cpp
+++ b/engines/agi/graphics.cpp
@@ -23,773 +23,1314 @@
#include "common/config-manager.h"
#include "common/file.h"
#include "common/textconsole.h"
+#include "engines/util.h"
#include "graphics/cursorman.h"
#include "graphics/palette.h"
#include "agi/agi.h"
#include "agi/graphics.h"
+#include "agi/mouse_cursor.h"
+#include "agi/palette.h"
+#include "agi/picture.h"
+#include "agi/text.h"
namespace Agi {
-#define DEV_X0(x) ((x) << 1)
-#define DEV_X1(x) (((x) << 1) + 1)
-#define DEV_Y(x) (x)
+#include "agi/font.h"
-#ifndef MAX_INT
-# define MAX_INT (int)((unsigned)~0 >> 1)
-#endif
+GfxMgr::GfxMgr(AgiBase *vm, GfxFont *font) : _vm(vm), _font(font) {
+ _agipalFileNum = 0;
-#include "agi/font.h"
+ memset(&_paletteGfxMode, 0, sizeof(_paletteGfxMode));
+ memset(&_paletteTextMode, 0, sizeof(_paletteTextMode));
-/**
- * 16 color RGB palette.
- * This array contains the 6-bit RGB values of the EGA palette exported
- * to the console drivers.
- */
-static const uint8 egaPalette[16 * 3] = {
- 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x2a,
- 0x00, 0x2a, 0x00,
- 0x00, 0x2a, 0x2a,
- 0x2a, 0x00, 0x00,
- 0x2a, 0x00, 0x2a,
- 0x2a, 0x15, 0x00,
- 0x2a, 0x2a, 0x2a,
- 0x15, 0x15, 0x15,
- 0x15, 0x15, 0x3f,
- 0x15, 0x3f, 0x15,
- 0x15, 0x3f, 0x3f,
- 0x3f, 0x15, 0x15,
- 0x3f, 0x15, 0x3f,
- 0x3f, 0x3f, 0x15,
- 0x3f, 0x3f, 0x3f
-};
+ memset(&_mouseCursor, 0, sizeof(_mouseCursor));
+ memset(&_mouseCursorBusy, 0, sizeof(_mouseCursorBusy));
-/**
- * Atari ST AGI palette.
- * Used by all of the tested Atari ST AGI games
- * from Donald Duck's Playground (1986) to Manhunter II (1989).
- * 16 RGB colors. 3 bits per color component.
- */
-#if 0
-static const uint8 atariStAgiPalette[16 * 3] = {
- 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x7,
- 0x0, 0x4, 0x0,
- 0x0, 0x5, 0x4,
- 0x5, 0x0, 0x0,
- 0x5, 0x3, 0x6,
- 0x4, 0x3, 0x0,
- 0x5, 0x5, 0x5,
- 0x3, 0x3, 0x2,
- 0x0, 0x5, 0x7,
- 0x0, 0x6, 0x0,
- 0x0, 0x7, 0x6,
- 0x7, 0x2, 0x3,
- 0x7, 0x4, 0x7,
- 0x7, 0x7, 0x4,
- 0x7, 0x7, 0x7
-};
-#endif
+ initPriorityTable();
-/**
- * Second generation Apple IIGS AGI palette.
- * A 16-color, 12-bit RGB palette.
- *
- * Used by at least the following Apple IIGS AGI versions:
- * 1.003 (Leisure Suit Larry I v1.0E, intro says 1987)
- * 1.005 (AGI Demo 2 1987-06-30?)
- * 1.006 (King's Quest I v1.0S 1988-02-23)
- * 1.007 (Police Quest I v2.0B 1988-04-21 8:00am)
- * 1.013 (King's Quest II v2.0A 1988-06-16 (CE))
- * 1.013 (Mixed-Up Mother Goose v2.0A 1988-05-31 10:00am)
- * 1.014 (King's Quest III v2.0A 1988-08-28 (CE))
- * 1.014 (Space Quest II v2.0A, LOGIC.141 says 1988)
- * 2.004 (Manhunter I v2.0E 1988-10-05 (CE))
- * 2.006 (King's Quest IV v1.0K 1988-11-22 (CE))
- * 3.001 (Black Cauldron v1.0O 1989-02-24 (CE))
- * 3.003 (Gold Rush! v1.0M 1989-02-28 (CE))
- */
-#if 0
-// FIXME: Identical to amigaAgiPaletteV2
-static const uint8 appleIIgsAgiPaletteV2[16 * 3] = {
- 0x0, 0x0, 0x0,
- 0x0, 0x0, 0xF,
- 0x0, 0x8, 0x0,
- 0x0, 0xD, 0xB,
- 0xC, 0x0, 0x0,
- 0xB, 0x7, 0xD,
- 0x8, 0x5, 0x0,
- 0xB, 0xB, 0xB,
- 0x7, 0x7, 0x7,
- 0x0, 0xB, 0xF,
- 0x0, 0xE, 0x0,
- 0x0, 0xF, 0xD,
- 0xF, 0x9, 0x8,
- 0xD, 0x9, 0xF, // Only this differs from the 1st generation palette
- 0xE, 0xE, 0x0,
- 0xF, 0xF, 0xF
-};
-#endif
+ _renderStartVisualOffsetY = 0;
+ _renderStartDisplayOffsetY = 0;
-/**
- * First generation Amiga & Apple IIGS AGI palette.
- * A 16-color, 12-bit RGB palette.
- *
- * Used by at least the following Amiga AGI versions:
- * 2.082 (King's Quest I v1.0U 1986)
- * 2.082 (Space Quest I v1.2 1986)
- * 2.090 (King's Quest III v1.01 1986-11-08)
- * 2.107 (King's Quest II v2.0J 1987-01-29)
- * x.yyy (Black Cauldron v2.00 1987-06-14)
- * x.yyy (Larry I v1.05 1987-06-26)
- *
- * Also used by at least the following Apple IIGS AGI versions:
- * 1.002 (Space Quest I, intro says v2.2 1987)
- */
-static const uint8 amigaAgiPaletteV1[16 * 3] = {
- 0x0, 0x0, 0x0,
- 0x0, 0x0, 0xF,
- 0x0, 0x8, 0x0,
- 0x0, 0xD, 0xB,
- 0xC, 0x0, 0x0,
- 0xB, 0x7, 0xD,
- 0x8, 0x5, 0x0,
- 0xB, 0xB, 0xB,
- 0x7, 0x7, 0x7,
- 0x0, 0xB, 0xF,
- 0x0, 0xE, 0x0,
- 0x0, 0xF, 0xD,
- 0xF, 0x9, 0x8,
- 0xF, 0x7, 0x0,
- 0xE, 0xE, 0x0,
- 0xF, 0xF, 0xF
-};
+ _upscaledHires = DISPLAY_UPSCALED_DISABLED;
+ _displayScreenWidth = DISPLAY_DEFAULT_WIDTH;
+ _displayScreenHeight = DISPLAY_DEFAULT_HEIGHT;
+ _displayFontWidth = 8;
+ _displayFontHeight = 8;
+
+ _displayWidthMulAdjust = 0; // visualPos * (2+0) = displayPos
+ _displayHeightMulAdjust = 0; // visualPos * (1+0) = displayPos
+
+ _pixels = 0;
+ _displayPixels = 0;
+
+ _activeScreen = NULL;
+ _gameScreen = NULL;
+ _priorityScreen = NULL;
+ _displayScreen = NULL;
+}
/**
- * Second generation Amiga AGI palette.
- * A 16-color, 12-bit RGB palette.
+ * Initialize graphics device.
*
- * Used by at least the following Amiga AGI versions:
- * 2.202 (Space Quest II v2.0F. Intro says 1988. ScummVM 0.10.0 detects as 1986-12-09)
+ * @see deinit_video()
*/
-static const uint8 amigaAgiPaletteV2[16 * 3] = {
- 0x0, 0x0, 0x0,
- 0x0, 0x0, 0xF,
- 0x0, 0x8, 0x0,
- 0x0, 0xD, 0xB,
- 0xC, 0x0, 0x0,
- 0xB, 0x7, 0xD,
- 0x8, 0x5, 0x0,
- 0xB, 0xB, 0xB,
- 0x7, 0x7, 0x7,
- 0x0, 0xB, 0xF,
- 0x0, 0xE, 0x0,
- 0x0, 0xF, 0xD,
- 0xF, 0x9, 0x8,
- 0xD, 0x0, 0xF,
- 0xE, 0xE, 0x0,
- 0xF, 0xF, 0xF
-};
+int GfxMgr::initVideo() {
+ bool forceHires = false;
+
+ // Set up palettes
+ initPalette(_paletteTextMode, PALETTE_EGA);
+
+ switch (_vm->_renderMode) {
+ case Common::kRenderEGA:
+ initPalette(_paletteGfxMode, PALETTE_EGA);
+ break;
+ case Common::kRenderCGA:
+ initPalette(_paletteGfxMode, PALETTE_CGA, 4, 8);
+ break;
+ case Common::kRenderVGA:
+ initPalette(_paletteGfxMode, PALETTE_VGA, 256, 8);
+ break;
+ case Common::kRenderHercG:
+ initPalette(_paletteGfxMode, PALETTE_HERCULES_GREEN, 2, 8);
+ forceHires = true;
+ break;
+ case Common::kRenderHercA:
+ initPalette(_paletteGfxMode, PALETTE_HERCULES_AMBER, 2, 8);
+ forceHires = true;
+ break;
+ case Common::kRenderAmiga:
+ if (!ConfMan.getBool("altamigapalette")) {
+ // Set the correct Amiga palette depending on AGI interpreter version
+ if (_vm->getVersion() < 0x2936)
+ initPalette(_paletteGfxMode, PALETTE_AMIGA_V1, 16, 4);
+ else if (_vm->getVersion() == 0x2936)
+ initPalette(_paletteGfxMode, PALETTE_AMIGA_V2, 16, 4);
+ else if (_vm->getVersion() > 0x2936)
+ initPalette(_paletteGfxMode, PALETTE_AMIGA_V3, 16, 4);
+ } else {
+ // Set the old common alternative Amiga palette
+ initPalette(_paletteGfxMode, PALETTE_AMIGA_ALT);
+ }
+ break;
+ case Common::kRenderApple2GS:
+ switch (_vm->getGameID()) {
+ case GID_SQ1:
+ // Special one, only used for Space Quest 1 on Apple IIgs. Is the same as Amiga v1 palette
+ initPalette(_paletteGfxMode, PALETTE_APPLE_II_GS_SQ1, 16, 4);
+ break;
+ default:
+ // Regular "standard" Apple IIgs palette, used by everything else
+ initPalette(_paletteGfxMode, PALETTE_APPLE_II_GS, 16, 4);
+ break;
+ }
+ break;
+ case Common::kRenderAtariST:
+ initPalette(_paletteGfxMode, PALETTE_ATARI_ST, 16, 3);
+ break;
+ case Common::kRenderMacintosh:
+ switch (_vm->getGameID()) {
+ case GID_KQ3:
+ case GID_PQ1:
+ initPaletteCLUT(_paletteGfxMode, PALETTE_MACINTOSH_CLUT, 16);
+ break;
+ case GID_GOLDRUSH:
+ // We use the common KQ3/PQ1 palette at the moment.
+ // It seems the Gold Rush palette, that came with the game is quite ugly.
+ initPaletteCLUT(_paletteGfxMode, PALETTE_MACINTOSH_CLUT, 16);
+ break;
+ case GID_SQ2:
+ initPaletteCLUT(_paletteGfxMode, PALETTE_MACINTOSH_CLUT3, 16);
+ break;
+ default:
+ initPaletteCLUT(_paletteGfxMode, PALETTE_MACINTOSH_CLUT3, 16);
+ break;
+ }
+ break;
+ default:
+ error("initVideo: unsupported render mode");
+ break;
+ }
+
+ //bool forcedUpscale = true;
+
+ if (_font->isFontHires() || forceHires) {
+ // Upscaling enable
+ _upscaledHires = DISPLAY_UPSCALED_640x400;
+ _displayScreenWidth = 640;
+ _displayScreenHeight = 400;
+ _displayFontWidth = 16;
+ _displayFontHeight = 16;
+
+ _displayWidthMulAdjust = 2;
+ _displayHeightMulAdjust = 1;
+ }
+
+ // set up mouse cursors
+ switch (_vm->_renderMode) {
+ case Common::kRenderEGA:
+ case Common::kRenderCGA:
+ case Common::kRenderVGA:
+ case Common::kRenderHercG:
+ case Common::kRenderHercA:
+ initMouseCursor(&_mouseCursor, MOUSECURSOR_SCI, 11, 16, 0, 0);
+ initMouseCursor(&_mouseCursorBusy, MOUSECURSOR_SCI_BUSY, 15, 16, 7, 8);
+ break;
+ case Common::kRenderAmiga:
+ initMouseCursor(&_mouseCursor, MOUSECURSOR_AMIGA, 8, 11, 0, 0);
+ initMouseCursor(&_mouseCursorBusy, MOUSECURSOR_AMIGA_BUSY, 13, 16, 7, 8);
+ break;
+ case Common::kRenderApple2GS:
+ // had no special busy mouse cursor
+ initMouseCursor(&_mouseCursor, MOUSECURSOR_APPLE_II_GS, 9, 11, 0, 0);
+ initMouseCursor(&_mouseCursorBusy, MOUSECURSOR_SCI_BUSY, 15, 16, 7, 8);
+ break;
+ case Common::kRenderAtariST:
+ initMouseCursor(&_mouseCursor, MOUSECURSOR_ATARI_ST, 11, 16, 0, 0);
+ initMouseCursor(&_mouseCursorBusy, MOUSECURSOR_SCI_BUSY, 15, 16, 7, 8);
+ break;
+ case Common::kRenderMacintosh:
+ // It looks like Atari ST + Macintosh used the same standard mouse cursor
+ // TODO: Verify by checking actual hardware
+ initMouseCursor(&_mouseCursor, MOUSECURSOR_ATARI_ST, 11, 16, 0, 0);
+ initMouseCursor(&_mouseCursorBusy, MOUSECURSOR_MACINTOSH_BUSY, 10, 14, 7, 8);
+ break;
+ default:
+ error("initVideo: unsupported render mode");
+ break;
+ }
+
+ _pixels = SCRIPT_WIDTH * SCRIPT_HEIGHT;
+ _gameScreen = (byte *)calloc(_pixels, 1);
+ _priorityScreen = (byte *)calloc(_pixels, 1);
+ _activeScreen = _gameScreen;
+ //_activeScreen = _priorityScreen;
+
+ _displayPixels = _displayScreenWidth * _displayScreenHeight;
+ _displayScreen = (byte *)calloc(_displayPixels, 1);
+
+ initGraphics(_displayScreenWidth, _displayScreenHeight, _displayScreenWidth > 320);
+
+ setPalette(true); // set gfx-mode palette
+
+ // set up mouse cursor palette
+ CursorMan.replaceCursorPalette(MOUSECURSOR_PALETTE, 1, ARRAYSIZE(MOUSECURSOR_PALETTE) / 3);
+ setMouseCursor();
+
+ return errOK;
+}
/**
- * Third generation Amiga AGI palette.
- * A 16-color, 12-bit RGB palette.
+ * Deinitialize graphics device.
*
- * Used by at least the following Amiga AGI versions:
- * 2.310 (Police Quest I v2.0B 1989-02-22)
- * 2.316 (Gold Rush! v2.05 1989-03-09)
- * x.yyy (Manhunter I v1.06 1989-03-18)
- * 2.333 (Manhunter II v3.06 1989-08-17)
- * 2.333 (King's Quest III v2.15 1989-11-15)
+ * @see init_video()
*/
-static const uint8 amigaAgiPaletteV3[16 * 3] = {
- 0x0, 0x0, 0x0,
- 0x0, 0x0, 0xB,
- 0x0, 0xB, 0x0,
- 0x0, 0xB, 0xB,
- 0xB, 0x0, 0x0,
- 0xB, 0x0, 0xB,
- 0xC, 0x7, 0x0,
- 0xB, 0xB, 0xB,
- 0x7, 0x7, 0x7,
- 0x0, 0x0, 0xF,
- 0x0, 0xF, 0x0,
- 0x0, 0xF, 0xF,
- 0xF, 0x0, 0x0,
- 0xF, 0x0, 0xF,
- 0xF, 0xF, 0x0,
- 0xF, 0xF, 0xF
-};
+int GfxMgr::deinitVideo() {
+ // Free mouse cursors in case they were allocated
+ if (_mouseCursor.bitmapDataAllocated)
+ free(_mouseCursor.bitmapDataAllocated);
+ if (_mouseCursorBusy.bitmapDataAllocated)
+ free(_mouseCursorBusy.bitmapDataAllocated);
-/**
- * 16 color amiga-ish palette.
- */
-static const uint8 altAmigaPalette[16 * 3] = {
- 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x3f,
- 0x00, 0x2A, 0x00,
- 0x00, 0x2A, 0x2A,
- 0x33, 0x00, 0x00,
- 0x2f, 0x1c, 0x37,
- 0x23, 0x14, 0x00,
- 0x2f, 0x2f, 0x2f,
- 0x15, 0x15, 0x15,
- 0x00, 0x2f, 0x3f,
- 0x00, 0x33, 0x15,
- 0x15, 0x3F, 0x3F,
- 0x3f, 0x27, 0x23,
- 0x3f, 0x15, 0x3f,
- 0x3b, 0x3b, 0x00,
- 0x3F, 0x3F, 0x3F
-};
+ free(_displayScreen);
+ free(_gameScreen);
+ free(_priorityScreen);
-/**
- * 256 color palette used with AGI256 and AGI256-2 games.
- * Uses full 8 bits per color component.
- */
-static const uint8 vgaPalette[256 * 3] = {
- 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xA8,
- 0x00, 0xA8, 0x00,
- 0x00, 0xA8, 0xA8,
- 0xA8, 0x00, 0x00,
- 0xA8, 0x00, 0xA8,
- 0xA8, 0x54, 0x00,
- 0xA8, 0xA8, 0xA8,
- 0x54, 0x54, 0x54,
- 0x54, 0x54, 0xFC,
- 0x54, 0xFC, 0x54,
- 0x54, 0xFC, 0xFC,
- 0xFC, 0x54, 0x54,
- 0xFC, 0x54, 0xFC,
- 0xFC, 0xFC, 0x54,
- 0xFC, 0xFC, 0xFC,
- 0x00, 0x00, 0x00,
- 0x14, 0x14, 0x14,
- 0x20, 0x20, 0x20,
- 0x2C, 0x2C, 0x2C,
- 0x38, 0x38, 0x38,
- 0x44, 0x44, 0x44,
- 0x50, 0x50, 0x50,
- 0x60, 0x60, 0x60,
- 0x70, 0x70, 0x70,
- 0x80, 0x80, 0x80,
- 0x90, 0x90, 0x90,
- 0xA0, 0xA0, 0xA0,
- 0xB4, 0xB4, 0xB4,
- 0xC8, 0xC8, 0xC8,
- 0xE0, 0xE0, 0xE0,
- 0xFC, 0xFC, 0xFC,
- 0x00, 0x00, 0xFC,
- 0x40, 0x00, 0xFC,
- 0x7C, 0x00, 0xFC,
- 0xBC, 0x00, 0xFC,
- 0xFC, 0x00, 0xFC,
- 0xFC, 0x00, 0xBC,
- 0xFC, 0x00, 0x7C,
- 0xFC, 0x00, 0x40,
- 0xFC, 0x00, 0x00,
- 0xFC, 0x40, 0x00,
- 0xFC, 0x7C, 0x00,
- 0xFC, 0xBC, 0x00,
- 0xFC, 0xFC, 0x00,
- 0xBC, 0xFC, 0x00,
- 0x7C, 0xFC, 0x00,
- 0x40, 0xFC, 0x00,
- 0x00, 0xFC, 0x00,
- 0x00, 0xFC, 0x40,
- 0x00, 0xFC, 0x7C,
- 0x00, 0xFC, 0xBC,
- 0x00, 0xFC, 0xFC,
- 0x00, 0xBC, 0xFC,
- 0x00, 0x7C, 0xFC,
- 0x00, 0x40, 0xFC,
- 0x7C, 0x7C, 0xFC,
- 0x9C, 0x7C, 0xFC,
- 0xBC, 0x7C, 0xFC,
- 0xDC, 0x7C, 0xFC,
- 0xFC, 0x7C, 0xFC,
- 0xFC, 0x7C, 0xDC,
- 0xFC, 0x7C, 0xBC,
- 0xFC, 0x7C, 0x9C,
- 0xFC, 0x7C, 0x7C,
- 0xFC, 0x9C, 0x7C,
- 0xFC, 0xBC, 0x7C,
- 0xFC, 0xDC, 0x7C,
- 0xFC, 0xFC, 0x7C,
- 0xDC, 0xFC, 0x7C,
- 0xBC, 0xFC, 0x7C,
- 0x9C, 0xFC, 0x7C,
- 0x7C, 0xFC, 0x7C,
- 0x7C, 0xFC, 0x9C,
- 0x7C, 0xFC, 0xBC,
- 0x7C, 0xFC, 0xDC,
- 0x7C, 0xFC, 0xFC,
- 0x7C, 0xDC, 0xFC,
- 0x7C, 0xBC, 0xFC,
- 0x7C, 0x9C, 0xFC,
- 0xB4, 0xB4, 0xFC,
- 0xC4, 0xB4, 0xFC,
- 0xD8, 0xB4, 0xFC,
- 0xE8, 0xB4, 0xFC,
- 0xFC, 0xB4, 0xFC,
- 0xFC, 0xB4, 0xE8,
- 0xFC, 0xB4, 0xD8,
- 0xFC, 0xB4, 0xC4,
- 0xFC, 0xB4, 0xB4,
- 0xFC, 0xC4, 0xB4,
- 0xFC, 0xD8, 0xB4,
- 0xFC, 0xE8, 0xB4,
- 0xFC, 0xFC, 0xB4,
- 0xE8, 0xFC, 0xB4,
- 0xD8, 0xFC, 0xB4,
- 0xC4, 0xFC, 0xB4,
- 0xB4, 0xFC, 0xB4,
- 0xB4, 0xFC, 0xC4,
- 0xB4, 0xFC, 0xD8,
- 0xB4, 0xFC, 0xE8,
- 0xB4, 0xFC, 0xFC,
- 0xB4, 0xE8, 0xFC,
- 0xB4, 0xD8, 0xFC,
- 0xB4, 0xC4, 0xFC,
- 0x00, 0x00, 0x70,
- 0x1C, 0x00, 0x70,
- 0x38, 0x00, 0x70,
- 0x54, 0x00, 0x70,
- 0x70, 0x00, 0x70,
- 0x70, 0x00, 0x54,
- 0x70, 0x00, 0x38,
- 0x70, 0x00, 0x1C,
- 0x70, 0x00, 0x00,
- 0x70, 0x1C, 0x00,
- 0x70, 0x38, 0x00,
- 0x70, 0x54, 0x00,
- 0x70, 0x70, 0x00,
- 0x54, 0x70, 0x00,
- 0x38, 0x70, 0x00,
- 0x1C, 0x70, 0x00,
- 0x00, 0x70, 0x00,
- 0x00, 0x70, 0x1C,
- 0x00, 0x70, 0x38,
- 0x00, 0x70, 0x54,
- 0x00, 0x70, 0x70,
- 0x00, 0x54, 0x70,
- 0x00, 0x38, 0x70,
- 0x00, 0x1C, 0x70,
- 0x38, 0x38, 0x70,
- 0x44, 0x38, 0x70,
- 0x54, 0x38, 0x70,
- 0x60, 0x38, 0x70,
- 0x70, 0x38, 0x70,
- 0x70, 0x38, 0x60,
- 0x70, 0x38, 0x54,
- 0x70, 0x38, 0x44,
- 0x70, 0x38, 0x38,
- 0x70, 0x44, 0x38,
- 0x70, 0x54, 0x38,
- 0x70, 0x60, 0x38,
- 0x70, 0x70, 0x38,
- 0x60, 0x70, 0x38,
- 0x54, 0x70, 0x38,
- 0x44, 0x70, 0x38,
- 0x38, 0x70, 0x38,
- 0x38, 0x70, 0x44,
- 0x38, 0x70, 0x54,
- 0x38, 0x70, 0x60,
- 0x38, 0x70, 0x70,
- 0x38, 0x60, 0x70,
- 0x38, 0x54, 0x70,
- 0x38, 0x44, 0x70,
- 0x50, 0x50, 0x70,
- 0x58, 0x50, 0x70,
- 0x60, 0x50, 0x70,
- 0x68, 0x50, 0x70,
- 0x70, 0x50, 0x70,
- 0x70, 0x50, 0x68,
- 0x70, 0x50, 0x60,
- 0x70, 0x50, 0x58,
- 0x70, 0x50, 0x50,
- 0x70, 0x58, 0x50,
- 0x70, 0x60, 0x50,
- 0x70, 0x68, 0x50,
- 0x70, 0x70, 0x50,
- 0x68, 0x70, 0x50,
- 0x60, 0x70, 0x50,
- 0x58, 0x70, 0x50,
- 0x50, 0x70, 0x50,
- 0x50, 0x70, 0x58,
- 0x50, 0x70, 0x60,
- 0x50, 0x70, 0x68,
- 0x50, 0x70, 0x70,
- 0x50, 0x68, 0x70,
- 0x50, 0x60, 0x70,
- 0x50, 0x58, 0x70,
- 0x00, 0x00, 0x40,
- 0x10, 0x00, 0x40,
- 0x20, 0x00, 0x40,
- 0x30, 0x00, 0x40,
- 0x40, 0x00, 0x40,
- 0x40, 0x00, 0x30,
- 0x40, 0x00, 0x20,
- 0x40, 0x00, 0x10,
- 0x40, 0x00, 0x00,
- 0x40, 0x10, 0x00,
- 0x40, 0x20, 0x00,
- 0x40, 0x30, 0x00,
- 0x40, 0x40, 0x00,
- 0x30, 0x40, 0x00,
- 0x20, 0x40, 0x00,
- 0x10, 0x40, 0x00,
- 0x00, 0x40, 0x00,
- 0x00, 0x40, 0x10,
- 0x00, 0x40, 0x20,
- 0x00, 0x40, 0x30,
- 0x00, 0x40, 0x40,
- 0x00, 0x30, 0x40,
- 0x00, 0x20, 0x40,
- 0x00, 0x10, 0x40,
- 0x20, 0x20, 0x40,
- 0x28, 0x20, 0x40,
- 0x30, 0x20, 0x40,
- 0x38, 0x20, 0x40,
- 0x40, 0x20, 0x40,
- 0x40, 0x20, 0x38,
- 0x40, 0x20, 0x30,
- 0x40, 0x20, 0x28,
- 0x40, 0x20, 0x20,
- 0x40, 0x28, 0x20,
- 0x40, 0x30, 0x20,
- 0x40, 0x38, 0x20,
- 0x40, 0x40, 0x20,
- 0x38, 0x40, 0x20,
- 0x30, 0x40, 0x20,
- 0x28, 0x40, 0x20,
- 0x20, 0x40, 0x20,
- 0x20, 0x40, 0x28,
- 0x20, 0x40, 0x30,
- 0x20, 0x40, 0x38,
- 0x20, 0x40, 0x40,
- 0x20, 0x38, 0x40,
- 0x20, 0x30, 0x40,
- 0x20, 0x28, 0x40,
- 0x2C, 0x2C, 0x40,
- 0x30, 0x2C, 0x40,
- 0x34, 0x2C, 0x40,
- 0x3C, 0x2C, 0x40,
- 0x40, 0x2C, 0x40,
- 0x40, 0x2C, 0x3C,
- 0x40, 0x2C, 0x34,
- 0x40, 0x2C, 0x30,
- 0x40, 0x2C, 0x2C,
- 0x40, 0x30, 0x2C,
- 0x40, 0x34, 0x2C,
- 0x40, 0x3C, 0x2C,
- 0x40, 0x40, 0x2C,
- 0x3C, 0x40, 0x2C,
- 0x34, 0x40, 0x2C,
- 0x30, 0x40, 0x2C,
- 0x2C, 0x40, 0x2C,
- 0x2C, 0x40, 0x30,
- 0x2C, 0x40, 0x34,
- 0x2C, 0x40, 0x3C,
- 0x2C, 0x40, 0x40,
- 0x2C, 0x3C, 0x40,
- 0x2C, 0x34, 0x40,
- 0x2C, 0x30, 0x40,
- 0x40, 0x40, 0x40,
- 0x38, 0x38, 0x38,
- 0x30, 0x30, 0x30,
- 0x28, 0x28, 0x28,
- 0x24, 0x24, 0x24,
- 0x1C, 0x1C, 0x1C,
- 0x14, 0x14, 0x14,
- 0x0C, 0x0C, 0x0C
-};
+ return errOK;
+}
-static const uint16 cgaMap[16] = {
- 0x0000, // 0 - black
- 0x0d00, // 1 - blue
- 0x0b00, // 2 - green
- 0x0f00, // 3 - cyan
- 0x000b, // 4 - red
- 0x0b0d, // 5 - magenta
- 0x000d, // 6 - brown
- 0x0b0b, // 7 - gray
- 0x0d0d, // 8 - dark gray
- 0x0b0f, // 9 - light blue
- 0x0b0d, // 10 - light green
- 0x0f0d, // 11 - light cyan
- 0x0f0d, // 12 - light red
- 0x0f00, // 13 - light magenta
- 0x0f0b, // 14 - yellow
- 0x0f0f // 15 - white
-};
+void GfxMgr::setRenderStartOffset(uint16 offsetY) {
+ if (offsetY >= (VISUAL_HEIGHT - SCRIPT_HEIGHT))
+ error("invalid render start offset");
-struct UpdateBlock {
- int x1, y1;
- int x2, y2;
-};
+ _renderStartVisualOffsetY = offsetY;
+ _renderStartDisplayOffsetY = offsetY * (1 + _displayHeightMulAdjust);
+}
+uint16 GfxMgr::getRenderStartDisplayOffsetY() {
+ return _renderStartDisplayOffsetY;
+}
-static struct UpdateBlock update = {
- MAX_INT, MAX_INT, 0, 0
-};
+// Translates a game screen coordinate to a display screen coordinate
+// Game screen to 320x200 -> x * 2, y + renderStart
+// Game screen to 640x400 -> x * 4, (y * 2) + renderStart
+void GfxMgr::translateGamePosToDisplayScreen(int16 &x, int16 &y) {
+ x = x * (2 + _displayWidthMulAdjust);
+ y = y * (1 + _displayHeightMulAdjust) + _renderStartDisplayOffsetY;
+}
-GfxMgr::GfxMgr(AgiBase *vm) : _vm(vm) {
- _shakeH = NULL;
- _shakeV = NULL;
- _agipalFileNum = 0;
- _currentCursorPalette = 0; // cursor palette not set
+// Translates a visual coordinate to a display screen coordinate
+// Visual to 320x200 -> x * 2, y
+// Visual to 640x400 -> x * 4, y * 2
+void GfxMgr::translateVisualPosToDisplayScreen(int16 &x, int16 &y) {
+ x = x * (2 + _displayWidthMulAdjust);
+ y = y * (1 + _displayHeightMulAdjust);
}
+// Translates a display screen coordinate to a game screen coordinate
+// Display screen to 320x200 -> x / 2, y - renderStart
+// Display screen to 640x400 -> x / 4, (y / 2) - renderStart
+void GfxMgr::translateDisplayPosToGameScreen(int16 &x, int16 &y) {
+ y -= _renderStartDisplayOffsetY; // remove status bar line
+ x = x / (2 + _displayWidthMulAdjust);
+ y = y / (1 + _displayHeightMulAdjust);
+ if (y < 0)
+ y = 0;
+ if (y >= SCRIPT_HEIGHT)
+ y = SCRIPT_HEIGHT + 1; // 1 beyond
+}
-//
-// Layer 4: 640x480? ================== User display
-// ^
-// | do_update(), put_block()
-// |
-// Layer 3: 640x480? ================== Framebuffer
-// ^
-// | flush_block(), put_pixels()
-// |
-// Layer 2: 320x200 ================== AGI engine screen (console), put_pixel()
-// |
-// Layer 1: 160x336 ================== AGI screen
-//
-// Upper half (160x168) of Layer 1 is for the normal 16 color & control line/priority info.
-// Lower half (160x168) of Layer 1 is for the 256 color information (Used with AGI256 & AGI256-2).
-//
+// Translates dimension from visual screen to display screen
+void GfxMgr::translateVisualDimensionToDisplayScreen(int16 &width, int16 &height) {
+ width = width * (2 + _displayWidthMulAdjust);
+ height = height * (1 + _displayHeightMulAdjust);
+}
+
+// Translates dimension from display screen to visual screen
+void GfxMgr::translateDisplayDimensionToVisualScreen(int16 &width, int16 &height) {
+ width = width / (2 + _displayWidthMulAdjust);
+ height = height / (1 + _displayHeightMulAdjust);
+}
-#define SHAKE_MAG 3
+// Translates a rect from game screen to display screen
+void GfxMgr::translateGameRectToDisplayScreen(int16 &x, int16 &y, int16 &width, int16 &height) {
+ translateGamePosToDisplayScreen(x, y);
+ translateVisualDimensionToDisplayScreen(width, height);
+}
-void GfxMgr::shakeStart() {
- int i;
+// Translates a rect from visual screen to display screen
+void GfxMgr::translateVisualRectToDisplayScreen(int16 &x, int16 &y, int16 &width, int16 &height) {
+ translateVisualPosToDisplayScreen(x, y);
+ translateVisualDimensionToDisplayScreen(width, height);
+}
- if ((_shakeH = (uint8 *)malloc(GFX_WIDTH * SHAKE_MAG)) == NULL)
- return;
+uint32 GfxMgr::getDisplayOffsetToGameScreenPos(int16 x, int16 y) {
+ translateGamePosToDisplayScreen(x, y);
+ return (y * _displayScreenWidth) + x;
+}
+
+uint32 GfxMgr::getDisplayOffsetToVisualScreenPos(int16 x, int16 y) {
+ translateVisualPosToDisplayScreen(x, y);
+ return (y * _displayScreenWidth) + x;
+}
+
+// Attention: uses display screen coordinates!
+void GfxMgr::copyDisplayRectToScreen(int16 x, int16 y, int16 width, int16 height) {
+ g_system->copyRectToScreen(_displayScreen + y * _displayScreenWidth + x, _displayScreenWidth, x, y, width, height);
+}
+void GfxMgr::copyDisplayRectToScreen(int16 x, int16 adjX, int16 y, int16 adjY, int16 width, int16 adjWidth, int16 height, int16 adjHeight) {
+ switch (_upscaledHires) {
+ case DISPLAY_UPSCALED_DISABLED:
+ break;
+ case DISPLAY_UPSCALED_640x400:
+ adjX *= 2; adjY *= 2;
+ adjWidth *= 2; adjHeight *= 2;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ x += adjX; y += adjY;
+ width += adjWidth; height += adjHeight;
+ g_system->copyRectToScreen(_displayScreen + y * _displayScreenWidth + x, _displayScreenWidth, x, y, width, height);
+}
+void GfxMgr::copyDisplayRectToScreenUsingGamePos(int16 x, int16 y, int16 width, int16 height) {
+ translateGameRectToDisplayScreen(x, y, width, height);
+ g_system->copyRectToScreen(_displayScreen + (y * _displayScreenWidth) + x, _displayScreenWidth, x, y, width, height);
+}
+void GfxMgr::copyDisplayRectToScreenUsingVisualPos(int16 x, int16 y, int16 width, int16 height) {
+ translateVisualRectToDisplayScreen(x, y, width, height);
+ g_system->copyRectToScreen(_displayScreen + (y * _displayScreenWidth) + x, _displayScreenWidth, x, y, width, height);
+}
+void GfxMgr::copyDisplayToScreen() {
+ g_system->copyRectToScreen(_displayScreen, _displayScreenWidth, 0, 0, _displayScreenWidth, _displayScreenHeight);
+}
+
+void GfxMgr::translateFontPosToDisplayScreen(int16 &x, int16 &y) {
+ x *= _displayFontWidth;
+ y *= _displayFontHeight;
+}
+void GfxMgr::translateDisplayPosToFontScreen(int16 &x, int16 &y) {
+ x /= _displayFontWidth;
+ y /= _displayFontHeight;
+}
+void GfxMgr::translateFontDimensionToDisplayScreen(int16 &width, int16 &height) {
+ width *= _displayFontWidth;
+ height *= _displayFontHeight;
+}
+void GfxMgr::translateFontRectToDisplayScreen(int16 &x, int16 &y, int16 &width, int16 &height) {
+ translateFontPosToDisplayScreen(x, y);
+ translateFontDimensionToDisplayScreen(width, height);
+}
+Common::Rect GfxMgr::getFontRectForDisplayScreen(int16 column, int16 row, int16 width, int16 height) {
+ Common::Rect displayRect(width * _displayFontWidth, height * _displayFontHeight);
+ displayRect.moveTo(column * _displayFontWidth, row * _displayFontHeight);
+ return displayRect;
+}
+
+void GfxMgr::debugShowMap(int mapNr) {
+ switch (mapNr) {
+ case 0:
+ _activeScreen = _gameScreen;
+ break;
+ case 1:
+ _activeScreen = _priorityScreen;
+ break;
+ default:
+ break;
+ }
+
+ render_Block(0, 0, SCRIPT_WIDTH, SCRIPT_HEIGHT);
+}
+
+void GfxMgr::clear(byte color, byte priority) {
+ memset(_gameScreen, color, _pixels);
+ memset(_priorityScreen, priority, _pixels);
+}
- if ((_shakeV = (uint8 *)malloc(SHAKE_MAG * (GFX_HEIGHT - SHAKE_MAG))) == NULL) {
- free(_shakeH);
+void GfxMgr::clearDisplay(byte color, bool copyToScreen) {
+ memset(_displayScreen, color, _displayPixels);
+
+ if (copyToScreen) {
+ copyDisplayToScreen();
+ }
+}
+
+void GfxMgr::putPixel(int16 x, int16 y, byte drawMask, byte color, byte priority) {
+ int offset = y * SCRIPT_WIDTH + x;
+
+ if (drawMask & GFX_SCREEN_MASK_VISUAL) {
+ _gameScreen[offset] = color;
+ }
+ if (drawMask & GFX_SCREEN_MASK_PRIORITY) {
+ _priorityScreen[offset] = priority;
+ }
+}
+
+void GfxMgr::putPixelOnDisplay(int16 x, int16 y, byte color) {
+ uint32 offset = 0;
+
+ switch (_upscaledHires) {
+ case DISPLAY_UPSCALED_DISABLED:
+ offset = y * _displayScreenWidth + x;
+
+ _displayScreen[offset] = color;
+ break;
+ case DISPLAY_UPSCALED_640x400:
+ offset = (y * _displayScreenWidth) + x;
+
+ _displayScreen[offset + 0] = color;
+ _displayScreen[offset + 1] = color;
+ _displayScreen[offset + _displayScreenWidth + 0] = color;
+ _displayScreen[offset + _displayScreenWidth + 1] = color;
+ break;
+ default:
+ break;
+ }
+}
+
+void GfxMgr::putPixelOnDisplay(int16 x, int16 adjX, int16 y, int16 adjY, byte color) {
+ switch (_upscaledHires) {
+ case DISPLAY_UPSCALED_DISABLED:
+ break;
+ case DISPLAY_UPSCALED_640x400:
+ adjX *= 2; adjY *= 2;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ x += adjX;
+ y += adjY;
+ putPixelOnDisplay(x, y, color);
+}
+
+void GfxMgr::putFontPixelOnDisplay(int16 baseX, int16 baseY, int16 addX, int16 addY, byte color, bool isHires) {
+ uint32 offset = 0;
+
+ switch (_upscaledHires) {
+ case DISPLAY_UPSCALED_DISABLED:
+ offset = ((baseY + addY) * _displayScreenWidth) + (baseX + addX);
+ _displayScreen[offset] = color;
+ break;
+ case DISPLAY_UPSCALED_640x400:
+ if (isHires) {
+ offset = ((baseY + addY) * _displayScreenWidth) + (baseX + addX);
+ _displayScreen[offset] = color;
+ } else {
+ offset = ((baseY + addY * 2) * _displayScreenWidth) + (baseX + addX * 2);
+ _displayScreen[offset + 0] = color;
+ _displayScreen[offset + 1] = color;
+ _displayScreen[offset + _displayScreenWidth + 0] = color;
+ _displayScreen[offset + _displayScreenWidth + 1] = color;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+byte GfxMgr::getColor(int16 x, int16 y) {
+ int offset = y * SCRIPT_WIDTH + x;
+
+ return _gameScreen[offset];
+}
+
+byte GfxMgr::getPriority(int16 x, int16 y) {
+ int offset = y * SCRIPT_WIDTH + x;
+
+ return _priorityScreen[offset];
+}
+
+// used, when a control pixel is found
+// will search downwards and compare priority in case any is found
+bool GfxMgr::checkControlPixel(int16 x, int16 y, byte viewPriority) {
+ int offset = y * SCRIPT_WIDTH + x;
+ byte curPriority;
+
+ while (1) {
+ y++;
+ offset += SCRIPT_WIDTH;
+ if (y >= SCRIPT_HEIGHT) {
+ // end of screen, nothing but control pixels found
+ return true; // draw view pixel
+ }
+ curPriority = _priorityScreen[offset];
+ if (curPriority > 2) // valid priority found?
+ break;
+ }
+ if (curPriority <= viewPriority)
+ return true; // view priority is higher, draw
+ return false; // view priority is lower, don't draw
+}
+
+static byte CGA_MixtureColorTable[] = {
+ 0x00, 0x08, 0x04, 0x0C, 0x01, 0x09, 0x02, 0x05,
+ 0x0A, 0x0D, 0x06, 0x0E, 0x0B, 0x03, 0x07, 0x0F
+};
+
+byte GfxMgr::getCGAMixtureColor(byte color) {
+ return CGA_MixtureColorTable[color & 0x0F];
+}
+
+// Attention: in our implementation, y-coordinate is upper left.
+// Sierra passed the lower left instead. We changed it to make upscaling easier.
+void GfxMgr::render_Block(int16 x, int16 y, int16 width, int16 height, bool copyToScreen) {
+ if (!render_Clip(x, y, width, height))
return;
+
+ switch (_vm->_renderMode) {
+ case Common::kRenderHercG:
+ case Common::kRenderHercA:
+ render_BlockHercules(x, y, width, height, copyToScreen);
+ break;
+ case Common::kRenderCGA:
+ render_BlockCGA(x, y, width, height, copyToScreen);
+ break;
+ case Common::kRenderEGA:
+ default:
+ render_BlockEGA(x, y, width, height, copyToScreen);
+ break;
+ }
+
+ if (copyToScreen) {
+ copyDisplayRectToScreenUsingGamePos(x, y, width, height);
+ }
+}
+
+bool GfxMgr::render_Clip(int16 &x, int16 &y, int16 &width, int16 &height, int16 clipAgainstWidth, int16 clipAgainstHeight) {
+ if ((x >= clipAgainstWidth) || ((x + width - 1) < 0) ||
+ (y < 0) || ((y + (height - 1)) >= clipAgainstHeight)) {
+ return false;
+ }
+
+ if (y < 0) {
+ height += y;
+ y = 0;
+ }
+
+ if ((y + height - 1) >= clipAgainstHeight) {
+ height = clipAgainstHeight - y;
}
- for (i = 0; i < GFX_HEIGHT - SHAKE_MAG; i++) {
- memcpy(_shakeV + i * SHAKE_MAG, _agiScreen + i * GFX_WIDTH, SHAKE_MAG);
+#if 0
+ if ((y - height + 1) < 0)
+ height = y + 1;
+
+ if (y >= clipAgainstHeight) {
+ height -= y - (clipAgainstHeight - 1);
+ y = clipAgainstHeight - 1;
}
+#endif
- for (i = 0; i < SHAKE_MAG; i++) {
- memcpy(_shakeH + i * GFX_WIDTH, _agiScreen + i * GFX_WIDTH, GFX_WIDTH);
+ if (x < 0) {
+ width += x;
+ x = 0;
}
+
+ if ((x + width - 1) >= clipAgainstWidth) {
+ width = clipAgainstWidth - x;
+ }
+ return true;
}
-void GfxMgr::shakeScreen(int n) {
- int i;
+void GfxMgr::render_BlockEGA(int16 x, int16 y, int16 width, int16 height, bool copyToScreen) {
+ uint32 offsetVisual = SCRIPT_WIDTH * y + x;
+ uint32 offsetDisplay = getDisplayOffsetToGameScreenPos(x, y);
+ int16 remainingWidth = width;
+ int16 remainingHeight = height;
+ byte curColor = 0;
+ int16 displayWidth = width * (2 + _displayWidthMulAdjust);
+
+ while (remainingHeight) {
+ remainingWidth = width;
+
+ switch (_upscaledHires) {
+ case DISPLAY_UPSCALED_DISABLED:
+ while (remainingWidth) {
+ curColor = _activeScreen[offsetVisual++];
+ _displayScreen[offsetDisplay++] = curColor;
+ _displayScreen[offsetDisplay++] = curColor;
+ remainingWidth--;
+ }
+ break;
+ case DISPLAY_UPSCALED_640x400:
+ while (remainingWidth) {
+ curColor = _activeScreen[offsetVisual++];
+ memset(&_displayScreen[offsetDisplay], curColor, 4);
+ memset(&_displayScreen[offsetDisplay + _displayScreenWidth], curColor, 4);
+ offsetDisplay += 4;
+ remainingWidth--;
+ }
+ break;
+ default:
+ assert(0);
+ break;
+ }
- if (n == 0) {
- for (i = 0; i < (GFX_HEIGHT - SHAKE_MAG); i++) {
- memmove(&_agiScreen[GFX_WIDTH * i],
- &_agiScreen[GFX_WIDTH * (i + SHAKE_MAG) + SHAKE_MAG],
- GFX_WIDTH - SHAKE_MAG);
+ offsetVisual += SCRIPT_WIDTH - width;
+ offsetDisplay += _displayScreenWidth - displayWidth;
+
+ switch (_upscaledHires) {
+ case DISPLAY_UPSCALED_640x400:
+ offsetDisplay += _displayScreenWidth;
+ break;
+ default:
+ break;
}
- } else {
- for (i = GFX_HEIGHT - SHAKE_MAG - 1; i >= 0; i--) {
- memmove(&_agiScreen[GFX_WIDTH * (i + SHAKE_MAG) + SHAKE_MAG],
- &_agiScreen[GFX_WIDTH * i], GFX_WIDTH - SHAKE_MAG);
+
+ remainingHeight--;
+ }
+}
+
+void GfxMgr::render_BlockCGA(int16 x, int16 y, int16 width, int16 height, bool copyToScreen) {
+ uint32 offsetVisual = SCRIPT_WIDTH * y + x;
+ uint32 offsetDisplay = getDisplayOffsetToGameScreenPos(x, y);
+ int16 remainingWidth = width;
+ int16 remainingHeight = height;
+ byte curColor = 0;
+ int16 displayWidth = width * (2 + _displayWidthMulAdjust);
+
+ while (remainingHeight) {
+ remainingWidth = width;
+
+ switch (_upscaledHires) {
+ case DISPLAY_UPSCALED_DISABLED:
+ while (remainingWidth) {
+ curColor = _activeScreen[offsetVisual++];
+ _displayScreen[offsetDisplay++] = curColor & 0x03; // we process CGA mixture
+ _displayScreen[offsetDisplay++] = curColor >> 2;
+ remainingWidth--;
+ }
+ break;
+ case DISPLAY_UPSCALED_640x400:
+ while (remainingWidth) {
+ curColor = _activeScreen[offsetVisual++];
+ _displayScreen[offsetDisplay + 0] = curColor & 0x03; // we process CGA mixture
+ _displayScreen[offsetDisplay + 1] = curColor >> 2;
+ _displayScreen[offsetDisplay + 2] = curColor & 0x03;
+ _displayScreen[offsetDisplay + 3] = curColor >> 2;
+ _displayScreen[offsetDisplay + _displayScreenWidth + 0] = curColor & 0x03;
+ _displayScreen[offsetDisplay + _displayScreenWidth + 1] = curColor >> 2;
+ _displayScreen[offsetDisplay + _displayScreenWidth + 2] = curColor & 0x03;
+ _displayScreen[offsetDisplay + _displayScreenWidth + 3] = curColor >> 2;
+ offsetDisplay += 4;
+ remainingWidth--;
+ }
+ break;
+ default:
+ assert(0);
+ break;
}
+
+ offsetVisual += SCRIPT_WIDTH - width;
+ offsetDisplay += _displayScreenWidth - displayWidth;
+
+ switch (_upscaledHires) {
+ case DISPLAY_UPSCALED_640x400:
+ offsetDisplay += _displayScreenWidth;
+ break;
+ default:
+ break;
+ }
+
+ remainingHeight--;
}
}
-void GfxMgr::shakeEnd() {
- int i;
+static const uint8 herculesColorMapping[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x88, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
+ 0x80, 0x10, 0x02, 0x20, 0x01, 0x08, 0x40, 0x04,
+ 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00,
+ 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,
+ 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00,
+ 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88,
+ 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
+ 0x22, 0x00, 0x88, 0x00, 0x22, 0x00, 0x88, 0x00,
+ 0xD7, 0xFF, 0x7D, 0xFF, 0xD7, 0xFF, 0x7D, 0xFF,
+ 0xDD, 0x55, 0x77, 0xAA, 0xDD, 0x55, 0x77, 0xAA,
+ 0x7F, 0xEF, 0xFD, 0xDF, 0xFE, 0xF7, 0xBF, 0xFB,
+ 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF,
+ 0x77, 0xBB, 0xDD, 0xEE, 0x77, 0xBB, 0xDD, 0xEE,
+ 0x77, 0xFF, 0xFF, 0xFF, 0xDD, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+// Sierra actually seems to have rendered the whole screen all the time
+void GfxMgr::render_BlockHercules(int16 x, int16 y, int16 width, int16 height, bool copyToScreen) {
+ uint32 offsetVisual = SCRIPT_WIDTH * y + x;
+ uint32 offsetDisplay = getDisplayOffsetToGameScreenPos(x, y);
+ int16 remainingWidth = width;
+ int16 remainingHeight = height;
+ byte curColor = 0;
+ int16 displayWidth = width * (2 + _displayWidthMulAdjust);
+
+ assert(_upscaledHires == DISPLAY_UPSCALED_640x400);
+
+ uint16 lookupOffset1 = (y * 2 & 0x07);
+ uint16 lookupOffset2 = 0;
+ bool getUpperNibble = false;
+ byte herculesColors1 = 0;
+ byte herculesColors2 = 0;
+
+ while (remainingHeight) {
+ remainingWidth = width;
+
+ lookupOffset1 = (lookupOffset1 + 0) & 0x07;
+ lookupOffset2 = (lookupOffset1 + 1) & 0x07;
+
+ getUpperNibble = (x & 1) ? false : true;
+ while (remainingWidth) {
+ curColor = _activeScreen[offsetVisual++] & 0x0F;
+
+ if (getUpperNibble) {
+ herculesColors1 = herculesColorMapping[curColor * 8 + lookupOffset1] & 0x0F;
+ herculesColors2 = herculesColorMapping[curColor * 8 + lookupOffset2] & 0x0F;
+ } else {
+ herculesColors1 = herculesColorMapping[curColor * 8 + lookupOffset1] >> 4;
+ herculesColors2 = herculesColorMapping[curColor * 8 + lookupOffset2] >> 4;
+ }
+ getUpperNibble ^= true;
+
+ _displayScreen[offsetDisplay + 0] = (herculesColors1 & 0x08) ? 1 : 0;
+ _displayScreen[offsetDisplay + 1] = (herculesColors1 & 0x04) ? 1 : 0;
+ _displayScreen[offsetDisplay + 2] = (herculesColors1 & 0x02) ? 1 : 0;
+ _displayScreen[offsetDisplay + 3] = (herculesColors1 & 0x01) ? 1 : 0;
+
+ _displayScreen[offsetDisplay + _displayScreenWidth + 0] = (herculesColors2 & 0x08) ? 1 : 0;
+ _displayScreen[offsetDisplay + _displayScreenWidth + 1] = (herculesColors2 & 0x04) ? 1 : 0;
+ _displayScreen[offsetDisplay + _displayScreenWidth + 2] = (herculesColors2 & 0x02) ? 1 : 0;
+ _displayScreen[offsetDisplay + _displayScreenWidth + 3] = (herculesColors2 & 0x01) ? 1 : 0;
+
+ offsetDisplay += 4;
+ remainingWidth--;
+ }
+
+ lookupOffset1 += 2;
+
+ offsetVisual += SCRIPT_WIDTH - width;
+ offsetDisplay += _displayScreenWidth - displayWidth;
+ offsetDisplay += _displayScreenWidth;
- for (i = 0; i < GFX_HEIGHT - SHAKE_MAG; i++) {
- memcpy(_agiScreen + i * GFX_WIDTH, _shakeV + i * SHAKE_MAG, SHAKE_MAG);
+ remainingHeight--;
}
+}
- for (i = 0; i < SHAKE_MAG; i++) {
- memcpy(_agiScreen + i * GFX_WIDTH, _shakeH + i * GFX_WIDTH, GFX_WIDTH);
+// Table used for at least Manhunter 2, it renders 2 lines -> 3 lines instead of 4
+// Manhunter 1 is shipped with a broken Hercules font
+// King's Quest 4 aborts right at the start, when Hercules rendering is active
+#if 0
+static const uint8 herculesCoordinateOffset[] = {
+ 0x00, 0x01, 0x03, 0x04, 0x06, 0x07, 0x01, 0x02,
+ 0x04, 0x05, 0x07, 0x00, 0x02, 0x03, 0x05, 0x06
+};
+
+static const uint8 herculesColorMapping[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x02, 0x00, 0x40, 0x00, 0x08, 0x00,
+ 0x80, 0x10, 0x02, 0x20, 0x01, 0x08, 0x40, 0x04, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00,
+ 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00,
+ 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
+ 0x22, 0x00, 0x88, 0x00, 0x22, 0x00, 0x88, 0x00, 0xD7, 0xFF, 0x7D, 0xFF, 0xD7, 0xFF, 0x7D, 0xFF,
+ 0xDD, 0x55, 0x77, 0xAA, 0xDD, 0x55, 0x77, 0xAA, 0x7F, 0xEF, 0xFD, 0xDF, 0xFE, 0xF7, 0xBF, 0xFB,
+ 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0x77, 0xBB, 0xDD, 0xEE, 0x77, 0xBB, 0xDD, 0xEE,
+ 0x7F, 0xEF, 0xFB, 0xBF, 0xEF, 0xFE, 0xBF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+#endif
+
+void GfxMgr::transition_Amiga() {
+ uint16 screenPos = 1;
+ uint32 screenStepPos = 1;
+ int16 posY = 0, posX = 0;
+ int16 stepCount = 0;
+
+ // disable mouse while transition is taking place
+ if ((_vm->_game.mouseEnabled) && (!_vm->_game.mouseHidden)) {
+ CursorMan.showMouse(false);
}
- flushBlock(0, 0, GFX_WIDTH - 1, GFX_HEIGHT - 1);
+ do {
+ if (screenPos & 1) {
+ screenPos = screenPos >> 1;
+ screenPos = screenPos ^ 0x3500; // 13568d
+ } else {
+ screenPos = screenPos >> 1;
+ }
+
+ if ((screenPos < 13440) && (screenPos & 1)) {
+ screenStepPos = screenPos >> 1;
+ posY = screenStepPos / SCRIPT_WIDTH;
+ posX = screenStepPos - (posY * SCRIPT_WIDTH);
+
+ // Adjust to only update the game screen, not the status bar
+ translateGamePosToDisplayScreen(posX, posY);
+
+ switch (_upscaledHires) {
+ case DISPLAY_UPSCALED_DISABLED:
+ for (int16 multiPixel = 0; multiPixel < 4; multiPixel++) {
+ screenStepPos = (posY * _displayScreenWidth) + posX;
+ g_system->copyRectToScreen(_displayScreen + screenStepPos, _displayScreenWidth, posX, posY, 2, 1);
+ posY += 42;
+ }
+ break;
+ case DISPLAY_UPSCALED_640x400:
+ for (int16 multiPixel = 0; multiPixel < 4; multiPixel++) {
+ screenStepPos = (posY * _displayScreenWidth) + posX;
+ g_system->copyRectToScreen(_displayScreen + screenStepPos, _displayScreenWidth, posX, posY, 4, 2);
+ posY += 42 * 2;
+ }
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ stepCount++;
+ if (stepCount == 220) {
+ // 30 times for the whole transition, so should take around 0.5 seconds
+ g_system->updateScreen();
+ g_system->delayMillis(16);
+ stepCount = 0;
+ }
+ }
+ } while (screenPos != 1);
+
+ // Enable mouse again
+ if ((_vm->_game.mouseEnabled) && (!_vm->_game.mouseHidden)) {
+ CursorMan.showMouse(true);
+ }
- free(_shakeV);
- free(_shakeH);
+ g_system->updateScreen();
}
-void GfxMgr::putTextCharacter(int l, int x, int y, unsigned char c, int fg, int bg, bool checkerboard, const uint8 *font) {
- int x1, y1, xx, yy, cc;
- const uint8 *p;
+// This transition code was not reverse engineered, but created based on the Amiga transition code
+// Atari ST definitely had a hi-res transition using the full resolution unlike the Amiga transition.
+void GfxMgr::transition_AtariSt() {
+ uint16 screenPos = 1;
+ uint32 screenStepPos = 1;
+ int16 posY = 0, posX = 0;
+ int16 stepCount = 0;
+
+ // disable mouse while transition is taking place
+ if ((_vm->_game.mouseEnabled) && (!_vm->_game.mouseHidden)) {
+ CursorMan.showMouse(false);
+ }
- assert(font);
+ do {
+ if (screenPos & 1) {
+ screenPos = screenPos >> 1;
+ screenPos = screenPos ^ 0x3500; // 13568d
+ } else {
+ screenPos = screenPos >> 1;
+ }
- p = font + ((unsigned int)c * CHAR_LINES);
- for (y1 = 0; y1 < CHAR_LINES; y1++) {
- for (x1 = 0; x1 < CHAR_COLS; x1++) {
- xx = x + x1;
- yy = y + y1;
- cc = (*p & (1 << (7 - x1))) ? fg : bg;
- _agiScreen[xx + yy * GFX_WIDTH] = cc;
+ if ((screenPos < 13440) && (screenPos & 1)) {
+ screenStepPos = screenPos >> 1;
+ posY = screenStepPos / DISPLAY_DEFAULT_WIDTH;
+ posX = screenStepPos - (posY * DISPLAY_DEFAULT_WIDTH);
+
+ switch (_upscaledHires) {
+ case DISPLAY_UPSCALED_DISABLED:
+ posY += _renderStartDisplayOffsetY; // adjust to only update the main area, not the status bar
+ for (int16 multiPixel = 0; multiPixel < 8; multiPixel++) {
+ screenStepPos = (posY * _displayScreenWidth) + posX;
+ g_system->copyRectToScreen(_displayScreen + screenStepPos, _displayScreenWidth, posX, posY, 1, 1);
+ posY += 21;
+ }
+ break;
+ case DISPLAY_UPSCALED_640x400:
+ posX *= 2; posY *= 2;
+ posY += _renderStartDisplayOffsetY; // adjust to only update the main area, not the status bar
+ for (int16 multiPixel = 0; multiPixel < 8; multiPixel++) {
+ screenStepPos = (posY * _displayScreenWidth) + posX;
+ g_system->copyRectToScreen(_displayScreen + screenStepPos, _displayScreenWidth, posX, posY, 2, 2);
+ posY += 21 * 2;
+ }
+ break;
+ default:
+ break;
+ }
+
+ stepCount++;
+ if (stepCount == 168) {
+ // 40 times for the whole transition, so should take around 0.7 seconds
+ // When using an Atari ST emulator, the transition seems to be even slower than this
+ // TODO: should get checked on real hardware
+ g_system->updateScreen();
+ g_system->delayMillis(16);
+ stepCount = 0;
+ }
}
+ } while (screenPos != 1);
+
+ // Enable mouse again
+ if ((_vm->_game.mouseEnabled) && (!_vm->_game.mouseHidden)) {
+ CursorMan.showMouse(true);
+ }
+
+ g_system->updateScreen();
+}
+
+// Attention: y coordinate is here supposed to be the upper one!
+void GfxMgr::block_save(int16 x, int16 y, int16 width, int16 height, byte *bufferPtr) {
+ int16 startOffset = y * SCRIPT_WIDTH + x;
+ int16 offset = startOffset;
+ int16 remainingHeight = height;
+ byte *curBufferPtr = bufferPtr;
+
+ //warning("block_save: %d, %d -> %d, %d", x, y, width, height);
+
+ while (remainingHeight) {
+ memcpy(curBufferPtr, _gameScreen + offset, width);
+ offset += SCRIPT_WIDTH;
+ curBufferPtr += width;
+ remainingHeight--;
+ }
+
+ remainingHeight = height;
+ offset = startOffset;
+ while (remainingHeight) {
+ memcpy(curBufferPtr, _priorityScreen + offset, width);
+ offset += SCRIPT_WIDTH;
+ curBufferPtr += width;
+ remainingHeight--;
+ }
+}
+
+// Attention: y coordinate is here supposed to be the upper one!
+void GfxMgr::block_restore(int16 x, int16 y, int16 width, int16 height, byte *bufferPtr) {
+ int16 startOffset = y * SCRIPT_WIDTH + x;
+ int16 offset = startOffset;
+ int16 remainingHeight = height;
+ byte *curBufferPtr = bufferPtr;
- p++;
+ //warning("block_restore: %d, %d -> %d, %d", x, y, width, height);
+
+ while (remainingHeight) {
+ memcpy(_gameScreen + offset, curBufferPtr, width);
+ offset += SCRIPT_WIDTH;
+ curBufferPtr += width;
+ remainingHeight--;
}
- // Simple checkerboard effect to simulate "greyed out" text.
- // This is what Sierra's interpreter does for things like menu items
- // that aren't selectable (such as separators). -- dsymonds
- if (checkerboard) {
- for (yy = y; yy < y + CHAR_LINES; yy++)
- for (xx = x + (~yy & 1); xx < x + CHAR_COLS; xx += 2)
- _agiScreen[xx + yy * GFX_WIDTH] = 15;
+ remainingHeight = height;
+ offset = startOffset;
+ while (remainingHeight) {
+ memcpy(_priorityScreen + offset, curBufferPtr, width);
+ offset += SCRIPT_WIDTH;
+ curBufferPtr += width;
+ remainingHeight--;
}
+}
- // FIXME: we don't want this when we're writing on the
- // console!
- flushBlock(x, y, x + CHAR_COLS - 1, y + CHAR_LINES - 1);
-}
-
-void GfxMgr::drawRectangle(int x1, int y1, int x2, int y2, int c) {
- int y, w, h;
- uint8 *p0;
-
- if (x1 >= GFX_WIDTH)
- x1 = GFX_WIDTH - 1;
- if (y1 >= GFX_HEIGHT)
- y1 = GFX_HEIGHT - 1;
- if (x2 >= GFX_WIDTH)
- x2 = GFX_WIDTH - 1;
- if (y2 >= GFX_HEIGHT)
- y2 = GFX_HEIGHT - 1;
-
- w = x2 - x1 + 1;
- h = y2 - y1 + 1;
- p0 = &_agiScreen[x1 + y1 * GFX_WIDTH];
- for (y = 0; y < h; y++) {
- memset(p0, c, w);
- p0 += GFX_WIDTH;
+// coordinates are for visual screen, but are supposed to point somewhere inside the playscreen
+// x, y is the upper left. Sierra passed them as lower left. We change that to make upscaling easier.
+// attention: Clipping is done here against 160x200 instead of 160x168
+// Original interpreter didn't do any clipping, we do it for security.
+// Clipping against the regular script width/height must not be done,
+// because at least during the intro one message box goes beyond playscreen
+// Going beyond 160x168 will result in messageboxes not getting fully removed
+// In KQ4's case, the scripts clear the screen that's why it works.
+void GfxMgr::drawBox(int16 x, int16 y, int16 width, int16 height, byte backgroundColor, byte lineColor) {
+ if (!render_Clip(x, y, width, height, VISUAL_WIDTH, VISUAL_HEIGHT - _renderStartVisualOffsetY))
+ return;
+
+ // coordinate translation: visual-screen -> display-screen
+ translateVisualRectToDisplayScreen(x, y, width, height);
+
+ y = y + _renderStartDisplayOffsetY; // drawDisplayRect paints anywhere on the whole screen, our coordinate is within playscreen
+
+ // draw box background
+ drawDisplayRect(x, y, width, height, backgroundColor);
+
+ // draw lines
+ switch (_vm->_renderMode) {
+ case Common::kRenderApple2GS:
+ case Common::kRenderAmiga:
+ // Slightly different window frame, and actually using 1-pixel width, which is "hi-res"
+ drawDisplayRect(x, +2, y, +2, width, -4, 0, 1, lineColor);
+ drawDisplayRect(x + width, -3, y, +2, 0, 1, height, -4, lineColor);
+ drawDisplayRect(x, +2, y + height, -3, width, -4, 0, 1, lineColor);
+ drawDisplayRect(x, +2, y, +2, 0, 1, height, -4, lineColor);
+ break;
+ case Common::kRenderMacintosh:
+ // 1 pixel between box and frame lines. Frame lines were black
+ drawDisplayRect(x, +1, y, +1, width, -2, 0, 1, 0);
+ drawDisplayRect(x + width, -2, y, +1, 0, 1, height, -2, 0);
+ drawDisplayRect(x, +1, y + height, -2, width, -2, 0, 1, 0);
+ drawDisplayRect(x, +1, y, +1, 0, 1, height, -2, 0);
+ break;
+ case Common::kRenderHercA:
+ case Common::kRenderHercG:
+ lineColor = 0; // change linecolor to black
+ // supposed to fall through
+ case Common::kRenderCGA:
+ case Common::kRenderEGA:
+ case Common::kRenderVGA:
+ case Common::kRenderAtariST:
+ default:
+ drawDisplayRect(x, +2, y, +1, width, -4, 0, 1, lineColor);
+ drawDisplayRect(x + width, -4, y, +2, 0, 2, height, -4, lineColor);
+ drawDisplayRect(x, +2, y + height, -2, width, -4, 0, 1, lineColor);
+ drawDisplayRect(x, +2, y, +2, 0, 2, height, -4, lineColor);
+ break;
}
}
-void GfxMgr::drawFrame(int x1, int y1, int x2, int y2, int c1, int c2) {
- int y, w;
- uint8 *p0;
+// coordinates are directly for display screen
+void GfxMgr::drawDisplayRect(int16 x, int16 y, int16 width, int16 height, byte color, bool copyToScreen) {
+ switch (_vm->_renderMode) {
+ case Common::kRenderCGA:
+ drawDisplayRectCGA(x, y, width, height, color);
+ break;
+ case Common::kRenderHercG:
+ case Common::kRenderHercA:
+ if (color)
+ color = 1; // change any color except black to green/amber
+ // supposed to fall through
+ case Common::kRenderEGA:
+ default:
+ drawDisplayRectEGA(x, y, width, height, color);
+ break;
+ }
+ if (copyToScreen) {
+ copyDisplayRectToScreen(x, y, width, height);
+ }
+}
+
+void GfxMgr::drawDisplayRect(int16 x, int16 adjX, int16 y, int16 adjY, int16 width, int16 adjWidth, int16 height, int16 adjHeight, byte color, bool copyToScreen) {
+ switch (_upscaledHires) {
+ case DISPLAY_UPSCALED_DISABLED:
+ x += adjX; y += adjY;
+ width += adjWidth; height += adjHeight;
+ break;
+ case DISPLAY_UPSCALED_640x400:
+ x += adjX * 2; y += adjY * 2;
+ width += adjWidth * 2; height += adjHeight * 2;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ drawDisplayRect(x, y, width, height, color, copyToScreen);
+}
- // top line
- w = x2 - x1 + 1;
- p0 = &_agiScreen[x1 + y1 * GFX_WIDTH];
- memset(p0, c1, w);
+void GfxMgr::drawDisplayRectEGA(int16 x, int16 y, int16 width, int16 height, byte color) {
+ uint32 offsetDisplay = (y * _displayScreenWidth) + x;
+ int16 remainingHeight = height;
- // bottom line
- p0 = &_agiScreen[x1 + y2 * GFX_WIDTH];
- memset(p0, c2, w);
+ while (remainingHeight) {
+ memset(_displayScreen + offsetDisplay, color, width);
- // side lines
- for (y = y1; y <= y2; y++) {
- _agiScreen[x1 + y * GFX_WIDTH] = c1;
- _agiScreen[x2 + y * GFX_WIDTH] = c2;
+ offsetDisplay += _displayScreenWidth;
+ remainingHeight--;
}
}
-void GfxMgr::drawBox(int x1, int y1, int x2, int y2, int color1, int color2, int m) {
- x1 += m;
- y1 += m;
- x2 -= m;
- y2 -= m;
+void GfxMgr::drawDisplayRectCGA(int16 x, int16 y, int16 width, int16 height, byte color) {
+ uint32 offsetDisplay = (y * _displayScreenWidth) + x;
+ int16 remainingHeight = height;
+ int16 remainingWidth = width;
+ byte CGAMixtureColor = getCGAMixtureColor(color);
+ byte *displayScreen = nullptr;
+
+ // we should never get an uneven width
+ assert((width & 1) == 0);
- drawRectangle(x1, y1, x2, y2, color1);
- drawFrame(x1 + 2, y1 + 2, x2 - 2, y2 - 2, color2, color2);
- flushBlock(x1, y1, x2, y2);
+ while (remainingHeight) {
+ remainingWidth = width;
+
+ // set up pointer
+ displayScreen = _displayScreen + offsetDisplay;
+
+ while (remainingWidth) {
+ *displayScreen++ = CGAMixtureColor & 0x03;
+ *displayScreen++ = CGAMixtureColor >> 2;
+ remainingWidth -= 2;
+ }
+
+ offsetDisplay += _displayScreenWidth;
+ remainingHeight--;
+ }
}
-void GfxMgr::printCharacter(int x, int y, char c, int fg, int bg) {
- x *= CHAR_COLS;
- y *= CHAR_LINES;
+// row + column are text-coordinates
+void GfxMgr::drawCharacter(int16 row, int16 column, byte character, byte foreground, byte background, bool disabledLook) {
+ int16 x = column;
+ int16 y = row;
+ byte transformXOR = 0;
+ byte transformOR = 0;
+
+ translateFontPosToDisplayScreen(x, y);
+
+ // Now figure out, if special handling needs to be done
+ if (_vm->_game.gfxMode) {
+ if (background & 0x08) {
+ // invert enabled
+ background &= 0x07; // remove invert bit
+ transformXOR = 0xFF;
+ }
+ if (disabledLook) {
+ transformOR = 0x55;
+ }
+ }
- putTextCharacter(0, x, y, c, fg, bg, false, _vm->getFontData());
- // redundant! already inside put_text_character!
- // flush_block (x, y, x + CHAR_COLS - 1, y + CHAR_LINES - 1);
+ drawCharacterOnDisplay(x, y, character, foreground, background, transformXOR, transformOR);
}
-/**
- * Draw a default style button.
- * Swaps background and foreground color if button is in focus or being pressed.
- * @param x x coordinate of the button
- * @param y y coordinate of the button
- * @param a set if the button has focus
- * @param p set if the button is pressed
- * @param fgcolor foreground color of the button when it is neither in focus nor being pressed
- * @param bgcolor background color of the button when it is neither in focus nor being pressed
- */
-void GfxMgr::drawDefaultStyleButton(int x, int y, const char *s, int a, int p, int fgcolor, int bgcolor) {
- int textOffset = _vm->_defaultButtonStyle.getTextOffset(a > 0, p > 0);
- AgiTextColor color = _vm->_defaultButtonStyle.getColor (a > 0, p > 0, fgcolor, bgcolor);
- bool border = _vm->_defaultButtonStyle.getBorder (a > 0, p > 0);
+// only meant for internal use (SystemUI)
+void GfxMgr::drawStringOnDisplay(int16 x, int16 y, const char *text, byte foregroundColor, byte backgroundColor) {
+ while (*text) {
+ drawCharacterOnDisplay(x, y, *text, foregroundColor, backgroundColor);
+ text++;
+ x += _displayFontWidth;
+ }
+}
- rawDrawButton(x, y, s, color.fg, color.bg, border, textOffset);
+void GfxMgr::drawStringOnDisplay(int16 x, int16 adjX, int16 y, int16 adjY, const char *text, byte foregroundColor, byte backgroundColor) {
+ switch (_upscaledHires) {
+ case DISPLAY_UPSCALED_DISABLED:
+ x += adjX;
+ y += adjY;
+ break;
+ case DISPLAY_UPSCALED_640x400:
+ x += adjX * 2;
+ y += adjY * 2;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ drawStringOnDisplay(x, y, text, foregroundColor, backgroundColor);
}
-/**
- * Draw a button using the currently chosen style.
- * Amiga-style is used for the Amiga-rendering mode, PC-style is used otherwise.
- * @param x x coordinate of the button
- * @param y y coordinate of the button
- * @param hasFocus set if the button has focus
- * @param pressed set if the button is pressed
- * @param positive set if button is positive, otherwise button is negative (Only matters with Amiga-style buttons)
- * TODO: Make Amiga-style buttons a bit wider as they were in Amiga AGI games.
- */
-void GfxMgr::drawCurrentStyleButton(int x, int y, const char *label, bool hasFocus, bool pressed, bool positive) {
- int textOffset = _vm->_buttonStyle.getTextOffset(hasFocus, pressed);
- AgiTextColor color = _vm->_buttonStyle.getColor(hasFocus, pressed, positive);
- bool border = _vm->_buttonStyle.getBorder(hasFocus, pressed);
+void GfxMgr::drawCharacterOnDisplay(int16 x, int16 y, const byte character, byte foreground, byte background, byte transformXOR, byte transformOR) {
+ int16 curX, curY;
+ const byte *fontData;
+ bool fontIsHires = _font->isFontHires();
+ int16 fontHeight = fontIsHires ? 16 : FONT_DISPLAY_HEIGHT;
+ int16 fontWidth = fontIsHires ? 16 : FONT_DISPLAY_WIDTH;
+ int16 fontBytesPerCharacter = fontIsHires ? 32 : FONT_BYTES_PER_CHARACTER;
+ byte curByte = 0;
+ uint16 curBit;
+
+ // get font data of specified character
+ fontData = _font->getFontData() + character * fontBytesPerCharacter;
+
+ curBit = 0;
+ for (curY = 0; curY < fontHeight; curY++) {
+ for (curX = 0; curX < fontWidth; curX++) {
+ if (!curBit) {
+ curByte = *fontData;
+ // do transformations in case they are needed (invert/disabled look)
+ curByte ^= transformXOR;
+ curByte |= transformOR;
+ fontData++;
+ curBit = 0x80;
+ }
+ if (curByte & curBit) {
+ putFontPixelOnDisplay(x, y, curX, curY, foreground, fontIsHires);
+ } else {
+ putFontPixelOnDisplay(x, y, curX, curY, background, fontIsHires);
+ }
+ curBit = curBit >> 1;
+ }
+ if (transformOR)
+ transformOR ^= 0xFF;
+ }
+
+ copyDisplayRectToScreen(x, y, _displayFontWidth, _displayFontHeight);
+}
+
+#define SHAKE_VERTICAL_PIXELS 4
+#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(shakeHorizontalPixels * _displayScreenWidth, 1)) == NULL)
+ return;
+
+ shakeCount = repeatCount * 8; // effectively 4 shakes per repeat
+
+ // it's 4 pixels down and 8 pixels to the right
+ // and it's also filling the remaining space with black
+ for (shakeNr = 0; shakeNr < shakeCount; shakeNr++) {
+ if (shakeNr & 1) {
+ // move back
+ copyDisplayToScreen();
+ } else {
+ g_system->copyRectToScreen(_displayScreen, _displayScreenWidth, shakeHorizontalPixels, shakeVerticalPixels, _displayScreenWidth - shakeHorizontalPixels, _displayScreenHeight - shakeVerticalPixels);
+ // additionally fill the remaining space with black
+ g_system->copyRectToScreen(blackSpace, _displayScreenWidth, 0, 0, _displayScreenWidth, shakeVerticalPixels);
+ g_system->copyRectToScreen(blackSpace, shakeHorizontalPixels, 0, 0, shakeHorizontalPixels, _displayScreenHeight);
+ }
+ g_system->updateScreen();
+ g_system->delayMillis(66); // Sierra waited for 4 V'Syncs, which is around 66 milliseconds
+ }
+
+ free(blackSpace);
+}
- rawDrawButton(x, y, label, color.fg, color.bg, border, textOffset);
+void GfxMgr::updateScreen() {
+ g_system->updateScreen();
}
-void GfxMgr::rawDrawButton(int x, int y, const char *s, int fgcolor, int bgcolor, bool border, int textOffset) {
- int len = strlen(s);
- int x1, y1, x2, y2;
+void GfxMgr::initPriorityTable() {
+ _priorityTableSet = false;
- x1 = x - 3;
- y1 = y - 3;
- x2 = x + CHAR_COLS * len + 2;
- y2 = y + CHAR_LINES + 2;
+ createDefaultPriorityTable(_priorityTable);
+}
- // Draw a filled rectangle that's larger than the button. Used for drawing
- // a border around the button as the button itself is drawn after this.
- drawRectangle(x1, y1, x2, y2, border ? BUTTON_BORDER : MSG_BOX_COLOR);
+void GfxMgr::createDefaultPriorityTable(uint8 *priorityTable) {
+ int16 priority, step;
+ int16 yPos = 0;
- while (*s) {
- putTextCharacter(0, x + textOffset, y + textOffset, *s++, fgcolor, bgcolor, false, _vm->getFontData());
- x += CHAR_COLS;
+ for (priority = 1; priority < 15; priority++) {
+ for (step = 0; step < 12; step++) {
+ priorityTable[yPos++] = priority < 4 ? 4 : priority;
+ }
}
+}
+
+void GfxMgr::setPriorityTable(int16 priorityBase) {
+ int16 x, priorityY, priority;
- x1 -= 2;
- y1 -= 2;
- x2 += 2;
- y2 += 2;
+ _priorityTableSet = true;
+ x = (SCRIPT_HEIGHT - priorityBase) * SCRIPT_HEIGHT / 10;
- flushBlock(x1, y1, x2, y2);
+ for (priorityY = 0; priorityY < SCRIPT_HEIGHT; priorityY++) {
+ priority = (priorityY - priorityBase) < 0 ? 4 : (priorityY - priorityBase) * SCRIPT_HEIGHT / x + 5;
+ if (priority > 15)
+ priority = 15;
+ _priorityTable[priorityY] = priority;
+ }
}
-int GfxMgr::testButton(int x, int y, const char *s) {
- int len = strlen(s);
- Common::Rect rect(x - 3, y - 3, x + CHAR_COLS * len + 3, y + CHAR_LINES + 3);
- return rect.contains(_vm->_mouse.x, _vm->_mouse.y);
+// used for saving
+int16 GfxMgr::saveLoadGetPriority(int16 yPos) {
+ assert(yPos < SCRIPT_HEIGHT);
+ return _priorityTable[yPos];
+}
+bool GfxMgr::saveLoadWasPriorityTableModified() {
+ return _priorityTableSet;
}
-void GfxMgr::putBlock(int x1, int y1, int x2, int y2) {
- gfxPutBlock(x1, y1, x2, y2);
+// used for restoring
+void GfxMgr::saveLoadSetPriority(int16 yPos, int16 priority) {
+ assert(yPos < SCRIPT_HEIGHT);
+ _priorityTable[yPos] = priority;
+}
+void GfxMgr::saveLoadSetPriorityTableModifiedBool(bool wasModified) {
+ _priorityTableSet = wasModified;
}
+void GfxMgr::saveLoadFigureOutPriorityTableModifiedBool() {
+ uint8 defaultPriorityTable[SCRIPT_HEIGHT]; /**< priority table */
-void GfxMgr::putScreen() {
- putBlock(0, 0, GFX_WIDTH - 1, GFX_HEIGHT - 1);
+ createDefaultPriorityTable(defaultPriorityTable);
+
+ if (memcmp(defaultPriorityTable, _priorityTable, sizeof(_priorityTable)) == 0) {
+ // Match, it is the default table, so reset the flag
+ _priorityTableSet = false;
+ } else {
+ _priorityTableSet = true;
+ }
}
-/*
- * Public functions
+/**
+ * Convert sprite priority to y value.
*/
+int16 GfxMgr::priorityToY(int16 priority) {
+ int16 currentY;
+
+ if (!_priorityTableSet) {
+ // priority table wasn't set by scripts? calculate directly
+ return (priority - 5) * 12 + 48;
+ }
+
+ // Dynamic priority bands were introduced in 2.425, but removed again until 2.936 (effectively last version of AGI2)
+ // They are available from 2.936 onwards.
+ // It seems there was a glitch, that caused priority bands to not get calculated properly.
+ // It was caused by this function starting with Y = 168 instead of 167, which meant it always
+ // returned with 168 as result.
+ // This glitch is required in King's Quest 4 2.0, otherwise in room 54 ego will get drawn over
+ // the last dwarf, that enters the house.
+ // Dwarf is screen object 13 (view 152), gets fixed priority of 8, which would normally
+ // result in a Y of 101. Ego is priority (non-fixed) 8, which would mean that dwarf is
+ // drawn first, followed by ego, which would then draw ego over the dwarf.
+ // For more information see bug #1712585 (dwarf sprite priority)
+ //
+ // This glitch is definitely present in 2.425, 2.936 and 3.002.086.
+ //
+ // Priority bands were working properly in: 3.001.098 (Black Cauldron)
+ uint16 agiVersion = _vm->getVersion();
+
+ if (agiVersion <= 0x3086) {
+ return 168; // Buggy behavior, see above
+ }
+
+ currentY = 167;
+ while (_priorityTable[currentY] >= priority) {
+ currentY--;
+ if (currentY < 0) // Original AGI didn't do this, we abort in that case and return -1
+ break;
+ }
+ return currentY;
+}
+
+int16 GfxMgr::priorityFromY(int16 yPos) {
+ assert(yPos < SCRIPT_HEIGHT);
+ return _priorityTable[yPos];
+}
+
/**
* Initialize the color palette
@@ -800,18 +1341,34 @@ void GfxMgr::putScreen() {
* @param fromBits Bits per source color component.
* @param toBits Bits per destination color component.
*/
-void GfxMgr::initPalette(const uint8 *p, uint colorCount, uint fromBits, uint toBits) {
+void GfxMgr::initPalette(uint8 *destPalette, const uint8 *paletteData, uint colorCount, uint fromBits, uint toBits) {
const uint srcMax = (1 << fromBits) - 1;
const uint destMax = (1 << toBits) - 1;
- for (uint col = 0; col < colorCount; col++) {
- for (uint comp = 0; comp < 3; comp++) { // Convert RGB components
- _palette[col * 3 + comp] = (p[col * 3 + comp] * destMax) / srcMax;
+ for (uint colorNr = 0; colorNr < colorCount; colorNr++) {
+ for (uint componentNr = 0; componentNr < 3; componentNr++) { // Convert RGB components
+ destPalette[colorNr * 3 + componentNr] = (paletteData[colorNr * 3 + componentNr] * destMax) / srcMax;
+ }
+ }
+}
+
+// Converts CLUT data to a palette, that we can use
+void GfxMgr::initPaletteCLUT(uint8 *destPalette, const uint16 *paletteCLUTData, uint colorCount) {
+ for (uint colorNr = 0; colorNr < colorCount; colorNr++) {
+ for (uint componentNr = 0; componentNr < 3; componentNr++) { // RGB component
+ byte component = (paletteCLUTData[colorNr * 3 + componentNr] >> 8);
+ // Adjust gamma (1.8 to 2.2)
+ component = (byte)(255 * pow(component / 255.0f, 0.8181f));
+ destPalette[colorNr * 3 + componentNr] = component;
}
}
}
-void GfxMgr::gfxSetPalette() {
- g_system->getPaletteManager()->setPalette(_palette, 0, 256);
+void GfxMgr::setPalette(bool gfxModePalette) {
+ if (gfxModePalette) {
+ g_system->getPaletteManager()->setPalette(_paletteGfxMode, 0, 256);
+ } else {
+ g_system->getPaletteManager()->setPalette(_paletteTextMode, 0, 256);
+ }
}
//Gets AGIPAL Data
@@ -863,8 +1420,8 @@ void GfxMgr::setAGIPal(int p0) {
_agipalFileNum = p0;
- initPalette(_agipalPalette);
- gfxSetPalette();
+ initPalette(_paletteGfxMode, _agipalPalette);
+ setPalette(true); // set gfx-mode palette
debug(1, "Using AGIPAL palette from '%s'", filename);
}
@@ -873,137 +1430,64 @@ int GfxMgr::getAGIPalFileNum() {
return _agipalFileNum;
}
-// put a block onto the screen
-void GfxMgr::gfxPutBlock(int x1, int y1, int x2, int y2) {
- if (x1 >= GFX_WIDTH)
- x1 = GFX_WIDTH - 1;
- if (y1 >= GFX_HEIGHT)
- y1 = GFX_HEIGHT - 1;
- if (x2 >= GFX_WIDTH)
- x2 = GFX_WIDTH - 1;
- if (y2 >= GFX_HEIGHT)
- y2 = GFX_HEIGHT - 1;
+void GfxMgr::initMouseCursor(MouseCursorData *mouseCursor, const byte *bitmapData, uint16 width, uint16 height, int hotspotX, int hotspotY) {
+ switch (_upscaledHires) {
+ case DISPLAY_UPSCALED_DISABLED:
+ mouseCursor->bitmapData = bitmapData;
+ break;
+ case DISPLAY_UPSCALED_640x400: {
+ mouseCursor->bitmapDataAllocated = (byte *)malloc(width * height * 4);
+ mouseCursor->bitmapData = mouseCursor->bitmapDataAllocated;
+
+ // Upscale mouse cursor
+ byte *upscaledData = mouseCursor->bitmapDataAllocated;
+
+ for (uint16 y = 0; y < height; y++) {
+ for (uint16 x = 0; x < width; x++) {
+ byte curColor = *bitmapData++;
+ upscaledData[x * 2 + 0] = curColor;
+ upscaledData[x * 2 + 1] = curColor;
+ upscaledData[x * 2 + (width * 2) + 0] = curColor;
+ upscaledData[x * 2 + (width * 2) + 1] = curColor;
+ }
+ upscaledData += width * 2 * 2;
+ }
- g_system->copyRectToScreen(_screen + y1 * 320 + x1, 320, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
+ width *= 2;
+ height *= 2;
+ hotspotX *= 2;
+ hotspotY *= 2;
+ break;
+ }
+ default:
+ assert(0);
+ break;
+ }
+ mouseCursor->width = width;
+ mouseCursor->height = height;
+ mouseCursor->hotspotX = hotspotX;
+ mouseCursor->hotspotY = hotspotY;
}
-/**
- * A black and white SCI-style arrow cursor (11x16).
- * 0 = Transparent.
- * 1 = Black (#000000 in 24-bit RGB).
- * 2 = White (#FFFFFF in 24-bit RGB).
- */
-static const byte sciMouseCursor[] = {
- 1,1,0,0,0,0,0,0,0,0,0,
- 1,2,1,0,0,0,0,0,0,0,0,
- 1,2,2,1,0,0,0,0,0,0,0,
- 1,2,2,2,1,0,0,0,0,0,0,
- 1,2,2,2,2,1,0,0,0,0,0,
- 1,2,2,2,2,2,1,0,0,0,0,
- 1,2,2,2,2,2,2,1,0,0,0,
- 1,2,2,2,2,2,2,2,1,0,0,
- 1,2,2,2,2,2,2,2,2,1,0,
- 1,2,2,2,2,2,2,2,2,2,1,
- 1,2,2,2,2,2,1,0,0,0,0,
- 1,2,1,0,1,2,2,1,0,0,0,
- 1,1,0,0,1,2,2,1,0,0,0,
- 0,0,0,0,0,1,2,2,1,0,0,
- 0,0,0,0,0,1,2,2,1,0,0,
- 0,0,0,0,0,0,1,2,2,1,0
-};
-
-#if 0
-/**
- * A black and white Apple IIGS style arrow cursor (9x11).
- * 0 = Transparent.
- * 1 = Black (#000000 in 24-bit RGB).
- * 2 = White (#FFFFFF in 24-bit RGB).
- */
-static const byte appleIIgsMouseCursor[] = {
- 2,2,0,0,0,0,0,0,0,
- 2,1,2,0,0,0,0,0,0,
- 2,1,1,2,0,0,0,0,0,
- 2,1,1,1,2,0,0,0,0,
- 2,1,1,1,1,2,0,0,0,
- 2,1,1,1,1,1,2,0,0,
- 2,1,1,1,1,1,1,2,0,
- 2,1,1,1,1,1,1,1,2,
- 2,1,1,2,1,1,2,2,0,
- 2,2,2,0,2,1,1,2,0,
- 0,0,0,0,0,2,2,2,0
-};
-#endif
-
-/**
- * RGB-palette for the black and white SCI and Apple IIGS arrow cursors.
- */
-static const byte sciMouseCursorPalette[] = {
- 0x00, 0x00, 0x00, // Black
- 0xFF, 0xFF, 0xFF // White
-};
-
-/**
- * An Amiga-style arrow cursor (8x11).
- * 0 = Transparent.
- * 1 = Black (#000000 in 24-bit RGB).
- * 2 = Red (#DE2021 in 24-bit RGB).
- * 3 = Light red (#FFCFAD in 24-bit RGB).
- */
-static const byte amigaMouseCursor[] = {
- 2,3,1,0,0,0,0,0,
- 2,2,3,1,0,0,0,0,
- 2,2,2,3,1,0,0,0,
- 2,2,2,2,3,1,0,0,
- 2,2,2,2,2,3,1,0,
- 2,2,2,2,2,2,3,1,
- 2,0,2,2,3,1,0,0,
- 0,0,0,2,3,1,0,0,
- 0,0,0,2,2,3,1,0,
- 0,0,0,0,2,3,1,0,
- 0,0,0,0,2,2,3,1
-};
+void GfxMgr::setMouseCursor(bool busy) {
+ MouseCursorData *mouseCursor = nullptr;
-/**
- * RGB-palette for the Amiga-style arrow cursor
- * and the Amiga-style busy cursor.
- */
-static const byte amigaMouseCursorPalette[] = {
- 0x00, 0x00, 0x00, // Black
- 0xDE, 0x20, 0x21, // Red
- 0xFF, 0xCF, 0xAD // Light red
-};
+ if (!busy) {
+ mouseCursor = &_mouseCursor;
+ } else {
+ mouseCursor = &_mouseCursorBusy;
+ }
-/**
- * An Amiga-style busy cursor showing an hourglass (13x16).
- * 0 = Transparent.
- * 1 = Black (#000000 in 24-bit RGB).
- * 2 = Red (#DE2021 in 24-bit RGB).
- * 3 = Light red (#FFCFAD in 24-bit RGB).
- */
-static const byte busyAmigaMouseCursor[] = {
- 1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,2,2,2,2,2,2,2,2,2,2,2,1,
- 1,2,2,2,2,2,2,2,2,2,2,2,1,
- 0,1,3,3,3,3,3,3,3,3,3,1,0,
- 0,0,1,3,3,3,3,3,3,3,1,0,0,
- 0,0,0,1,3,3,3,3,3,1,0,0,0,
- 0,0,0,0,1,3,3,3,1,0,0,0,0,
- 0,0,0,0,0,1,3,1,0,0,0,0,0,
- 0,0,0,0,0,1,3,1,0,0,0,0,0,
- 0,0,0,0,1,2,3,2,1,0,0,0,0,
- 0,0,0,1,2,2,3,2,2,1,0,0,0,
- 0,0,1,2,2,2,3,2,2,2,1,0,0,
- 0,1,2,2,2,3,3,3,2,2,2,1,0,
- 1,3,3,3,3,3,3,3,3,3,3,3,1,
- 1,3,3,3,3,3,3,3,3,3,3,3,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1
-};
+ if (mouseCursor) {
+ CursorMan.replaceCursor(mouseCursor->bitmapData, mouseCursor->width, mouseCursor->height, mouseCursor->hotspotX, mouseCursor->hotspotY, 0);
+ }
+}
+#if 0
void GfxMgr::setCursor(bool amigaStyleCursor, bool busy) {
if (busy) {
- CursorMan.replaceCursorPalette(amigaMouseCursorPalette, 1, ARRAYSIZE(amigaMouseCursorPalette) / 3);
- CursorMan.replaceCursor(busyAmigaMouseCursor, 13, 16, 7, 8, 0);
-
+ CursorMan.replaceCursorPalette(MOUSECURSOR_AMIGA_PALETTE, 1, ARRAYSIZE(MOUSECURSOR_AMIGA_PALETTE) / 3);
+ CursorMan.replaceCursor(MOUSECURSOR_AMIGA_BUSY, 13, 16, 7, 8, 0);
return;
}
@@ -1029,241 +1513,6 @@ void GfxMgr::setCursorPalette(bool amigaStyleCursor) {
}
}
}
-
-/**
- * Initialize graphics device.
- *
- * @see deinit_video()
- */
-int GfxMgr::initVideo() {
- if (_vm->getFeatures() & (GF_AGI256 | GF_AGI256_2))
- initPalette(vgaPalette, 256, 8);
- else if (_vm->_renderMode == Common::kRenderEGA)
- initPalette(egaPalette);
- else if (_vm->_renderMode == Common::kRenderAmiga) {
- if (!ConfMan.getBool("altamigapalette")) {
- // Set the correct Amiga palette
- if (_vm->getVersion() < 0x2936)
- // TODO: This palette isn't used for Apple IIGS games yet, as
- // we don't set a separate render mode for them yet
- initPalette(amigaAgiPaletteV1, 16, 4);
- else if (_vm->getVersion() == 0x2936)
- initPalette(amigaAgiPaletteV2, 16, 4);
- else if (_vm->getVersion() > 0x2936)
- initPalette(amigaAgiPaletteV3, 16, 4);
- } else
- // Set the old common alternative Amiga palette
- initPalette(altAmigaPalette);
- } else
- error("initVideo: Unhandled render mode");
-
- if ((_agiScreen = (uint8 *)calloc(GFX_WIDTH, GFX_HEIGHT)) == NULL)
- return errNotEnoughMemory;
-
- gfxSetPalette();
-
- setCursor(_vm->_renderMode == Common::kRenderAmiga);
-
- return errOK;
-}
-
-/**
- * Deinitialize graphics device.
- *
- * @see init_video()
- */
-int GfxMgr::deinitVideo() {
- free(_agiScreen);
-
- return errOK;
-}
-
-int GfxMgr::initMachine() {
- _screen = (unsigned char *)malloc(320 * 200);
- _vm->_clockCount = 0;
-
- return errOK;
-}
-
-int GfxMgr::deinitMachine() {
- free(_screen);
-
- return errOK;
-}
-
-/**
- * Write pixels on the output device.
- * This function writes a row of pixels on the output device. Only the
- * lower 4 bits of each pixel in the row will be used, making this
- * function suitable for use with rows from the AGI screen.
- * @param x x coordinate of the row start (AGI coord.)
- * @param y y coordinate of the row start (AGI coord.)
- * @param n number of pixels in the row
- * @param p pointer to the row start in the AGI screen (Always use sbuf16c as base, not sbuf256c)
- * FIXME: CGA rendering doesn't work correctly with AGI256 or AGI256-2.
- */
-void GfxMgr::putPixelsA(int x, int y, int n, uint8 *p) {
- const uint rShift = _vm->_debug.priority ? 4 : 0; // Priority information is in the top 4 bits of a byte taken from sbuf16c.
-
- // Choose the correct screen to read from. If AGI256 or AGI256-2 is used and we're not trying to show the priority information,
- // then choose the 256 color screen, otherwise choose the 16 color screen (Which also has the priority information).
- p += ((_vm->getFeatures() & (GF_AGI256 | GF_AGI256_2)) && !_vm->_debug.priority) ? FROM_SBUF16_TO_SBUF256_OFFSET : 0;
-
- if (_vm->_renderMode == Common::kRenderCGA) {
- for (x *= 2; n--; p++, x += 2) {
- register uint16 q = (cgaMap[(*p & 0xf0) >> 4] << 4) | cgaMap[*p & 0x0f];
- *(uint16 *)&_agiScreen[x + y * GFX_WIDTH] = (q >> rShift) & 0x0f0f;
- }
- } else {
- const uint16 mask = ((_vm->getFeatures() & (GF_AGI256 | GF_AGI256_2)) && !_vm->_debug.priority) ? 0xffff : 0x0f0f;
- for (x *= 2; n--; p++, x += 2) {
- register uint16 q = ((uint16)*p << 8) | *p;
- *(uint16 *)&_agiScreen[x + y * GFX_WIDTH] = (q >> rShift) & mask;
- }
- }
-}
-
-/**
- * Schedule blocks for blitting on the output device.
- * This function gets the coordinates of a block in the AGI screen and
- * schedule it to be updated in the output device.
- * @param x1 x coordinate of the upper left corner of the block (AGI coord.)
- * @param y1 y coordinate of the upper left corner of the block (AGI coord.)
- * @param x2 x coordinate of the lower right corner of the block (AGI coord.)
- * @param y2 y coordinate of the lower right corner of the block (AGI coord.)
- *
- * @see do_update()
- */
-void GfxMgr::scheduleUpdate(int x1, int y1, int x2, int y2) {
- if (x1 < update.x1)
- update.x1 = x1;
- if (y1 < update.y1)
- update.y1 = y1;
- if (x2 > update.x2)
- update.x2 = x2;
- if (y2 > update.y2)
- update.y2 = y2;
-}
-
-/**
- * Update scheduled blocks on the output device.
- * This function exposes the blocks scheduled for updating to the output
- * device. Blocks can be scheduled at any point of the AGI cycle.
- *
- * @see schedule_update()
- */
-void GfxMgr::doUpdate() {
- if (update.x1 <= update.x2 && update.y1 <= update.y2) {
- gfxPutBlock(update.x1, update.y1, update.x2, update.y2);
- }
-
- // reset update block variables
- update.x1 = MAX_INT;
- update.y1 = MAX_INT;
- update.x2 = 0;
- update.y2 = 0;
-
- g_system->updateScreen();
-}
-
-/**
- * Updates a block of the framebuffer with contents of the AGI engine screen.
- * This function updates a block in the output device with the contents of
- * the AGI engine screen, handling console transparency.
- * @param x1 x coordinate of the upper left corner of the block
- * @param y1 y coordinate of the upper left corner of the block
- * @param x2 x coordinate of the lower right corner of the block
- * @param y2 y coordinate of the lower right corner of the block
- *
- * @see flush_block_a()
- */
-void GfxMgr::flushBlock(int x1, int y1, int x2, int y2) {
- int y, w;
- uint8 *p0;
-
- scheduleUpdate(x1, y1, x2, y2);
-
- p0 = &_agiScreen[x1 + y1 * GFX_WIDTH];
- w = x2 - x1 + 1;
-
- for (y = y1; y <= y2; y++) {
- memcpy(_screen + 320 * y + x1, p0, w);
- p0 += GFX_WIDTH;
- }
-}
-
-/**
- * Updates a block of the framebuffer receiving AGI picture coordinates.
- * @param x1 x AGI picture coordinate of the upper left corner of the block
- * @param y1 y AGI picture coordinate of the upper left corner of the block
- * @param x2 x AGI picture coordinate of the lower right corner of the block
- * @param y2 y AGI picture coordinate of the lower right corner of the block
- *
- * @see flush_block()
- */
-void GfxMgr::flushBlockA(int x1, int y1, int x2, int y2) {
- //y1 += 8;
- //y2 += 8;
- flushBlock(DEV_X0(x1), DEV_Y(y1), DEV_X1(x2), DEV_Y(y2));
-}
-
-/**
- * Updates the framebuffer with contents of the AGI engine screen (console-aware).
- * This function updates the output device with the contents of the AGI
- * screen, handling console transparency.
- */
-void GfxMgr::flushScreen() {
- flushBlock(0, 0, GFX_WIDTH - 1, GFX_HEIGHT - 1);
-
- doUpdate();
-}
-
-/**
- * Clear the output device screen (console-aware).
- * This function clears the output device screen and updates the
- * output device. Contents of the AGI screen are left untouched. This
- * function can be used to simulate a switch to a text mode screen in
- * a graphic-only device.
- * @param c color to clear the screen
- */
-void GfxMgr::clearScreen(int c) {
- memset(_agiScreen, c, GFX_WIDTH * GFX_HEIGHT);
- flushScreen();
-}
-
-/**
- * Save a block of the AGI engine screen
- */
-void GfxMgr::saveBlock(int x1, int y1, int x2, int y2, uint8 *b) {
- uint8 *p0;
- int w, h;
-
- p0 = &_agiScreen[x1 + GFX_WIDTH * y1];
- w = x2 - x1 + 1;
- h = y2 - y1 + 1;
- while (h--) {
- memcpy(b, p0, w);
- b += w;
- p0 += GFX_WIDTH;
- }
-}
-
-/**
- * Restore a block of the AGI engine screen
- */
-void GfxMgr::restoreBlock(int x1, int y1, int x2, int y2, uint8 *b) {
- uint8 *p0;
- int w, h;
-
- p0 = &_agiScreen[x1 + GFX_WIDTH * y1];
- w = x2 - x1 + 1;
- h = y2 - y1 + 1;
- while (h--) {
- memcpy(p0, b, w);
- b += w;
- p0 += GFX_WIDTH;
- }
- flushBlock(x1, y1, x2, y2);
-}
+#endif
} // End of namespace Agi
diff --git a/engines/agi/graphics.h b/engines/agi/graphics.h
index 506a9d93d6..1cb595cdfa 100644
--- a/engines/agi/graphics.h
+++ b/engines/agi/graphics.h
@@ -27,73 +27,195 @@
namespace Agi {
-#define GFX_WIDTH 320
-#define GFX_HEIGHT 200
-#define CHAR_COLS 8
-#define CHAR_LINES 8
+#define SCRIPT_WIDTH 160
+#define SCRIPT_HEIGHT 168
+#define VISUAL_WIDTH 160
+#define VISUAL_HEIGHT 200
+#define DISPLAY_DEFAULT_WIDTH 320
+#define DISPLAY_DEFAULT_HEIGHT 200
+
+enum GfxScreenUpscaledMode {
+ DISPLAY_UPSCALED_DISABLED = 0,
+ DISPLAY_UPSCALED_640x400 = 1
+};
class AgiEngine;
+enum GfxScreenMasks {
+ GFX_SCREEN_MASK_VISUAL = 1,
+ GFX_SCREEN_MASK_PRIORITY = 2,
+ GFX_SCREEN_MASK_ALL = GFX_SCREEN_MASK_VISUAL | GFX_SCREEN_MASK_PRIORITY
+};
+
+struct MouseCursorData {
+ const byte *bitmapData;
+ byte *bitmapDataAllocated;
+ uint16 width;
+ uint16 height;
+ int hotspotX;
+ int hotspotY;
+};
+
class GfxMgr {
private:
AgiBase *_vm;
+ GfxFont *_font;
- uint8 _palette[256 * 3];
- uint8 *_agiScreen;
- unsigned char *_screen;
-
- uint8 *_shakeH, *_shakeV;
+ uint8 _paletteGfxMode[256 * 3];
+ uint8 _paletteTextMode[256 * 3];
uint8 _agipalPalette[16 * 3];
int _agipalFileNum;
- int _currentCursorPalette; // 0 - palette not set, 1 - PC, 2 - Amiga
-
-private:
- void rawDrawButton(int x, int y, const char *s, int fgcolor, int bgcolor, bool border, int textOffset);
public:
- GfxMgr(AgiBase *vm);
-
- void gfxPutBlock(int x1, int y1, int x2, int y2);
-
- void putTextCharacter(int, int, int, unsigned char, int, int, bool checkerboard = false, const uint8 *font = fontData_Sierra);
- void shakeScreen(int);
- void shakeStart();
- void shakeEnd();
- void saveScreen();
- void restoreScreen();
+ GfxMgr(AgiBase *vm, GfxFont *font);
int initVideo();
int deinitVideo();
- void scheduleUpdate(int, int, int, int);
- void doUpdate();
- void putScreen();
- void flushBlock(int, int, int, int);
- void flushBlockA(int, int, int, int);
- void putPixelsA(int, int, int, uint8 *);
- void flushScreen();
- void clearScreen(int);
- void clearConsoleScreen(int);
- void drawBox(int, int, int, int, int, int, int);
- void drawDefaultStyleButton(int, int, const char *, int, int, int fgcolor = 0, int bgcolor = 0);
- void drawCurrentStyleButton(int x, int y, const char *label, bool hasFocus, bool pressed = false, bool positive = true);
- int testButton(int, int, const char *);
- void drawRectangle(int, int, int, int, int);
- void saveBlock(int, int, int, int, uint8 *);
- void restoreBlock(int, int, int, int, uint8 *);
- void initPalette(const uint8 *p, uint colorCount = 16, uint fromBits = 6, uint toBits = 8);
+ void initPalette(uint8 *destPalette, const uint8 *paletteData, uint colorCount = 16, uint fromBits = 6, uint toBits = 8);
+ void initPaletteCLUT(uint8 *destPalette, const uint16 *paletteCLUTData, uint colorCount = 16);
void setAGIPal(int);
int getAGIPalFileNum();
- void drawFrame(int x1, int y1, int x2, int y2, int c1, int c2);
+ void setPalette(bool GfxModePalette);
- void putBlock(int x1, int y1, int x2, int y2);
- void gfxSetPalette();
- void setCursor(bool amigaStyleCursor = false, bool busy = false);
- void setCursorPalette(bool amigaStylePalette = false);
+ void initMouseCursor(MouseCursorData *mouseCursor, const byte *bitmapData, uint16 width, uint16 height, int hotspotX, int hotspotY);
+ void setMouseCursor(bool busy = false);
+
+ void setRenderStartOffset(uint16 offsetY);
+ uint16 getRenderStartDisplayOffsetY();
+
+ void translateGamePosToDisplayScreen(int16 &x, int16 &y);
+ void translateVisualPosToDisplayScreen(int16 &x, int16 &y);
+ void translateDisplayPosToGameScreen(int16 &x, int16 &y);
+
+ void translateVisualDimensionToDisplayScreen(int16 &width, int16 &height);
+ void translateDisplayDimensionToVisualScreen(int16 &width, int16 &height);
+
+ void translateGameRectToDisplayScreen(int16 &x, int16 &y, int16 &width, int16 &height);
+ void translateVisualRectToDisplayScreen(int16 &x, int16 &y, int16 &width, int16 &height);
+ void translateDisplayRectToVisualScreen(int16 &x, int16 &y, int16 &width, int16 &height);
+
+ uint32 getDisplayOffsetToGameScreenPos(int16 x, int16 y);
+ uint32 getDisplayOffsetToVisualScreenPos(int16 x, int16 y);
+
+ void copyDisplayRectToScreen(int16 x, int16 y, int16 width, int16 height);
+ void copyDisplayRectToScreen(int16 x, int16 adjX, int16 y, int16 adjY, int16 width, int16 adjWidth, int16 height, int16 adjHeight);
+ void copyDisplayRectToScreenUsingGamePos(int16 x, int16 y, int16 width, int16 height);
+ void copyDisplayRectToScreenUsingVisualPos(int16 x, int16 y, int16 width, int16 height);
+ void copyDisplayToScreen();
+
+ void translateFontPosToDisplayScreen(int16 &x, int16 &y);
+ void translateDisplayPosToFontScreen(int16 &x, int16 &y);
+ void translateFontDimensionToDisplayScreen(int16 &width, int16 &height);
+ void translateFontRectToDisplayScreen(int16 &x, int16 &y, int16 &width, int16 &height);
+ Common::Rect getFontRectForDisplayScreen(int16 column, int16 row, int16 width, int16 height);
+
+private:
+ uint _pixels;
+ uint _displayPixels;
- void printCharacter(int, int, char, int, int);
- int initMachine();
- int deinitMachine();
+ byte *_activeScreen;
+ byte *_gameScreen; // 160x168 - screen, where the actual game content is drawn to (actual graphics, not including status line, prompt, etc.)
+ byte *_priorityScreen; // 160x168 - screen contains priority information of the game screen
+ // the term "visual screen" is effectively the display screen, but at 160x200 resolution. Used for coordinate translation
+ byte *_displayScreen; // 320x200 or 640x400 - screen, that the game is rendered to and which is then copied to framebuffer
+
+ uint16 _displayScreenWidth;
+ uint16 _displayScreenHeight;
+
+ uint16 _displayFontWidth;
+ uint16 _displayFontHeight;
+
+ uint16 _displayWidthMulAdjust;
+ uint16 _displayHeightMulAdjust;
+
+ /**
+ * This variable defines, if upscaled hires is active and what upscaled mode
+ * is used.
+ */
+ GfxScreenUpscaledMode _upscaledHires;
+
+ bool _priorityTableSet;
+ uint8 _priorityTable[SCRIPT_HEIGHT]; /**< priority table */
+
+ MouseCursorData _mouseCursor;
+ MouseCursorData _mouseCursorBusy;
+
+ uint16 _renderStartVisualOffsetY;
+ uint16 _renderStartDisplayOffsetY;
+
+public:
+ uint16 getDisplayScreenWidth() {
+ return _displayScreenWidth;
+ }
+ uint16 getDisplayFontWidth() {
+ return _displayFontWidth;
+ }
+ uint16 getDisplayFontHeight() {
+ return _displayFontHeight;
+ }
+
+ GfxScreenUpscaledMode getUpscaledHires() {
+ return _upscaledHires;
+ }
+
+ void debugShowMap(int mapNr);
+
+ void clear(byte color, byte priority);
+ void clearDisplay(byte color, bool copyToScreen = true);
+ void putPixel(int16 x, int16 y, byte drawMask, byte color, byte priority);
+ void putPixelOnDisplay(int16 x, int16 y, byte color);
+ void putPixelOnDisplay(int16 x, int16 adjX, int16 y, int16 adjY, byte color);
+ void putFontPixelOnDisplay(int16 baseX, int16 baseY, int16 addX, int16 addY, byte color, bool isHires);
+
+ byte getColor(int16 x, int16 y);
+ byte getPriority(int16 x, int16 y);
+ bool checkControlPixel(int16 x, int16 y, byte newPriority);
+
+ byte getCGAMixtureColor(byte color);
+
+ void render_Block(int16 x, int16 y, int16 width, int16 height, bool copyToScreen = true);
+ bool render_Clip(int16 &x, int16 &y, int16 &width, int16 &height, int16 clipAgainstWidth = SCRIPT_WIDTH, int16 clipAgainstHeight = SCRIPT_HEIGHT);
+
+private:
+ void render_BlockEGA(int16 x, int16 y, int16 width, int16 height, bool copyToScreen);
+ void render_BlockCGA(int16 x, int16 y, int16 width, int16 height, bool copyToScreen);
+ void render_BlockHercules(int16 x, int16 y, int16 width, int16 height, bool copyToScreen);
+
+public:
+ void transition_Amiga();
+ void transition_AtariSt();
+
+ void block_save(int16 x, int16 y, int16 width, int16 height, byte *bufferPtr);
+ void block_restore(int16 x, int16 y, int16 width, int16 height, byte *bufferPtr);
+
+ void drawBox(int16 x, int16 y, int16 width, int16 height, byte backgroundColor, byte lineColor);
+ void drawDisplayRect(int16 x, int16 y, int16 width, int16 height, byte color, bool copyToScreen = true);
+ void drawDisplayRect(int16 x, int16 adjX, int16 y, int16 adjY, int16 width, int16 adjWidth, int16 height, int16 adjHeight, byte color, bool copyToScreen = true);
+private:
+ void drawDisplayRectEGA(int16 x, int16 y, int16 width, int16 height, byte color);
+ void drawDisplayRectCGA(int16 x, int16 y, int16 width, int16 height, byte color);
+
+public:
+ void drawCharacter(int16 row, int16 column, byte character, byte foreground, byte background, bool disabledLook);
+ void drawStringOnDisplay(int16 x, int16 y, const char *text, byte foreground, byte background);
+ void drawStringOnDisplay(int16 x, int16 adjX, int16 y, int16 adjY, const char *text, byte foregroundColor, byte backgroundColor);
+ void drawCharacterOnDisplay(int16 x, int16 y, byte character, byte foreground, byte background, byte transformXOR = 0, byte transformOR = 0);
+
+ void shakeScreen(int16 repeatCount);
+ void updateScreen();
+
+ void initPriorityTable();
+ void createDefaultPriorityTable(uint8 *priorityTable);
+ void setPriorityTable(int16 priorityBase);
+ bool saveLoadWasPriorityTableModified();
+ int16 saveLoadGetPriority(int16 yPos);
+ void saveLoadSetPriorityTableModifiedBool(bool wasModified);
+ void saveLoadSetPriority(int16 yPos, int16 priority);
+ void saveLoadFigureOutPriorityTableModifiedBool();
+
+ int16 priorityToY(int16 priority);
+ int16 priorityFromY(int16 yPos);
};
} // End of namespace Agi
diff --git a/engines/agi/id.cpp b/engines/agi/id.cpp
index c35ff36488..7985d3b9e4 100644
--- a/engines/agi/id.cpp
+++ b/engines/agi/id.cpp
@@ -42,7 +42,7 @@ int AgiEngine::setupV2Game(int ver) {
// Should this go above the previous lines, so we can force emulation versions
// even for AGDS games? -- dsymonds
if (getFeatures() & GF_AGDS)
- setVersion(ver = 0x2440); // ALL AGDS games built for 2.440
+ setVersion(ver = 0x2440); // ALL AGDS games built for 2.440
debug(0, "Setting up for version 0x%04X", ver);
diff --git a/engines/agi/inv.cpp b/engines/agi/inv.cpp
index f1e4e5094b..834fa9badc 100644
--- a/engines/agi/inv.cpp
+++ b/engines/agi/inv.cpp
@@ -22,221 +22,195 @@
#include "agi/agi.h"
#include "agi/graphics.h"
+#include "agi/inv.h"
+#include "agi/text.h"
#include "agi/keyboard.h"
+#include "agi/systemui.h"
namespace Agi {
-//
-// Messages and coordinates
-//
+InventoryMgr::InventoryMgr(AgiEngine *agi, GfxMgr *gfx, TextMgr *text, SystemUI *systemUI) {
+ _vm = agi;
+ _gfx = gfx;
+ _text = text;
+ _systemUI = systemUI;
-#define NOTHING_X 16
-#define NOTHING_Y 3
-#define NOTHING_MSG "nothing"
-
-#define ANY_KEY_X 4
-#define ANY_KEY_Y 24
-#define ANY_KEY_MSG "Press a key to return to the game"
-
-#define YOUHAVE_X 11
-#define YOUHAVE_Y 0
-#define YOUHAVE_MSG "You are carrying:"
+ _activeItemNr = -1;
+}
-#define SELECT_X 2
-#define SELECT_Y 24
-#define SELECT_MSG "Press ENTER to select, ESC to cancel"
+InventoryMgr::~InventoryMgr() {
+}
-#define NOTHING_X_RU 16
-#define NOTHING_Y_RU 3
-#define NOTHING_MSG_RU "\xad\xa8\xe7\xa5\xa3\xae"
+void InventoryMgr::getPlayerInventory() {
+ AgiGame game = _vm->_game;
+ int16 selectedInventoryItem = _vm->getVar(VM_VAR_SELECTED_INVENTORY_ITEM);
+ uint16 objectNr = 0;
+ int16 curRow = 2; // starting at position 2,1
+ int16 curColumn = 1;
+
+ _array.clear();
+ _activeItemNr = 0;
+
+ for (objectNr = 0; objectNr < game.numObjects; objectNr++) {
+ if (_vm->objectGetLocation(objectNr) == EGO_OWNED) {
+ // item is in the possession of ego, so add it to our internal list
+ if (objectNr == selectedInventoryItem) {
+ // it's the currently selected inventory item, remember that
+ _activeItemNr = _array.size();
+ }
-#define ANY_KEY_X_RU 4
-#define ANY_KEY_Y_RU 24
-#define ANY_KEY_MSG_RU "\x8b\xee\xa1\xa0\xef \xaa\xab\xa0\xa2\xa8\xe8\xa0 - \xa2\xae\xa7\xa2\xe0\xa0\xe2 \xa2 \xa8\xa3\xe0\xe3."
+ InventoryEntry inventoryEntry;
-#define YOUHAVE_X_RU 11
-#define YOUHAVE_Y_RU 0
-#define YOUHAVE_MSG_RU " \x93 \xa2\xa0\xe1 \xa5\xe1\xe2\xec: "
+ inventoryEntry.objectNr = objectNr;
+ inventoryEntry.name = _vm->objectName(objectNr);
+ inventoryEntry.row = curRow;
+ inventoryEntry.column = curColumn;
+ if (inventoryEntry.column > 1) {
+ // right side, adjust column accordingly
+ inventoryEntry.column -= strlen(inventoryEntry.name);
+ }
+ _array.push_back(inventoryEntry);
+
+ // go to next position
+ if (curColumn == 1) {
+ // current position is left side, go to right side
+ curColumn = 39;
+ } else {
+ // current position is right side, so go to left side again and new row
+ curColumn = 1;
+ curRow++;
+ }
+ }
+ }
-#define SELECT_X_RU 2
-#define SELECT_Y_RU 24
-#define SELECT_MSG_RU "ENTER - \xa2\xeb\xa1\xe0\xa0\xe2\xec, ESC - \xae\xe2\xac\xa5\xad\xa8\xe2\xec."
+ if (_array.size() == 0) {
+ // empty inventory
+ InventoryEntry inventoryEntry;
-void AgiEngine::printItem(int n, int fg, int bg) {
- printText(objectName(_intobj[n]), 0, ((n % 2) ? 39 - strlen(objectName(_intobj[n])) : 1),
- (n / 2) + 2, 40, fg, bg);
+ inventoryEntry.objectNr = 0;
+ inventoryEntry.name = _systemUI->getInventoryTextNothing();
+ inventoryEntry.row = 2;
+ inventoryEntry.column = 19 - (strlen(inventoryEntry.name) / 2);
+ _array.push_back(inventoryEntry);
+ }
}
-int AgiEngine::findItem() {
- int r, c;
+void InventoryMgr::drawAll() {
+ int16 inventoryCount = _array.size();
+ int16 inventoryNr = 0;
- r = _mouse.y / CHAR_LINES;
- c = _mouse.x / CHAR_COLS;
+ _text->charPos_Set(0, 11);
+ _text->displayText(_systemUI->getInventoryTextYouAreCarrying());
- debugC(6, kDebugLevelInventory, "r = %d, c = %d", r, c);
+ for (inventoryNr = 0; inventoryNr < inventoryCount; inventoryNr++) {
+ drawItem(inventoryNr);
+ }
+}
- if (r < 2)
- return -1;
+void InventoryMgr::drawItem(int16 itemNr) {
+ if (itemNr == _activeItemNr) {
+ _text->charAttrib_Set(15, 0);
+ } else {
+ _text->charAttrib_Set(0, 15);
+ }
- return (r - 2) * 2 + (c > 20);
+ _text->charPos_Set(_array[itemNr].row, _array[itemNr].column);
+ // original interpreter used printf here
+ // this doesn't really make sense, because for length calculation it's using strlen without printf
+ // which means right-aligned inventory items on the right side would not be displayed properly
+ // in case printf-formatting was actually used
+ // I have to assume that no game uses this, because behavior in original interpreter would have been buggy.
+ _text->displayText(_array[itemNr].name);
}
-int AgiEngine::showItems() {
- unsigned int x, i;
+void InventoryMgr::show() {
+ bool selectItems = false;
- for (x = i = 0; x < _game.numObjects; x++) {
- if (objectGetLocation(x) == EGO_OWNED) {
- // add object to our list!
- _intobj[i] = x;
- printItem(i, STATUS_FG, STATUS_BG);
- i++;
- }
+ // figure out current inventory of the player
+ getPlayerInventory();
+
+ if (_vm->getFlag(VM_FLAG_STATUS_SELECTS_ITEMS)) {
+ selectItems = true;
+ } else {
+ _activeItemNr = -1; // so that none is shown as active
}
- if (i == 0) {
- switch (getLanguage()) {
- case Common::RU_RUS:
- printText(NOTHING_MSG_RU, 0, NOTHING_X_RU, NOTHING_Y_RU, 40, STATUS_FG, STATUS_BG);
- break;
- default:
- printText(NOTHING_MSG, 0, NOTHING_X, NOTHING_Y, 40, STATUS_FG, STATUS_BG);
- break;
- }
+ drawAll();
+
+ _text->charAttrib_Set(0, 15);
+ if (selectItems) {
+ _text->charPos_Set(24, 2);
+ _text->displayText(_systemUI->getInventoryTextSelectItems());
+ } else {
+ _text->charPos_Set(24, 4);
+ _text->displayText(_systemUI->getInventoryTextReturnToGame());
}
- return i;
-}
+ if (selectItems) {
+ _vm->cycleInnerLoopActive(CYCLE_INNERLOOP_INVENTORY);
-void AgiEngine::selectItems(int n) {
- int fsel = 0;
- bool exit_select = false;
-
- while (!exit_select && !(shouldQuit() || _restartGame)) {
- if (n > 0)
- printItem(fsel, STATUS_BG, STATUS_FG);
-
- switch (waitAnyKey()) {
- case KEY_ENTER:
- setvar(vSelItem, _intobj[fsel]);
- exit_select = true;
- break;
- case KEY_ESCAPE:
- setvar(vSelItem, 0xff);
- exit_select = true;
- break;
- case KEY_UP:
- if (fsel >= 2)
- fsel -= 2;
- break;
- case KEY_DOWN:
- if (fsel + 2 < n)
- fsel += 2;
- break;
- case KEY_LEFT:
- if (fsel % 2 == 1)
- fsel--;
- break;
- case KEY_RIGHT:
- if (fsel % 2 == 0 && fsel + 1 < n)
- fsel++;
- break;
- case BUTTON_LEFT:{
- int i = findItem();
- if (i >= 0 && i < n) {
- setvar(vSelItem, _intobj[fsel = i]);
- debugC(6, kDebugLevelInventory, "item found: %d", fsel);
- showItems();
- printItem(fsel, STATUS_BG, STATUS_FG);
- _gfx->doUpdate();
- exit_select = true;
- }
- break;
- }
- default:
- break;
- }
+ do {
+ _vm->processAGIEvents();
+ } while (_vm->cycleInnerLoopIsActive() && !(_vm->shouldQuit() || _vm->_restartGame));
- if (!exit_select) {
- showItems();
- _gfx->doUpdate();
+ if (_activeItemNr >= 0) {
+ // pass selected object number
+ _vm->setVar(VM_VAR_SELECTED_INVENTORY_ITEM, _array[_activeItemNr].objectNr);
+ } else {
+ // nothing was selected
+ _vm->setVar(VM_VAR_SELECTED_INVENTORY_ITEM, 0xff);
}
- }
- debugC(6, kDebugLevelInventory, "selected: %d", fsel);
+ } else {
+ // no selection is supposed to be possible, just wait for key and exit
+ _vm->waitAnyKey();
+ }
}
-/*
- * Public functions
- */
-
-/**
- * Display inventory items.
- */
-void AgiEngine::inventory() {
- int oldFg, oldBg;
- int n;
-
- // screen is white with black text
- oldFg = _game.colorFg;
- oldBg = _game.colorBg;
- _game.colorFg = 0;
- _game.colorBg = 15;
- _gfx->clearScreen(_game.colorBg);
-
- switch (getLanguage()) {
- case Common::RU_RUS:
- printText(YOUHAVE_MSG_RU, 0, YOUHAVE_X_RU, YOUHAVE_Y_RU, 40, STATUS_FG, STATUS_BG);
- break;
- default:
- printText(YOUHAVE_MSG, 0, YOUHAVE_X, YOUHAVE_Y, 40, STATUS_FG, STATUS_BG);
+void InventoryMgr::keyPress(uint16 newKey) {
+ switch (newKey) {
+ case AGI_KEY_ENTER: {
+ _vm->cycleInnerLoopInactive(); // exit show-loop
break;
}
- // FIXME: doesn't check if objects overflow off screen...
-
- _intobj = (uint8 *)malloc(4 + _game.numObjects);
- memset(_intobj, 0, (4 + _game.numObjects));
-
- n = showItems();
+ case AGI_KEY_ESCAPE: {
+ _vm->cycleInnerLoopInactive(); // exit show-loop
+ _activeItemNr = -1; // no item selected
+ break;
+ }
- switch (getLanguage()) {
- case Common::RU_RUS:
- if (getflag(fStatusSelectsItems)) {
- printText(SELECT_MSG_RU, 0, SELECT_X_RU, SELECT_Y_RU, 40, STATUS_FG, STATUS_BG);
- } else {
- printText(ANY_KEY_MSG_RU, 0, ANY_KEY_X_RU, ANY_KEY_Y_RU, 40, STATUS_FG, STATUS_BG);
- }
+ case AGI_KEY_UP:
+ changeActiveItem(-2);
break;
+ case AGI_KEY_DOWN:
+ changeActiveItem(+2);
+ break;
+ case AGI_KEY_LEFT:
+ changeActiveItem(-1);
+ break;
+ case AGI_KEY_RIGHT:
+ changeActiveItem(+1);
+ break;
+
default:
- if (getflag(fStatusSelectsItems)) {
- printText(SELECT_MSG, 0, SELECT_X, SELECT_Y, 40, STATUS_FG, STATUS_BG);
- } else {
- printText(ANY_KEY_MSG, 0, ANY_KEY_X, ANY_KEY_Y, 40, STATUS_FG, STATUS_BG);
- }
break;
}
+}
- _gfx->flushScreen();
-
- // If flag 13 is set, we want to highlight & select an item.
- // opon selection, put objnum in var 25. Then on esc put in
- // var 25 = 0xff.
-
- if (getflag(fStatusSelectsItems))
- selectItems(n);
-
- free(_intobj);
+void InventoryMgr::changeActiveItem(int16 direction) {
+ int16 orgItemNr = _activeItemNr;
- if (!getflag(fStatusSelectsItems))
- waitAnyKey();
+ _activeItemNr += direction;
- _gfx->clearScreen(0);
- writeStatus();
- _picture->showPic();
- _game.colorFg = oldFg;
- _game.colorBg = oldBg;
- _game.hasPrompt = 0;
- flushLines(_game.lineUserInput, 24);
+ if ((_activeItemNr >= 0) && (_activeItemNr < (int16)_array.size())) {
+ // within bounds
+ drawItem(orgItemNr);
+ drawItem(_activeItemNr);
+ } else {
+ // out of bounds, revert change
+ _activeItemNr = orgItemNr;
+ }
}
} // End of namespace Agi
diff --git a/engines/agi/inv.h b/engines/agi/inv.h
new file mode 100644
index 0000000000..4cdb4900c6
--- /dev/null
+++ b/engines/agi/inv.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 AGI_INV_H
+#define AGI_INV_H
+
+namespace Agi {
+
+struct InventoryEntry {
+ uint16 objectNr;
+ int16 row;
+ int16 column;
+ const char *name;
+};
+typedef Common::Array<InventoryEntry> InventoryArray;
+
+class InventoryMgr {
+private:
+ GfxMgr *_gfx;
+ TextMgr *_text;
+ AgiEngine *_vm;
+ SystemUI *_systemUI;
+
+ InventoryArray _array;
+ int16 _activeItemNr;
+
+public:
+ InventoryMgr(AgiEngine *agi, GfxMgr *gfx, TextMgr *text, SystemUI *systemUI);
+ ~InventoryMgr();
+
+ void getPlayerInventory();
+ void drawAll();
+ void drawItem(int16 itemNr);
+ void show();
+
+ void keyPress(uint16 newKey);
+ void changeActiveItem(int16 direction);
+};
+
+} // End of namespace Agi
+
+#endif /* AGI_INV_H */
diff --git a/engines/agi/keyboard.cpp b/engines/agi/keyboard.cpp
index 0aa521bdc8..7ed67949b5 100644
--- a/engines/agi/keyboard.cpp
+++ b/engines/agi/keyboard.cpp
@@ -20,12 +20,14 @@
*
*/
+#include "common/events.h"
+#include "gui/predictivedialog.h"
+
#include "agi/agi.h"
#include "agi/graphics.h"
#include "agi/keyboard.h"
-#ifdef __DS__
-#include "wordcompletion.h"
-#endif
+#include "agi/menu.h"
+#include "agi/text.h"
namespace Agi {
@@ -33,49 +35,257 @@ namespace Agi {
// IBM-PC keyboard scancodes
//
const uint8 scancodeTable[26] = {
- 30, // A
- 48, // B
- 46, // C
- 32, // D
- 18, // E
- 33, // F
- 34, // G
- 35, // H
- 23, // I
- 36, // J
- 37, // K
- 38, // L
- 50, // M
- 49, // N
- 24, // O
- 25, // P
- 16, // Q
- 19, // R
- 31, // S
- 20, // T
- 22, // U
- 47, // V
- 17, // W
- 45, // X
- 21, // Y
- 44 // Z
+ 30, // A
+ 48, // B
+ 46, // C
+ 32, // D
+ 18, // E
+ 33, // F
+ 34, // G
+ 35, // H
+ 23, // I
+ 36, // J
+ 37, // K
+ 38, // L
+ 50, // M
+ 49, // N
+ 24, // O
+ 25, // P
+ 16, // Q
+ 19, // R
+ 31, // S
+ 20, // T
+ 22, // U
+ 47, // V
+ 17, // W
+ 45, // X
+ 21, // Y
+ 44 // Z
};
-void AgiEngine::initWords() {
- _game.numEgoWords = 0;
-}
+void AgiEngine::processScummVMEvents() {
+ Common::Event event;
+ int key = 0;
-void AgiEngine::cleanInput() {
- while (_game.numEgoWords)
- free(_game.egoWords[--_game.numEgoWords].word);
-}
+ while (_eventMan->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_PREDICTIVE_DIALOG:
+ showPredictiveDialog();
+ break;
+ case Common::EVENT_LBUTTONDOWN:
+ if (_game.mouseEnabled) {
+ key = AGI_MOUSE_BUTTON_LEFT;
+ _mouse.button = kAgiMouseButtonLeft;
+ keyEnqueue(key);
+ _mouse.pos.x = event.mouse.x;
+ _mouse.pos.y = event.mouse.y;
+ }
+ break;
+ case Common::EVENT_RBUTTONDOWN:
+ if (_game.mouseEnabled) {
+ key = AGI_MOUSE_BUTTON_RIGHT;
+ _mouse.button = kAgiMouseButtonRight;
+ keyEnqueue(key);
+ _mouse.pos.x = event.mouse.x;
+ _mouse.pos.y = event.mouse.y;
+ }
+ break;
+ case Common::EVENT_WHEELUP:
+ if (_game.mouseEnabled) {
+ key = AGI_MOUSE_WHEEL_UP;
+ keyEnqueue(key);
+ }
+ break;
+ case Common::EVENT_WHEELDOWN:
+ if (_game.mouseEnabled) {
+ key = AGI_MOUSE_WHEEL_DOWN;
+ keyEnqueue(key);
+ }
+ break;
+ case Common::EVENT_MOUSEMOVE:
+ if (_game.mouseEnabled) {
+ _mouse.pos.x = event.mouse.x;
+ _mouse.pos.y = event.mouse.y;
+
+ if (!_game.mouseFence.isEmpty()) {
+ if (_mouse.pos.x < _game.mouseFence.left)
+ _mouse.pos.x = _game.mouseFence.left;
+ if (_mouse.pos.x > _game.mouseFence.right)
+ _mouse.pos.x = _game.mouseFence.right;
+ if (_mouse.pos.y < _game.mouseFence.top)
+ _mouse.pos.y = _game.mouseFence.top;
+ if (_mouse.pos.y > _game.mouseFence.bottom)
+ _mouse.pos.y = _game.mouseFence.bottom;
+
+ g_system->warpMouse(_mouse.pos.x, _mouse.pos.y);
+ }
+ }
+
+ break;
+ case Common::EVENT_LBUTTONUP:
+ case Common::EVENT_RBUTTONUP:
+ if (_game.mouseEnabled) {
+ _mouse.button = kAgiMouseButtonUp;
+ _mouse.pos.x = event.mouse.x;
+ _mouse.pos.y = event.mouse.y;
+ }
+ break;
+ case Common::EVENT_KEYDOWN:
+ if (event.kbd.hasFlags(Common::KBD_CTRL | Common::KBD_SHIFT) && event.kbd.keycode == Common::KEYCODE_d) {
+ _console->attach();
+ break;
+ }
+
+ key = event.kbd.ascii;
+ if (event.kbd.keycode >= Common::KEYCODE_KP0 && event.kbd.keycode <= Common::KEYCODE_KP9) {
+ if (!(event.kbd.flags & Common::KBD_NUM)) {
+ // HACK: Num-Lock not enabled
+ // We shouldn't get a valid ascii code in these cases. We fix it here, so that cursor keys
+ // on the numpad work properly.
+ key = 0;
+ }
+ }
-void AgiEngine::getString(int x, int y, int len, int str) {
- newInputMode(INPUT_GETSTRING);
- _stringdata.x = x;
- _stringdata.y = y;
- _stringdata.len = len;
- _stringdata.str = str;
+ if ((key) && (key <= 0xFF)) {
+ // No special key, directly accept it
+ // Is ISO-8859-1, we need lower 128 characters only, which is plain ASCII, so no mapping required
+ if (Common::isAlpha(key)) {
+ // Key is A-Z.
+ // Map Ctrl-A to 1, Ctrl-B to 2, etc.
+ if (event.kbd.flags & Common::KBD_CTRL) {
+ key = toupper(key) - 'A' + 1;
+ } else if (event.kbd.flags & Common::KBD_ALT) {
+ // Map Alt-A, Alt-B etc. to special scancode values according to an internal scancode table.
+ key = scancodeTable[toupper(key) - 'A'] << 8;
+ }
+ }
+ } else {
+ key = 0;
+ switch (event.kbd.keycode) {
+ case Common::KEYCODE_LEFT:
+ case Common::KEYCODE_KP4:
+ if (_allowSynthetic || !event.synthetic)
+ key = AGI_KEY_LEFT;
+ break;
+ case Common::KEYCODE_RIGHT:
+ case Common::KEYCODE_KP6:
+ if (_allowSynthetic || !event.synthetic)
+ key = AGI_KEY_RIGHT;
+ break;
+ case Common::KEYCODE_UP:
+ case Common::KEYCODE_KP8:
+ if (_allowSynthetic || !event.synthetic)
+ key = AGI_KEY_UP;
+ break;
+ case Common::KEYCODE_DOWN:
+ case Common::KEYCODE_KP2:
+ if (_allowSynthetic || !event.synthetic)
+ key = AGI_KEY_DOWN;
+ break;
+ case Common::KEYCODE_PAGEUP:
+ case Common::KEYCODE_KP9:
+ if (_allowSynthetic || !event.synthetic)
+ key = AGI_KEY_UP_RIGHT;
+ break;
+ case Common::KEYCODE_PAGEDOWN:
+ case Common::KEYCODE_KP3:
+ if (_allowSynthetic || !event.synthetic)
+ key = AGI_KEY_DOWN_RIGHT;
+ break;
+ case Common::KEYCODE_HOME:
+ case Common::KEYCODE_KP7:
+ if (_allowSynthetic || !event.synthetic)
+ key = AGI_KEY_UP_LEFT;
+ break;
+ case Common::KEYCODE_END:
+ case Common::KEYCODE_KP1:
+ if (_allowSynthetic || !event.synthetic)
+ key = AGI_KEY_DOWN_LEFT;
+ break;
+ case Common::KEYCODE_KP5:
+ key = AGI_KEY_STATIONARY;
+ break;
+ case Common::KEYCODE_F1:
+ key = AGI_KEY_F1;
+ break;
+ case Common::KEYCODE_F2:
+ key = AGI_KEY_F2;
+ break;
+ case Common::KEYCODE_F3:
+ key = AGI_KEY_F3;
+ break;
+ case Common::KEYCODE_F4:
+ key = AGI_KEY_F4;
+ break;
+ case Common::KEYCODE_F5:
+ key = AGI_KEY_F5;
+ break;
+ case Common::KEYCODE_F6:
+ key = AGI_KEY_F6;
+ break;
+ case Common::KEYCODE_F7:
+ key = AGI_KEY_F7;
+ break;
+ case Common::KEYCODE_F8:
+ key = AGI_KEY_F8;
+ break;
+ case Common::KEYCODE_F9:
+ key = AGI_KEY_F9;
+ break;
+ case Common::KEYCODE_F10:
+ key = AGI_KEY_F10;
+ break;
+ case Common::KEYCODE_F11:
+ key = AGI_KEY_F11;
+ break;
+ case Common::KEYCODE_F12:
+ key = AGI_KEY_F12;
+ break;
+ case Common::KEYCODE_KP_ENTER:
+ key = AGI_KEY_ENTER;
+ break;
+ default:
+ break;
+ }
+ }
+ if (key)
+ keyEnqueue(key);
+ break;
+
+ case Common::EVENT_KEYUP:
+ if (_keyHoldMode) {
+ // Original AGI actually created direction events in here
+ // We don't do that, that's why we create a stationary event instead, which will
+ // result in a direction change to 0 in handleController().
+ switch (event.kbd.keycode) {
+ case Common::KEYCODE_LEFT:
+ case Common::KEYCODE_RIGHT:
+ case Common::KEYCODE_UP:
+ case Common::KEYCODE_DOWN:
+ case Common::KEYCODE_HOME:
+ case Common::KEYCODE_END:
+ case Common::KEYCODE_PAGEUP:
+ case Common::KEYCODE_PAGEDOWN:
+ case Common::KEYCODE_KP4:
+ case Common::KEYCODE_KP6:
+ case Common::KEYCODE_KP8:
+ case Common::KEYCODE_KP2:
+ case Common::KEYCODE_KP9:
+ case Common::KEYCODE_KP3:
+ case Common::KEYCODE_KP7:
+ case Common::KEYCODE_KP1:
+ keyEnqueue(AGI_KEY_STATIONARY);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
}
/**
@@ -97,308 +307,259 @@ int AgiEngine::doPollKeyboard() {
return key;
}
-int AgiEngine::handleController(int key) {
- VtEntry *v = &_game.viewTable[0];
- int i;
-
- // AGI 3.149 games, The Black Cauldron and King's Quest 4 need KEY_ESCAPE to use menus
- // Games with the GF_ESCPAUSE flag need KEY_ESCAPE to pause the game
- if (key == 0 ||
- (key == KEY_ESCAPE && getVersion() != 0x3149 && getGameID() != GID_BC && getGameID() != GID_KQ4 && !(getFeatures() & GF_ESCPAUSE)) )
+bool AgiEngine::handleMouseClicks(uint16 &key) {
+ // No mouse click? -> exit
+ if (key != AGI_MOUSE_BUTTON_LEFT)
return false;
- if ((getGameID() == GID_MH1 || getGameID() == GID_MH2) && (key == KEY_ENTER) &&
- (_game.inputMode == INPUT_NONE)) {
- key = 0x20; // Set Enter key to Space in Manhunter when there's no text input
- }
-
- debugC(3, kDebugLevelInput, "key = %04x", key);
-
- for (i = 0; i < MAX_CONTROLLERS; i++) {
- if (_game.controllers[i].keycode == key) {
- debugC(3, kDebugLevelInput, "event %d: key press", _game.controllers[i].controller);
- _game.controllerOccured[_game.controllers[i].controller] = true;
- return true;
- }
- }
-
- if (key == BUTTON_LEFT) {
- if ((getflag(fMenusWork) || (getFeatures() & GF_MENUS)) && _mouse.y <= CHAR_LINES) {
- newInputMode(INPUT_MENU);
- return true;
- }
- }
-
- // Show predictive dialog if the user clicks on input area
- if (key == BUTTON_LEFT &&
- (int)_mouse.y >= _game.lineUserInput * CHAR_LINES &&
- (int)_mouse.y <= (_game.lineUserInput + 1) * CHAR_LINES) {
- GUI::PredictiveDialog _predictiveDialog;
- _predictiveDialog.runModal();
- strcpy(_predictiveResult, _predictiveDialog.getResult());
- if (strcmp(_predictiveResult, "")) {
- if (_game.inputMode == INPUT_NONE) {
- for (int n = 0; _predictiveResult[n]; n++)
- keyEnqueue(_predictiveResult[n]);
- } else {
- strcpy((char *)_game.inputBuffer, _predictiveResult);
- handleKeys(KEY_ENTER);
+ if (!cycleInnerLoopIsActive()) {
+ // Only do this, when no inner loop is currently active
+ Common::Rect displayLineRect = _gfx->getFontRectForDisplayScreen(0, 0, FONT_COLUMN_CHARACTERS, 1);
+// Common::Rect displayLineRect(_gfx->getDisplayScreenWidth(), _gfx->getDisplayFontHeight());
+
+ if (displayLineRect.contains(_mouse.pos)) {
+ // Mouse is inside first line of the screen
+ if (getFlag(VM_FLAG_MENUS_ACCESSIBLE) && _menu->isAvailable()) {
+ _menu->delayedExecuteViaMouse();
+ key = 0; // eat event
+ return true;
}
}
- /*
- if (predictiveDialog()) {
- if (_game.inputMode == INPUT_NONE) {
- for (int n = 0; _predictiveResult[n]; n++)
- keyEnqueue(_predictiveResult[n]);
- } else {
- strcpy((char *)_game.inputBuffer, _predictiveResult);
- handleKeys(KEY_ENTER);
- }
- }
- */
- return true;
- }
- if (_game.playerControl) {
- int d = 0;
+ if (_text->promptIsEnabled()) {
+ // Prompt is currently enabled
+ int16 promptRow = _text->promptRow_Get();
- if (!KEY_ASCII(key)) {
- switch (key) {
- case KEY_UP:
- d = 1;
- break;
- case KEY_DOWN:
- d = 5;
- break;
- case KEY_LEFT:
- d = 7;
- break;
- case KEY_RIGHT:
- d = 3;
- break;
- case KEY_UP_RIGHT:
- d = 2;
- break;
- case KEY_DOWN_RIGHT:
- d = 4;
- break;
- case KEY_UP_LEFT:
- d = 8;
- break;
- case KEY_DOWN_LEFT:
- d = 6;
- break;
- }
- }
+ displayLineRect.moveTo(0, promptRow * _gfx->getDisplayFontHeight());
- if (!(getFeatures() & GF_AGIMOUSE)) {
- // Handle mouse button events
- if (key == BUTTON_LEFT) {
- if (getGameID() == GID_PQ1 && _game.vars[vCurRoom] == 116) {
- // WORKAROUND: Special handling for mouse clicks in the newspaper
- // screen of PQ1. Fixes bug #3018770.
- d = 3; // fake a right arrow key (next page)
- } else {
- // Click-to-walk mouse interface
- v->flags |= fAdjEgoXY;
- v->parm1 = WIN_TO_PIC_X(_mouse.x);
- v->parm2 = WIN_TO_PIC_Y(_mouse.y);
- return true;
- }
- }
- }
+ if (displayLineRect.contains(_mouse.pos)) {
+ // and user clicked within the line of the prompt
+ showPredictiveDialog();
- if (d || key == KEY_STATIONARY) {
- v->flags &= ~fAdjEgoXY;
- v->direction = v->direction == d ? 0 : d;
- return true;
+ key = 0; // eat event
+ return true;
+ }
}
}
- return false;
-}
+ if (cycleInnerLoopIsActive()) {
+ // inner loop active, check what kind of loop it is. Then process / forward it
+ switch (_game.cycleInnerLoopType) {
+ case CYCLE_INNERLOOP_GETSTRING:
+ case CYCLE_INNERLOOP_GETNUMBER: {
+ // process in here
+ int16 stringRow, stringColumn, stringMaxLen;
-void AgiEngine::handleGetstring(int key) {
- static int pos = 0; // Cursor position
- static char buf[40];
+ _text->stringPos_Get(stringRow, stringColumn);
+ stringMaxLen = _text->stringGetMaxLen();
- if (KEY_ASCII(key) == 0)
- return;
+ Common::Rect displayRect = _gfx->getFontRectForDisplayScreen(stringColumn, stringRow, stringMaxLen, 1);
+ if (displayRect.contains(_mouse.pos)) {
+ // user clicked inside the input space
+ showPredictiveDialog();
- debugC(3, kDebugLevelInput, "handling key: %02x", key);
-
- switch (key) {
- case BUTTON_LEFT:
- if ((int)_mouse.y >= _stringdata.y * CHAR_LINES &&
- (int)_mouse.y <= (_stringdata.y + 1) * CHAR_LINES) {
- GUI::PredictiveDialog _predictiveDialog;
- _predictiveDialog.runModal();
- strcpy(_predictiveResult, _predictiveDialog.getResult());
- if (strcmp(_predictiveResult, "")) {
- strcpy(_game.strings[_stringdata.str], _predictiveResult);
- newInputMode(INPUT_NORMAL);
- _gfx->printCharacter(_stringdata.x + strlen(_game.strings[_stringdata.str]) + 1,
- _stringdata.y, ' ', _game.colorFg, _game.colorBg);
- return;
+ key = 0; // eat event
+ return true;
}
- /*
- if (predictiveDialog()) {
- strcpy(_game.strings[_stringdata.str], _predictiveResult);
- newInputMode(INPUT_NORMAL);
- _gfx->printCharacter(_stringdata.x + strlen(_game.strings[_stringdata.str]) + 1,
- _stringdata.y, ' ', _game.colorFg, _game.colorBg);
- return;
- }
- */
+ break;
}
- break;
- case KEY_ENTER:
- debugC(3, kDebugLevelInput, "KEY_ENTER");
- _game.hasPrompt = 0;
- buf[pos] = 0;
-
- strcpy(_game.strings[_stringdata.str], buf);
- debugC(3, kDebugLevelInput, "buffer=[%s]", buf);
- buf[pos = 0] = 0;
-
- newInputMode(INPUT_NORMAL);
- _gfx->printCharacter(_stringdata.x + strlen(_game.strings[_stringdata.str]) + 1,
- _stringdata.y, ' ', _game.colorFg, _game.colorBg);
- return;
- case KEY_ESCAPE:
- debugC(3, kDebugLevelInput, "KEY_ESCAPE");
- _game.hasPrompt = 0;
- buf[pos = 0] = 0;
-
- strcpy(_game.strings[_stringdata.str], buf);
- newInputMode(INPUT_NORMAL);
-
- // newInputMode(INPUT_MENU);
- break;
- case KEY_BACKSPACE: // 0x08
- if (!pos)
+ case CYCLE_INNERLOOP_INVENTORY:
+ // TODO: forward
break;
- _gfx->printCharacter(_stringdata.x + (pos + 1), _stringdata.y,
- ' ', _game.colorFg, _game.colorBg);
- pos--;
- buf[pos] = 0;
- break;
- default:
- if (key < 0x20 || key > 0x7f)
+ case CYCLE_INNERLOOP_MENU_VIA_KEYBOARD:
+ _menu->mouseEvent(key);
+ key = 0; // eat event
break;
- if (pos >= _stringdata.len)
+ case CYCLE_INNERLOOP_SYSTEMUI_SELECTSAVEDGAMESLOT:
+ // TODO: forward
break;
- buf[pos++] = key;
- buf[pos] = 0;
-
- // Echo
- _gfx->printCharacter(_stringdata.x + pos, _stringdata.y, buf[pos - 1],
- _game.colorFg, _game.colorBg);
-
- break;
+ default:
+ break;
+ }
}
-
- // print cursor
- _gfx->printCharacter(_stringdata.x + pos + 1, _stringdata.y,
- (char)_game.cursorChar, _game.colorFg, _game.colorBg);
+ return false;
}
-void AgiEngine::handleKeys(int key) {
- uint8 *p = NULL;
- int c = 0;
- static uint8 formattedEntry[40];
- int l = _game.lineUserInput;
- int fg = _game.colorFg, bg = _game.colorBg;
- int promptLength = strlen(agiSprintf(_game.strings[0]));
-
- setvar(vWordNotFound, 0);
+bool AgiEngine::handleController(uint16 key) {
+ ScreenObjEntry *screenObjEgo = &_game.screenObjTable[SCREENOBJECTS_EGO_ENTRY];
- debugC(3, kDebugLevelInput, "handling key: %02x", key);
+ if (key == 0) // nothing pressed
+ return false;
- switch (key) {
- case KEY_ENTER:
- debugC(3, kDebugLevelInput, "KEY_ENTER");
- _game.keypress = 0;
-
- // Remove all leading spaces
- for (p = _game.inputBuffer; *p && *p == 0x20; p++)
- ;
-
- // Copy to internal buffer
- for (; *p && c < 40-1; p++) {
- // Squash spaces
- if (*p == 0x20 && *(p + 1) == 0x20) {
- p++;
- continue;
+ // This previously skipped processing, when ESC was pressed and called menu directly.
+ // This original approach was bad, because games check different flags before actually allowing the
+ // user to enter the menu. We checked a few common flags, like for example the availability of the prompt.
+ // But this stopped the user being able to enter the menu, when the original interpreter actually allowed it.
+ // We now instead implement this feature using another way for those platforms.
+ if (key == AGI_KEY_ESCAPE) {
+ // Escape pressed, user probably wants to trigger the menu
+ // For PC, just passing ASCII code for ESC will normally trigger a controller
+ // and the scripts will then trigger the menu
+ switch (getPlatform()) {
+ case Common::kPlatformAmiga:
+ case Common::kPlatformApple2GS:
+ case Common::kPlatformAtariST:
+ // For these platforms, the button ESC normally triggered "pause"
+ // But users could at the same time trigger the menu by clicking on the status line
+ // We check, if menu is currently available and supposed to be accessible.
+ // If yes, we do a delayed trigger now, otherwise we continue processing the key just like normal.
+ //
+ // This is probably the solution with the highest compatibility.
+ // Several games also look for special keys see AGI_MENU_TRIGGER_*
+ // And then there's also Mixed Up Mother Goose, which actually hooks the ESC key for the regular menu
+ //
+ // We risk in here of course, that we let the user access the menu, when it shouldn't be possible.
+ // I'm not 100% sure if those other interpreters really only check VM_FLAG_MENUS_ACCESSIBLE
+ // Needs further investigation.
+ if (getFlag(VM_FLAG_MENUS_ACCESSIBLE) && _menu->isAvailable()) {
+ // menu is supposed to be accessible and is also available
+ _menu->delayedExecuteViaKeyboard();
+ return true;
}
- formattedEntry[c++] = tolower(*p);
+ default:
+ break;
}
- formattedEntry[c++] = 0;
+ // Otherwise go on and look for the ESC controller
+ }
- // Handle string only if it's not empty
- if (formattedEntry[0]) {
- strcpy((char *)_game.echoBuffer, (const char *)_game.inputBuffer);
- strcpy(_lastSentence, (const char *)formattedEntry);
- dictionaryWords(_lastSentence);
- }
+ // AGI 3.149 games, The Black Cauldron and King's Quest 4 need KEY_ESCAPE to use menus
+ // Games with the GF_ESCPAUSE flag need KEY_ESCAPE to pause the game
+ // (key == KEY_ESCAPE && getVersion() != 0x3149 && getGameID() != GID_BC && getGameID() != GID_KQ4 && !(getFeatures() & GF_ESCPAUSE)) )
+ // return false;
- // Clear to start a new line
- _game.hasPrompt = 0;
- _game.inputBuffer[_game.cursorPos = 0] = 0;
- debugC(3, kDebugLevelInput | kDebugLevelText, "clear lines");
- clearLines(l, l + 1, bg);
- flushLines(l, l + 1);
-#ifdef __DS__
- DS::findWordCompletions((char *) _game.inputBuffer);
-#endif
+ if ((getGameID() == GID_MH1 || getGameID() == GID_MH2) && (key == AGI_KEY_ENTER) &&
+ (!_text->promptIsEnabled())) {
+ key = 0x20; // Set Enter key to Space in Manhunter when prompt is disabled
+ }
- break;
- case KEY_ESCAPE:
- debugC(3, kDebugLevelInput, "KEY_ESCAPE");
- newInputMode(INPUT_MENU);
- break;
- case KEY_BACKSPACE:
- // Ignore backspace at start of line
- if (_game.cursorPos == 0)
- break;
+ debugC(3, kDebugLevelInput, "key = %04x", key);
- // erase cursor
- _gfx->printCharacter(_game.cursorPos + promptLength, l, ' ', fg, bg);
- _game.inputBuffer[--_game.cursorPos] = 0;
+ for (uint16 curMapping = 0; curMapping < MAX_CONTROLLER_KEYMAPPINGS; curMapping++) {
+ if (_game.controllerKeyMapping[curMapping].keycode == key) {
+ debugC(3, kDebugLevelInput, "event %d: key press", _game.controllerKeyMapping[curMapping].controllerSlot);
+ _game.controllerOccured[_game.controllerKeyMapping[curMapping].controllerSlot] = true;
+ return true;
+ }
+ }
- // Print cursor
- _gfx->printCharacter(_game.cursorPos + promptLength, l, _game.cursorChar, fg, bg);
+ int16 newDirection = 0;
-#ifdef __DS__
- DS::findWordCompletions((char *) _game.inputBuffer);
-#endif
+ switch (key) {
+ case AGI_KEY_UP:
+ newDirection = 1;
+ break;
+ case AGI_KEY_DOWN:
+ newDirection = 5;
+ break;
+ case AGI_KEY_LEFT:
+ newDirection = 7;
+ break;
+ case AGI_KEY_RIGHT:
+ newDirection = 3;
+ break;
+ case AGI_KEY_UP_RIGHT:
+ newDirection = 2;
+ break;
+ case AGI_KEY_DOWN_RIGHT:
+ newDirection = 4;
+ break;
+ case AGI_KEY_UP_LEFT:
+ newDirection = 8;
+ break;
+ case AGI_KEY_DOWN_LEFT:
+ newDirection = 6;
break;
default:
- // Ignore invalid keystrokes
- if (key < 0x20 || key > 0x7f)
- break;
+ break;
+ }
- // Maximum input size reached
- if (_game.cursorPos >= getvar(vMaxInputChars))
- break;
+ if (_game.playerControl) {
+ if (!(getFeatures() & GF_AGIMOUSE)) {
+ // Handle mouse button events
+ if (!_game.mouseHidden) {
+ if (key == AGI_MOUSE_BUTTON_LEFT) {
+ if (getGameID() == GID_PQ1 && getVar(VM_VAR_CURRENT_ROOM) == 116) {
+ // WORKAROUND: Special handling for mouse clicks in the newspaper
+ // screen of PQ1. Fixes bug #3018770.
+ newDirection = 3; // fake a right arrow key (next page)
+
+ } else {
+ // Click-to-walk mouse interface
+ //v->flags |= fAdjEgoXY;
+ // setting fAdjEgoXY here will at least break "climbing the log" in SQ2
+ // in case you walked to the log by using the mouse, so don't!!!
+ int16 egoDestinationX = _mouse.pos.x;
+ int16 egoDestinationY = _mouse.pos.y;
+ _gfx->translateDisplayPosToGameScreen(egoDestinationX, egoDestinationY);
+
+ screenObjEgo->motionType = kMotionEgo;
+ if (egoDestinationX < (screenObjEgo->xSize / 2)) {
+ screenObjEgo->move_x = -1;
+ } else {
+ screenObjEgo->move_x = egoDestinationX - (screenObjEgo->xSize / 2);
+ }
+ screenObjEgo->move_y = egoDestinationY;
+ screenObjEgo->move_stepSize = screenObjEgo->stepSize;
+ return true;
+ }
+ }
+ }
+ }
+ }
- _game.inputBuffer[_game.cursorPos++] = key;
- _game.inputBuffer[_game.cursorPos] = 0;
+ if (newDirection || key == AGI_KEY_STATIONARY) {
+ // TODO: not sure, what original AGI did with AdjEgoXY
+ screenObjEgo->flags &= ~fAdjEgoXY;
+ if (screenObjEgo->direction == newDirection) {
+ setVar(VM_VAR_EGO_DIRECTION, 0);
+ } else {
+ setVar(VM_VAR_EGO_DIRECTION, newDirection);
+ }
+ if (_game.playerControl) {
+ screenObjEgo->motionType = kMotionNormal;
+ }
+ return true;
+ }
-#ifdef __DS__
- DS::findWordCompletions((char *) _game.inputBuffer);
-#endif
+ return false;
+}
- // echo
- _gfx->printCharacter(_game.cursorPos + promptLength - 1, l, _game.inputBuffer[_game.cursorPos - 1], fg, bg);
+bool AgiEngine::showPredictiveDialog() {
+ GUI::PredictiveDialog predictiveDialog;
- // Print cursor
- _gfx->printCharacter(_game.cursorPos + promptLength, l, _game.cursorChar, fg, bg);
- break;
+ inGameTimerPause();
+ predictiveDialog.runModal();
+ inGameTimerResume();
+
+ Common::String predictiveResult(predictiveDialog.getResult());
+ uint16 predictiveResultLen = predictiveResult.size();
+ if (predictiveResult.size()) {
+ // User actually entered something
+ for (int16 resultPos = 0; resultPos < predictiveResultLen; resultPos++) {
+ keyEnqueue(predictiveResult[resultPos]);
+ }
+ if (!cycleInnerLoopIsActive()) {
+ if (_text->promptIsEnabled()) {
+ // add ENTER, when the input is probably meant for the prompt
+ keyEnqueue(AGI_KEY_ENTER);
+ }
+ } else {
+ switch (_game.cycleInnerLoopType) {
+ case CYCLE_INNERLOOP_GETSTRING:
+ case CYCLE_INNERLOOP_GETNUMBER:
+ // add ENTER, when the input is probably meant for GetString/GetNumber
+ keyEnqueue(AGI_KEY_ENTER);
+ break;
+ default:
+ break;
+ }
+ }
+ return true;
}
+ return false;
}
int AgiEngine::waitKey() {
@@ -407,22 +568,12 @@ int AgiEngine::waitKey() {
clearKeyQueue();
debugC(3, kDebugLevelInput, "waiting...");
- while (!(shouldQuit() || _restartGame || getflag(fRestoreJustRan))) {
- pollTimer();
+ while (!(shouldQuit() || _restartGame || getFlag(VM_FLAG_RESTORE_JUST_RAN))) {
+ wait(10);
key = doPollKeyboard();
- if (key == KEY_ENTER || key == KEY_ESCAPE || key == BUTTON_LEFT)
+ if (key == AGI_KEY_ENTER || key == AGI_KEY_ESCAPE || key == AGI_MOUSE_BUTTON_LEFT)
break;
-
- pollTimer();
- updateTimer();
-
- _gfx->doUpdate();
}
-
- // Have to clear it as original did not set this variable, and we do it in doPollKeyboard()
- // Fixes bug #2823759
- _game.keypress = 0;
-
return key;
}
@@ -433,29 +584,24 @@ int AgiEngine::waitAnyKey() {
debugC(3, kDebugLevelInput, "waiting... (any key)");
while (!(shouldQuit() || _restartGame)) {
- pollTimer();
+ wait(10);
key = doPollKeyboard();
if (key)
break;
- _gfx->doUpdate();
}
-
- // Have to clear it as original did not set this variable, and we do it in doPollKeyboard()
- _game.keypress = 0;
-
return key;
}
bool AgiEngine::isKeypress() {
- processEvents();
+ processScummVMEvents();
return _keyQueueStart != _keyQueueEnd;
}
int AgiEngine::getKeypress() {
int k;
- while (_keyQueueStart == _keyQueueEnd) // block
- pollTimer();
+ while (_keyQueueStart == _keyQueueEnd) // block
+ wait(10);
keyDequeue(k);
diff --git a/engines/agi/keyboard.h b/engines/agi/keyboard.h
index 89d6a89ce3..84ef2870af 100644
--- a/engines/agi/keyboard.h
+++ b/engines/agi/keyboard.h
@@ -25,10 +25,16 @@
namespace Agi {
-#define keyEnqueue(k) do { _keyQueue[_keyQueueEnd++] = (k); \
- _keyQueueEnd %= KEY_QUEUE_SIZE; } while (0)
-#define keyDequeue(k) do { (k) = _keyQueue[_keyQueueStart++]; \
- _keyQueueStart %= KEY_QUEUE_SIZE; } while (0)
+#define keyEnqueue(k) \
+ do { \
+ _keyQueue[_keyQueueEnd++] = (k); \
+ _keyQueueEnd %= KEY_QUEUE_SIZE; \
+ } while (0)
+#define keyDequeue(k) \
+ do { \
+ (k) = _keyQueue[_keyQueueStart++]; \
+ _keyQueueStart %= KEY_QUEUE_SIZE; \
+ } while (0)
// Class to turn on synthetic events temporarily. Usually until the end of the
// current function.
@@ -46,49 +52,50 @@ public:
}
};
-// QNX4 has a KEY_DOWN defined which we don't need to care about
-#undef KEY_DOWN
-
-// Allegro defines these
-#undef KEY_BACKSPACE
-#undef KEY_ENTER
-#undef KEY_LEFT
-#undef KEY_RIGHT
-#undef KEY_UP
-#undef KEY_PGUP
-#undef KEY_PGDN
-#undef KEY_HOME
-#undef KEY_END
-
-#define KEY_BACKSPACE 0x08
-#define KEY_ESCAPE 0x1B
-#define KEY_ENTER 0x0D
-#define KEY_UP 0x4800
-#define KEY_DOWN 0x5000
-#define KEY_LEFT 0x4B00
-#define KEY_STATIONARY 0x4C00
-#define KEY_RIGHT 0x4D00
-
-#define KEY_DOWN_LEFT 0x4F00
-#define KEY_DOWN_RIGHT 0x5100
-#define KEY_UP_LEFT 0x4700
-#define KEY_UP_RIGHT 0x4900
-
-#define KEY_STATUSLN 0xd900 // F11
-#define KEY_PRIORITY 0xda00 // F12
-
-#define KEY_PGUP 0x4900 // Page Up (fixed by Ziv Barber)
-#define KEY_PGDN 0x5100 // Page Down
-#define KEY_HOME 0x4700 // Home
-#define KEY_END 0x4f00 // End *
-
-#define BUTTON_LEFT 0xF101 // Left mouse button
-#define BUTTON_RIGHT 0xF202 // Right mouse button
-#define WHEEL_UP 0xF203 // Mouse wheel up
-#define WHEEL_DOWN 0xF204 // Mouse wheel down
-
-#define KEY_SCAN(k) (k >> 8)
-#define KEY_ASCII(k) (k & 0xff)
+#define AGI_KEY_BACKSPACE 0x08
+#define AGI_KEY_ESCAPE 0x1B
+#define AGI_KEY_ENTER 0x0D
+#define AGI_KEY_UP 0x4800
+#define AGI_KEY_DOWN 0x5000
+#define AGI_KEY_LEFT 0x4B00
+#define AGI_KEY_STATIONARY 0x4C00
+#define AGI_KEY_RIGHT 0x4D00
+
+#define AGI_KEY_DOWN_LEFT 0x4F00
+#define AGI_KEY_DOWN_RIGHT 0x5100
+#define AGI_KEY_UP_LEFT 0x4700
+#define AGI_KEY_UP_RIGHT 0x4900
+
+#define AGI_KEY_F1 0x3B00
+#define AGI_KEY_F2 0x3C00
+#define AGI_KEY_F3 0x3D00
+#define AGI_KEY_F4 0x3E00
+#define AGI_KEY_F5 0x3F00
+#define AGI_KEY_F6 0x4000
+#define AGI_KEY_F7 0x4100
+#define AGI_KEY_F8 0x4200
+#define AGI_KEY_F9 0x4300
+#define AGI_KEY_F10 0x4400
+#define AGI_KEY_F11 0xd900 // F11
+#define AGI_KEY_F12 0xda00 // F12
+
+#define AGI_KEY_PAGE_UP 0x4900 // Page Up (fixed by Ziv Barber)
+#define AGI_KEY_PAGE_DOWN 0x5100 // Page Down
+#define AGI_KEY_HOME 0x4700 // Home
+#define AGI_KEY_END 0x4f00 // End *
+
+#define AGI_MOUSE_BUTTON_LEFT 0xF101 // Left mouse button
+#define AGI_MOUSE_BUTTON_RIGHT 0xF202 // Right mouse button
+#define AGI_MOUSE_WHEEL_UP 0xF203 // Mouse wheel up
+#define AGI_MOUSE_WHEEL_DOWN 0xF204 // Mouse wheel down
+
+// special menu triggers
+// Attention: at least Mixed Up Mother Goose on Apple IIgs actually hooks ESC for menu only
+// Which is why we have to check, if the corresponding trigger is hooked before changing it
+// And otherwise simply use the regular ESC.
+#define AGI_MENU_TRIGGER_PC 0x001B // will trigger menu for PC
+#define AGI_MENU_TRIGGER_APPLE2GS 0x0301 // will trigger menu for AppleIIgs + Amiga
+#define AGI_MENU_TRIGGER_ATARIST 0x0101 // will trigger menu for Atari ST
extern const uint8 scancodeTable[];
diff --git a/engines/agi/loader_v1.cpp b/engines/agi/loader_v1.cpp
index 404fb6ee0e..0c569382cf 100644
--- a/engines/agi/loader_v1.cpp
+++ b/engines/agi/loader_v1.cpp
@@ -21,31 +21,33 @@
*/
#include "agi/agi.h"
+#include "agi/words.h"
+
#include "common/md5.h"
#define IMAGE_SIZE 368640 // = 40 * 2 * 9 * 512 = tracks * sides * sectors * sector size
#define SECTOR_OFFSET(s) ((s) * 512)
-#define DDP_BASE_SECTOR 0x1C2
-#define DDP_LOGDIR_SEC SECTOR_OFFSET(171) + 5
-#define DDP_LOGDIR_MAX 43
-#define DDP_PICDIR_SEC SECTOR_OFFSET(180) + 5
-#define DDP_PICDIR_MAX 30
-#define DDP_VIEWDIR_SEC SECTOR_OFFSET(189) + 5
-#define DDP_VIEWDIR_MAX 171
-#define DDP_SNDDIR_SEC SECTOR_OFFSET(198) + 5
-#define DDP_SNDDIR_MAX 64
-
-#define BC_LOGDIR_SEC SECTOR_OFFSET(90) + 5
-#define BC_LOGDIR_MAX 118
-#define BC_VIEWDIR_SEC SECTOR_OFFSET(96) + 5
-#define BC_VIEWDIR_MAX 180
-#define BC_PICDIR_SEC SECTOR_OFFSET(93) + 8
-#define BC_PICDIR_MAX 117
-#define BC_SNDDIR_SEC SECTOR_OFFSET(99) + 5
-#define BC_SNDDIR_MAX 29
-#define BC_WORDS SECTOR_OFFSET(0x26D) + 5
-#define BC_OBJECTS SECTOR_OFFSET(0x1E6) + 3
+#define DDP_BASE_SECTOR 0x1C2
+#define DDP_LOGDIR_SEC SECTOR_OFFSET(171) + 5
+#define DDP_LOGDIR_MAX 43
+#define DDP_PICDIR_SEC SECTOR_OFFSET(180) + 5
+#define DDP_PICDIR_MAX 30
+#define DDP_VIEWDIR_SEC SECTOR_OFFSET(189) + 5
+#define DDP_VIEWDIR_MAX 171
+#define DDP_SNDDIR_SEC SECTOR_OFFSET(198) + 5
+#define DDP_SNDDIR_MAX 64
+
+#define BC_LOGDIR_SEC SECTOR_OFFSET(90) + 5
+#define BC_LOGDIR_MAX 118
+#define BC_VIEWDIR_SEC SECTOR_OFFSET(96) + 5
+#define BC_VIEWDIR_MAX 180
+#define BC_PICDIR_SEC SECTOR_OFFSET(93) + 8
+#define BC_PICDIR_MAX 117
+#define BC_SNDDIR_SEC SECTOR_OFFSET(99) + 5
+#define BC_SNDDIR_MAX 29
+#define BC_WORDS SECTOR_OFFSET(0x26D) + 5
+#define BC_OBJECTS SECTOR_OFFSET(0x1E6) + 3
namespace Agi {
@@ -69,7 +71,7 @@ int AgiLoader_v1::loadDir_DDP(AgiDir *agid, int offset, int max) {
return errBadFileOpen;
// Cleanup
- for (int i = 0; i < MAX_DIRS; i++) {
+ for (int i = 0; i < MAX_DIRECTORY_ENTRIES; i++) {
agid[i].volume = 0xFF;
agid[i].offset = _EMPTY;
}
@@ -103,7 +105,7 @@ int AgiLoader_v1::loadDir_BC(AgiDir *agid, int offset, int max) {
return errBadFileOpen;
// Cleanup
- for (int i = 0; i < MAX_DIRS; i++) {
+ for (int i = 0; i < MAX_DIRECTORY_ENTRIES; i++) {
agid[i].volume = 0xFF;
agid[i].offset = _EMPTY;
}
@@ -197,84 +199,84 @@ uint8 *AgiLoader_v1::loadVolRes(struct AgiDir *agid) {
return data;
}
-int AgiLoader_v1::loadResource(int t, int n) {
+int AgiLoader_v1::loadResource(int16 resourceType, int16 resourceNr) {
int ec = errOK;
uint8 *data = NULL;
- debugC(3, kDebugLevelResources, "(t = %d, n = %d)", t, n);
- if (n >= MAX_DIRS)
+ debugC(3, kDebugLevelResources, "(t = %d, n = %d)", resourceType, resourceNr);
+ if (resourceNr >= MAX_DIRECTORY_ENTRIES)
return errBadResource;
- switch (t) {
- case rLOGIC:
- if (~_vm->_game.dirLogic[n].flags & RES_LOADED) {
- debugC(3, kDebugLevelResources, "loading logic resource %d", n);
- unloadResource(rLOGIC, n);
+ switch (resourceType) {
+ case RESOURCETYPE_LOGIC:
+ if (~_vm->_game.dirLogic[resourceNr].flags & RES_LOADED) {
+ debugC(3, kDebugLevelResources, "loading logic resource %d", resourceNr);
+ unloadResource(RESOURCETYPE_LOGIC, resourceNr);
// load raw resource into data
- data = loadVolRes(&_vm->_game.dirLogic[n]);
+ data = loadVolRes(&_vm->_game.dirLogic[resourceNr]);
- _vm->_game.logics[n].data = data;
- ec = data ? _vm->decodeLogic(n) : errBadResource;
+ _vm->_game.logics[resourceNr].data = data;
+ ec = data ? _vm->decodeLogic(resourceNr) : errBadResource;
- _vm->_game.logics[n].sIP = 2;
+ _vm->_game.logics[resourceNr].sIP = 2;
}
// if logic was cached, we get here
// reset code pointers incase it was cached
- _vm->_game.logics[n].cIP = _vm->_game.logics[n].sIP;
+ _vm->_game.logics[resourceNr].cIP = _vm->_game.logics[resourceNr].sIP;
break;
- case rPICTURE:
+ case RESOURCETYPE_PICTURE:
// if picture is currently NOT loaded *OR* cacheing is off,
// unload the resource (caching == off) and reload it
- debugC(3, kDebugLevelResources, "loading picture resource %d", n);
- if (_vm->_game.dirPic[n].flags & RES_LOADED)
+ debugC(3, kDebugLevelResources, "loading picture resource %d", resourceNr);
+ if (_vm->_game.dirPic[resourceNr].flags & RES_LOADED)
break;
// if loaded but not cached, unload it
// if cached but not loaded, etc
- unloadResource(rPICTURE, n);
- data = loadVolRes(&_vm->_game.dirPic[n]);
+ unloadResource(RESOURCETYPE_PICTURE, resourceNr);
+ data = loadVolRes(&_vm->_game.dirPic[resourceNr]);
if (data != NULL) {
- _vm->_game.pictures[n].rdata = data;
- _vm->_game.dirPic[n].flags |= RES_LOADED;
+ _vm->_game.pictures[resourceNr].rdata = data;
+ _vm->_game.dirPic[resourceNr].flags |= RES_LOADED;
} else {
ec = errBadResource;
}
break;
- case rSOUND:
- debugC(3, kDebugLevelResources, "loading sound resource %d", n);
- if (_vm->_game.dirSound[n].flags & RES_LOADED)
+ case RESOURCETYPE_SOUND:
+ debugC(3, kDebugLevelResources, "loading sound resource %d", resourceNr);
+ if (_vm->_game.dirSound[resourceNr].flags & RES_LOADED)
break;
- data = loadVolRes(&_vm->_game.dirSound[n]);
+ data = loadVolRes(&_vm->_game.dirSound[resourceNr]);
if (data != NULL) {
// Freeing of the raw resource from memory is delegated to the createFromRawResource-function
- _vm->_game.sounds[n] = AgiSound::createFromRawResource(data, _vm->_game.dirSound[n].len, n, _vm->_soundemu);
- _vm->_game.dirSound[n].flags |= RES_LOADED;
+ _vm->_game.sounds[resourceNr] = AgiSound::createFromRawResource(data, _vm->_game.dirSound[resourceNr].len, resourceNr, _vm->_soundemu);
+ _vm->_game.dirSound[resourceNr].flags |= RES_LOADED;
} else {
ec = errBadResource;
}
break;
- case rVIEW:
+ case RESOURCETYPE_VIEW:
// Load a VIEW resource into memory...
// Since VIEWS alter the view table ALL the time
// can we cache the view? or must we reload it all
// the time?
- if (_vm->_game.dirView[n].flags & RES_LOADED)
+ if (_vm->_game.dirView[resourceNr].flags & RES_LOADED)
break;
- debugC(3, kDebugLevelResources, "loading view resource %d", n);
- unloadResource(rVIEW, n);
- data = loadVolRes(&_vm->_game.dirView[n]);
+ debugC(3, kDebugLevelResources, "loading view resource %d", resourceNr);
+ unloadResource(RESOURCETYPE_VIEW, resourceNr);
+ data = loadVolRes(&_vm->_game.dirView[resourceNr]);
if (data) {
- _vm->_game.views[n].rdata = data;
- _vm->_game.dirView[n].flags |= RES_LOADED;
- ec = _vm->decodeView(n);
+ _vm->_game.dirView[resourceNr].flags |= RES_LOADED;
+ ec = _vm->decodeView(data, _vm->_game.dirView[resourceNr].len, resourceNr);
+ free(data);
} else {
ec = errBadResource;
}
@@ -287,19 +289,19 @@ int AgiLoader_v1::loadResource(int t, int n) {
return ec;
}
-int AgiLoader_v1::unloadResource(int t, int n) {
- switch (t) {
- case rLOGIC:
- _vm->unloadLogic(n);
+int AgiLoader_v1::unloadResource(int16 resourceType, int16 resourceNr) {
+ switch (resourceType) {
+ case RESOURCETYPE_LOGIC:
+ _vm->unloadLogic(resourceNr);
break;
- case rPICTURE:
- _vm->_picture->unloadPicture(n);
+ case RESOURCETYPE_PICTURE:
+ _vm->_picture->unloadPicture(resourceNr);
break;
- case rVIEW:
- _vm->unloadView(n);
+ case RESOURCETYPE_VIEW:
+ _vm->unloadView(resourceNr);
break;
- case rSOUND:
- _vm->_sound->unloadSound(n);
+ case RESOURCETYPE_SOUND:
+ _vm->_sound->unloadSound(resourceNr);
break;
}
@@ -321,7 +323,7 @@ int AgiLoader_v1::loadWords(const char *fname) {
Common::File f;
f.open(_filenameDisk0);
f.seek(BC_WORDS, SEEK_SET);
- return _vm->loadWords_v1(f);
+ return _vm->_words->loadDictionary_v1(f);
}
return errOK;
}
diff --git a/engines/agi/loader_v2.cpp b/engines/agi/loader_v2.cpp
index 693c53c2bf..43ef46bd72 100644
--- a/engines/agi/loader_v2.cpp
+++ b/engines/agi/loader_v2.cpp
@@ -23,14 +23,15 @@
#include "common/textconsole.h"
#include "agi/agi.h"
+#include "agi/words.h"
namespace Agi {
int AgiLoader_v2::detectGame() {
if (!Common::File::exists(LOGDIR) ||
- !Common::File::exists(PICDIR) ||
- !Common::File::exists(SNDDIR) ||
- !Common::File::exists(VIEWDIR))
+ !Common::File::exists(PICDIR) ||
+ !Common::File::exists(SNDDIR) ||
+ !Common::File::exists(VIEWDIR))
return errInvalidAGIFile;
return _vm->setupV2Game(_vm->getVersion());
@@ -60,7 +61,7 @@ int AgiLoader_v2::loadDir(AgiDir *agid, const char *fname) {
fp.read(mem, flen);
// set all directory resources to gone
- for (i = 0; i < MAX_DIRS; i++) {
+ for (i = 0; i < MAX_DIRECTORY_ENTRIES; i++) {
agid[i].volume = 0xff;
agid[i].offset = _EMPTY;
}
@@ -107,21 +108,21 @@ int AgiLoader_v2::deinit() {
return ec;
}
-int AgiLoader_v2::unloadResource(int t, int n) {
+int AgiLoader_v2::unloadResource(int16 resourceType, int16 resourceNr) {
debugC(3, kDebugLevelResources, "unload resource");
- switch (t) {
- case rLOGIC:
- _vm->unloadLogic(n);
+ switch (resourceType) {
+ case RESOURCETYPE_LOGIC:
+ _vm->unloadLogic(resourceNr);
break;
- case rPICTURE:
- _vm->_picture->unloadPicture(n);
+ case RESOURCETYPE_PICTURE:
+ _vm->_picture->unloadPicture(resourceNr);
break;
- case rVIEW:
- _vm->unloadView(n);
+ case RESOURCETYPE_VIEW:
+ _vm->unloadView(resourceNr);
break;
- case rSOUND:
- _vm->_sound->unloadSound(n);
+ case RESOURCETYPE_SOUND:
+ _vm->_sound->unloadSound(resourceNr);
break;
}
@@ -129,7 +130,7 @@ int AgiLoader_v2::unloadResource(int t, int n) {
}
/**
- * This function does noting but load a raw resource into memory,
+ * This function loads a raw resource into memory,
* if further decoding is required, it must be done by another
* routine. NULL is returned if unsucsessfull.
*/
@@ -173,84 +174,84 @@ uint8 *AgiLoader_v2::loadVolRes(struct AgiDir *agid) {
* Loads a resource into memory, a raw resource is loaded in
* with above routine, then further decoded here.
*/
-int AgiLoader_v2::loadResource(int t, int n) {
+int AgiLoader_v2::loadResource(int16 resourceType, int16 resourceNr) {
int ec = errOK;
uint8 *data = NULL;
- debugC(3, kDebugLevelResources, "(t = %d, n = %d)", t, n);
- if (n >= MAX_DIRS)
+ debugC(3, kDebugLevelResources, "(t = %d, n = %d)", resourceType, resourceNr);
+ if (resourceNr >= MAX_DIRECTORY_ENTRIES)
return errBadResource;
- switch (t) {
- case rLOGIC:
- if (~_vm->_game.dirLogic[n].flags & RES_LOADED) {
- debugC(3, kDebugLevelResources, "loading logic resource %d", n);
- unloadResource(rLOGIC, n);
+ switch (resourceType) {
+ case RESOURCETYPE_LOGIC:
+ if (~_vm->_game.dirLogic[resourceNr].flags & RES_LOADED) {
+ debugC(3, kDebugLevelResources, "loading logic resource %d", resourceNr);
+ unloadResource(RESOURCETYPE_LOGIC, resourceNr);
// load raw resource into data
- data = loadVolRes(&_vm->_game.dirLogic[n]);
+ data = loadVolRes(&_vm->_game.dirLogic[resourceNr]);
- _vm->_game.logics[n].data = data;
- ec = data ? _vm->decodeLogic(n) : errBadResource;
+ _vm->_game.logics[resourceNr].data = data;
+ ec = data ? _vm->decodeLogic(resourceNr) : errBadResource;
- _vm->_game.logics[n].sIP = 2;
+ _vm->_game.logics[resourceNr].sIP = 2;
}
// if logic was cached, we get here
// reset code pointers incase it was cached
- _vm->_game.logics[n].cIP = _vm->_game.logics[n].sIP;
+ _vm->_game.logics[resourceNr].cIP = _vm->_game.logics[resourceNr].sIP;
break;
- case rPICTURE:
+ case RESOURCETYPE_PICTURE:
// if picture is currently NOT loaded *OR* cacheing is off,
// unload the resource (caching == off) and reload it
- debugC(3, kDebugLevelResources, "loading picture resource %d", n);
- if (_vm->_game.dirPic[n].flags & RES_LOADED)
+ debugC(3, kDebugLevelResources, "loading picture resource %d", resourceNr);
+ if (_vm->_game.dirPic[resourceNr].flags & RES_LOADED)
break;
// if loaded but not cached, unload it
// if cached but not loaded, etc
- unloadResource(rPICTURE, n);
- data = loadVolRes(&_vm->_game.dirPic[n]);
+ unloadResource(RESOURCETYPE_PICTURE, resourceNr);
+ data = loadVolRes(&_vm->_game.dirPic[resourceNr]);
if (data != NULL) {
- _vm->_game.pictures[n].rdata = data;
- _vm->_game.dirPic[n].flags |= RES_LOADED;
+ _vm->_game.pictures[resourceNr].rdata = data;
+ _vm->_game.dirPic[resourceNr].flags |= RES_LOADED;
} else {
ec = errBadResource;
}
break;
- case rSOUND:
- debugC(3, kDebugLevelResources, "loading sound resource %d", n);
- if (_vm->_game.dirSound[n].flags & RES_LOADED)
+ case RESOURCETYPE_SOUND:
+ debugC(3, kDebugLevelResources, "loading sound resource %d", resourceNr);
+ if (_vm->_game.dirSound[resourceNr].flags & RES_LOADED)
break;
- data = loadVolRes(&_vm->_game.dirSound[n]);
+ data = loadVolRes(&_vm->_game.dirSound[resourceNr]);
if (data != NULL) {
// Freeing of the raw resource from memory is delegated to the createFromRawResource-function
- _vm->_game.sounds[n] = AgiSound::createFromRawResource(data, _vm->_game.dirSound[n].len, n, _vm->_soundemu);
- _vm->_game.dirSound[n].flags |= RES_LOADED;
+ _vm->_game.sounds[resourceNr] = AgiSound::createFromRawResource(data, _vm->_game.dirSound[resourceNr].len, resourceNr, _vm->_soundemu);
+ _vm->_game.dirSound[resourceNr].flags |= RES_LOADED;
} else {
ec = errBadResource;
}
break;
- case rVIEW:
+ case RESOURCETYPE_VIEW:
// Load a VIEW resource into memory...
// Since VIEWS alter the view table ALL the time
// can we cache the view? or must we reload it all
// the time?
- if (_vm->_game.dirView[n].flags & RES_LOADED)
+ if (_vm->_game.dirView[resourceNr].flags & RES_LOADED)
break;
- debugC(3, kDebugLevelResources, "loading view resource %d", n);
- unloadResource(rVIEW, n);
- data = loadVolRes(&_vm->_game.dirView[n]);
+ debugC(3, kDebugLevelResources, "loading view resource %d", resourceNr);
+ unloadResource(RESOURCETYPE_VIEW, resourceNr);
+ data = loadVolRes(&_vm->_game.dirView[resourceNr]);
if (data) {
- _vm->_game.views[n].rdata = data;
- _vm->_game.dirView[n].flags |= RES_LOADED;
- ec = _vm->decodeView(n);
+ _vm->_game.dirView[resourceNr].flags |= RES_LOADED;
+ ec = _vm->decodeView(data, _vm->_game.dirView[resourceNr].len, resourceNr);
+ free(data);
} else {
ec = errBadResource;
}
@@ -268,7 +269,7 @@ int AgiLoader_v2::loadObjects(const char *fname) {
}
int AgiLoader_v2::loadWords(const char *fname) {
- return _vm->loadWords(fname);
+ return _vm->_words->loadDictionary(fname);
}
} // End of namespace Agi
diff --git a/engines/agi/loader_v3.cpp b/engines/agi/loader_v3.cpp
index 39759b4649..5a208a5114 100644
--- a/engines/agi/loader_v3.cpp
+++ b/engines/agi/loader_v3.cpp
@@ -22,6 +22,7 @@
#include "agi/agi.h"
#include "agi/lzw.h"
+#include "agi/words.h"
#include "common/config-manager.h"
#include "common/fs.h"
@@ -42,7 +43,7 @@ int AgiLoader_v3::detectGame() {
}
for (Common::FSList::const_iterator file = fslist.begin();
- file != fslist.end() && !found; ++file) {
+ file != fslist.end() && !found; ++file) {
Common::String f = file->getName();
f.toLowercase();
@@ -66,7 +67,7 @@ int AgiLoader_v3::detectGame() {
}
int AgiLoader_v3::loadDir(struct AgiDir *agid, Common::File *fp,
- uint32 offs, uint32 len) {
+ uint32 offs, uint32 len) {
int ec = errOK;
uint8 *mem;
unsigned int i;
@@ -76,7 +77,7 @@ int AgiLoader_v3::loadDir(struct AgiDir *agid, Common::File *fp,
fp->read(mem, len);
// set all directory resources to gone
- for (i = 0; i < MAX_DIRS; i++) {
+ for (i = 0; i < MAX_DIRECTORY_ENTRIES; i++) {
agid[i].volume = 0xff;
agid[i].offset = _EMPTY;
}
@@ -171,19 +172,19 @@ int AgiLoader_v3::deinit() {
return ec;
}
-int AgiLoader_v3::unloadResource(int t, int n) {
- switch (t) {
- case rLOGIC:
- _vm->unloadLogic(n);
+int AgiLoader_v3::unloadResource(int16 resourceType, int16 resourceNr) {
+ switch (resourceType) {
+ case RESOURCETYPE_LOGIC:
+ _vm->unloadLogic(resourceNr);
break;
- case rPICTURE:
- _vm->_picture->unloadPicture(n);
+ case RESOURCETYPE_PICTURE:
+ _vm->_picture->unloadPicture(resourceNr);
break;
- case rVIEW:
- _vm->unloadView(n);
+ case RESOURCETYPE_VIEW:
+ _vm->unloadView(resourceNr);
break;
- case rSOUND:
- _vm->_sound->unloadSound(n);
+ case RESOURCETYPE_SOUND:
+ _vm->_sound->unloadSound(resourceNr);
break;
}
@@ -191,7 +192,7 @@ int AgiLoader_v3::unloadResource(int t, int n) {
}
/**
- * This function does noting but load a raw resource into memory.
+ * This function loads a raw resource into memory.
* If further decoding is required, it must be done by another
* routine.
*
@@ -215,17 +216,21 @@ uint8 *AgiLoader_v3::loadVolRes(AgiDir *agid) {
debugC(3, kDebugLevelResources, "offset = %d", agid->offset);
debugC(3, kDebugLevelResources, "x = %x %x", x[0], x[1]);
error("ACK! BAD RESOURCE");
- _vm->quitGame(); // for compilers that don't support NORETURN
+ _vm->quitGame(); // for compilers that don't support NORETURN
}
- agid->len = READ_LE_UINT16((uint8 *) x + 3); // uncompressed size
- agid->clen = READ_LE_UINT16((uint8 *) x + 5); // compressed len
+ agid->len = READ_LE_UINT16((uint8 *) x + 3); // uncompressed size
+ agid->clen = READ_LE_UINT16((uint8 *) x + 5); // compressed len
compBuffer = (uint8 *)calloc(1, agid->clen + 32);
fp.read(compBuffer, agid->clen);
if (x[2] & 0x80) { // compressed pic
- data = _vm->_picture->convertV3Pic(compBuffer, agid->clen);
+ // effectively uncompressed, but having only 4-bit parameters for F0 / F2 commands
+ // Manhunter 2 uses such pictures
+ data = compBuffer;
+ agid->flags |= RES_PICTURE_V3_NIBBLE_PARM;
+ //data = _vm->_picture->convertV3Pic(compBuffer, agid->clen);
// compBuffer has been freed inside convertV3Pic()
} else if (agid->len == agid->clen) {
// do not decompress
@@ -252,31 +257,31 @@ uint8 *AgiLoader_v3::loadVolRes(AgiDir *agid) {
* Loads a resource into memory, a raw resource is loaded in
* with above routine, then further decoded here.
*/
-int AgiLoader_v3::loadResource(int t, int n) {
+int AgiLoader_v3::loadResource(int16 resourceType, int16 resourceNr) {
int ec = errOK;
uint8 *data = NULL;
- if (n >= MAX_DIRS)
+ if (resourceNr >= MAX_DIRECTORY_ENTRIES)
return errBadResource;
- switch (t) {
- case rLOGIC:
+ switch (resourceType) {
+ case RESOURCETYPE_LOGIC:
// load resource into memory, decrypt messages at the end
// and build the message list (if logic is in memory)
- if (~_vm->_game.dirLogic[n].flags & RES_LOADED) {
+ if (~_vm->_game.dirLogic[resourceNr].flags & RES_LOADED) {
// if logic is already in memory, unload it
- unloadResource(rLOGIC, n);
+ unloadResource(RESOURCETYPE_LOGIC, resourceNr);
// load raw resource into data
- data = loadVolRes(&_vm->_game.dirLogic[n]);
- _vm->_game.logics[n].data = data;
+ data = loadVolRes(&_vm->_game.dirLogic[resourceNr]);
+ _vm->_game.logics[resourceNr].data = data;
// uncompressed logic files need to be decrypted
if (data != NULL) {
// resloaded flag gets set by decode logic
// needed to build string table
- ec = _vm->decodeLogic(n);
- _vm->_game.logics[n].sIP = 2;
+ ec = _vm->decodeLogic(resourceNr);
+ _vm->_game.logics[resourceNr].sIP = 2;
} else {
ec = errBadResource;
}
@@ -284,56 +289,56 @@ int AgiLoader_v3::loadResource(int t, int n) {
// logics[n].sIP=2; // saved IP = 2
// logics[n].cIP=2; // current IP = 2
- _vm->_game.logics[n].cIP = _vm->_game.logics[n].sIP;
+ _vm->_game.logics[resourceNr].cIP = _vm->_game.logics[resourceNr].sIP;
}
// if logic was cached, we get here
// reset code pointers incase it was cached
- _vm->_game.logics[n].cIP = _vm->_game.logics[n].sIP;
+ _vm->_game.logics[resourceNr].cIP = _vm->_game.logics[resourceNr].sIP;
break;
- case rPICTURE:
+ case RESOURCETYPE_PICTURE:
// if picture is currently NOT loaded *OR* cacheing is off,
// unload the resource (caching==off) and reload it
- if (~_vm->_game.dirPic[n].flags & RES_LOADED) {
- unloadResource(rPICTURE, n);
- data = loadVolRes(&_vm->_game.dirPic[n]);
+ if (~_vm->_game.dirPic[resourceNr].flags & RES_LOADED) {
+ unloadResource(RESOURCETYPE_PICTURE, resourceNr);
+ data = loadVolRes(&_vm->_game.dirPic[resourceNr]);
if (data != NULL) {
- _vm->_game.pictures[n].rdata = data;
- _vm->_game.dirPic[n].flags |= RES_LOADED;
+ _vm->_game.pictures[resourceNr].rdata = data;
+ _vm->_game.dirPic[resourceNr].flags |= RES_LOADED;
} else {
ec = errBadResource;
}
}
break;
- case rSOUND:
- if (_vm->_game.dirSound[n].flags & RES_LOADED)
+ case RESOURCETYPE_SOUND:
+ if (_vm->_game.dirSound[resourceNr].flags & RES_LOADED)
break;
- data = loadVolRes(&_vm->_game.dirSound[n]);
+ data = loadVolRes(&_vm->_game.dirSound[resourceNr]);
if (data != NULL) {
// Freeing of the raw resource from memory is delegated to the createFromRawResource-function
- _vm->_game.sounds[n] = AgiSound::createFromRawResource(data, _vm->_game.dirSound[n].len, n, _vm->_soundemu);
- _vm->_game.dirSound[n].flags |= RES_LOADED;
+ _vm->_game.sounds[resourceNr] = AgiSound::createFromRawResource(data, _vm->_game.dirSound[resourceNr].len, resourceNr, _vm->_soundemu);
+ _vm->_game.dirSound[resourceNr].flags |= RES_LOADED;
} else {
ec = errBadResource;
}
break;
- case rVIEW:
+ case RESOURCETYPE_VIEW:
// Load a VIEW resource into memory...
// Since VIEWS alter the view table ALL the time can we
// cache the view? or must we reload it all the time?
//
// load a raw view from a VOL file into data
- if (_vm->_game.dirView[n].flags & RES_LOADED)
+ if (_vm->_game.dirView[resourceNr].flags & RES_LOADED)
break;
- unloadResource(rVIEW, n);
- data = loadVolRes(&_vm->_game.dirView[n]);
+ unloadResource(RESOURCETYPE_VIEW, resourceNr);
+ data = loadVolRes(&_vm->_game.dirView[resourceNr]);
if (data != NULL) {
- _vm->_game.views[n].rdata = data;
- _vm->_game.dirView[n].flags |= RES_LOADED;
- ec = _vm->decodeView(n);
+ _vm->_game.dirView[resourceNr].flags |= RES_LOADED;
+ ec = _vm->decodeView(data, _vm->_game.dirView[resourceNr].len, resourceNr);
+ free(data);
} else {
ec = errBadResource;
}
@@ -351,7 +356,7 @@ int AgiLoader_v3::loadObjects(const char *fname) {
}
int AgiLoader_v3::loadWords(const char *fname) {
- return _vm->loadWords(fname);
+ return _vm->_words->loadDictionary(fname);
}
} // End of namespace Agi
diff --git a/engines/agi/logic.cpp b/engines/agi/logic.cpp
index 7429b117c8..c6dd04b814 100644
--- a/engines/agi/logic.cpp
+++ b/engines/agi/logic.cpp
@@ -30,56 +30,57 @@ namespace Agi {
* into a message list.
* @param n The number of the logic resource to decode.
*/
-int AgiEngine::decodeLogic(int n) {
+int AgiEngine::decodeLogic(int16 logicNr) {
int ec = errOK;
int mstart, mend, mc;
uint8 *m0;
+ AgiLogic *curLogic = &_game.logics[logicNr];
// decrypt messages at end of logic + build message list
// report ("decoding logic #%d\n", n);
- m0 = _game.logics[n].data;
+ m0 = curLogic->data;
mstart = READ_LE_UINT16(m0) + 2;
mc = *(m0 + mstart);
mend = READ_LE_UINT16(m0 + mstart + 1);
- m0 += mstart + 3; // cover header info
+ m0 += mstart + 3; // cover header info
mstart = mc << 1;
// if the logic was not compressed, decrypt the text messages
// only if there are more than 0 messages
- if ((~_game.dirLogic[n].flags & RES_COMPRESSED) && mc > 0)
- decrypt(m0 + mstart, mend - mstart); // decrypt messages
+ if ((~_game.dirLogic[logicNr].flags & RES_COMPRESSED) && mc > 0)
+ decrypt(m0 + mstart, mend - mstart); // decrypt messages
// build message list
- m0 = _game.logics[n].data;
- mstart = READ_LE_UINT16(m0) + 2; // +2 covers pointer
- _game.logics[n].numTexts = *(m0 + mstart);
+ m0 = curLogic->data;
+ mstart = READ_LE_UINT16(m0) + 2; // +2 covers pointer
+ _game.logics[logicNr].numTexts = *(m0 + mstart);
// resetp logic pointers
- _game.logics[n].sIP = 2;
- _game.logics[n].cIP = 2;
- _game.logics[n].size = READ_LE_UINT16(m0) + 2; // logic end pointer
+ curLogic->sIP = 2;
+ curLogic->cIP = 2;
+ curLogic->size = READ_LE_UINT16(m0) + 2; // logic end pointer
// allocate list of pointers to point into our data
- _game.logics[n].texts = (const char **)calloc(1 + _game.logics[n].numTexts, sizeof(char *));
+ curLogic->texts = (const char **)calloc(1 + curLogic->numTexts, sizeof(char *));
// cover header info
m0 += mstart + 3;
- if (_game.logics[n].texts != NULL) {
+ if (curLogic->texts != NULL) {
// move list of strings into list to make real pointers
- for (mc = 0; mc < _game.logics[n].numTexts; mc++) {
+ for (mc = 0; mc < curLogic->numTexts; mc++) {
mend = READ_LE_UINT16(m0 + mc * 2);
- _game.logics[n].texts[mc] = mend ? (const char *)m0 + mend - 2 : (const char *)"";
+ _game.logics[logicNr].texts[mc] = mend ? (const char *)m0 + mend - 2 : (const char *)"";
}
// set loaded flag now its all completly loaded
- _game.dirLogic[n].flags |= RES_LOADED;
+ _game.dirLogic[logicNr].flags |= RES_LOADED;
} else {
// unload data
// Note that not every logic has text
- free(_game.logics[n].data);
+ free(curLogic->data);
ec = errNotEnoughMemory;
}
@@ -92,18 +93,17 @@ int AgiEngine::decodeLogic(int n) {
* memory chunks allocated for this resource.
* @param n The number of the logic resource to unload
*/
-void AgiEngine::unloadLogic(int n) {
- if (_game.dirLogic[n].flags & RES_LOADED) {
- free(_game.logics[n].data);
- if (_game.logics[n].numTexts)
- free(_game.logics[n].texts);
- _game.logics[n].numTexts = 0;
- _game.dirLogic[n].flags &= ~RES_LOADED;
+void AgiEngine::unloadLogic(int16 logicNr) {
+ if (_game.dirLogic[logicNr].flags & RES_LOADED) {
+ free(_game.logics[logicNr].data);
+ free(_game.logics[logicNr].texts);
+ _game.logics[logicNr].numTexts = 0;
+ _game.dirLogic[logicNr].flags &= ~RES_LOADED;
}
// if cached, we end up here
- _game.logics[n].sIP = 2;
- _game.logics[n].cIP = 2;
+ _game.logics[logicNr].sIP = 2;
+ _game.logics[logicNr].cIP = 2;
}
} // End of namespace Agi
diff --git a/engines/agi/logic.h b/engines/agi/logic.h
index a30a37bc47..b46362056f 100644
--- a/engines/agi/logic.h
+++ b/engines/agi/logic.h
@@ -29,12 +29,12 @@ namespace Agi {
* AGI logic resource structure.
*/
struct AgiLogic {
- uint8 *data; /**< raw resource data */
- int size; /**< size of data */
- int sIP; /**< saved IP */
- int cIP; /**< current IP */
- int numTexts; /**< number of messages */
- const char **texts; /**< message list */
+ uint8 *data; /**< raw resource data */
+ int size; /**< size of data */
+ int sIP; /**< saved IP */
+ int cIP; /**< current IP */
+ int numTexts; /**< number of messages */
+ const char **texts; /**< message list */
};
} // End of namespace Agi
diff --git a/engines/agi/lzw.cpp b/engines/agi/lzw.cpp
index ba47c13543..ecb69543d7 100644
--- a/engines/agi/lzw.cpp
+++ b/engines/agi/lzw.cpp
@@ -42,16 +42,16 @@ class LZWDecoder {
private:
enum {
- MAXBITS = 12,
- TABLE_SIZE = 18041, // strange number
- START_BITS = 9
+ MAXBITS = 12,
+ TABLE_SIZE = 18041, // strange number
+ START_BITS = 9
};
int32 BITS, MAX_VALUE, MAX_CODE;
uint32 *prefixCode;
uint8 *appendCharacter;
uint8 *decodeStack;
- int32 inputBitCount; // Number of bits in input bit buffer
+ int32 inputBitCount; // Number of bits in input bit buffer
uint32 inputBitBuffer;
public:
@@ -70,8 +70,9 @@ LZWDecoder::LZWDecoder() {
decodeStack = (uint8 *)calloc(1, 8192);
prefixCode = (uint32 *)malloc(TABLE_SIZE * sizeof(uint32));
appendCharacter = (uint8 *)malloc(TABLE_SIZE * sizeof(uint8));
- inputBitCount = 0; // Number of bits in input bit buffer
+ inputBitCount = 0; // Number of bits in input bit buffer
inputBitBuffer = 0L;
+ BITS = MAX_VALUE = MAX_CODE = 0;
}
LZWDecoder::~LZWDecoder() {
@@ -147,12 +148,12 @@ void LZWDecoder::lzwExpand(uint8 *in, uint8 *out, int32 len) {
LZWDecoder d;
- setBits(START_BITS); // Starts at 9-bits
- lzwnext = 257; // Next available code to define
+ setBits(START_BITS); // Starts at 9-bits
+ lzwnext = 257; // Next available code to define
end = (uint8 *)(out + (uint32)len);
- lzwold = inputCode(&in); // Read in the first code
+ lzwold = inputCode(&in); // Read in the first code
c = lzwold;
lzwnew = inputCode(&in);
diff --git a/engines/agi/menu.cpp b/engines/agi/menu.cpp
index 008c208c82..49c2d0eeab 100644
--- a/engines/agi/menu.cpp
+++ b/engines/agi/menu.cpp
@@ -22,534 +22,665 @@
#include "agi/agi.h"
#include "agi/graphics.h"
+#include "agi/text.h"
#include "agi/keyboard.h"
#include "agi/menu.h"
namespace Agi {
-// TODO: add constructor/destructor for agi_menu, agi_menu_option
-
-struct AgiMenuOption {
- int enabled; /**< option is enabled or disabled */
- int event; /**< menu event */
- int index; /**< number of option in this menu */
- char *text; /**< text of menu option */
-};
-
-struct AgiMenu {
- MenuOptionList down; /**< list head for menu options */
- int index; /**< number of menu in menubar */
- int width; /**< width of menu in characters */
- int height; /**< height of menu in characters */
- int col; /**< column of menubar entry */
- int wincol; /**< column of menu window */
- char *text; /**< menu name */
-};
-
-AgiMenu *Menu::getMenu(int i) {
- MenuList::iterator iter;
- for (iter = _menubar.begin(); iter != _menubar.end(); ++iter) {
- AgiMenu *m = *iter;
- if (m->index == i)
- return m;
- }
- return NULL;
-}
+GfxMenu::GfxMenu(AgiEngine *vm, GfxMgr *gfx, PictureMgr *picture, TextMgr *text) {
+ _vm = vm;
+ _gfx = gfx;
+ _picture = picture;
+ _text = text;
-AgiMenuOption *Menu::getMenuOption(int i, int j) {
- AgiMenu *m = getMenu(i);
- MenuOptionList::iterator iter;
+ _allowed = true;
+ _submitted = false;
+ _delayedExecuteViaKeyboard = false;
+ _delayedExecuteViaMouse = false;
- for (iter = m->down.begin(); iter != m->down.end(); ++iter) {
- AgiMenuOption* d = *iter;
- if (d->index == j)
- return d;
- }
+ _setupMenuColumn = 1;
+ _setupMenuItemColumn = 1;
+
+ _lastSelectedMenuNr = 0;
+
+ _mouseModeItemNr = -1;
- return NULL;
+ _drawnMenuNr = -1;
+ _drawnMenuHeight = 0;
+ _drawnMenuWidth = 0;
+ _drawnMenuY = 0;
+ _drawnMenuX = 0;
}
-void Menu::drawMenuBar() {
- _vm->clearLines(0, 0, MENU_BG);
- _vm->flushLines(0, 0);
+GfxMenu::~GfxMenu() {
+ for (GuiMenuArray::iterator itemIter = _array.begin(); itemIter != _array.end(); ++itemIter)
+ delete *itemIter;
+ _array.clear();
- MenuList::iterator iter;
- for (iter = _menubar.begin(); iter != _menubar.end(); ++iter) {
- AgiMenu *m = *iter;
+ for (GuiMenuItemArray::iterator menuIter = _itemArray.begin(); menuIter != _itemArray.end(); ++menuIter)
+ delete *menuIter;
+ _itemArray.clear();
+}
+
+void GfxMenu::addMenu(const char *menuText) {
+ int16 curColumnEnd = _setupMenuColumn;
+
+ // already submitted? in that case no further changes possible
+ if (_submitted)
+ return;
+
+ GuiMenuEntry *menuEntry = new GuiMenuEntry();
- _vm->printText(m->text, 0, m->col, 0, 40, MENU_FG, MENU_BG);
+ menuEntry->text = menuText;
+ menuEntry->textLen = menuEntry->text.size();
+
+ // Cut menu name in case menu bar is full
+ // Happens in at least the fan game Get Outta Space Quest
+ // Original interpreter had graphical issues in this case
+ // TODO: this whole code needs to get reworked anyway to support different types of menu bars depending on platform
+ curColumnEnd += menuEntry->textLen;
+ while ((menuEntry->textLen) && (curColumnEnd > 40)) {
+ menuEntry->text.deleteLastChar();
+ menuEntry->textLen--;
+ curColumnEnd--;
}
+ menuEntry->row = 0;
+ menuEntry->column = _setupMenuColumn;
+ menuEntry->itemCount = 0;
+ menuEntry->firstItemNr = _itemArray.size();
+ menuEntry->selectedItemNr = menuEntry->firstItemNr;
+ menuEntry->maxItemTextLen = 0;
+ _array.push_back(menuEntry);
+
+ _setupMenuColumn += menuEntry->textLen + 1;
}
-void Menu::drawMenuHilite(int curMenu) {
- AgiMenu *m = getMenu(curMenu);
+void GfxMenu::addMenuItem(const char *menuItemText, uint16 controllerSlot) {
+ int16 arrayCount = _array.size();
- debugC(6, kDebugLevelMenu, "[%s]", m->text);
+ // already submitted? in that case no further changes possible
+ if (_submitted)
+ return;
- _vm->printText(m->text, 0, m->col, 0, 40, MENU_BG, MENU_FG);
- _vm->flushLines(0, 0);
-}
+ if (arrayCount == 0)
+ error("tried to add a menu item before adding an actual menu");
-// draw box and pulldowns.
-void Menu::drawMenuOption(int hMenu) {
- // find which vertical menu it is
- AgiMenu *m = getMenu(hMenu);
+ // go to latest menu entry
+ GuiMenuEntry *curMenuEntry = _array.back();
- _gfx->drawBox(m->wincol * CHAR_COLS, 1 * CHAR_LINES, (m->wincol + m->width + 2) * CHAR_COLS,
- (1 + m->height + 2) * CHAR_LINES, MENU_BG, MENU_LINE, 0);
+ GuiMenuItemEntry *menuItemEntry = new GuiMenuItemEntry();
- MenuOptionList::iterator iter;
+ menuItemEntry->enabled = true;
+ menuItemEntry->text = menuItemText;
+ menuItemEntry->textLen = menuItemEntry->text.size();
+ menuItemEntry->controllerSlot = controllerSlot;
- for (iter = m->down.begin(); iter != m->down.end(); ++iter) {
- AgiMenuOption* d = *iter;
+ // Original interpreter on PC used the length of the first item for drawing
+ // At least in KQ2 on Apple IIgs follow-up items are longer, which would result in graphic glitches.
+ // That's why we remember the longest item and draw according to that
+ if (curMenuEntry->maxItemTextLen < menuItemEntry->textLen) {
+ curMenuEntry->maxItemTextLen = menuItemEntry->textLen;
+ }
- _vm->printText(d->text, 0, m->wincol + 1, d->index + 2, m->width + 2,
- MENU_FG, MENU_BG, !d->enabled);
+ if (curMenuEntry->itemCount == 0) {
+ // for first menu item of menu calculated column
+ if (menuItemEntry->textLen + curMenuEntry->column < (FONT_COLUMN_CHARACTERS - 1)) {
+ _setupMenuItemColumn = curMenuEntry->column;
+ } else {
+ _setupMenuItemColumn = (FONT_COLUMN_CHARACTERS - 1) - menuItemEntry->textLen;
+ }
}
-}
-void Menu::drawMenuOptionHilite(int hMenu, int vMenu) {
- AgiMenu *m = getMenu(hMenu);
- AgiMenuOption *d = getMenuOption(hMenu, vMenu);
+ menuItemEntry->row = 2 + curMenuEntry->itemCount;
+ menuItemEntry->column = _setupMenuItemColumn;
- // Disabled menu items are "greyed out" with a checkerboard effect,
- // rather than having a different color. -- dsymonds
- _vm->printText(d->text, 0, m->wincol + 1, vMenu + 2, m->width + 2,
- MENU_BG, MENU_FG, !d->enabled);
-}
+ _itemArray.push_back(menuItemEntry);
-void Menu::newMenuSelected(int i) {
- _picture->showPic();
- drawMenuBar();
- drawMenuHilite(i);
- drawMenuOption(i);
+ curMenuEntry->itemCount++;
}
-bool Menu::mouseOverText(int line, int col, char *s) {
- if (_vm->_mouse.x < col * CHAR_COLS)
- return false;
-
- if (_vm->_mouse.x > (int)(col + strlen(s)) * CHAR_COLS)
- return false;
-
- if (_vm->_mouse.y < line * CHAR_LINES)
- return false;
+void GfxMenu::submit() {
+ GuiMenuEntry *menuEntry = nullptr;
+ GuiMenuItemEntry *menuItemEntry = nullptr;
+ int16 menuCount = _array.size();
+ int16 menuNr = 0;
+ int16 menuItemNr = 0;
+ int16 menuItemLastNr = 0;
+
+ if ((_array.size() == 0) || (_itemArray.size() == 0))
+ return;
+
+ _submitted = true;
+
+ // WORKAROUND: For Apple II gs we try to fix the menu text
+ // On this platform it seems a system font was used and the menu was drawn differently (probably system menu?)
+ // Still the text was misaligned anyway, but it looks worse in our (the original PC) implementation
+ // Atari ST SQ1 had one bad menu entry as well, we fix that too.
+ switch (_vm->getPlatform()) {
+ case Common::kPlatformApple2GS:
+ case Common::kPlatformAtariST:
+ // Go through all menus
+ for (menuNr = 0; menuNr < menuCount; menuNr++) {
+ menuEntry = _array[menuNr];
+ menuItemLastNr = menuEntry->firstItemNr + menuEntry->itemCount;
+
+ // Go through all items of current menu
+ for (menuItemNr = menuEntry->firstItemNr; menuItemNr < menuItemLastNr; menuItemNr++) {
+ menuItemEntry = _itemArray[menuItemNr];
+
+ if (menuItemEntry->textLen < menuEntry->maxItemTextLen) {
+ // current item text is shorter than the maximum?
+ int16 missingCharCount = menuEntry->maxItemTextLen - menuItemEntry->textLen;
+
+ if (menuItemEntry->text.contains('>')) {
+ // text contains '>', we now try to find a '<'
+ // and then add spaces in case this item is shorter than the first item
+ int16 textPos = menuItemEntry->textLen - 1;
+
+ while (textPos > 0) {
+ if (menuItemEntry->text[textPos] == '<')
+ break;
+ textPos--;
+ }
+
+ if (textPos > 0) {
+ while (missingCharCount) {
+ menuItemEntry->text.insertChar(' ', textPos);
+ missingCharCount--;
+ }
+ }
+ } else {
+ // Also check if text consists only of '-', which is the separator
+ // These were sometimes also too small
+ int16 separatorCount = 0;
+ int16 charPos = 0;
+
+ while (charPos < menuItemEntry->textLen) {
+ if (menuItemEntry->text[charPos] != '-')
+ break;
+ separatorCount++;
+ charPos++;
+ }
+
+ if (separatorCount == menuItemEntry->textLen) {
+ // Separator detected
+ while (missingCharCount) {
+ menuItemEntry->text.insertChar('-', 0);
+ missingCharCount--;
+ }
+ } else {
+ // Append spaces to the end to fill it up
+ int16 textPos = menuItemEntry->textLen;
+ while (missingCharCount) {
+ menuItemEntry->text.insertChar(' ', textPos);
+ textPos++;
+ missingCharCount--;
+ }
+ }
+ }
- if (_vm->_mouse.y >= (line + 1) * CHAR_LINES)
- return false;
+ menuItemEntry->textLen = menuItemEntry->text.size();
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
- return true;
+void GfxMenu::itemEnable(uint16 controllerSlot) {
+ itemEnableDisable(controllerSlot, true);
}
-#if 0
-static void add_about_option() {
- const char *text = "About AGI engine";
-
- agi_menu_option *d = new agi_menu_option;
- d->text = strdup(text);
- d->enabled = true;
- d->event = 255;
- d->index = (v_max_menu[0] += 1);
-
- agi_menu *m = *menubar.begin();
- m->down.push_back(d);
- m->height++;
- if (m->width < (int)strlen(text))
- m->width = strlen(text);
+void GfxMenu::itemDisable(uint16 controllerSlot) {
+ itemEnableDisable(controllerSlot, false);
}
-#endif
-/*
- * Public functions
- */
+void GfxMenu::itemEnableDisable(uint16 controllerSlot, bool enabled) {
+ GuiMenuItemArray::iterator listIterator;
+ GuiMenuItemArray::iterator listEnd = _itemArray.end();
+ GuiMenuItemEntry *menuItemEntry;
-Menu::Menu(AgiEngine *vm, GfxMgr *gfx, PictureMgr *picture) {
- _vm = vm;
- _gfx = gfx;
- _picture = picture;
- _hIndex = 0;
- _hCol = 1;
- _hMaxMenu = 0;
- _hCurMenu = 0;
- _vCurMenu = 0;
-}
+ listIterator = _itemArray.begin();
+ while (listIterator != listEnd) {
+ menuItemEntry = *listIterator;
+ if (menuItemEntry->controllerSlot == controllerSlot) {
+ menuItemEntry->enabled = enabled;
+ }
-Menu::~Menu() {
- MenuList::iterator iterh;
- for (iterh = _menubar.reverse_begin(); iterh != _menubar.end(); ) {
- AgiMenu *m = *iterh;
+ listIterator++;
+ }
+}
- debugC(3, kDebugLevelMenu, "deiniting hmenu %s", m->text);
+void GfxMenu::itemEnableAll() {
+ GuiMenuItemArray::iterator listIterator;
+ GuiMenuItemArray::iterator listEnd = _itemArray.end();
+ GuiMenuItemEntry *menuItemEntry;
- MenuOptionList::iterator iterv;
+ listIterator = _itemArray.begin();
+ while (listIterator != listEnd) {
+ menuItemEntry = *listIterator;
+ menuItemEntry->enabled = true;
- for (iterv = m->down.reverse_begin(); iterv != m->down.end(); ) {
- AgiMenuOption *d = *iterv;
+ listIterator++;
+ }
+}
- debugC(3, kDebugLevelMenu, " deiniting vmenu %s", d->text);
+// return true, in case a menu was actually created and submitted by the scripts
+bool GfxMenu::isAvailable() {
+ return _submitted;
+}
- free(d->text);
- delete d;
+void GfxMenu::accessAllow() {
+ _allowed = true;
+}
- iterv = m->down.reverse_erase(iterv);
- }
- free(m->text);
- delete m;
+void GfxMenu::accessDeny() {
+ _allowed = false;
+}
- iterh = _menubar.reverse_erase(iterh);
- }
+void GfxMenu::delayedExecuteViaKeyboard() {
+ _delayedExecuteViaKeyboard = true;
+ _delayedExecuteViaMouse = false;
+}
+void GfxMenu::delayedExecuteViaMouse() {
+ _delayedExecuteViaKeyboard = false;
+ _delayedExecuteViaMouse = true;
}
-void Menu::add(const char *s) {
- AgiMenu *m = new AgiMenu;
- m->text = strdup(s);
-
- while (m->text[strlen(m->text) - 1] == ' ')
- m->text[strlen(m->text) - 1] = 0;
-
- m->width = 0;
- m->height = 0;
- m->index = _hIndex++;
- m->col = _hCol;
- m->wincol = _hCol - 1;
- _vIndex = 0;
- _vMaxMenu[m->index] = 0;
- _hCol += strlen(m->text) + 1;
- _hMaxMenu = m->index;
-
- debugC(3, kDebugLevelMenu, "add menu: '%s' %02x", s, m->text[strlen(m->text)]);
- _menubar.push_back(m);
+bool GfxMenu::delayedExecuteActive() {
+ return _delayedExecuteViaKeyboard | _delayedExecuteViaMouse;
}
-void Menu::addItem(const char *s, int code) {
- int l;
+void GfxMenu::execute() {
+ bool viaKeyboard = _delayedExecuteViaKeyboard;
+ bool viaMouse = _delayedExecuteViaMouse;
+ _delayedExecuteViaKeyboard = false;
+ _delayedExecuteViaMouse = false;
- AgiMenuOption* d = new AgiMenuOption;
+ // got submitted? -> safety check
+ if (!_submitted)
+ return;
- d->text = strdup(s);
- d->enabled = true;
- d->event = code;
- d->index = _vIndex++;
+ // access allowed at the moment?
+ if (!_allowed)
+ return;
- // add to last menu in list
- assert(_menubar.reverse_begin() != _menubar.end());
- AgiMenu *m = *_menubar.reverse_begin();
- m->height++;
+ _text->charPos_Push();
+ _text->charAttrib_Push();
+ _text->clearLine(0, _text->calculateTextBackground(15));
- _vMaxMenu[m->index] = d->index;
+ // Draw all menus
+ for (uint16 menuNr = 0; menuNr < _array.size(); menuNr++) {
+ drawMenuName(menuNr, false);
+ }
- l = strlen(d->text);
- if (l > 40)
- l = 38;
- if (m->wincol + l > 38)
- m->wincol = 38 - l;
- if (l > m->width)
- m->width = l;
+ // Draw last selected menu
+ _drawnMenuNr = _lastSelectedMenuNr;
- debugC(3, kDebugLevelMenu, "Adding menu item: %s (size = %d)", s, m->height);
+ // Unless we are in "via mouse" mode. In that case check current mouse position
+ if (viaMouse) {
+ int16 mouseRow = _vm->_mouse.pos.y;
+ int16 mouseColumn = _vm->_mouse.pos.x;
+ _gfx->translateDisplayPosToFontScreen(mouseColumn, mouseRow);
- m->down.push_back(d);
-}
+ mouseFindMenuSelection(mouseRow, mouseColumn, _drawnMenuNr, _mouseModeItemNr);
+ }
-void Menu::submit() {
- debugC(3, kDebugLevelMenu, "Submitting menu");
+ if (_drawnMenuNr >= 0) {
+ if (viaKeyboard) {
+ drawMenu(_drawnMenuNr, _array[_drawnMenuNr]->selectedItemNr);
+ }
+ if (viaMouse) {
+ drawMenu(_drawnMenuNr, _mouseModeItemNr);
+ }
+ }
- // add_about_option ();
+ if (viaKeyboard) {
+ _vm->cycleInnerLoopActive(CYCLE_INNERLOOP_MENU_VIA_KEYBOARD);
+ } else if (viaMouse) {
+ _vm->cycleInnerLoopActive(CYCLE_INNERLOOP_MENU_VIA_MOUSE);
+ }
- // If a menu has no options, delete it
- MenuList::iterator iter;
- for (iter = _menubar.reverse_begin(); iter != _menubar.end(); ) {
- AgiMenu *m = *iter;
+ do {
+ _vm->processAGIEvents();
+ } while (_vm->cycleInnerLoopIsActive() && !(_vm->shouldQuit() || _vm->_restartGame));
- if (m->down.empty()) {
- free(m->text);
- delete m;
+ if (_drawnMenuNr >= 0) {
+ removeActiveMenu(_drawnMenuNr);
+ }
- _hMaxMenu--;
+ if (viaKeyboard) {
+ // In "via Keyboard" mode, remember last selection
+ _lastSelectedMenuNr = _drawnMenuNr;
+ }
- iter = _menubar.reverse_erase(iter);
+ _text->charAttrib_Pop();
+ _text->charPos_Pop();
+
+ // Restore status line
+ if (_text->statusEnabled()) {
+ _text->statusDraw();
+ } else {
+ if (_text->getWindowRowMin() == 0) {
+ // WORKAROUND: Playarea starts right at the stop, so instead of clearing that part, render it from playarea
+ // Required for at least Donald Duck
+ // This was not done by original AGI, which means the upper pixel line were cleared in this case.
+ _gfx->render_Block(0, 0, SCRIPT_WIDTH, FONT_VISUAL_HEIGHT);
} else {
- --iter;
+ _text->clearLine(0, 0);
}
}
}
-bool Menu::keyhandler(int key) {
- static int clockVal;
- static int menuActive = false;
- static int buttonUsed = 0;
- bool exitMenu = false;
+void GfxMenu::drawMenuName(int16 menuNr, bool inverted) {
+ GuiMenuEntry *menuEntry = _array[menuNr];
+ bool disabledLook = false;
- if (!_vm->getflag(fMenusWork) && !(_vm->getFeatures() & GF_MENUS))
- return false;
+ // Don't draw in case there is no text
+ if (!menuEntry->text.size())
+ return;
- if (!menuActive) {
- clockVal = _vm->_game.clockEnabled;
- _vm->_game.clockEnabled = false;
- drawMenuBar();
+ if (!inverted) {
+ _text->charAttrib_Set(0, _text->calculateTextBackground(15));
+ } else {
+ _text->charAttrib_Set(15, _text->calculateTextBackground(0));
}
- // Mouse handling
- if (_vm->_mouse.button) {
- int hmenu, vmenu;
+ _text->charPos_Set(menuEntry->row, menuEntry->column);
- buttonUsed = 1; // Button has been used at least once
+ if (menuEntry->itemCount == 0)
+ disabledLook = true;
- if (_vm->_mouse.y <= CHAR_LINES) {
- // on the menubar
- hmenu = 0;
+ _text->displayText(menuEntry->text.c_str(), disabledLook);
+}
- MenuList::iterator iterh;
+void GfxMenu::drawItemName(int16 itemNr, bool inverted) {
+ GuiMenuItemEntry *itemEntry = _itemArray[itemNr];
+ bool disabledLook = false;
- for (iterh = _menubar.begin(); iterh != _menubar.end(); ++iterh) {
- AgiMenu *m = *iterh;
+ if (!inverted) {
+ _text->charAttrib_Set(0, _text->calculateTextBackground(15));
+ } else {
+ _text->charAttrib_Set(15, _text->calculateTextBackground(0));
+ }
- if (mouseOverText(0, m->col, m->text)) {
- break;
- } else {
- hmenu++;
- }
- }
+ _text->charPos_Set(itemEntry->row, itemEntry->column);
- if (hmenu <= _hMaxMenu) {
- if (_hCurMenu != hmenu) {
- _vCurMenu = -1;
- newMenuSelected(hmenu);
- }
- _hCurMenu = hmenu;
- }
- } else {
- // not in menubar
- vmenu = 0;
+ if (itemEntry->enabled == false)
+ disabledLook = true;
- AgiMenu *m = getMenu(_hCurMenu);
+ _text->displayText(itemEntry->text.c_str(), disabledLook);
+}
- MenuOptionList::iterator iterv;
+void GfxMenu::drawMenu(int16 selectedMenuNr, int16 selectedMenuItemNr) {
+ GuiMenuEntry *menuEntry = _array[selectedMenuNr];
+ GuiMenuItemEntry *itemEntry = _itemArray[menuEntry->firstItemNr];
+ int16 itemNr = menuEntry->firstItemNr;
+ int16 itemCount = menuEntry->itemCount;
- for (iterv = m->down.begin(); iterv != m->down.end(); ++iterv) {
- AgiMenuOption *do1 = *iterv;
+ // draw menu name as inverted
+ drawMenuName(selectedMenuNr, true);
- if (mouseOverText(2 + do1->index, m->wincol + 1, do1->text)) {
- break;
- } else {
- vmenu++;
- }
- }
+ // calculate active menu dimensions
+ _drawnMenuHeight = (menuEntry->itemCount + 2) * FONT_VISUAL_HEIGHT;
+ _drawnMenuWidth = (menuEntry->maxItemTextLen * FONT_VISUAL_WIDTH) + 8;
+ _drawnMenuY = (1 - _text->getWindowRowMin()) * FONT_VISUAL_HEIGHT;
+ //(menuEntry->itemCount + 3 - _text->getWindowRowMin()) * FONT_VISUAL_HEIGHT - 1;
+ _drawnMenuX = (itemEntry->column - 1) * FONT_VISUAL_WIDTH;
- if (vmenu <= _vMaxMenu[_hCurMenu]) {
- if (_vCurMenu != vmenu) {
- drawMenuOption(_hCurMenu);
- drawMenuOptionHilite(_hCurMenu, vmenu);
- }
- _vCurMenu = vmenu;
- }
- }
- } else if (buttonUsed) {
- // Button released
- buttonUsed = 0;
+ _gfx->drawBox(_drawnMenuX, _drawnMenuY, _drawnMenuWidth, _drawnMenuHeight, 15, 0);
- debugC(6, kDebugLevelMenu | kDebugLevelInput, "button released!");
+ while (itemCount) {
+ if (itemNr == selectedMenuItemNr) {
+ drawItemName(itemNr, true);
+ } else {
+ drawItemName(itemNr, false);
+ }
+ itemNr++;
+ itemCount--;
+ }
+}
- if (_vCurMenu < 0)
- _vCurMenu = 0;
+void GfxMenu::removeActiveMenu(int16 selectedMenuNr) {
+ // draw menu name normally again
+ drawMenuName(selectedMenuNr, false);
- drawMenuOptionHilite(_hCurMenu, _vCurMenu);
+ // overwrite actual menu items by rendering play screen
+ _gfx->render_Block(_drawnMenuX, _drawnMenuY, _drawnMenuWidth, _drawnMenuHeight);
+}
- if (_vm->_mouse.y <= CHAR_LINES) {
- // on the menubar
- } else {
- // see which option we selected
- AgiMenu *m = getMenu(_hCurMenu);
- MenuOptionList::iterator iterv;
-
- for (iterv = m->down.begin(); iterv != m->down.end(); ++iterv) {
- AgiMenuOption *d = *iterv;
-
- if (mouseOverText(2 + d->index, m->wincol + 1, d->text)) {
- // activate that option
- if (d->enabled) {
- debugC(6, kDebugLevelMenu | kDebugLevelInput, "event %d registered", d->event);
- _vm->_game.controllerOccured[d->event] = true;
- _vm->_menuSelected = true;
- break;
- }
- }
- }
- exitMenu = true;
- }
+void GfxMenu::keyPress(uint16 newKey) {
+ GuiMenuEntry *menuEntry = _array[_drawnMenuNr];
+ GuiMenuItemEntry *itemEntry = _itemArray[menuEntry->selectedItemNr];
+ int16 newMenuNr = _drawnMenuNr;
+ int16 newItemNr = menuEntry->selectedItemNr;
+
+ switch (newKey) {
+ case AGI_KEY_ENTER:
+ // check, if current item is actually enabled
+ if (!itemEntry->enabled)
+ return;
+
+ // Trigger controller
+ _vm->_game.controllerOccured[itemEntry->controllerSlot] = true;
+
+ _vm->cycleInnerLoopInactive(); // exit execute-loop
+ break;
+ case AGI_KEY_ESCAPE:
+ _vm->cycleInnerLoopInactive(); // exit execute-loop
+ break;
+
+ // these here change menu item
+ case AGI_KEY_UP:
+ newItemNr--;
+ break;
+ case AGI_KEY_DOWN:
+ newItemNr++;
+ break;
+ case AGI_KEY_PAGE_UP:
+ // select first item of current menu
+ newItemNr = menuEntry->firstItemNr;
+ break;
+ case AGI_KEY_PAGE_DOWN:
+ // select last item of current menu
+ newItemNr = menuEntry->firstItemNr + menuEntry->itemCount - 1;
+ break;
+
+ case AGI_KEY_LEFT:
+ newMenuNr--;
+ break;
+ case AGI_KEY_RIGHT:
+ newMenuNr++;
+ break;
+ case AGI_KEY_HOME:
+ // select first menu
+ newMenuNr = 0;
+ break;
+ case AGI_KEY_END:
+ // select last menu
+ newMenuNr = _array.size() - 1;
+ break;
+
+ default:
+ break;
}
- if (!exitMenu) {
- if (!menuActive) {
- if (_hCurMenu >= 0) {
- drawMenuHilite(_hCurMenu);
- drawMenuOption(_hCurMenu);
- if (!buttonUsed && _vCurMenu >= 0)
- drawMenuOptionHilite(_hCurMenu, _vCurMenu);
- }
- menuActive = true;
- }
+ if (newMenuNr != _drawnMenuNr) {
+ // selected menu was changed
+ int16 lastMenuNr = _array.size() - 1;
- switch (key) {
- case KEY_ESCAPE:
- debugC(6, kDebugLevelMenu | kDebugLevelInput, "KEY_ESCAPE");
- exitMenu = true;
- break;
- case KEY_ENTER:
- {
- debugC(6, kDebugLevelMenu | kDebugLevelInput, "KEY_ENTER");
- AgiMenuOption* d = getMenuOption(_hCurMenu, _vCurMenu);
-
- if (d->enabled) {
- debugC(6, kDebugLevelMenu | kDebugLevelInput, "event %d registered", d->event);
- _vm->_game.controllerOccured[d->event] = true;
- _vm->_menuSelected = true;
- exitMenu = true;
- }
- break;
+ if (newMenuNr < 0) {
+ newMenuNr = lastMenuNr;
+ } else if (newMenuNr > lastMenuNr) {
+ newMenuNr = 0;
}
- case KEY_DOWN:
- case KEY_UP:
- _vCurMenu += key == KEY_DOWN ? 1 : -1;
-
- if (_vCurMenu < 0)
- _vCurMenu = _vMaxMenu[_hCurMenu];
- if (_vCurMenu > _vMaxMenu[_hCurMenu])
- _vCurMenu = 0;
-
- drawMenuOption(_hCurMenu);
- drawMenuOptionHilite(_hCurMenu, _vCurMenu);
- break;
- case KEY_RIGHT:
- case KEY_LEFT:
- _hCurMenu += key == KEY_RIGHT ? 1 : -1;
-
- if (_hCurMenu < 0)
- _hCurMenu = _hMaxMenu;
- if (_hCurMenu > _hMaxMenu)
- _hCurMenu = 0;
-
- _vCurMenu = 0;
- newMenuSelected(_hCurMenu);
- drawMenuOptionHilite(_hCurMenu, _vCurMenu);
- break;
+
+ if (newMenuNr != _drawnMenuNr) {
+ removeActiveMenu(_drawnMenuNr);
+ _drawnMenuNr = newMenuNr;
+ drawMenu(_drawnMenuNr, _array[_drawnMenuNr]->selectedItemNr);
}
}
- if (exitMenu) {
- buttonUsed = 0;
- _picture->showPic();
- _vm->writeStatus();
+ if (newItemNr != menuEntry->selectedItemNr) {
+ // selected item was changed
+ int16 lastItemNr = menuEntry->firstItemNr + menuEntry->itemCount - 1;
- _vm->setvar(vKey, 0);
- _vm->_game.keypress = 0;
- _vm->_game.clockEnabled = clockVal;
- _vm->oldInputMode();
+ if (newItemNr < menuEntry->firstItemNr) {
+ newItemNr = lastItemNr;
+ } else if (newItemNr > lastItemNr) {
+ newItemNr = menuEntry->firstItemNr;
+ }
- debugC(3, kDebugLevelMenu, "exit_menu: input mode reset to %d", _vm->_game.inputMode);
- menuActive = false;
+ if (newItemNr != menuEntry->selectedItemNr) {
+ // still changed after clip -> draw changes
+ drawItemName(menuEntry->selectedItemNr, false);
+ drawItemName(newItemNr, true);
+ menuEntry->selectedItemNr = newItemNr;
+ }
}
-
- return true;
}
-void Menu::setItem(int event, int state) {
- // scan all menus for event number #
+// This gets called:
+// During "via keyboard" mode in case user actively clicks on something
+// During "via mouse" mode all the time, so that current mouse cursor position modifies active selection
+// In "via mouse" mode, we check if user let go of the left mouse button and then select the item that way
+void GfxMenu::mouseEvent(uint16 newKey) {
+ // Find out, where current mouse cursor actually is
+ int16 mouseRow = _vm->_mouse.pos.y;
+ int16 mouseColumn = _vm->_mouse.pos.x;
+
+ _gfx->translateDisplayPosToFontScreen(mouseColumn, mouseRow);
+
+ int16 activeMenuNr, activeItemNr;
+ mouseFindMenuSelection(mouseRow, mouseColumn, activeMenuNr, activeItemNr);
- debugC(6, kDebugLevelMenu, "event = %d, state = %d", event, state);
- MenuList::iterator iterh;
+ switch (newKey) {
+ case AGI_MOUSE_BUTTON_LEFT:
+ // User clicked somewhere, in this case check if user clicked on status bar or on one of the currently shown menu items
+ // Happens in "via keyboard" mode only
+ // We do not close menu in case user clicked on something invalid
- for (iterh = _menubar.begin(); iterh != _menubar.end(); ++iterh) {
- AgiMenu *m = *iterh;
- MenuOptionList::iterator iterv;
+ if (activeItemNr >= 0) {
+ GuiMenuItemEntry *itemEntry = _itemArray[activeItemNr];
+ if (!itemEntry->enabled)
+ return;
- for (iterv = m->down.begin(); iterv != m->down.end(); ++iterv) {
- AgiMenuOption *d = *iterv;
+ // Trigger controller
+ _vm->_game.controllerOccured[itemEntry->controllerSlot] = true;
- if (d->event == event) {
- d->enabled = state;
- // keep going; we need to set the state of every menu item
- // with this event code. -- dsymonds
+ _vm->cycleInnerLoopInactive(); // exit execute-loop
+ return;
+ }
+ if (activeMenuNr >= 0) {
+ // User clicked on a menu, check if that menu is already active
+ if (activeMenuNr != _drawnMenuNr) {
+ removeActiveMenu(_drawnMenuNr);
+ _drawnMenuNr = activeMenuNr;
+ drawMenu(_drawnMenuNr, _array[_drawnMenuNr]->selectedItemNr);
}
}
+ return; // exit all the time, we do not want to change the user selection while in "via keyboard" mode
+ break;
+ default:
+ break;
}
-}
-void Menu::enableAll() {
- MenuList::iterator iterh;
- for (iterh = _menubar.begin(); iterh != _menubar.end(); ++iterh) {
- AgiMenu *m = *iterh;
- MenuOptionList::iterator iterv;
+ // If mouse is not selecting any menu, just use the last menu instead
+ if (activeMenuNr < 0) {
+ activeMenuNr = _drawnMenuNr;
+ }
- for (iterv = m->down.begin(); iterv != m->down.end(); ++iterv) {
- AgiMenuOption *d = *iterv;
+ if (activeMenuNr != _drawnMenuNr) {
+ if (_drawnMenuNr >= 0) {
+ removeActiveMenu(_drawnMenuNr);
+ }
- d->enabled = true;
+ _drawnMenuNr = activeMenuNr;
+
+ if (_drawnMenuNr >= 0) {
+ drawMenu(_drawnMenuNr, activeItemNr);
}
+ _mouseModeItemNr = activeItemNr;
}
-}
-
-AgiTextColor AgiButtonStyle::getColor(bool hasFocus, bool pressed, bool positive) const {
- if (_amigaStyle) {
- if (positive) {
- if (pressed) { // Positive pressed Amiga-style button
- if (_olderAgi) {
- return AgiTextColor(amigaBlack, amigaOrange);
- } else {
- return AgiTextColor(amigaBlack, amigaPurple);
- }
- } else { // Positive unpressed Amiga-style button
- return AgiTextColor(amigaWhite, amigaGreen);
- }
- } else { // _amigaStyle && !positive
- if (pressed) { // Negative pressed Amiga-style button
- return AgiTextColor(amigaBlack, amigaCyan);
- } else { // Negative unpressed Amiga-style button
- return AgiTextColor(amigaWhite, amigaRed);
- }
+ if (activeItemNr != _mouseModeItemNr) {
+ if (_mouseModeItemNr >= 0) {
+ drawItemName(_mouseModeItemNr, false);
}
- } else { // PC-style button
- if (hasFocus || pressed) { // A pressed or in focus PC-style button
- return AgiTextColor(pcWhite, pcBlack);
- } else { // An unpressed PC-style button without focus
- return AgiTextColor(pcBlack, pcWhite);
+ if (activeItemNr >= 0) {
+ drawItemName(activeItemNr, true);
}
+ _mouseModeItemNr = activeItemNr;
}
-}
-AgiTextColor AgiButtonStyle::getColor(bool hasFocus, bool pressed, int baseFgColor, int baseBgColor) const {
- return getColor(hasFocus, pressed, AgiTextColor(baseFgColor, baseBgColor));
-}
-
-AgiTextColor AgiButtonStyle::getColor(bool hasFocus, bool pressed, const AgiTextColor &baseColor) const {
- if (hasFocus || pressed)
- return baseColor.swap();
- else
- return baseColor;
-}
+ if (_vm->_mouse.button == kAgiMouseButtonUp) {
+ // User has stopped pressing the mouse button, if any item number is selected -> execute it
+ if (activeItemNr >= 0) {
+ GuiMenuItemEntry *itemEntry = _itemArray[activeItemNr];
+ if (itemEntry->enabled) {
+ // Trigger controller
+ _vm->_game.controllerOccured[itemEntry->controllerSlot] = true;
+ }
+ }
-int AgiButtonStyle::getTextOffset(bool hasFocus, bool pressed) const {
- return (pressed && !_amigaStyle) ? 1 : 0;
+ _vm->cycleInnerLoopInactive(); // exit execute-loop
+ return;
+ }
}
-bool AgiButtonStyle::getBorder(bool hasFocus, bool pressed) const {
- return _amigaStyle && !_authenticAmiga && (hasFocus || pressed);
-}
+void GfxMenu::mouseFindMenuSelection(int16 mouseRow, int16 mouseColumn, int16 &activeMenuNr, int16 &activeMenuItemNr) {
+ GuiMenuEntry *menuEntry = nullptr;
+ int16 menuCount = _array.size();
-void AgiButtonStyle::setAmigaStyle(bool amigaStyle, bool olderAgi, bool authenticAmiga) {
- _amigaStyle = amigaStyle;
- _olderAgi = olderAgi;
- _authenticAmiga = authenticAmiga;
-}
+ for (int16 menuNr = 0; menuNr < menuCount; menuNr++) {
+ menuEntry = _array[menuNr];
-void AgiButtonStyle::setPcStyle(bool pcStyle) {
- setAmigaStyle(!pcStyle);
-}
+ if (mouseRow == menuEntry->row) {
+ // line match
+ if ((mouseColumn >= menuEntry->column) && (mouseColumn < (menuEntry->column + menuEntry->textLen))) {
+ // full match
+ activeMenuNr = menuNr;
+ activeMenuItemNr = -1; // no item selected
+ return;
+ }
+ }
+ }
-AgiButtonStyle::AgiButtonStyle(Common::RenderMode renderMode) {
- setAmigaStyle(renderMode == Common::kRenderAmiga);
+ // Now also check current menu
+ if (_drawnMenuNr >= 0) {
+ // A menu is currently shown
+ menuEntry = _array[_drawnMenuNr];
+
+ int16 itemNr = menuEntry->firstItemNr;
+ int16 itemCount = menuEntry->itemCount;
+
+ while (itemCount) {
+ GuiMenuItemEntry *itemEntry = _itemArray[itemNr];
+
+ if (mouseRow == itemEntry->row) {
+ // line match
+ if ((mouseColumn >= itemEntry->column) && (mouseColumn < (itemEntry->column + itemEntry->textLen))) {
+ // full match
+ if (itemEntry->enabled) {
+ // Only see it, when it's currently enabled
+ activeMenuNr = _drawnMenuNr;
+ activeMenuItemNr = itemNr;
+ return;
+ }
+ }
+ }
+ itemNr++;
+ itemCount--;
+ }
+ }
+ activeMenuNr = -1;
+ activeMenuItemNr = -1;
+ return;
}
} // End of namespace Agi
diff --git a/engines/agi/menu.h b/engines/agi/menu.h
index 000973db23..b47289180b 100644
--- a/engines/agi/menu.h
+++ b/engines/agi/menu.h
@@ -25,58 +25,97 @@
namespace Agi {
-#define MENU_BG 0x0f // White
-#define MENU_DISABLED 0x07 // Grey
+struct GuiMenuEntry {
+ Common::String text;
+ int16 textLen;
-#define MENU_FG 0x00 // Black
-#define MENU_LINE 0x00 // Black
+ int16 row;
+ int16 column;
-struct AgiMenu;
-struct AgiMenuOption;
-typedef Common::List<AgiMenu *> MenuList;
-typedef Common::List<AgiMenuOption *> MenuOptionList;
+ int16 itemCount; // total number of menu items
+ int16 firstItemNr; // first menu item number, points into _itemArray[]
-class GfxMgr;
-class PictureMgr;
+ int16 selectedItemNr; // currently selected menu item
+
+ int16 maxItemTextLen; // maximum text length of all menu items
+};
+typedef Common::Array<GuiMenuEntry *> GuiMenuArray;
+
+struct GuiMenuItemEntry {
+ Common::String text;
+ int16 textLen;
+
+ int16 row;
+ int16 column;
+
+ bool enabled; // enabled-state, set by scripts
+ uint16 controllerSlot; // controller to trigger, when item is executed
+};
+typedef Common::Array<GuiMenuItemEntry *> GuiMenuItemArray;
+
+class GfxMenu {
+public:
+ GfxMenu(AgiEngine *vm, GfxMgr *gfx, PictureMgr *picture, TextMgr *text);
+ ~GfxMenu();
+
+ void addMenu(const char *menuText);
+ void addMenuItem(const char *menuText, uint16 controlCode);
+ void submit();
+ void itemEnable(uint16 controllerSlot);
+ void itemDisable(uint16 controllerSlot);
+ void itemEnableAll();
+
+ void keyPress(uint16 newKey);
+ void mouseEvent(uint16 newKey);
+
+ bool isAvailable();
+
+ void accessAllow();
+ void accessDeny();
+
+ void delayedExecuteViaKeyboard();
+ void delayedExecuteViaMouse();
+ bool delayedExecuteActive();
+ void execute();
-class Menu {
private:
+ void itemEnableDisable(uint16 controllerSlot, bool enabled);
+
+ void drawMenuName(int16 menuNr, bool inverted);
+ void drawItemName(int16 itemNr, bool inverted);
+ void drawMenu(int16 selectedMenuNr, int16 selectedMenuItemNr);
+ void removeActiveMenu(int16 selectedMenuNr);
+
+ void mouseFindMenuSelection(int16 mouseRow, int16 mouseColumn, int16 &activeMenuNr, int16 &activeMenuItemNr);
+
AgiEngine *_vm;
GfxMgr *_gfx;
PictureMgr *_picture;
+ TextMgr *_text;
-public:
- Menu(AgiEngine *vm, GfxMgr *gfx, PictureMgr *picture);
- ~Menu();
+ bool _allowed;
+ bool _submitted;
+ bool _delayedExecuteViaKeyboard;
+ bool _delayedExecuteViaMouse;
- void add(const char *s);
- void addItem(const char *s, int code);
- void submit();
- void setItem(int event, int state);
- bool keyhandler(int key);
- void enableAll();
+ // for initial setup of the menu
+ int16 _setupMenuColumn;
+ int16 _setupMenuItemColumn;
-private:
- MenuList _menubar;
-
- int _hCurMenu;
- int _vCurMenu;
-
- int _hIndex;
- int _vIndex;
- int _hCol;
- int _hMaxMenu;
- int _vMaxMenu[10];
-
- AgiMenu* getMenu(int i);
- AgiMenuOption *getMenuOption(int i, int j);
- void drawMenuBar();
- void drawMenuHilite(int curMenu);
- void drawMenuOption(int hMenu);
- void drawMenuOptionHilite(int hMenu, int vMenu);
- void newMenuSelected(int i);
- bool mouseOverText(int line, int col, char *s);
+ GuiMenuArray _array;
+ GuiMenuItemArray _itemArray;
+
+ int16 _lastSelectedMenuNr; // only used for "via keyboard" mode
+
+ int16 _drawnMenuNr;
+
+ uint16 _drawnMenuHeight;
+ uint16 _drawnMenuWidth;
+ int16 _drawnMenuY;
+ int16 _drawnMenuX;
+ // Following variables are used in "via mouse" mode
+ int16 _mouseModeItemNr;
};
} // End of namespace Agi
diff --git a/engines/agi/module.mk b/engines/agi/module.mk
index 331a10c16e..32c3ac23ed 100644
--- a/engines/agi/module.mk
+++ b/engines/agi/module.mk
@@ -6,6 +6,7 @@ MODULE_OBJS := \
console.o \
cycle.o \
detection.o \
+ font.o \
global.o \
graphics.o \
id.o \
@@ -36,6 +37,7 @@ MODULE_OBJS := \
sound_pcjr.o \
sound_sarien.o \
sprite.o \
+ systemui.o \
text.o \
view.o \
wagparser.o \
diff --git a/engines/agi/motion.cpp b/engines/agi/motion.cpp
index 363291ac0b..f408ba35e6 100644
--- a/engines/agi/motion.cpp
+++ b/engines/agi/motion.cpp
@@ -29,7 +29,7 @@ int AgiEngine::checkStep(int delta, int step) {
return (-step >= delta) ? 0 : (step <= delta) ? 2 : 1;
}
-int AgiEngine::checkBlock(int x, int y) {
+bool AgiEngine::checkBlock(int16 x, int16 y) {
if (x <= _game.block.x1 || x >= _game.block.x2)
return false;
@@ -39,87 +39,144 @@ int AgiEngine::checkBlock(int x, int y) {
return true;
}
-void AgiEngine::changePos(VtEntry *v) {
- int b, x, y;
+void AgiEngine::changePos(ScreenObjEntry *screenObj) {
+ bool insideBlock;
+ int16 x, y;
int dx[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 };
int dy[9] = { 0, -1, -1, 0, 1, 1, 1, 0, -1 };
- x = v->xPos;
- y = v->yPos;
- b = checkBlock(x, y);
+ x = screenObj->xPos;
+ y = screenObj->yPos;
+ insideBlock = checkBlock(x, y);
- x += v->stepSize * dx[v->direction];
- y += v->stepSize * dy[v->direction];
+ x += screenObj->stepSize * dx[screenObj->direction];
+ y += screenObj->stepSize * dy[screenObj->direction];
- if (checkBlock(x, y) == b) {
- v->flags &= ~fMotion;
+ if (checkBlock(x, y) == insideBlock) {
+ screenObj->flags &= ~fMotion;
} else {
- v->flags |= fMotion;
- v->direction = 0;
- if (isEgoView(v))
- _game.vars[vEgoDir] = 0;
+ screenObj->flags |= fMotion;
+ screenObj->direction = 0;
+ if (isEgoView(screenObj))
+ setVar(VM_VAR_EGO_DIRECTION, 0);
}
}
-void AgiEngine::motionWander(VtEntry *v) {
- if (v->parm1--) {
- if (~v->flags & fDidntMove)
- return;
+// WORKAROUND:
+// A motion was just activated, check if "end.of.loop"/"reverse.loop" is currently active for the same screen object
+// If this is the case, it would result in some random flag getting overwritten in original AGI after the loop was
+// completed, because in original AGI loop_flag + wander_count/follow_stepSize/move_X shared the same memory location.
+// This is basically an implementation error in the original interpreter.
+// Happens in at least:
+// - BC: right at the end when the witches disappear at least on Apple IIgs (room 12, screen object 13, view 84)
+// - KQ1: when grabbing the eagle (room 22).
+// - KQ2: happened somewhere in the game, LordHoto couldn't remember exactly where
+void AgiEngine::motionActivated(ScreenObjEntry *screenObj) {
+ if (screenObj->flags & fCycling) {
+ // Cycling active too
+ switch (screenObj->cycle) {
+ case kCycleEndOfLoop: // "end.of.loop"
+ case kCycleRevLoop: // "reverse.loop"
+ // Disable it
+ screenObj->flags &= ~fCycling;
+ screenObj->cycle = kCycleNormal;
+
+ warning("Motion activated for screen object %d, but cycler also active", screenObj->objectNr);
+ warning("This would have resulted in flag corruption in original AGI. Cycler disabled.");
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+// WORKAROUND:
+// See comment for motionActivated()
+// This way no flag would have been overwritten, but certain other variables of the motions.
+void AgiEngine::cyclerActivated(ScreenObjEntry *screenObj) {
+ switch (screenObj->motionType) {
+ case kMotionWander:
+ // this would have resulted in wander_count to get corrupted
+ // We don't stop it.
+ break;
+ case kMotionFollowEgo:
+ // this would have resulted in follow_stepSize to get corrupted
+ // do not stop motion atm - screenObj->direction = 0;
+ // do not stop motion atm - screenObj->motionType = kMotionNormal;
+ break;
+ case kMotionMoveObj:
+ // this would have resulted in move_x to get corrupted
+ // do not stop motion atm - motionMoveObjStop(screenObj);
+ break;
+ default:
+ return;
+ break;
}
+ warning("Cycler activated for screen object %d, but motion also active", screenObj->objectNr);
+ warning("This would have resulted in corruption in original AGI. Motion disabled.");
+}
+
+void AgiEngine::motionWander(ScreenObjEntry *screenObj) {
+ uint8 originalWanderCount = screenObj->wander_count;
- v->direction = _rnd->getRandomNumber(8);
+ screenObj->wander_count--;
+ if ((originalWanderCount == 0) || (screenObj->flags & fDidntMove)) {
+ screenObj->direction = _rnd->getRandomNumber(8);
- if (isEgoView(v)) {
- _game.vars[vEgoDir] = v->direction;
- while (v->parm1 < 6) {
- v->parm1 = _rnd->getRandomNumber(50); // huh?
+ if (isEgoView(screenObj)) {
+ setVar(VM_VAR_EGO_DIRECTION, screenObj->direction);
+ }
+
+ while (screenObj->wander_count < 6) {
+ screenObj->wander_count = _rnd->getRandomNumber(50); // huh?
}
}
}
-void AgiEngine::motionFollowEgo(VtEntry *v) {
+void AgiEngine::motionFollowEgo(ScreenObjEntry *screenObj) {
+ ScreenObjEntry *screenObjEgo = &_game.screenObjTable[SCREENOBJECTS_EGO_ENTRY];
int egoX, egoY;
int objX, objY;
int dir;
- egoX = _game.viewTable[0].xPos + _game.viewTable[0].xSize / 2;
- egoY = _game.viewTable[0].yPos;
+ egoX = screenObjEgo->xPos + screenObjEgo->xSize / 2;
+ egoY = screenObjEgo->yPos;
- objX = v->xPos + v->xSize / 2;
- objY = v->yPos;
+ objX = screenObj->xPos + screenObj->xSize / 2;
+ objY = screenObj->yPos;
// Get direction to reach ego
- dir = getDirection(objX, objY, egoX, egoY, v->parm1);
+ dir = getDirection(objX, objY, egoX, egoY, screenObj->follow_stepSize);
// Already at ego coordinates
if (dir == 0) {
- v->direction = 0;
- v->motion = kMotionNormal;
- setflag(v->parm2, true);
+ screenObj->direction = 0;
+ screenObj->motionType = kMotionNormal;
+ setFlag(screenObj->follow_flag, true);
return;
}
- if (v->parm3 == 0xff) {
- v->parm3 = 0;
- } else if (v->flags & fDidntMove) {
+ if (screenObj->follow_count == 0xff) {
+ screenObj->follow_count = 0;
+ } else if (screenObj->flags & fDidntMove) {
int d;
- while ((v->direction = _rnd->getRandomNumber(8)) == 0) {
+ while ((screenObj->direction = _rnd->getRandomNumber(8)) == 0) {
}
d = (ABS(egoY - objY) + ABS(egoX - objX)) / 2;
- if (d < v->stepSize) {
- v->parm3 = v->stepSize;
+ if (d < screenObj->stepSize) {
+ screenObj->follow_count = screenObj->stepSize;
return;
}
- while ((v->parm3 = _rnd->getRandomNumber(d)) < v->stepSize) {
+ while ((screenObj->follow_count = _rnd->getRandomNumber(d)) < screenObj->stepSize) {
}
return;
}
- if (v->parm3 != 0) {
+ if (screenObj->follow_count != 0) {
int k;
// DF: this is ugly and I dont know why this works, but
@@ -128,45 +185,46 @@ void AgiEngine::motionFollowEgo(VtEntry *v) {
// if (((int8)v->parm3 -= v->step_size) < 0)
// v->parm3 = 0;
- k = v->parm3;
- k -= v->stepSize;
- v->parm3 = k;
+ k = screenObj->follow_count;
+ k -= screenObj->stepSize;
+ screenObj->follow_count = k;
- if ((int8) v->parm3 < 0)
- v->parm3 = 0;
+ if ((int8) screenObj->follow_count < 0)
+ screenObj->follow_count = 0;
} else {
- v->direction = dir;
+ screenObj->direction = dir;
}
}
-void AgiEngine::motionMoveObj(VtEntry *v) {
- v->direction = getDirection(v->xPos, v->yPos, v->parm1, v->parm2, v->stepSize);
+void AgiEngine::motionMoveObj(ScreenObjEntry *screenObj) {
+ screenObj->direction = getDirection(screenObj->xPos, screenObj->yPos, screenObj->move_x, screenObj->move_y, screenObj->stepSize);
// Update V6 if ego
- if (isEgoView(v))
- _game.vars[vEgoDir] = v->direction;
+ if (isEgoView(screenObj))
+ setVar(VM_VAR_EGO_DIRECTION, screenObj->direction);
- if (v->direction == 0)
- inDestination(v);
+ if (screenObj->direction == 0)
+ motionMoveObjStop(screenObj);
}
-void AgiEngine::checkMotion(VtEntry *v) {
- switch (v->motion) {
+void AgiEngine::checkMotion(ScreenObjEntry *screenObj) {
+ switch (screenObj->motionType) {
case kMotionNormal:
break;
case kMotionWander:
- motionWander(v);
+ motionWander(screenObj);
break;
case kMotionFollowEgo:
- motionFollowEgo(v);
+ motionFollowEgo(screenObj);
break;
+ case kMotionEgo:
case kMotionMoveObj:
- motionMoveObj(v);
+ motionMoveObj(screenObj);
break;
}
- if ((_game.block.active && (~v->flags & fIgnoreBlocks)) && v->direction)
- changePos(v);
+ if ((_game.block.active && (~screenObj->flags & fIgnoreBlocks)) && screenObj->direction)
+ changePos(screenObj);
}
/*
@@ -177,12 +235,12 @@ void AgiEngine::checkMotion(VtEntry *v) {
*
*/
void AgiEngine::checkAllMotions() {
- VtEntry *v;
+ ScreenObjEntry *screenObj;
- for (v = _game.viewTable; v < &_game.viewTable[MAX_VIEWTABLE]; v++) {
- if ((v->flags & (fAnimated | fUpdate | fDrawn)) == (fAnimated | fUpdate | fDrawn)
- && v->stepTimeCount == 1) {
- checkMotion(v);
+ for (screenObj = _game.screenObjTable; screenObj < &_game.screenObjTable[SCREENOBJECTS_MAX]; screenObj++) {
+ if ((screenObj->flags & (fAnimated | fUpdate | fDrawn)) == (fAnimated | fUpdate | fDrawn)
+ && screenObj->stepTimeCount == 1) {
+ checkMotion(screenObj);
}
}
}
@@ -193,14 +251,30 @@ void AgiEngine::checkAllMotions() {
* type motion that * has reached its final destination coordinates.
* @param v Pointer to view table entry
*/
-void AgiEngine::inDestination(VtEntry *v) {
- if (v->motion == kMotionMoveObj) {
- v->stepSize = v->parm3;
- setflag(v->parm4, true);
+void AgiEngine::inDestination(ScreenObjEntry *screenObj) {
+ if (screenObj->motionType == kMotionMoveObj) {
+ screenObj->stepSize = screenObj->move_stepSize;
+ setFlag(screenObj->move_flag, true);
+ }
+ screenObj->motionType = kMotionNormal;
+ if (isEgoView(screenObj))
+ _game.playerControl = true;
+}
+
+void AgiEngine::motionMoveObjStop(ScreenObjEntry *screenObj) {
+ screenObj->stepSize = screenObj->move_stepSize;
+
+ // This check for motionType was only done in AGI3.
+ // But we use this motion type for mouse movement, so we need to check in any case, otherwise it will cause glitches.
+ if (screenObj->motionType != kMotionEgo) {
+ setFlag(screenObj->move_flag, true);
}
- v->motion = kMotionNormal;
- if (isEgoView(v))
+
+ screenObj->motionType = kMotionNormal;
+ if (isEgoView(screenObj)) {
_game.playerControl = true;
+ setVar(VM_VAR_EGO_DIRECTION, 0);
+ }
}
/**
@@ -209,8 +283,8 @@ void AgiEngine::inDestination(VtEntry *v) {
* after setting the motion mode to kMotionMoveObj.
* @param v Pointer to view table entry
*/
-void AgiEngine::moveObj(VtEntry *v) {
- motionMoveObj(v);
+void AgiEngine::moveObj(ScreenObjEntry *screenObj) {
+ motionMoveObj(screenObj);
}
/**
@@ -223,9 +297,9 @@ void AgiEngine::moveObj(VtEntry *v) {
* @param y y coordinate of the object
* @param s step size
*/
-int AgiEngine::getDirection(int x0, int y0, int x, int y, int s) {
+int AgiEngine::getDirection(int16 objX, int16 objY, int16 destX, int16 destY, int16 stepSize) {
int dirTable[9] = { 8, 1, 2, 7, 0, 3, 6, 5, 4 };
- return dirTable[checkStep(x - x0, s) + 3 * checkStep(y - y0, s)];
+ return dirTable[checkStep(destX - objX, stepSize) + 3 * checkStep(destY - objY, stepSize)];
}
} // End of namespace Agi
diff --git a/engines/agi/mouse_cursor.h b/engines/agi/mouse_cursor.h
new file mode 100644
index 0000000000..c086359b0f
--- /dev/null
+++ b/engines/agi/mouse_cursor.h
@@ -0,0 +1,206 @@
+/* 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 AGI_MOUSE_CURSOR_H
+#define AGI_MOUSE_CURSOR_H
+
+namespace Agi {
+
+/**
+ * RGB-palette for the Amiga-style arrow cursor
+ * and the Amiga-style busy cursor.
+ */
+static const byte MOUSECURSOR_PALETTE[] = {
+ 0x00, 0x00, 0x00, // Black
+ 0xFF, 0xFF, 0xFF, // White
+ 0xDE, 0x20, 0x21, // Red
+ 0xFF, 0xCF, 0xAD // Light red
+};
+
+/**
+ * A black and white SCI-style arrow cursor (11x16).
+ * 0 = Transparent.
+ * 1 = Black (#000000 in 24-bit RGB).
+ * 2 = White (#FFFFFF in 24-bit RGB).
+ */
+static const byte MOUSECURSOR_SCI[] = {
+ 1,1,0,0,0,0,0,0,0,0,0,
+ 1,2,1,0,0,0,0,0,0,0,0,
+ 1,2,2,1,0,0,0,0,0,0,0,
+ 1,2,2,2,1,0,0,0,0,0,0,
+ 1,2,2,2,2,1,0,0,0,0,0,
+ 1,2,2,2,2,2,1,0,0,0,0,
+ 1,2,2,2,2,2,2,1,0,0,0,
+ 1,2,2,2,2,2,2,2,1,0,0,
+ 1,2,2,2,2,2,2,2,2,1,0,
+ 1,2,2,2,2,2,2,2,2,2,1,
+ 1,2,2,2,2,2,1,0,0,0,0,
+ 1,2,1,0,1,2,2,1,0,0,0,
+ 1,1,0,0,1,2,2,1,0,0,0,
+ 0,0,0,0,0,1,2,2,1,0,0,
+ 0,0,0,0,0,1,2,2,1,0,0,
+ 0,0,0,0,0,0,1,2,2,1,0
+};
+
+/**
+ * A black and white SCI-style busy cursor (15x16).
+ * 0 = Transparent.
+ * 1 = Black (#000000 in 24-bit RGB).
+ * 2 = White (#FFFFFF in 24-bit RGB).
+ */
+static const byte MOUSECURSOR_SCI_BUSY[] = {
+ 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,
+ 0,0,0,0,1,1,1,2,2,1,1,1,0,0,0,
+ 0,0,0,1,2,2,1,2,2,1,2,2,1,0,0,
+ 0,1,1,1,2,2,1,2,2,1,2,2,1,0,0,
+ 1,2,2,1,2,2,1,2,2,1,2,2,1,0,0,
+ 1,2,2,1,2,2,1,2,2,1,2,2,1,0,0,
+ 1,2,2,1,2,2,1,2,2,1,2,1,2,1,0,
+ 1,2,2,1,2,2,1,2,2,1,1,2,2,1,1,
+ 1,2,2,1,2,2,1,2,2,1,1,2,2,2,1,
+ 1,2,2,2,2,2,2,2,2,1,1,2,2,2,1,
+ 1,2,2,2,2,2,2,2,1,2,2,2,2,1,0,
+ 1,2,2,2,2,2,2,1,2,2,2,2,2,1,0,
+ 0,1,2,2,2,2,2,1,2,2,2,2,1,0,0,
+ 0,1,2,2,2,2,2,2,2,2,2,2,1,0,0,
+ 0,0,1,2,2,2,2,2,2,2,2,1,0,0,0,
+ 0,0,0,1,1,1,1,1,1,1,1,0,0,0,0
+};
+
+/**
+ * A black and white Atari ST style arrow cursor (11x16).
+ * 0 = Transparent.
+ * 1 = Black (#000000 in 24-bit RGB).
+ * 2 = White (#FFFFFF in 24-bit RGB).
+ */
+static const byte MOUSECURSOR_ATARI_ST[] = {
+ 2,2,0,0,0,0,0,0,0,0,0,
+ 2,1,2,0,0,0,0,0,0,0,0,
+ 2,1,1,2,0,0,0,0,0,0,0,
+ 2,1,1,1,2,0,0,0,0,0,0,
+ 2,1,1,1,1,2,0,0,0,0,0,
+ 2,1,1,1,1,1,2,0,0,0,0,
+ 2,1,1,1,1,1,1,2,0,0,0,
+ 2,1,1,1,1,1,1,1,2,0,0,
+ 2,1,1,1,1,1,1,1,1,2,0,
+ 2,1,1,1,1,1,2,2,2,2,2,
+ 2,1,1,2,1,1,2,0,0,0,0,
+ 2,1,2,0,2,1,1,2,0,0,0,
+ 2,2,0,0,2,1,1,2,0,0,0,
+ 2,0,0,0,0,2,1,1,2,0,0,
+ 0,0,0,0,0,2,1,1,2,0,0,
+ 0,0,0,0,0,0,2,2,2,0,0
+};
+
+/**
+ * A black and white Apple IIGS style arrow cursor (9x11).
+ * 0 = Transparent.
+ * 1 = Black (#000000 in 24-bit RGB).
+ * 2 = White (#FFFFFF in 24-bit RGB).
+ */
+static const byte MOUSECURSOR_APPLE_II_GS[] = {
+ 2,2,0,0,0,0,0,0,0,
+ 2,1,2,0,0,0,0,0,0,
+ 2,1,1,2,0,0,0,0,0,
+ 2,1,1,1,2,0,0,0,0,
+ 2,1,1,1,1,2,0,0,0,
+ 2,1,1,1,1,1,2,0,0,
+ 2,1,1,1,1,1,1,2,0,
+ 2,1,1,1,1,1,1,1,2,
+ 2,1,1,2,1,1,2,2,0,
+ 2,2,2,0,2,1,1,2,0,
+ 0,0,0,0,0,2,2,2,0
+};
+
+/**
+ * An Amiga-style arrow cursor (8x11).
+ * 0 = Transparent.
+ * 1 = Black (#000000 in 24-bit RGB).
+ * 3 = Red (#DE2021 in 24-bit RGB).
+ * 4 = Light red (#FFCFAD in 24-bit RGB).
+ */
+static const byte MOUSECURSOR_AMIGA[] = {
+ 3,4,1,0,0,0,0,0,
+ 3,3,4,1,0,0,0,0,
+ 3,3,3,4,1,0,0,0,
+ 3,3,3,3,4,1,0,0,
+ 3,3,3,3,3,4,1,0,
+ 3,3,3,3,3,3,4,1,
+ 3,0,3,3,4,1,0,0,
+ 0,0,0,3,4,1,0,0,
+ 0,0,0,3,3,4,1,0,
+ 0,0,0,0,3,4,1,0,
+ 0,0,0,0,3,3,4,1
+};
+
+/**
+ * An Amiga-style busy cursor showing an hourglass (13x16).
+ * 0 = Transparent.
+ * 1 = Black (#000000 in 24-bit RGB).
+ * 3 = Red (#DE2021 in 24-bit RGB).
+ * 4 = Light red (#FFCFAD in 24-bit RGB).
+ */
+static const byte MOUSECURSOR_AMIGA_BUSY[] = {
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,3,3,3,3,3,3,3,3,3,3,3,1,
+ 1,3,3,3,3,3,3,3,3,3,3,3,1,
+ 0,1,4,4,4,4,4,4,4,4,4,1,0,
+ 0,0,1,4,4,4,4,4,4,4,1,0,0,
+ 0,0,0,1,4,4,4,4,4,1,0,0,0,
+ 0,0,0,0,1,4,4,4,1,0,0,0,0,
+ 0,0,0,0,0,1,4,1,0,0,0,0,0,
+ 0,0,0,0,0,1,4,1,0,0,0,0,0,
+ 0,0,0,0,1,3,4,3,1,0,0,0,0,
+ 0,0,0,1,3,3,4,3,3,1,0,0,0,
+ 0,0,1,3,3,3,4,3,3,3,1,0,0,
+ 0,1,3,3,3,4,4,4,3,3,3,1,0,
+ 1,4,4,4,4,4,4,4,4,4,4,4,1,
+ 1,4,4,4,4,4,4,4,4,4,4,4,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1
+};
+
+/**
+ * A Macintosh-style busy cursor showing an hourglass (10x14).
+ * 0 = Transparent.
+ * 1 = Black (#000000 in 24-bit RGB).
+ * 2 = White (#FFFFFF in 24-bit RGB).
+ */
+static const byte MOUSECURSOR_MACINTOSH_BUSY[] = {
+ 0,0,1,1,1,1,1,1,0,0,
+ 0,0,1,1,1,1,1,1,0,0,
+ 0,0,1,1,1,1,1,1,0,0,
+ 0,1,2,2,2,2,2,2,1,0,
+ 1,2,2,2,2,1,2,2,2,1,
+ 1,2,2,2,2,1,2,2,2,1,
+ 1,2,2,2,2,1,2,2,2,1,
+ 1,2,2,1,1,1,2,2,2,1,
+ 1,2,2,2,2,2,2,2,2,1,
+ 1,2,2,2,2,2,2,2,2,1,
+ 0,1,2,2,2,2,2,2,1,0,
+ 0,0,1,1,1,1,1,1,0,0,
+ 0,0,1,1,1,1,1,1,0,0,
+ 0,0,1,1,1,1,1,1,0,0
+};
+
+} // End of namespace Agi
+
+#endif /* AGI_MOUSE_CURSOR_H */
diff --git a/engines/agi/objects.cpp b/engines/agi/objects.cpp
index 27cde61065..b6c628c32d 100644
--- a/engines/agi/objects.cpp
+++ b/engines/agi/objects.cpp
@@ -144,28 +144,28 @@ void AgiEngine::unloadObjects() {
}
}
-void AgiEngine::objectSetLocation(unsigned int n, int i) {
- if (n >= _game.numObjects) {
- warning("AgiEngine::objectSetLocation: Can't access object %d.\n", n);
+void AgiEngine::objectSetLocation(uint16 objectNr, int i) {
+ if (objectNr >= _game.numObjects) {
+ warning("AgiEngine::objectSetLocation: Can't access object %d.\n", objectNr);
return;
}
- _objects[n].location = i;
+ _objects[objectNr].location = i;
}
-int AgiEngine::objectGetLocation(unsigned int n) {
- if (n >= _game.numObjects) {
- warning("AgiEngine::objectGetLocation: Can't access object %d.\n", n);
+int AgiEngine::objectGetLocation(uint16 objectNr) {
+ if (objectNr >= _game.numObjects) {
+ warning("AgiEngine::objectGetLocation: Can't access object %d.\n", objectNr);
return 0;
}
- return _objects[n].location;
+ return _objects[objectNr].location;
}
-const char *AgiEngine::objectName(unsigned int n) {
- if (n >= _game.numObjects) {
- warning("AgiEngine::objectName: Can't access object %d.\n", n);
+const char *AgiEngine::objectName(uint16 objectNr) {
+ if (objectNr >= _game.numObjects) {
+ warning("AgiEngine::objectName: Can't access object %d.\n", objectNr);
return "";
}
- return _objects[n].name;
+ return _objects[objectNr].name;
}
} // End of namespace Agi
diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index 662454f3c1..8a62fce86c 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -23,55 +23,56 @@
#include "base/version.h"
#include "agi/agi.h"
+#include "agi/inv.h"
#include "agi/sprite.h"
+#include "agi/text.h"
#include "agi/graphics.h"
#include "agi/opcodes.h"
#include "agi/menu.h"
+#include "agi/systemui.h"
+#include "agi/words.h"
#include "common/random.h"
#include "common/textconsole.h"
namespace Agi {
-#define p0 (p[0])
-#define p1 (p[1])
-#define p2 (p[2])
-#define p3 (p[3])
-#define p4 (p[4])
-#define p5 (p[5])
-#define p6 (p[6])
-
-#define code state->_curLogic->data
-#define ip state->_curLogic->cIP
-#define vt state->viewTable[p0]
-#define vt_v state->viewTable[state->vars[p0]]
-
-#define _v state->vars
-
-#define getGameID() state->_vm->getGameID()
#define getFeatures() state->_vm->getFeatures()
#define getVersion() state->_vm->getVersion()
#define getLanguage() state->_vm->getLanguage()
-#define setflag(a,b) state->_vm->setflag(a,b)
-#define getflag(a) state->_vm->getflag(a)
-void cmdIncrement(AgiGame *state, uint8 *p) {
+void cmdIncrement(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ byte varVal = vm->getVar(varNr);
+
if (getVersion() < 0x2000) {
- if (_v[p0] < 0xf0)
- ++_v[p0];
+ if (varVal < 0xf0) {
+ varVal++;
+ vm->setVar(varNr, varVal);
+ }
} else {
- if (_v[p0] != 0xff)
- ++_v[p0];
+ if (varVal != 0xff) {
+ varVal++;
+ vm->setVar(varNr, varVal);
+ }
}
}
-void cmdDecrement(AgiGame *state, uint8 *p) {
- if (_v[p0] != 0)
- --_v[p0];
+void cmdDecrement(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ byte varVal = vm->getVar(varNr);
+
+ if (varVal != 0) {
+ varVal--;
+ vm->setVar(varNr, varVal);
+ }
}
-void cmdAssignN(AgiGame *state, uint8 *p) {
- _v[p0] = p1;
+void cmdAssignN(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ uint16 value = parameter[1];
+
+ vm->setVar(varNr, value);
// WORKAROUND for a bug in fan game "Get outta SQ"
// Total number of points is stored in variable 7, which
@@ -80,459 +81,725 @@ void cmdAssignN(AgiGame *state, uint8 *p) {
// variable to the correct value here
// Fixes bug #1942476 - "AGI: Fan(Get Outta SQ) - Score
// is lost on restart"
- if (getGameID() == GID_GETOUTTASQ && p0 == 7)
- _v[p0] = 8;
+ if (vm->getGameID() == GID_GETOUTTASQ && varNr == 7)
+ vm->setVar(varNr, 8);
}
-void cmdAddN(AgiGame *state, uint8 *p) {
- _v[p0] += p1;
+void cmdAddN(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ uint16 value = parameter[1];
+ byte varVal = vm->getVar(varNr);
+
+ vm->setVar(varNr, varVal + value);
}
-void cmdSubN(AgiGame *state, uint8 *p) {
- _v[p0] -= p1;
+void cmdSubN(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ uint16 value = parameter[1];
+ byte varVal = vm->getVar(varNr);
+
+ vm->setVar(varNr, varVal - value);
}
-void cmdAssignV(AgiGame *state, uint8 *p) {
- _v[p0] = _v[p1];
+void cmdAssignV(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr1 = parameter[0];
+ uint16 varNr2 = parameter[1];
+ byte varVal2 = vm->getVar(varNr2);
+
+ vm->setVar(varNr1, varVal2);
}
-void cmdAddV(AgiGame *state, uint8 *p) {
- _v[p0] += _v[p1];
+void cmdAddV(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr1 = parameter[0];
+ uint16 varNr2 = parameter[1];
+ byte varVal1 = vm->getVar(varNr1);
+ byte varVal2 = vm->getVar(varNr2);
+
+ vm->setVar(varNr1, varVal1 + varVal2);
}
-void cmdSubV(AgiGame *state, uint8 *p) {
- _v[p0] -= _v[p1];
+void cmdSubV(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr1 = parameter[0];
+ uint16 varNr2 = parameter[1];
+ byte varVal1 = vm->getVar(varNr1);
+ byte varVal2 = vm->getVar(varNr2);
+
+ vm->setVar(varNr1, varVal1 - varVal2);
}
-void cmdMulN(AgiGame *state, uint8 *p) {
- _v[p0] *= p1;
+void cmdMulN(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ uint16 value = parameter[1];
+ byte varVal = vm->getVar(varNr);
+
+ vm->setVar(varNr, varVal * value);
}
-void cmdMulV(AgiGame *state, uint8 *p) {
- _v[p0] *= _v[p1];
+void cmdMulV(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr1 = parameter[0];
+ uint16 varNr2 = parameter[1];
+ byte varVal1 = vm->getVar(varNr1);
+ byte varVal2 = vm->getVar(varNr2);
+
+ vm->setVar(varNr1, varVal1 * varVal2);
}
-void cmdDivN(AgiGame *state, uint8 *p) {
- _v[p0] /= p1;
+void cmdDivN(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ uint16 value = parameter[1];
+ byte varVal = vm->getVar(varNr);
+
+ vm->setVar(varNr, varVal / value);
}
-void cmdDivV(AgiGame *state, uint8 *p) {
- _v[p0] /= _v[p1];
+void cmdDivV(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr1 = parameter[0];
+ uint16 varNr2 = parameter[1];
+ byte varVal1 = vm->getVar(varNr1);
+ byte varVal2 = vm->getVar(varNr2);
+
+ vm->setVar(varNr1, varVal1 / varVal2);
}
-void cmdRandomV1(AgiGame *state, uint8 *p) {
- _v[p0] = state->_vm->_rnd->getRandomNumber(250);
+void cmdRandomV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+
+ vm->setVar(varNr, vm->_rnd->getRandomNumber(250));
}
-void cmdRandom(AgiGame *state, uint8 *p) {
- _v[p2] = state->_vm->_rnd->getRandomNumber(p1 - p0) + p0;
+void cmdRandom(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 valueMin = parameter[0];
+ uint16 valueMax = parameter[1];
+ uint16 varNr = parameter[2];
+
+ vm->setVar(varNr, vm->_rnd->getRandomNumber(valueMax - valueMin) + valueMin);
}
-void cmdLindirectN(AgiGame *state, uint8 *p) {
- _v[_v[p0]] = p1;
+void cmdLindirectN(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ uint16 value = parameter[1];
+ byte varVal = vm->getVar(varNr);
+
+ vm->setVar(varVal, value);
}
-void cmdLindirectV(AgiGame *state, uint8 *p) {
- _v[_v[p0]] = _v[p1];
+void cmdLindirectV(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr1 = parameter[0];
+ uint16 varNr2 = parameter[1];
+ byte varVal1 = vm->getVar(varNr1);
+ byte varVal2 = vm->getVar(varNr2);
+
+ vm->setVar(varVal1, varVal2);
}
-void cmdRindirect(AgiGame *state, uint8 *p) {
- _v[p0] = _v[_v[p1]];
+void cmdRindirect(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr1 = parameter[0];
+ uint16 varNr2 = parameter[1];
+ byte varVal2 = vm->getVar(varNr2);
+ byte value = vm->getVar(varVal2);
+
+ vm->setVar(varNr1, value);
}
-void cmdSet(AgiGame *state, uint8 *p) {
- setflag(*p, true);
+void cmdSet(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 flagNr = parameter[0];
+
+ vm->setFlag(flagNr, true);
}
-void cmdReset(AgiGame *state, uint8 *p) {
- setflag(*p, false);
+void cmdReset(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 flagNr = parameter[0];
+
+ vm->setFlag(flagNr, false);
}
-void cmdToggle(AgiGame *state, uint8 *p) {
- setflag(*p, !getflag(*p));
+void cmdToggle(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 flagNr = parameter[0];
+ bool curFlagState = vm->getFlag(flagNr);
+
+ vm->setFlag(flagNr, !curFlagState);
}
-void cmdSetV(AgiGame *state, uint8 *p) {
+void cmdSetV(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 flagNr = parameter[0];
+
if (getVersion() < 0x2000) {
- _v[p0] = 1;
+ vm->setVar(flagNr, 1);
} else {
- setflag(_v[p0], true);
+ flagNr = vm->getVar(flagNr);
+
+ vm->setFlag(flagNr, true);
}
}
-void cmdResetV(AgiGame *state, uint8 *p) {
+void cmdResetV(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 flagNr = parameter[0];
+
if (getVersion() < 0x2000) {
- _v[p0] = 0;
+ vm->setVar(flagNr, 0);
} else {
- setflag(_v[p0], false);
+ flagNr = vm->getVar(flagNr);
+
+ vm->setFlag(flagNr, false);
}
}
-void cmdToggleV(AgiGame *state, uint8 *p) {
+void cmdToggleV(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 flagNr = parameter[0];
+
if (getVersion() < 0x2000) {
- _v[p0] ^= 1;
+ byte value = vm->getVar(flagNr);
+ vm->setVar(flagNr, value ^ 1);
} else {
- setflag(_v[p0], !getflag(_v[p0]));
+ flagNr = vm->getVar(flagNr);
+ bool curFlagState = vm->getFlag(flagNr);
+
+ vm->setFlag(flagNr, !curFlagState);
}
}
-void cmdNewRoom(AgiGame *state, uint8 *p) {
- state->_vm->newRoom(p0);
+void cmdNewRoom(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 newRoomNr = parameter[0];
- // WORKAROUND: Works around intro skipping bug (#1737343) in Gold Rush.
- // Intro was skipped because the enter-keypress finalizing the entering
- // of the copy protection string (Copy protection is in logic.128) was
- // left over to the intro scene (Starts with room 73 i.e. logic.073).
- // The intro scene checks for any keys pressed and if it finds any it
- // jumps to the game's start (Room 1 i.e. logic.001). We clear the
- // keyboard buffer when the intro sequence's first room (Room 73) is
- // loaded so that no keys from the copy protection scene can be left
- // over to cause the intro to skip to the game's start.
- if (getGameID() == GID_GOLDRUSH && p0 == 73)
- state->keypress = 0;
+ state->_vm->newRoom(newRoomNr);
}
-void cmdNewRoomF(AgiGame *state, uint8 *p) {
- state->_vm->newRoom(_v[p0]);
+void cmdNewRoomF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ byte value = vm->getVar(varNr);
+
+ state->_vm->newRoom(value);
}
-void cmdLoadView(AgiGame *state, uint8 *p) {
- state->_vm->agiLoadResource(rVIEW, p0);
+void cmdLoadView(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 resourceNr = parameter[0];
+
+ state->_vm->agiLoadResource(RESOURCETYPE_VIEW, resourceNr);
}
-void cmdLoadLogic(AgiGame *state, uint8 *p) {
- state->_vm->agiLoadResource(rLOGIC, p0);
+void cmdLoadLogic(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 resourceNr = parameter[0];
+
+ state->_vm->agiLoadResource(RESOURCETYPE_LOGIC, resourceNr);
}
-void cmdLoadSound(AgiGame *state, uint8 *p) {
- state->_vm->agiLoadResource(rSOUND, p0);
+void cmdLoadSound(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 resourceNr = parameter[0];
+
+ state->_vm->agiLoadResource(RESOURCETYPE_SOUND, resourceNr);
}
-void cmdLoadViewF(AgiGame *state, uint8 *p) {
- state->_vm->agiLoadResource(rVIEW, _v[p0]);
+void cmdLoadViewF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ byte value = vm->getVar(varNr);
+
+ vm->agiLoadResource(RESOURCETYPE_VIEW, value);
}
-void cmdLoadLogicF(AgiGame *state, uint8 *p) {
- state->_vm->agiLoadResource(rLOGIC, _v[p0]);
+void cmdLoadLogicF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ byte value = vm->getVar(varNr);
+
+ state->_vm->agiLoadResource(RESOURCETYPE_LOGIC, value);
}
-void cmdDiscardView(AgiGame *state, uint8 *p) {
- state->_vm->agiUnloadResource(rVIEW, p0);
+void cmdDiscardView(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 resourceNr = parameter[0];
+
+ state->_vm->agiUnloadResource(RESOURCETYPE_VIEW, resourceNr);
}
-void cmdObjectOnAnything(AgiGame *state, uint8 *p) {
- vt.flags &= ~(fOnWater | fOnLand);
+void cmdObjectOnAnything(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags &= ~(fOnWater | fOnLand);
}
-void cmdObjectOnLand(AgiGame *state, uint8 *p) {
- vt.flags |= fOnLand;
+void cmdObjectOnLand(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags |= fOnLand;
}
-void cmdObjectOnWater(AgiGame *state, uint8 *p) {
- vt.flags |= fOnWater;
+void cmdObjectOnWater(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags |= fOnWater;
}
-void cmdObserveHorizon(AgiGame *state, uint8 *p) {
- vt.flags &= ~fIgnoreHorizon;
+void cmdObserveHorizon(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags &= ~fIgnoreHorizon;
}
-void cmdIgnoreHorizon(AgiGame *state, uint8 *p) {
- vt.flags |= fIgnoreHorizon;
+void cmdIgnoreHorizon(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags |= fIgnoreHorizon;
}
-void cmdObserveObjs(AgiGame *state, uint8 *p) {
- vt.flags &= ~fIgnoreObjects;
+void cmdObserveObjs(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags &= ~fIgnoreObjects;
}
-void cmdIgnoreObjs(AgiGame *state, uint8 *p) {
- vt.flags |= fIgnoreObjects;
+void cmdIgnoreObjs(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags |= fIgnoreObjects;
}
-void cmdObserveBlocks(AgiGame *state, uint8 *p) {
- vt.flags &= ~fIgnoreBlocks;
+void cmdObserveBlocks(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags &= ~fIgnoreBlocks;
}
-void cmdIgnoreBlocks(AgiGame *state, uint8 *p) {
- vt.flags |= fIgnoreBlocks;
+void cmdIgnoreBlocks(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags |= fIgnoreBlocks;
}
-void cmdSetHorizon(AgiGame *state, uint8 *p) {
- state->horizon = p0;
+void cmdSetHorizon(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 horizonValue = parameter[0];
+
+ state->horizon = horizonValue;
}
-void cmdGetPriority(AgiGame *state, uint8 *p) {
- _v[p1] = vt.priority;
+void cmdGetPriority(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ vm->setVar(varNr, screenObj->priority);
}
-void cmdSetPriority(AgiGame *state, uint8 *p) {
- vt.flags |= fFixedPriority;
- vt.priority = p1;
+void cmdSetPriority(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 priority = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
- // WORKAROUND: this fixes bug #1712585 in KQ4 (dwarf sprite priority)
- // For this scene, ego (Rosella) hasn't got a fixed priority till script 54
- // explicitly sets priority 8 for her, so that she can walk back to the table
- // without being drawn over the other dwarfs
- // It seems that in this scene, ego's priority is set to 8, but the priority of
- // the last dwarf with the soup bowls (view 152) is also set to 8, which causes
- // the dwarf to be drawn behind ego
- // With this workaround, when the game scripts set the priority of view 152
- // (seventh dwarf with soup bowls), ego's priority is set to 7
- // The game script itself sets priotity 8 for ego before she starts walking,
- // and then releases the fixed priority set on ego after ego is seated
- // Therefore, this workaround only affects that specific part of this scene
- // Ego is set to object 19 by script 54
- if (getGameID() == GID_KQ4 && vt.currentView == 152) {
- state->viewTable[19].flags |= fFixedPriority;
- state->viewTable[19].priority = 7;
- }
+ screenObj->flags |= fFixedPriority;
+ screenObj->priority = priority;
}
-void cmdSetPriorityF(AgiGame *state, uint8 *p) {
- vt.flags |= fFixedPriority;
- vt.priority = _v[p1];
+void cmdSetPriorityF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags |= fFixedPriority;
+ screenObj->priority = vm->getVar(varNr);
}
-void cmdReleasePriority(AgiGame *state, uint8 *p) {
- vt.flags &= ~fFixedPriority;
+void cmdReleasePriority(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags &= ~fFixedPriority;
}
-void cmdSetUpperLeft(AgiGame *state, uint8 *p) { // do nothing (AGI 2.917)
+void cmdSetUpperLeft(AgiGame *state, AgiEngine *vm, uint8 *parameter) { // do nothing (AGI 2.917)
}
-void cmdStartUpdate(AgiGame *state, uint8 *p) {
- state->_vm->startUpdate(&vt);
+void cmdStartUpdate(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ state->_vm->startUpdate(screenObj);
}
-void cmdStopUpdate(AgiGame *state, uint8 *p) {
- state->_vm->stopUpdate(&vt);
+void cmdStopUpdate(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ state->_vm->stopUpdate(screenObj);
}
-void cmdCurrentView(AgiGame *state, uint8 *p) {
- _v[p1] = vt.currentView;
+void cmdCurrentView(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ vm->setVar(varNr, screenObj->currentViewNr);
}
-void cmdCurrentCel(AgiGame *state, uint8 *p) {
- _v[p1] = vt.currentCel;
- debugC(4, kDebugLevelScripts, "v%d=%d", p1, _v[p1]);
+void cmdCurrentCel(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ vm->setVar(varNr, screenObj->currentCelNr);
+ debugC(4, kDebugLevelScripts, "v%d=%d", varNr, screenObj->currentCelNr);
}
-void cmdCurrentLoop(AgiGame *state, uint8 *p) {
- _v[p1] = vt.currentLoop;
+void cmdCurrentLoop(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ vm->setVar(varNr, screenObj->currentLoopNr);
}
-void cmdLastCel(AgiGame *state, uint8 *p) {
- _v[p1] = vt.loopData->numCels - 1;
+void cmdLastCel(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ vm->setVar(varNr, screenObj->loopData->celCount - 1);
}
-void cmdSetCel(AgiGame *state, uint8 *p) {
- state->_vm->setCel(&vt, p1);
+void cmdSetCel(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 celNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+ vm->setCel(screenObj, celNr);
if (getVersion() >= 0x2000) {
- vt.flags &= ~fDontupdate;
+ screenObj->flags &= ~fDontupdate;
}
}
-void cmdSetCelF(AgiGame *state, uint8 *p) {
- state->_vm->setCel(&vt, _v[p1]);
- vt.flags &= ~fDontupdate;
+void cmdSetCelF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+ byte value = vm->getVar(varNr);
+
+ vm->setCel(screenObj, value);
+ screenObj->flags &= ~fDontupdate;
}
-void cmdSetView(AgiGame *state, uint8 *p) {
- state->_vm->setView(&vt, p1);
+void cmdSetView(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 viewNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ state->_vm->setView(screenObj, viewNr);
}
-void cmdSetViewF(AgiGame *state, uint8 *p) {
- state->_vm->setView(&vt, _v[p1]);
+void cmdSetViewF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+ byte value = vm->getVar(varNr);
+
+ state->_vm->setView(screenObj, value);
}
-void cmdSetLoop(AgiGame *state, uint8 *p) {
- state->_vm->setLoop(&vt, p1);
+void cmdSetLoop(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 loopNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ state->_vm->setLoop(screenObj, loopNr);
}
-void cmdSetLoopF(AgiGame *state, uint8 *p) {
- state->_vm->setLoop(&vt, _v[p1]);
+void cmdSetLoopF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+ byte value = vm->getVar(varNr);
+
+ state->_vm->setLoop(screenObj, value);
}
-void cmdNumberOfLoops(AgiGame *state, uint8 *p) {
- _v[p1] = vt.numLoops;
+void cmdNumberOfLoops(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ vm->setVar(varNr, screenObj->loopCount);
}
-void cmdFixLoop(AgiGame *state, uint8 *p) {
- vt.flags |= fFixLoop;
+void cmdFixLoop(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags |= fFixLoop;
}
-void cmdReleaseLoop(AgiGame *state, uint8 *p) {
- vt.flags &= ~fFixLoop;
+void cmdReleaseLoop(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags &= ~fFixLoop;
}
-void cmdStepSize(AgiGame *state, uint8 *p) {
- vt.stepSize = _v[p1];
+void cmdStepSize(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->stepSize = vm->getVar(varNr);
}
-void cmdStepTime(AgiGame *state, uint8 *p) {
- vt.stepTime = vt.stepTimeCount = _v[p1];
+void cmdStepTime(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->stepTime = screenObj->stepTimeCount = vm->getVar(varNr);
}
-void cmdCycleTime(AgiGame *state, uint8 *p) {
- vt.cycleTime = vt.cycleTimeCount = _v[p1];
+void cmdCycleTime(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->cycleTime = screenObj->cycleTimeCount = vm->getVar(varNr);
}
-void cmdStopCycling(AgiGame *state, uint8 *p) {
- vt.flags &= ~fCycling;
+void cmdStopCycling(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags &= ~fCycling;
}
-void cmdStartCycling(AgiGame *state, uint8 *p) {
- vt.flags |= fCycling;
+void cmdStartCycling(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags |= fCycling;
}
-void cmdNormalCycle(AgiGame *state, uint8 *p) {
- vt.cycle = kCycleNormal;
- vt.flags |= fCycling;
+void cmdNormalCycle(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->cycle = kCycleNormal;
+ screenObj->flags |= fCycling;
}
-void cmdReverseCycle(AgiGame *state, uint8 *p) {
- vt.cycle = kCycleReverse;
- vt.flags |= fCycling;
+void cmdReverseCycle(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->cycle = kCycleReverse;
+ screenObj->flags |= fCycling;
}
-void cmdSetDir(AgiGame *state, uint8 *p) {
- vt.direction = _v[p1];
+void cmdSetDir(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->direction = vm->getVar(varNr);
}
-void cmdGetDir(AgiGame *state, uint8 *p) {
- _v[p1] = vt.direction;
+void cmdGetDir(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ vm->setVar(varNr, screenObj->direction);
}
-void cmdGetRoomF(AgiGame *state, uint8 *p) {
- _v[p1] = state->_vm->objectGetLocation(_v[p0]);
+void cmdGetRoomF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr1 = parameter[0];
+ uint16 varNr2 = parameter[1];
+ byte varVal1 = vm->getVar(varNr1);
+
+ vm->setVar(varNr2, state->_vm->objectGetLocation(varVal1));
}
-void cmdPut(AgiGame *state, uint8 *p) {
- state->_vm->objectSetLocation(p0, _v[p1]);
+void cmdPut(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ byte varVal = vm->getVar(varNr);
+
+ vm->objectSetLocation(objectNr, varVal);
}
-void cmdPutF(AgiGame *state, uint8 *p) {
- state->_vm->objectSetLocation(_v[p0], _v[p1]);
+void cmdPutF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr1 = parameter[0];
+ uint16 varNr2 = parameter[1];
+ byte varVal1 = vm->getVar(varNr1);
+ byte varVal2 = vm->getVar(varNr2);
+
+ state->_vm->objectSetLocation(varVal1, varVal2);
}
-void cmdDrop(AgiGame *state, uint8 *p) {
- state->_vm->objectSetLocation(p0, 0);
+void cmdDrop(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+
+ state->_vm->objectSetLocation(objectNr, 0);
}
-void cmdGet(AgiGame *state, uint8 *p) {
- state->_vm->objectSetLocation(p0, EGO_OWNED);
+void cmdGet(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+
+ state->_vm->objectSetLocation(objectNr, EGO_OWNED);
}
-void cmdGetV1(AgiGame *state, uint8 *p) {
- state->_vm->objectSetLocation(p0, EGO_OWNED_V1);
+void cmdGetV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+
+ state->_vm->objectSetLocation(objectNr, EGO_OWNED_V1);
}
-void cmdGetF(AgiGame *state, uint8 *p) {
- state->_vm->objectSetLocation(_v[p0], EGO_OWNED);
+void cmdGetF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ byte varVal = vm->getVar(varNr);
+
+ state->_vm->objectSetLocation(varVal, EGO_OWNED);
}
-void cmdWordToString(AgiGame *state, uint8 *p) {
- strcpy(state->strings[p0], state->egoWords[p1].word);
+void cmdWordToString(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 stringNr = parameter[0];
+ uint16 wordNr = parameter[1];
+
+ Common::strlcpy(state->strings[stringNr], state->_vm->_words->getEgoWord(wordNr), MAX_STRINGLEN);
}
-void cmdOpenDialogue(AgiGame *state, uint8 *p) {
- state->hasWindow = true;
+void cmdOpenDialogue(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ vm->_text->dialogueOpen();
}
-void cmdCloseDialogue(AgiGame *state, uint8 *p) {
- state->hasWindow = false;
+void cmdCloseDialogue(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ vm->_text->dialogueClose();
}
-void cmdCloseWindow(AgiGame *state, uint8 *p) {
- state->_vm->closeWindow();
+void cmdCloseWindow(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ vm->_text->closeWindow();
}
-void cmdStatusLineOn(AgiGame *state, uint8 *p) {
- state->statusLine = true;
- state->_vm->writeStatus();
+void cmdStatusLineOn(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ TextMgr *text = state->_vm->_text;
+
+ text->statusEnable();
+ text->statusDraw();
}
-void cmdStatusLineOff(AgiGame *state, uint8 *p) {
- state->statusLine = false;
- state->_vm->writeStatus();
+void cmdStatusLineOff(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ TextMgr *text = state->_vm->_text;
+
+ text->statusDisable();
+ state->_vm->_text->statusClear();
}
-void cmdShowObj(AgiGame *state, uint8 *p) {
- state->_vm->_sprites->showObj(p0);
+void cmdShowObj(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+
+ state->_vm->_sprites->showObject(objectNr);
}
-void cmdShowObjV(AgiGame *state, uint8 *p) {
- state->_vm->_sprites->showObj(_v[p0]);
+void cmdShowObjV(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ byte varVal = vm->getVar(varNr);
+
+ state->_vm->_sprites->showObject(varVal);
}
-void cmdSound(AgiGame *state, uint8 *p) {
- state->_vm->_sound->startSound(p0, p1);
+void cmdSound(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 resourceNr = parameter[0];
+ uint16 flagNr = parameter[1];
+
+ state->_vm->_sound->startSound(resourceNr, flagNr);
}
-void cmdStopSound(AgiGame *state, uint8 *p) {
+void cmdStopSound(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
state->_vm->_sound->stopSound();
}
-void cmdMenuInput(AgiGame *state, uint8 *p) {
- state->_vm->newInputMode(INPUT_MENU);
+void cmdMenuInput(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ if (vm->getFlag(VM_FLAG_MENUS_ACCESSIBLE)) {
+ vm->_menu->delayedExecuteViaKeyboard();
+ }
}
-void cmdEnableItem(AgiGame *state, uint8 *p) {
- state->_vm->_menu->setItem(p0, true);
+void cmdEnableItem(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 controlCode = parameter[0];
+
+ state->_vm->_menu->itemEnable(controlCode);
}
-void cmdDisableItem(AgiGame *state, uint8 *p) {
- state->_vm->_menu->setItem(p0, false);
+void cmdDisableItem(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 controlCode = parameter[0];
+
+ state->_vm->_menu->itemDisable(controlCode);
}
-void cmdSubmitMenu(AgiGame *state, uint8 *p) {
+void cmdSubmitMenu(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
state->_vm->_menu->submit();
}
-void cmdSetScanStart(AgiGame *state, uint8 *p) {
+void cmdSetScanStart(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
state->_curLogic->sIP = state->_curLogic->cIP;
}
-void cmdResetScanStart(AgiGame *state, uint8 *p) {
+void cmdResetScanStart(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
state->_curLogic->sIP = 2;
}
-void cmdSaveGame(AgiGame *state, uint8 *p) {
- state->simpleSave ? state->_vm->saveGameSimple() : state->_vm->saveGameDialog();
-}
+void cmdSaveGame(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ vm->inGameTimerPause();
-void cmdLoadGame(AgiGame *state, uint8 *p) {
- assert(1);
- state->simpleSave ? state->_vm->loadGameSimple() : state->_vm->loadGameDialog();
+ if (state->automaticSave) {
+ if (vm->saveGameAutomatic()) {
+ // automatic save succeded
+ vm->inGameTimerResume();
+ return;
+ }
+ // fall back to regular dialog otherwise
+ }
+
+ vm->saveGameDialog();
+
+ vm->inGameTimerResume();
}
-void cmdInitDisk(AgiGame *state, uint8 *p) { // do nothing
+void cmdLoadGame(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ vm->inGameTimerPause();
+
+ if (state->automaticSave) {
+ if (vm->loadGameAutomatic()) {
+ // automatic restore succeded
+ vm->inGameTimerResume();
+ return;
+ }
+ // fall back to regular dialog otherwise
+ }
+
+ vm->loadGameDialog();
+
+ vm->inGameTimerResume();
}
-void cmdLog(AgiGame *state, uint8 *p) { // do nothing
+void cmdInitDisk(AgiGame *state, AgiEngine *vm, uint8 *parameter) { // do nothing
}
-void cmdTraceOn(AgiGame *state, uint8 *p) { // do nothing
+void cmdLog(AgiGame *state, AgiEngine *vm, uint8 *parameter) { // do nothing
}
-void cmdTraceInfo(AgiGame *state, uint8 *p) { // do nothing
+void cmdTraceOn(AgiGame *state, AgiEngine *vm, uint8 *parameter) { // do nothing
}
-void cmdShowMem(AgiGame *state, uint8 *p) {
- state->_vm->messageBox("Enough memory");
+void cmdTraceInfo(AgiGame *state, AgiEngine *vm, uint8 *parameter) { // do nothing
}
-void cmdInitJoy(AgiGame *state, uint8 *p) { // do nothing
+void cmdShowMem(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ state->_vm->_text->messageBox("Enough memory");
}
-void cmdScriptSize(AgiGame *state, uint8 *p) {
- debug(0, "script.size(%d)", p0);
+void cmdInitJoy(AgiGame *state, AgiEngine *vm, uint8 *parameter) { // do nothing
}
-void cmdCancelLine(AgiGame *state, uint8 *p) {
- state->inputBuffer[0] = 0;
- state->cursorPos = 0;
- state->_vm->writePrompt();
+void cmdScriptSize(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ debug(0, "script.size(%d)", parameter[0]);
}
// This implementation is based on observations of Amiga's Gold Rush.
@@ -545,13 +812,16 @@ void cmdCancelLine(AgiGame *state, uint8 *p) {
// 4051 (When ego is stationary),
// 471 (When walking on the first screen's bridge),
// 71 (When walking around, using the mouse or the keyboard).
-void cmdObjStatusF(AgiGame *state, uint8 *p) {
+void cmdObjStatusF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[vm->getVar(varNr)];
+
const char *cycleDesc; // Object's cycle description line
const char *motionDesc; // Object's motion description line
char msg[256]; // The whole object status message
// Generate cycle description line
- switch (vt_v.cycle) {
+ switch (screenObj->cycle) {
case kCycleNormal:
cycleDesc = "normal cycle";
break;
@@ -570,7 +840,7 @@ void cmdObjStatusF(AgiGame *state, uint8 *p) {
}
// Generate motion description line
- switch (vt_v.motion) {
+ switch (screenObj->motionType) {
case kMotionNormal:
motionDesc = "normal motion";
break;
@@ -592,21 +862,21 @@ void cmdObjStatusF(AgiGame *state, uint8 *p) {
}
sprintf(msg,
- "Object %d:\n" \
- "x: %d xsize: %d\n" \
- "y: %d ysize: %d\n" \
- "pri: %d\n" \
- "stepsize: %d\n" \
- "%s\n" \
- "%s",
- _v[p0],
- vt_v.xPos, vt_v.xSize,
- vt_v.yPos, vt_v.ySize,
- vt_v.priority,
- vt_v.stepSize,
- cycleDesc,
- motionDesc);
- state->_vm->messageBox(msg);
+ "Object %d:\n" \
+ "x: %d xsize: %d\n" \
+ "y: %d ysize: %d\n" \
+ "pri: %d\n" \
+ "stepsize: %d\n" \
+ "%s\n" \
+ "%s",
+ vm->getVar(varNr),
+ screenObj->xPos, screenObj->xSize,
+ screenObj->yPos, screenObj->ySize,
+ screenObj->priority,
+ screenObj->stepSize,
+ cycleDesc,
+ motionDesc);
+ state->_vm->_text->messageBox(msg);
}
// unknown commands:
@@ -617,49 +887,105 @@ void cmdObjStatusF(AgiGame *state, uint8 *p) {
// unk_174: Change priority table (used in KQ4) -- j5
// unk_177: Disable menus completely -- j5
// unk_181: Deactivate keypressed control (default control of ego)
-void cmdSetSimple(AgiGame *state, uint8 *p) {
+void cmdSetSimple(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
if (!(getFeatures() & (GF_AGI256 | GF_AGI256_2))) {
- state->simpleSave = true;
+ // set.simple is called by Larry 1 on Apple IIgs at the store, after answering the 555-6969 phone.
+ // load.sound(16) is called right before it. Interpreter is 2.440-like.
+ // it's called with parameter 16.
+ // Original interpreter doesn't seem to play any sound.
+ // TODO: Figure out what's going on. It can't be automatic saving of course.
+ // Also getting called in KQ1, when planting beans - parameter 12.
+ // And when killing the witch - parameter 40.
+ if ((getVersion() < 0x2425) || (getVersion() == 0x2440)) {
+ // was not available before 2.2425, but also not available in 2.440
+ warning("set.simple called, although not available for current AGI version");
+ return;
+ }
+
+ int16 stringNr = parameter[0];
+ const char *textPtr = nullptr;
+
+ state->automaticSave = false;
+
+ // Try to get description for automatic saves
+ textPtr = state->strings[stringNr];
+
+ strncpy(state->automaticSaveDescription, textPtr, sizeof(state->automaticSaveDescription));
+ state->automaticSaveDescription[sizeof(state->automaticSaveDescription) - 1] = 0;
+
+ if (state->automaticSaveDescription[0]) {
+ // We got it and it's set, so enable automatic saving
+ state->automaticSave = true;
+ }
+
} else { // AGI256 and AGI256-2 use this unknown170 command to load 256 color pictures.
- // Load the picture. Similar to void cmdLoad_pic(AgiGame *state, uint8 *p).
- state->_vm->_sprites->eraseBoth();
- state->_vm->agiLoadResource(rPICTURE, _v[p0]);
-
- // Draw the picture. Similar to void cmdDraw_pic(AgiGame *state, uint8 *p).
- state->_vm->_picture->decodePicture(_v[p0], false, true);
- state->_vm->_sprites->blitBoth();
- state->pictureShown = 0;
-
- // Show the picture. Similar to void cmdShow_pic(AgiGame *state, uint8 *p).
- setflag(fOutputMode, false);
- state->_vm->closeWindow();
- state->_vm->_picture->showPic();
- state->pictureShown = 1;
-
- // Simulate slowww computer. Many effects rely on this
- state->_vm->pause(kPausePicture);
+ // Load the picture. Similar to void cmdLoad_pic(AgiGame *state, AgiEngine *vm, uint8 *p).
+ SpritesMgr *spritesMgr = state->_vm->_sprites;
+ uint16 varNr = parameter[0];
+ uint16 resourceNr = vm->getVar(varNr);
+
+ spritesMgr->eraseSprites();
+ vm->agiLoadResource(RESOURCETYPE_PICTURE, resourceNr);
+
+ // Draw the picture. Similar to void cmdDraw_pic(AgiGame *state, AgiEngine *vm, uint8 *p).
+ vm->_picture->decodePicture(resourceNr, false, true);
+ spritesMgr->drawAllSpriteLists();
+ state->pictureShown = false;
+
+ // Loading trigger
+ vm->artificialDelayTrigger_DrawPicture(resourceNr);
+
+ // Show the picture. Similar to void cmdShow_pic(AgiGame *state, AgiEngine *vm, uint8 *p).
+ vm->setFlag(VM_FLAG_OUTPUT_MODE, false);
+ vm->_text->closeWindow();
+ vm->_picture->showPic();
+ state->pictureShown = true;
}
}
-void cmdPopScript(AgiGame *state, uint8 *p) {
- if (getVersion() >= 0x2915) {
- debug(0, "pop.script");
+// push.script was not available until 2.425, and also not available in 2.440
+void cmdPopScript(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ if ((getVersion() < 0x2425) || (getVersion() == 0x2440)) {
+ // was not available before 2.2425, but also not available in 2.440
+ warning("pop.script called, although not available for current AGI version");
+ return;
}
-}
-void cmdHoldKey(AgiGame *state, uint8 *p) {
- if (getVersion() >= 0x3098) {
- state->_vm->_egoHoldKey = true;
- }
+ debug(0, "pop.script");
}
-void cmdDiscardSound(AgiGame *state, uint8 *p) {
+void cmdDiscardSound(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
if (getVersion() >= 0x2936) {
debug(0, "discard.sound");
}
}
-void cmdHideMouse(AgiGame *state, uint8 *p) {
+void cmdShowMouse(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ if (state->mouseEnabled) {
+ state->mouseHidden = false;
+
+ g_system->showMouse(true);
+ }
+}
+
+// Seems to have been added for AGI3, at least according to PC AGI
+// Space Quest 2 on Apple IIgs (using AGI ) calls it during the spaceship cutscene in the intro
+// but show.mouse is never called afterwards. Game running under emulator doesn't seem to hide the mouse cursor.
+// TODO: figure out, what exactly happens. Probably some hacked-in command and not related to mouse cursor for that game?
+void cmdHideMouse(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ if (getVersion() < 0x3000) {
+ // was not available before 3.086
+ warning("hide.mouse, although not available for current AGI version");
+ return;
+ }
+
+ if ((vm->getGameID() == GID_MH1) && (vm->getPlatform() == Common::kPlatformApple2GS)) {
+ // Called right after beating arcade sequence on day 4 in the hospital Parameter is "1".
+ // Right before cutscene. show.mouse isn't called. Probably different function.
+ warning("hide.mouse called, disabled for MH1 Apple IIgs");
+ return;
+ }
+
// WORKAROUND: Turns off current movement that's being caused with the mouse.
// This fixes problems with too many popup boxes appearing in the Amiga
// Gold Rush's copy protection failure scene (i.e. the hanging scene, logic.192).
@@ -667,34 +993,64 @@ void cmdHideMouse(AgiGame *state, uint8 *p) {
// to walk somewhere else than to the right using the mouse.
// FIXME: Write a proper implementation using disassembly and
// apply it to other games as well if applicable.
- state->viewTable[0].flags &= ~fAdjEgoXY;
+ //state->screenObjTable[SCREENOBJECTS_EGO_ENTRY].flags &= ~fAdjEgoXY;
+ if (state->mouseEnabled) {
+ state->mouseHidden = true;
- g_system->showMouse(false);
+ g_system->showMouse(false);
+ }
}
-void cmdAllowMenu(AgiGame *state, uint8 *p) {
- if (getVersion() >= 0x3098) {
- setflag(fMenusWork, ((p0 != 0) ? true : false));
+void cmdAllowMenu(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ if (getVersion() < 0x3098) {
+ // was not available before 3.098
+ warning("allow.menu called, although not available for current AGI version");
+ return;
+ }
+
+ uint16 allowed = parameter[0];
+
+ if (allowed) {
+ state->_vm->_menu->accessAllow();
+ } else {
+ state->_vm->_menu->accessDeny();
}
}
-void cmdShowMouse(AgiGame *state, uint8 *p) {
- g_system->showMouse(true);
+void cmdFenceMouse(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr1 = parameter[0];
+ uint16 varNr2 = parameter[1];
+ uint16 varNr3 = parameter[2];
+ uint16 varNr4 = parameter[3];
+
+ state->mouseFence.moveTo(varNr1, varNr2);
+ state->mouseFence.setWidth(varNr3 - varNr1);
+ state->mouseFence.setHeight(varNr4 - varNr1);
}
-void cmdFenceMouse(AgiGame *state, uint8 *p) {
- state->mouseFence.moveTo(p0, p1);
- state->mouseFence.setWidth(p2 - p0);
- state->mouseFence.setHeight(p3 - p1);
+// HoldKey was added in 2.425
+// There was no way to disable this mode until 3.098 though
+void cmdHoldKey(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ if ((getVersion() < 0x2425) || (getVersion() == 0x2440)) {
+ // was not available before 2.425, but also not available in 2.440
+ warning("hold.key called, although not available for current AGI version");
+ return;
+ }
+
+ vm->_keyHoldMode = true;
}
-void cmdReleaseKey(AgiGame *state, uint8 *p) {
- if (getVersion() >= 0x3098) {
- state->_vm->_egoHoldKey = false;
+void cmdReleaseKey(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ if (getVersion() < 0x3098) {
+ // was not available before 3.098
+ warning("release.key called, although not available for current AGI version");
+ return;
}
+
+ vm->_keyHoldMode = false;
}
-void cmdAdjEgoMoveToXY(AgiGame *state, uint8 *p) {
+void cmdAdjEgoMoveToXY(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
int8 x, y;
switch (logicNamesCmd[182].argumentsLength()) {
@@ -703,8 +1059,8 @@ void cmdAdjEgoMoveToXY(AgiGame *state, uint8 *p) {
// (Using arguments (0, 0), (0, 7), (0, 8), (9, 9) and (-9, 9)).
case 2:
// Both arguments are signed 8-bit (i.e. in range -128 to +127).
- x = (int8) p0;
- y = (int8) p1;
+ x = (int8) parameter[0];
+ y = (int8) parameter[1];
// Turn off ego's current movement caused with the mouse if
// adj.ego.move.to.x.y is called with other arguments than previously.
@@ -717,7 +1073,7 @@ void cmdAdjEgoMoveToXY(AgiGame *state, uint8 *p) {
// by something else because this command doesn't do any flag manipulations
// in the Amiga version - checked it with disassembly).
if (x != state->adjMouseX || y != state->adjMouseY)
- state->viewTable[EGO_VIEW_TABLE].flags &= ~fAdjEgoXY;
+ state->screenObjTable[SCREENOBJECTS_EGO_ENTRY].flags &= ~fAdjEgoXY;
state->adjMouseX = x;
state->adjMouseY = y;
@@ -727,57 +1083,74 @@ void cmdAdjEgoMoveToXY(AgiGame *state, uint8 *p) {
// TODO: Check where (if anywhere) the 0 arguments version is used
case 0:
default:
- state->viewTable[0].flags |= fAdjEgoXY;
+ state->screenObjTable[SCREENOBJECTS_EGO_ENTRY].flags |= fAdjEgoXY;
break;
}
}
-void cmdParse(AgiGame *state, uint8 *p) {
- _v[vWordNotFound] = 0;
- setflag(fEnteredCli, false);
- setflag(fSaidAcceptedInput, false);
+void cmdParse(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ TextMgr *text = state->_vm->_text;
+ uint16 stringNr = parameter[0];
- state->_vm->dictionaryWords(state->_vm->agiSprintf(state->strings[p0]));
+ vm->setVar(VM_VAR_WORD_NOT_FOUND, 0);
+ vm->setFlag(VM_FLAG_ENTERED_CLI, false);
+ vm->setFlag(VM_FLAG_SAID_ACCEPTED_INPUT, false);
+
+ vm->_words->parseUsingDictionary(text->stringPrintf(state->strings[stringNr]));
}
-void cmdCall(AgiGame *state, uint8 *p) {
+void cmdCall(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 logicNr = parameter[0];
int oldCIP;
int oldLognum;
// CM: we don't save sIP because set.scan.start can be
// used in a called script (fixes xmas demo)
oldCIP = state->_curLogic->cIP;
- oldLognum = state->lognum;
+ oldLognum = state->curLogicNr;
- state->_vm->runLogic(p0);
+ state->_vm->runLogic(logicNr);
- state->lognum = oldLognum;
- state->_curLogic = &state->logics[state->lognum];
+ state->curLogicNr = oldLognum;
+ state->_curLogic = &state->logics[state->curLogicNr];
state->_curLogic->cIP = oldCIP;
}
-void cmdCallF(AgiGame *state, uint8 *p) {
- cmdCall(state, &_v[p0]);
+void cmdCallF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ byte logicNr = vm->getVar(varNr);
+
+ cmdCall(state, vm, &logicNr);
}
-void cmdDrawPicV1(AgiGame *state, uint8 *p) {
- debugC(6, kDebugLevelScripts, "=== draw pic V1 %d ===", _v[p0]);
- state->_vm->_picture->decodePicture(_v[p0], true);
+void cmdDrawPicV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ uint16 resourceNr = vm->getVar(varNr);
- state->_vm->clearPrompt();
+ debugC(6, kDebugLevelScripts, "=== draw pic V1 %d ===", resourceNr);
+ state->_vm->_picture->decodePicture(resourceNr, true);
- // Simulate slowww computer. Many effects rely on this
- state->_vm->pause(kPausePicture);
+ // TODO: check, if this was really done
+ vm->_text->promptClear();
+
+ // Loading trigger
+ vm->artificialDelayTrigger_DrawPicture(resourceNr);
}
-void cmdDrawPic(AgiGame *state, uint8 *p) {
- debugC(6, kDebugLevelScripts, "=== draw pic %d ===", _v[p0]);
- state->_vm->_sprites->eraseBoth();
- state->_vm->_picture->decodePicture(_v[p0], true);
- state->_vm->_sprites->blitBoth();
- state->_vm->_sprites->commitBoth();
- state->pictureShown = 0;
- debugC(6, kDebugLevelScripts, "--- end of draw pic %d ---", _v[p0]);
+void cmdDrawPic(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ SpritesMgr *spritesMgr = state->_vm->_sprites;
+ uint16 varNr = parameter[0];
+ uint16 resourceNr = vm->getVar(varNr);
+
+ debugC(6, kDebugLevelScripts, "=== draw pic %d ===", resourceNr);
+
+ spritesMgr->eraseSprites();
+ vm->_picture->decodePicture(resourceNr, true);
+
+ spritesMgr->buildAllSpriteLists();
+ spritesMgr->drawAllSpriteLists();
+ state->pictureShown = false;
+ debugC(6, kDebugLevelScripts, "--- end of draw pic %d ---", resourceNr);
// WORKAROUND for a script bug which exists in SQ1, logic scripts
// 20 and 110. Flag 103 is not reset correctly, which leads to erroneous
@@ -790,484 +1163,620 @@ void cmdDrawPic(AgiGame *state, uint8 *p) {
// With this workaround, when the player goes back to picture 20 (1 screen
// above the ground), flag 103 is reset, thereby fixing this issue. Note
// that this is a script bug and occurs in the original interpreter as well.
- // Fixes bug #1658514: AGI: SQ1 (2.2 DOS ENG) bizzare exploding roger
- if (getGameID() == GID_SQ1 && _v[p0] == 20)
- setflag(103, false);
+ // Fixes bug #3056: AGI: SQ1 (2.2 DOS ENG) bizzare exploding roger
+ if (vm->getGameID() == GID_SQ1 && resourceNr == 20)
+ vm->setFlag(103, false);
- // Simulate slowww computer. Many effects rely on this
- state->_vm->pause(kPausePicture);
+ // Loading trigger
+ vm->artificialDelayTrigger_DrawPicture(resourceNr);
}
-void cmdShowPic(AgiGame *state, uint8 *p) {
+void cmdShowPic(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
debugC(6, kDebugLevelScripts, "=== show pic ===");
- setflag(fOutputMode, false);
- state->_vm->closeWindow();
- state->_vm->_picture->showPic();
- state->pictureShown = 1;
+ vm->setFlag(VM_FLAG_OUTPUT_MODE, false);
+ vm->_text->closeWindow();
+ vm->_picture->showPicWithTransition();
+ state->pictureShown = true;
debugC(6, kDebugLevelScripts, "--- end of show pic ---");
}
-void cmdLoadPic(AgiGame *state, uint8 *p) {
- state->_vm->_sprites->eraseBoth();
- state->_vm->agiLoadResource(rPICTURE, _v[p0]);
- state->_vm->_sprites->blitBoth();
- state->_vm->_sprites->commitBoth();
+void cmdLoadPic(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ SpritesMgr *spritesMgr = state->_vm->_sprites;
+ uint16 varNr = parameter[0];
+ uint16 resourceNr = vm->getVar(varNr);
+
+ spritesMgr->eraseSprites();
+ vm->agiLoadResource(RESOURCETYPE_PICTURE, resourceNr);
+ spritesMgr->buildAllSpriteLists();
+ spritesMgr->drawAllSpriteLists();
}
-void cmdLoadPicV1(AgiGame *state, uint8 *p) {
- state->_vm->agiLoadResource(rPICTURE, _v[p0]);
+void cmdLoadPicV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ uint16 resourceNr = vm->getVar(varNr);
+
+ state->_vm->agiLoadResource(RESOURCETYPE_PICTURE, resourceNr);
}
-void cmdDiscardPic(AgiGame *state, uint8 *p) {
+void cmdDiscardPic(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
debugC(6, kDebugLevelScripts, "--- discard pic ---");
// do nothing
}
-void cmdOverlayPic(AgiGame *state, uint8 *p) {
+void cmdOverlayPic(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ SpritesMgr *spritesMgr = state->_vm->_sprites;
+ uint16 varNr = parameter[0];
+ uint16 resourceNr = vm->getVar(varNr);
+
debugC(6, kDebugLevelScripts, "--- overlay pic ---");
- state->_vm->_sprites->eraseBoth();
- state->_vm->_picture->decodePicture(_v[p0], false);
- state->_vm->_sprites->blitBoth();
- state->pictureShown = 0;
- state->_vm->_sprites->commitBoth();
+ spritesMgr->eraseSprites();
+ vm->_picture->decodePicture(resourceNr, false);
+ spritesMgr->buildAllSpriteLists();
+ spritesMgr->drawAllSpriteLists();
+ spritesMgr->showAllSpriteLists();
+ state->pictureShown = false;
- // Simulate slowww computer. Many effects rely on this
- state->_vm->pause(kPausePicture);
+ // Loading trigger
+ vm->artificialDelayTrigger_DrawPicture(resourceNr);
}
-void cmdShowPriScreen(AgiGame *state, uint8 *p) {
- state->_vm->_debug.priority = 1;
- state->_vm->_sprites->eraseBoth();
- state->_vm->_picture->showPic();
- state->_vm->_sprites->blitBoth();
+void cmdShowPriScreen(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ GfxMgr *gfx = state->_vm->_gfx;
+
+ gfx->debugShowMap(1); // switch to priority map
state->_vm->waitKey();
- state->_vm->_debug.priority = 0;
- state->_vm->_sprites->eraseBoth();
- state->_vm->_picture->showPic();
- state->_vm->_sprites->blitBoth();
+ gfx->debugShowMap(0); // switch back to visual map
}
-void cmdAnimateObj(AgiGame *state, uint8 *p) {
+void cmdAnimateObj(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
if (getVersion() < 0x2000) {
- if (vt.flags & fDidntMove)
+ if (screenObj->flags & fDidntMove)
return;
} else {
- if (vt.flags & fAnimated)
+ if (screenObj->flags & fAnimated)
return;
}
- debugC(4, kDebugLevelScripts, "animate vt entry #%d", p0);
- vt.flags = fAnimated | fUpdate | fCycling;
+ debugC(4, kDebugLevelScripts, "animate vt entry #%d", objectNr);
+ screenObj->flags = fAnimated | fUpdate | fCycling;
if (getVersion() < 0x2000) {
- vt.flags |= fDidntMove;
+ screenObj->flags |= fDidntMove;
}
- vt.motion = kMotionNormal;
- vt.cycle = kCycleNormal;
- vt.direction = 0;
+ screenObj->motionType = kMotionNormal;
+ screenObj->cycle = kCycleNormal;
+ screenObj->direction = 0;
}
-void cmdUnanimateAll(AgiGame *state, uint8 *p) {
+void cmdUnanimateAll(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
int i;
- for (i = 0; i < MAX_VIEWTABLE; i++)
- state->viewTable[i].flags &= ~(fAnimated | fDrawn);
+ state->_vm->_sprites->eraseSprites();
+
+ for (i = 0; i < SCREENOBJECTS_MAX; i++)
+ state->screenObjTable[i].flags &= ~(fAnimated | fDrawn);
}
-void cmdDraw(AgiGame *state, uint8 *p) {
- if (vt.flags & fDrawn)
- return;
+void cmdDraw(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
- if (vt.ySize <= 0 || vt.xSize <= 0)
+ if (screenObj->flags & fDrawn)
return;
- debugC(4, kDebugLevelScripts, "draw entry %d", vt.entry);
+// if (vt.ySize <= 0 || vt.xSize <= 0)
+// return;
+
+ debugC(4, kDebugLevelScripts, "draw entry %d", screenObj->objectNr);
- vt.flags |= fUpdate;
+ screenObj->flags |= fUpdate;
if (getVersion() >= 0x3000) {
- state->_vm->setLoop(&vt, vt.currentLoop);
- state->_vm->setCel(&vt, vt.currentCel);
+ state->_vm->setLoop(screenObj, screenObj->currentLoopNr);
+ state->_vm->setCel(screenObj, screenObj->currentCelNr);
}
- state->_vm->fixPosition(p0);
- vt.xPos2 = vt.xPos;
- vt.yPos2 = vt.yPos;
- vt.celData2 = vt.celData;
- state->_vm->_sprites->eraseUpdSprites();
- vt.flags |= fDrawn;
-
- // WORKAROUND: This fixes a bug with AGI Fanmade game Space Trek.
- // The original workaround checked if AGI version was <= 2.440, which could
- // cause regressions with some AGI games. The original workaround no longer
- // works for Space Trek in ScummVM, as all fanmade games are set to use
- // AGI version 2.917, but it applies to all other games where AGI version is
- // <= 2.440, which was not the original purpose of this workaround. It is
- // assumed that this bug is caused by AGI Studio, so this applies to all
- // fanmade games only.
- // TODO: Investigate this further and check if any other fanmade AGI
- // games are affected. If yes, then it'd be best to set this for Space
- // Trek only
- if (getFeatures() & GF_FANMADE) // See Sarien bug #546562
- vt.flags |= fAnimated;
-
- state->_vm->_sprites->blitUpdSprites();
- vt.flags &= ~fDontupdate;
-
- state->_vm->_sprites->commitBlock(vt.xPos, vt.yPos - vt.ySize + 1, vt.xPos + vt.xSize - 1, vt.yPos, true);
-
- debugC(4, kDebugLevelScripts, "vt entry #%d flags = %02x", p0, vt.flags);
-}
-
-void cmdErase(AgiGame *state, uint8 *p) {
- if (~vt.flags & fDrawn)
- return;
+ SpritesMgr *sprites = state->_vm->_sprites;
- state->_vm->_sprites->eraseUpdSprites();
+ state->_vm->fixPosition(objectNr);
+ screenObj->xPos_prev = screenObj->xPos;
+ screenObj->yPos_prev = screenObj->yPos;
+ screenObj->xSize_prev = screenObj->xSize;
+ screenObj->ySize_prev = screenObj->ySize;
+ //screenObj->celData2 = screenObj->celData;
+ sprites->eraseRegularSprites();
+ screenObj->flags |= fDrawn;
+ sprites->buildRegularSpriteList();
+ sprites->drawRegularSpriteList();
+ sprites->showSprite(screenObj);
+ screenObj->flags &= ~fDontupdate;
- if (vt.flags & fUpdate) {
- vt.flags &= ~fDrawn;
- } else {
- state->_vm->_sprites->eraseNonupdSprites();
- vt.flags &= ~fDrawn;
- state->_vm->_sprites->blitNonupdSprites();
- }
- state->_vm->_sprites->blitUpdSprites();
+ debugC(4, kDebugLevelScripts, "vt entry #%d flags = %02x", objectNr, screenObj->flags);
+}
+
+void cmdErase(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ SpritesMgr *sprites = state->_vm->_sprites;
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
- int x1, y1, x2, y2;
+ bool noUpdateFlag = false;
+
+ if (!(screenObj->flags & fDrawn))
+ return;
+
+ sprites->eraseRegularSprites();
+ if ((screenObj->flags & fUpdate) == 0) {
+ noUpdateFlag = true;
+ sprites->eraseStaticSprites();
+ }
- x1 = MIN((int)MIN(vt.xPos, vt.xPos2), MIN(vt.xPos + vt.celData->width, vt.xPos2 + vt.celData2->width));
- x2 = MAX((int)MAX(vt.xPos, vt.xPos2), MAX(vt.xPos + vt.celData->width, vt.xPos2 + vt.celData2->width));
- y1 = MIN((int)MIN(vt.yPos, vt.yPos2), MIN(vt.yPos - vt.celData->height, vt.yPos2 - vt.celData2->height));
- y2 = MAX((int)MAX(vt.yPos, vt.yPos2), MAX(vt.yPos - vt.celData->height, vt.yPos2 - vt.celData2->height));
+ screenObj->flags &= ~fDrawn;
- state->_vm->_sprites->commitBlock(x1, y1, x2, y2, true);
+ if (noUpdateFlag) {
+ sprites->buildStaticSpriteList();
+ sprites->drawStaticSpriteList();
+ }
+ sprites->buildRegularSpriteList();
+ sprites->drawRegularSpriteList();
+ sprites->showSprite(screenObj);
}
-void cmdPosition(AgiGame *state, uint8 *p) {
- vt.xPos = vt.xPos2 = p1;
- vt.yPos = vt.yPos2 = p2;
+void cmdPosition(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 xPos = parameter[1];
+ uint16 yPos = parameter[2];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
- // WORKAROUND: Part of the fix for bug #1659209 "AGI: Space Trek sprite duplication"
- // with an accompanying identical workaround in position.v-command (i.e. command 0x26).
- // These two workarounds together make up the whole fix. The bug was caused by
- // wrongly written script data in Space Trek v1.0's scripts (At least logics 4 and 11).
- // Position-command was called with horizontal values over 200 (Outside the screen!).
- // Clipping the coordinates so the views stay wholly on-screen seems to fix the problems.
- // It is probable (Would have to check better with disassembly to be completely sure)
- // that AGI 2.440 clipped its coordinates in its position and position.v-commands
- // although AGI 2.917 certainly doesn't (Checked that with disassembly) and that's why
- // Space Trek may have worked better with AGI 2.440 than with some other AGI versions.
- // I haven't checked but if Space Trek solely abuses the position-command we wouldn't
- // strictly need the identical workaround in the position.v-command but it does make
- // for a nice symmetry.
- if (getFeatures() & GF_CLIPCOORDS)
- state->_vm->clipViewCoordinates(&vt);
+ screenObj->xPos = screenObj->xPos_prev = xPos;
+ screenObj->yPos = screenObj->yPos_prev = yPos;
}
-void cmdPositionV1(AgiGame *state, uint8 *p) {
- vt.xPos = p1;
- vt.yPos = p2;
+void cmdPositionV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 xPos = parameter[1];
+ uint16 yPos = parameter[2];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->xPos = xPos;
+ screenObj->yPos = yPos;
}
-void cmdPositionF(AgiGame *state, uint8 *p) {
- vt.xPos = vt.xPos2 = _v[p1];
- vt.yPos = vt.yPos2 = _v[p2];
+void cmdPositionF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr1 = parameter[1];
+ uint16 varNr2 = parameter[2];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
- // WORKAROUND: Part of the fix for bug #1659209 "AGI: Space Trek sprite duplication"
- // with an accompanying identical workaround in position-command (i.e. command 0x25).
- // See that workaround's comment for more in-depth information.
- if (getFeatures() & GF_CLIPCOORDS)
- state->_vm->clipViewCoordinates(&vt);
+ screenObj->xPos = screenObj->xPos_prev = vm->getVar(varNr1);
+ screenObj->yPos = screenObj->yPos_prev = vm->getVar(varNr2);
}
-void cmdPositionFV1(AgiGame *state, uint8 *p) {
- vt.xPos = _v[p1];
- vt.yPos = _v[p2];
+void cmdPositionFV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr1 = parameter[1];
+ uint16 varNr2 = parameter[2];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->xPos = vm->getVar(varNr1);
+ screenObj->yPos = vm->getVar(varNr2);
}
-void cmdGetPosn(AgiGame *state, uint8 *p) {
- state->vars[p1] = (unsigned char)vt.xPos;
- state->vars[p2] = (unsigned char)vt.yPos;
+void cmdGetPosn(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr1 = parameter[1];
+ uint16 varNr2 = parameter[2];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ vm->setVar(varNr1, (unsigned char)screenObj->xPos);
+ vm->setVar(varNr2, (unsigned char)screenObj->yPos);
}
-void cmdReposition(AgiGame *state, uint8 *p) {
- int dx = (int8) _v[p1], dy = (int8) _v[p2];
+void cmdReposition(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr1 = parameter[1];
+ uint16 varNr2 = parameter[2];
+ int16 dx = (int8) vm->getVar(varNr1);
+ int16 dy = (int8) vm->getVar(varNr2);
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
debugC(4, kDebugLevelScripts, "dx=%d, dy=%d", dx, dy);
- vt.flags |= fUpdatePos;
+ screenObj->flags |= fUpdatePos;
- if (dx < 0 && vt.xPos < -dx)
- vt.xPos = 0;
+ if (dx < 0 && screenObj->xPos < -dx)
+ screenObj->xPos = 0;
else
- vt.xPos += dx;
+ screenObj->xPos += dx;
- if (dy < 0 && vt.yPos < -dy)
- vt.yPos = 0;
+ if (dy < 0 && screenObj->yPos < -dy)
+ screenObj->yPos = 0;
else
- vt.yPos += dy;
+ screenObj->yPos += dy;
- state->_vm->fixPosition(p0);
+ state->_vm->fixPosition(objectNr);
}
-void cmdRepositionV1(AgiGame *state, uint8 *p) {
- vt.xPos2 = vt.xPos;
- vt.yPos2 = vt.yPos;
- vt.flags |= fUpdatePos;
+void cmdRepositionV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 xPosPlus = parameter[1];
+ uint16 yPosPlus = parameter[2];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
- vt.xPos = (vt.xPos + p1) & 0xff;
- vt.yPos = (vt.yPos + p2) & 0xff;
+ screenObj->xPos_prev = screenObj->xPos;
+ screenObj->yPos_prev = screenObj->yPos;
+ screenObj->flags |= fUpdatePos;
+
+ screenObj->xPos = (screenObj->xPos + xPosPlus) & 0xff;
+ screenObj->yPos = (screenObj->yPos + yPosPlus) & 0xff;
}
-void cmdRepositionTo(AgiGame *state, uint8 *p) {
- vt.xPos = p1;
- vt.yPos = p2;
- vt.flags |= fUpdatePos;
- state->_vm->fixPosition(p0);
+void cmdRepositionTo(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 xPos = parameter[1];
+ uint16 yPos = parameter[2];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->xPos = xPos;
+ screenObj->yPos = yPos;
+ screenObj->flags |= fUpdatePos;
+ state->_vm->fixPosition(objectNr);
}
-void cmdRepositionToF(AgiGame *state, uint8 *p) {
- vt.xPos = _v[p1];
- vt.yPos = _v[p2];
- vt.flags |= fUpdatePos;
- state->_vm->fixPosition(p0);
+void cmdRepositionToF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr1 = parameter[1];
+ uint16 varNr2 = parameter[2];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->xPos = vm->getVar(varNr1);
+ screenObj->yPos = vm->getVar(varNr2);
+ screenObj->flags |= fUpdatePos;
+ state->_vm->fixPosition(objectNr);
}
-void cmdAddToPic(AgiGame *state, uint8 *p) {
- state->_vm->_sprites->addToPic(p0, p1, p2, p3, p4, p5, p6);
+void cmdAddToPic(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 viewNr = parameter[0];
+ uint16 loopNr = parameter[1];
+ uint16 celNr = parameter[2];
+ uint16 xPos = parameter[3];
+ uint16 yPos = parameter[4];
+ uint16 priority = parameter[5];
+ uint16 border = parameter[6];
+
+ state->_vm->_sprites->addToPic(viewNr, loopNr, celNr, xPos, yPos, priority, border);
}
-void cmdAddToPicV1(AgiGame *state, uint8 *p) {
- state->_vm->_sprites->addToPic(p0, p1, p2, p3, p4, p5, -1);
+void cmdAddToPicV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 viewNr = parameter[0];
+ uint16 loopNr = parameter[1];
+ uint16 celNr = parameter[2];
+ uint16 xPos = parameter[3];
+ uint16 yPos = parameter[4];
+ uint16 priority = parameter[5];
+
+ state->_vm->_sprites->addToPic(viewNr, loopNr, celNr, xPos, yPos, priority, -1);
}
-void cmdAddToPicF(AgiGame *state, uint8 *p) {
- state->_vm->_sprites->addToPic(_v[p0], _v[p1], _v[p2], _v[p3], _v[p4], _v[p5], _v[p6]);
+void cmdAddToPicF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 viewNr = vm->getVar(parameter[0]);
+ uint16 loopNr = vm->getVar(parameter[1]);
+ uint16 celNr = vm->getVar(parameter[2]);
+ uint16 xPos = vm->getVar(parameter[3]);
+ uint16 yPos = vm->getVar(parameter[4]);
+ uint16 priority = vm->getVar(parameter[5]);
+ uint16 border = vm->getVar(parameter[6]);
+
+ state->_vm->_sprites->addToPic(viewNr, loopNr, celNr, xPos, yPos, priority, border);
}
-void cmdForceUpdate(AgiGame *state, uint8 *p) {
- state->_vm->_sprites->eraseBoth();
- state->_vm->_sprites->blitBoth();
- state->_vm->_sprites->commitBoth();
+void cmdForceUpdate(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ SpritesMgr *spritesMgr = state->_vm->_sprites;
+
+ spritesMgr->eraseSprites();
+ spritesMgr->buildAllSpriteLists();
+ spritesMgr->drawAllSpriteLists();
+ spritesMgr->showAllSpriteLists();
}
-void cmdReverseLoop(AgiGame *state, uint8 *p) {
- debugC(4, kDebugLevelScripts, "o%d, f%d", p0, p1);
- vt.cycle = kCycleRevLoop;
- vt.flags |= (fDontupdate | fUpdate | fCycling);
- vt.parm1 = p1;
- setflag(p1, false);
+void cmdReverseLoop(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 loopFlag = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ debugC(4, kDebugLevelScripts, "o%d, f%d", objectNr, loopFlag);
+ screenObj->cycle = kCycleRevLoop;
+ screenObj->flags |= (fDontupdate | fUpdate | fCycling);
+ screenObj->loop_flag = loopFlag;
+ state->_vm->setFlag(screenObj->loop_flag, false);
+
+ vm->cyclerActivated(screenObj);
}
-void cmdReverseLoopV1(AgiGame *state, uint8 *p) {
- debugC(4, kDebugLevelScripts, "o%d, f%d", p0, p1);
- vt.cycle = kCycleRevLoop;
- state->_vm->setCel(&vt, 0);
- vt.flags |= (fDontupdate | fUpdate | fCycling);
- vt.parm1 = p1;
- vt.parm3 = 0;
+void cmdReverseLoopV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 loopFlag = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ debugC(4, kDebugLevelScripts, "o%d, f%d", objectNr, loopFlag);
+ screenObj->cycle = kCycleRevLoop;
+ state->_vm->setCel(screenObj, 0);
+ screenObj->flags |= (fDontupdate | fUpdate | fCycling);
+ screenObj->loop_flag = loopFlag;
+ //screenObj->parm3 = 0;
}
-void cmdEndOfLoop(AgiGame *state, uint8 *p) {
- debugC(4, kDebugLevelScripts, "o%d, f%d", p0, p1);
- vt.cycle = kCycleEndOfLoop;
- vt.flags |= (fDontupdate | fUpdate | fCycling);
- vt.parm1 = p1;
- setflag(p1, false);
+void cmdEndOfLoop(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 loopFlag = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ debugC(4, kDebugLevelScripts, "o%d, f%d", objectNr, loopFlag);
+ screenObj->cycle = kCycleEndOfLoop;
+ screenObj->flags |= (fDontupdate | fUpdate | fCycling);
+ screenObj->loop_flag = loopFlag;
+ vm->setFlag(screenObj->loop_flag, false);
+
+ vm->cyclerActivated(screenObj);
}
-void cmdEndOfLoopV1(AgiGame *state, uint8 *p) {
- debugC(4, kDebugLevelScripts, "o%d, f%d", p0, p1);
- vt.cycle = kCycleEndOfLoop;
- state->_vm->setCel(&vt, 0);
- vt.flags |= (fDontupdate | fUpdate | fCycling);
- vt.parm1 = p1;
- vt.parm3 = 0;
+void cmdEndOfLoopV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 loopFlag = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ debugC(4, kDebugLevelScripts, "o%d, f%d", objectNr, loopFlag);
+ screenObj->cycle = kCycleEndOfLoop;
+ state->_vm->setCel(screenObj, 0);
+ screenObj->flags |= (fDontupdate | fUpdate | fCycling);
+ screenObj->loop_flag = loopFlag;
+ //screenObj->parm3 = 0;
}
-void cmdBlock(AgiGame *state, uint8 *p) {
- debugC(4, kDebugLevelScripts, "x1=%d, y1=%d, x2=%d, y2=%d", p0, p1, p2, p3);
+void cmdBlock(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 x1 = parameter[0];
+ uint16 y1 = parameter[1];
+ uint16 x2 = parameter[2];
+ uint16 y2 = parameter[3];
+
+ debugC(4, kDebugLevelScripts, "x1=%d, y1=%d, x2=%d, y2=%d", x1, y1, x2, y2);
state->block.active = true;
- state->block.x1 = p0;
- state->block.y1 = p1;
- state->block.x2 = p2;
- state->block.y2 = p3;
+ state->block.x1 = x1;
+ state->block.y1 = y1;
+ state->block.x2 = x2;
+ state->block.y2 = y2;
}
-void cmdUnblock(AgiGame *state, uint8 *p) {
+void cmdUnblock(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
state->block.active = false;
}
-void cmdNormalMotion(AgiGame *state, uint8 *p) {
- vt.motion = kMotionNormal;
+void cmdNormalMotion(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->motionType = kMotionNormal;
}
-void cmdStopMotion(AgiGame *state, uint8 *p) {
- vt.direction = 0;
- vt.motion = kMotionNormal;
- if (p0 == 0) { // ego only
- _v[vEgoDir] = 0;
+void cmdStopMotion(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->direction = 0;
+ screenObj->motionType = kMotionNormal;
+ if (objectNr == 0) { // ego only
+ state->_vm->setVar(VM_VAR_EGO_DIRECTION, 0);
state->playerControl = false;
}
}
-void cmdStopMotionV1(AgiGame *state, uint8 *p) {
- vt.flags &= ~fAnimated;
+void cmdStopMotionV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags &= ~fAnimated;
}
-void cmdStartMotion(AgiGame *state, uint8 *p) {
- vt.motion = kMotionNormal;
- if (p0 == 0) { // ego only
- _v[vEgoDir] = 0;
+void cmdStartMotion(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->motionType = kMotionNormal;
+ if (objectNr == 0) { // ego only
+ state->_vm->setVar(VM_VAR_EGO_DIRECTION, 0);
state->playerControl = true;
}
}
-void cmdStartMotionV1(AgiGame *state, uint8 *p) {
- vt.flags |= fAnimated;
+void cmdStartMotionV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags |= fAnimated;
}
-void cmdPlayerControl(AgiGame *state, uint8 *p) {
+void cmdPlayerControl(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ ScreenObjEntry *screenObjEgo = &state->screenObjTable[SCREENOBJECTS_EGO_ENTRY];
+
state->playerControl = true;
- state->viewTable[0].motion = kMotionNormal;
+
+ if (screenObjEgo->motionType != kMotionEgo)
+ screenObjEgo->motionType = kMotionNormal;
}
-void cmdProgramControl(AgiGame *state, uint8 *p) {
+void cmdProgramControl(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
state->playerControl = false;
}
-void cmdFollowEgo(AgiGame *state, uint8 *p) {
- vt.motion = kMotionFollowEgo;
- vt.parm1 = p1 > vt.stepSize ? p1 : vt.stepSize;
- vt.parm2 = p2;
- vt.parm3 = 0xff;
+void cmdFollowEgo(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 followStepSize = parameter[1];
+ uint16 followFlag = parameter[2];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->motionType = kMotionFollowEgo;
+ if (followStepSize <= screenObj->stepSize) {
+ screenObj->follow_stepSize = screenObj->stepSize;
+ } else {
+ screenObj->follow_stepSize = followStepSize;
+ }
+ screenObj->follow_flag = followFlag;
+ screenObj->follow_count = 255;
if (getVersion() < 0x2000) {
- _v[p2] = 0;
- vt.flags |= fUpdate | fAnimated;
+ vm->setVar(screenObj->follow_flag, 0);
+ screenObj->flags |= fUpdate | fAnimated;
} else {
- setflag(p2, false);
- vt.flags |= fUpdate;
+ vm->setFlag(screenObj->follow_flag, false);
+ screenObj->flags |= fUpdate;
}
+
+ vm->motionActivated(screenObj);
}
-void cmdMoveObj(AgiGame *state, uint8 *p) {
+void cmdMoveObj(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 moveX = parameter[1];
+ uint16 moveY = parameter[2];
+ uint16 stepSize = parameter[3];
+ uint16 moveFlag = parameter[4];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
// _D (_D_WARN "o=%d, x=%d, y=%d, s=%d, f=%d", p0, p1, p2, p3, p4);
- vt.motion = kMotionMoveObj;
- vt.parm1 = p1;
- vt.parm2 = p2;
- vt.parm3 = vt.stepSize;
- vt.parm4 = p4;
+ screenObj->motionType = kMotionMoveObj;
+ screenObj->move_x = moveX;
+ screenObj->move_y = moveY;
+ screenObj->move_stepSize = screenObj->stepSize;
+ screenObj->move_flag = moveFlag;
- if (p3 != 0)
- vt.stepSize = p3;
+ if (stepSize != 0)
+ screenObj->stepSize = stepSize;
if (getVersion() < 0x2000) {
- _v[p4] = 0;
- vt.flags |= fUpdate | fAnimated;
+ vm->setVar(moveFlag, 0);
+ screenObj->flags |= fUpdate | fAnimated;
} else {
- setflag(p4, false);
- vt.flags |= fUpdate;
+ vm->setFlag(screenObj->move_flag, false);
+ screenObj->flags |= fUpdate;
}
- if (p0 == 0)
+ vm->motionActivated(screenObj);
+
+ if (objectNr == 0)
state->playerControl = false;
// AGI 2.272 (ddp, xmas) doesn't call move_obj!
if (getVersion() > 0x2272)
- state->_vm->moveObj(&vt);
+ vm->moveObj(screenObj);
}
-void cmdMoveObjF(AgiGame *state, uint8 *p) {
- vt.motion = kMotionMoveObj;
- vt.parm1 = _v[p1];
- vt.parm2 = _v[p2];
- vt.parm3 = vt.stepSize;
- vt.parm4 = p4;
+void cmdMoveObjF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 moveX = vm->getVar(parameter[1]);
+ uint16 moveY = vm->getVar(parameter[2]);
+ uint16 stepSize = vm->getVar(parameter[3]);
+ uint16 moveFlag = parameter[4];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
- if (_v[p3] != 0)
- vt.stepSize = _v[p3];
+ screenObj->motionType = kMotionMoveObj;
+ screenObj->move_x = moveX;
+ screenObj->move_y = moveY;
+ screenObj->move_stepSize = screenObj->stepSize;
+ screenObj->move_flag = moveFlag;
- setflag(p4, false);
- vt.flags |= fUpdate;
+ if (stepSize != 0)
+ screenObj->stepSize = stepSize;
- if (p0 == 0)
+ vm->setFlag(screenObj->move_flag, false);
+ screenObj->flags |= fUpdate;
+
+ vm->motionActivated(screenObj);
+
+ if (objectNr == 0)
state->playerControl = false;
// AGI 2.272 (ddp, xmas) doesn't call move_obj!
if (getVersion() > 0x2272)
- state->_vm->moveObj(&vt);
+ vm->moveObj(screenObj);
}
-void cmdWander(AgiGame *state, uint8 *p) {
- if (p0 == 0)
+void cmdWander(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ if (objectNr == 0)
state->playerControl = false;
- vt.motion = kMotionWander;
+ screenObj->motionType = kMotionWander;
if (getVersion() < 0x2000) {
- vt.flags |= fUpdate | fAnimated;
+ screenObj->flags |= fUpdate | fAnimated;
} else {
- vt.flags |= fUpdate;
+ screenObj->flags |= fUpdate;
}
+
+ vm->motionActivated(screenObj);
}
-void cmdSetGameID(AgiGame *state, uint8 *p) {
- if (state->_curLogic->texts && (p0 - 1) <= state->_curLogic->numTexts)
- Common::strlcpy(state->id, state->_curLogic->texts[p0 - 1], 8);
+void cmdSetGameID(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 textNr = parameter[0];
+
+ if (state->_curLogic->texts && (textNr - 1) <= state->_curLogic->numTexts)
+ Common::strlcpy(state->id, state->_curLogic->texts[textNr - 1], 8);
else
state->id[0] = 0;
debug(0, "Game ID: \"%s\"", state->id);
}
-void cmdPause(AgiGame *state, uint8 *p) {
- int tmp = state->clockEnabled;
- const char *b[] = { "Continue", NULL };
- const char *b_ru[] = { "\x8f\xe0\xae\xa4\xae\xab\xa6\xa8\xe2\xec", NULL };
+void cmdPause(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ // Show pause message box
+ vm->inGameTimerPause();
- state->clockEnabled = false;
+ state->_vm->_systemUI->pauseDialog();
- switch (getLanguage()) {
- case Common::RU_RUS:
- state->_vm->selectionBox(" \x88\xa3\xe0\xa0 \xae\xe1\xe2\xa0\xad\xae\xa2\xab\xa5\xad\xa0. \n\n\n", b_ru);
- break;
- default:
- state->_vm->selectionBox(" Game is paused. \n\n\n", b);
- break;
- }
- state->clockEnabled = tmp;
+ vm->inGameTimerResume();
}
-void cmdSetMenu(AgiGame *state, uint8 *p) {
- debugC(4, kDebugLevelScripts, "text %02x of %02x", p0, state->_curLogic->numTexts);
+void cmdSetMenu(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 textNr = parameter[0];
+
+ debugC(4, kDebugLevelScripts, "text %02x of %02x", textNr, state->_curLogic->numTexts);
- if (state->_curLogic->texts != NULL && p0 <= state->_curLogic->numTexts)
- state->_vm->_menu->add(state->_curLogic->texts[p0 - 1]);
+ if (state->_curLogic->texts != NULL && (textNr - 1) <= state->_curLogic->numTexts) {
+ const char *menuText = state->_curLogic->texts[textNr - 1];
+
+ state->_vm->_menu->addMenu(menuText);
+ }
}
-void cmdSetMenuItem(AgiGame *state, uint8 *p) {
- debugC(4, kDebugLevelScripts, "text %02x of %02x", p0, state->_curLogic->numTexts);
+void cmdSetMenuItem(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 textNr = parameter[0] - 1;
+ uint16 controllerSlot = parameter[1];
- if (state->_curLogic->texts != NULL && p0 <= state->_curLogic->numTexts)
- state->_vm->_menu->addItem(state->_curLogic->texts[p0 - 1], p1);
+ debugC(4, kDebugLevelScripts, "text %02x of %02x", textNr, state->_curLogic->numTexts);
+
+ if (state->_curLogic->texts != NULL && textNr <= state->_curLogic->numTexts) {
+ const char *menuItemText = state->_curLogic->texts[textNr];
+
+ state->_vm->_menu->addMenuItem(menuItemText, controllerSlot);
+ }
}
-void cmdVersion(AgiGame *state, uint8 *p) {
+void cmdVersion(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
char ver2Msg[] =
"\n"
" \n\n"
- " Emulating Sierra AGI v%x.%03x\n";
+ " ScummVM Sierra AGI v%x.%03x";
char ver3Msg[] =
"\n"
" \n\n"
- " Emulating AGI v%x.002.%03x\n";
- // no Sierra as it wraps textbox
+ "ScummVM Sierra AGI v%x.002.%03x";
Common::String verMsg = TITLE " v%s";
@@ -1278,98 +1787,112 @@ void cmdVersion(AgiGame *state, uint8 *p) {
verMsg += (maj == 2 ? ver2Msg : ver3Msg);
verMsg = Common::String::format(verMsg.c_str(), gScummVMVersion, maj, min);
- state->_vm->messageBox(verMsg.c_str());
+ state->_vm->_text->messageBox(verMsg.c_str());
}
-void cmdConfigureScreen(AgiGame *state, uint8 *p) {
- state->lineMinPrint = p0;
- state->lineUserInput = p1;
- state->lineStatus = p2;
+void cmdConfigureScreen(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ TextMgr *textMgr = state->_vm->_text;
+ uint16 lineMinPrint = parameter[0];
+ uint16 promptRow = parameter[1];
+ uint16 statusRow = parameter[2];
+
+ textMgr->configureScreen(lineMinPrint);
+ textMgr->statusRow_Set(statusRow);
+ textMgr->promptRow_Set(promptRow);
}
-void cmdTextScreen(AgiGame *state, uint8 *p) {
- debugC(4, kDebugLevelScripts, "switching to text mode");
- state->gfxMode = false;
+void cmdTextScreen(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ GfxMgr *gfxMgr = state->_vm->_gfx;
+ TextMgr *textMgr = state->_vm->_text;
- // Simulates the "bright background bit" of the PC video
- // controller.
- if (state->colorBg)
- state->colorBg |= 0x08;
+ debugC(4, kDebugLevelScripts, "switching to text mode");
- state->_vm->_gfx->clearScreen(state->colorBg);
+ state->gfxMode = false;
+ gfxMgr->setPalette(false); // set text-mode palette
+ textMgr->charAttrib_Set(textMgr->_textAttrib.foreground, textMgr->_textAttrib.background);
+ gfxMgr->clearDisplay(0);
+ textMgr->clearLines(0, 24, textMgr->_textAttrib.combinedBackground);
}
-void cmdGraphics(AgiGame *state, uint8 *p) {
+void cmdGraphics(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
debugC(4, kDebugLevelScripts, "switching to graphics mode");
- if (!state->gfxMode) {
- state->gfxMode = true;
- state->_vm->_gfx->clearScreen(0);
- state->_vm->_picture->showPic();
- state->_vm->writeStatus();
- state->_vm->writePrompt();
- }
+ state->_vm->redrawScreen();
}
-void cmdSetTextAttribute(AgiGame *state, uint8 *p) {
- state->colorFg = p0;
- state->colorBg = p1;
-
- if (state->gfxMode) {
- if (state->colorBg != 0) {
- state->colorFg = 0;
- state->colorBg = 15;
- }
- }
+void cmdSetTextAttribute(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ int16 foreground = parameter[0];
+ int16 background = parameter[1];
+ state->_vm->_text->charAttrib_Set(foreground, background);
}
-void cmdStatus(AgiGame *state, uint8 *p) {
- state->_vm->inventory();
+void cmdStatus(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ TextMgr *textMgr = state->_vm->_text;
+ InventoryMgr *inventoryMgr = state->_vm->_inventory;
+
+ textMgr->inputEditOn();
+ textMgr->charAttrib_Push();
+ textMgr->charAttrib_Set(0, 15);
+
+ cmdTextScreen(state, vm, parameter);
+
+ inventoryMgr->show();
+
+ //invent_state = 0;
+ textMgr->charAttrib_Pop();
+ state->_vm->redrawScreen();
}
-void cmdQuit(AgiGame *state, uint8 *p) {
- const char *buttons[] = { "Quit", "Continue", NULL };
+void cmdQuit(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 withoutPrompt = parameter[0];
+// const char *buttons[] = { "Quit", "Continue", NULL };
state->_vm->_sound->stopSound();
- if (p0) {
+ if (withoutPrompt) {
state->_vm->quitGame();
} else {
- if (state->_vm->selectionBox(" Quit the game, or continue? \n\n\n", buttons) == 0) {
+ if (state->_vm->_systemUI->quitDialog()) {
state->_vm->quitGame();
}
}
}
-void cmdQuitV1(AgiGame *state, uint8 *p) {
+void cmdQuitV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
state->_vm->_sound->stopSound();
state->_vm->quitGame();
}
-void cmdRestartGame(AgiGame *state, uint8 *p) {
- const char *buttons[] = { "Restart", "Continue", NULL };
- int sel;
+void cmdRestartGame(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ bool doRestart = false;
state->_vm->_sound->stopSound();
- sel = getflag(fAutoRestart) ? 0 :
- state->_vm->selectionBox(" Restart game, or continue? \n\n\n", buttons);
- if (sel == 0) {
- state->_vm->_restartGame = true;
- setflag(fRestartGame, true);
- state->_vm->_menu->enableAll();
+ if (vm->getFlag(VM_FLAG_AUTO_RESTART)) {
+ doRestart = true;
+ } else {
+ doRestart = vm->_systemUI->restartDialog();
+ }
+
+ if (doRestart) {
+ vm->_restartGame = true;
+ vm->setFlag(VM_FLAG_RESTART_GAME, true);
+ vm->_menu->itemEnableAll();
}
}
-void cmdDistance(AgiGame *state, uint8 *p) {
+void cmdDistance(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr1 = parameter[0];
+ uint16 objectNr2 = parameter[1];
+ uint16 destVarNr = parameter[2];
int16 x1, y1, x2, y2, d;
- VtEntry *v0 = &state->viewTable[p0];
- VtEntry *v1 = &state->viewTable[p1];
-
- if (v0->flags & fDrawn && v1->flags & fDrawn) {
- x1 = v0->xPos + v0->xSize / 2;
- y1 = v0->yPos;
- x2 = v1->xPos + v1->xSize / 2;
- y2 = v1->yPos;
+ ScreenObjEntry *screenObj1 = &state->screenObjTable[objectNr1];
+ ScreenObjEntry *screenObj2 = &state->screenObjTable[objectNr2];
+
+ if (screenObj1->flags & fDrawn && screenObj2->flags & fDrawn) {
+ x1 = screenObj1->xPos + screenObj1->xSize / 2;
+ y1 = screenObj1->yPos;
+ x2 = screenObj2->xPos + screenObj2->xSize / 2;
+ y2 = screenObj2->yPos;
d = ABS(x1 - x2) + ABS(y1 - y2);
if (d > 0xfe)
d = 0xfe;
@@ -1377,7 +1900,8 @@ void cmdDistance(AgiGame *state, uint8 *p) {
d = 0xff;
}
- // WORKAROUND: Fixes King's Quest IV's script bug #1660424 (KQ4: Zombie bug).
+ // WORKAROUND: Fixes King's Quest IV's script bug #3067 (KQ4: Zombie bug).
+ // This bug also happens in the original interpreter.
// In the graveyard (Rooms 16 and 18) at night if you had the Obsidian Scarab (Item 4)
// and you were very close to a spot where a zombie was going to rise up from the
// ground you could reproduce the bug. Just standing there and letting the zombie
@@ -1386,7 +1910,7 @@ void cmdDistance(AgiGame *state, uint8 *p) {
// wouldn't chase Rosella around anymore. If it had worked correctly the zombie
// wouldn't have come up at all or it would have come up and gone back down
// immediately. The latter approach is the one implemented here.
- if (getGameID() == GID_KQ4 && (_v[vCurRoom] == 16 || _v[vCurRoom] == 18) && p2 >= 221 && p2 <= 223) {
+ if (vm->getGameID() == GID_KQ4 && (vm->getVar(VM_VAR_CURRENT_ROOM) == 16 || vm->getVar(VM_VAR_CURRENT_ROOM) == 18) && destVarNr >= 221 && destVarNr <= 223) {
// Rooms 16 and 18 are graveyards where three zombies come up at night. They use logics 16 and 18.
// Variables 221-223 are used to save the distance between each zombie and Rosella.
// Variables 155, 156 and 162 are used to save the state of each zombie in room 16.
@@ -1399,343 +1923,388 @@ void cmdDistance(AgiGame *state, uint8 *p) {
// a zombie or the zombie getting turned away by the scarab) we make it appear the
// zombie is far away from Rosella if the zombie is not already up and chasing her.
enum zombieStates {ZOMBIE_SET_TO_RISE_UP, ZOMBIE_RISING_UP, ZOMBIE_CHASING_EGO};
- uint8 zombieStateVarNumList[] = {155, 156, (uint8)((_v[vCurRoom] == 16) ? 162 : 158)};
- uint8 zombieNum = p2 - 221; // Zombie's number (In range 0-2)
+ uint8 zombieStateVarNumList[] = {155, 156, (uint8)((vm->getVar(VM_VAR_CURRENT_ROOM) == 16) ? 162 : 158)};
+ uint8 zombieNum = destVarNr - 221; // Zombie's number (In range 0-2)
uint8 zombieStateVarNum = zombieStateVarNumList[zombieNum]; // Number of the variable containing zombie's state
- uint8 zombieState = _v[zombieStateVarNum]; // Zombie's state
+ uint8 zombieState = vm->getVar(zombieStateVarNum); // Zombie's state
// If zombie is not chasing Rosella then set its distance from Rosella to the maximum
if (zombieState != ZOMBIE_CHASING_EGO)
d = 0xff;
}
- _v[p2] = (unsigned char)d;
+ vm->setVar(destVarNr, (unsigned char)d);
}
-void cmdAcceptInput(AgiGame *state, uint8 *p) {
+void cmdAcceptInput(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ TextMgr *textMgr = state->_vm->_text;
+
debugC(4, kDebugLevelScripts | kDebugLevelInput, "input normal");
- state->_vm->newInputMode(INPUT_NORMAL);
- state->inputEnabled = true;
- state->_vm->writePrompt();
+ textMgr->promptEnable();
+ textMgr->promptRedraw();
}
-void cmdPreventInput(AgiGame *state, uint8 *p) {
+void cmdPreventInput(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ TextMgr *textMgr = state->_vm->_text;
+
debugC(4, kDebugLevelScripts | kDebugLevelInput, "no input");
- state->_vm->newInputMode(INPUT_NONE);
- state->inputEnabled = false;
+ textMgr->promptDisable();
- // Always clear with black background. Fixes bug #3080041.
- state->_vm->clearPrompt(true);
+ textMgr->inputEditOn();
+ textMgr->clearLine(textMgr->promptRow_Get(), 0);
}
-void cmdGetString(AgiGame *state, uint8 *p) {
- int tex, row, col;
+void cmdCancelLine(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ state->_vm->_text->promptCancelLine();
+}
+
+void cmdEchoLine(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ TextMgr *textMgr = state->_vm->_text;
+
+ if (textMgr->promptIsEnabled()) {
+ textMgr->promptEchoLine();
+ }
+}
- debugC(4, kDebugLevelScripts, "%d %d %d %d %d", p0, p1, p2, p3, p4);
+void cmdGetString(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ TextMgr *textMgr = state->_vm->_text;
+ int16 stringDestNr = parameter[0];
+ int16 leadInTextNr = parameter[1] - 1;
+ int16 stringRow = parameter[2];
+ int16 stringColumn = parameter[3];
+ int16 stringMaxLen = parameter[4];
+ bool previousEditState = false;
+ const char *leadInTextPtr = nullptr;
- tex = p1 - 1;
- row = p2;
- col = p3;
+ if (stringMaxLen > TEXT_STRING_MAX_SIZE)
+ stringMaxLen = TEXT_STRING_MAX_SIZE;
+
+ debugC(4, kDebugLevelScripts, "%d %d %d %d %d", stringDestNr, leadInTextNr, stringRow, stringColumn, stringMaxLen);
+
+ previousEditState = textMgr->inputGetEditStatus();
+
+ textMgr->charPos_Push();
+ textMgr->inputEditOn();
// Workaround for SQLC bug.
// See Sarien bug #792125 for details
- if (row > 24)
- row = 24;
- if (col > 39)
- col = 39;
+// if (promptRow > 24)
+// promptRow = 24;
+// if (promptColumn > 39)
+// promptColumn = 39;
- state->_vm->newInputMode(INPUT_GETSTRING);
+ if (stringRow < 25) {
+ textMgr->charPos_Set(stringRow, stringColumn);
+ }
- if (state->_curLogic->texts != NULL && state->_curLogic->numTexts >= tex) {
- int len = strlen(state->_curLogic->texts[tex]);
+ if (state->_curLogic->texts && state->_curLogic->numTexts >= leadInTextNr) {
+ leadInTextPtr = state->_curLogic->texts[leadInTextNr];
- state->_vm->printText(state->_curLogic->texts[tex], 0, col, row, len, state->colorFg, state->colorBg);
- state->_vm->getString(col + len - 1, row, p4, p0);
+ leadInTextPtr = textMgr->stringPrintf(leadInTextPtr);
+ leadInTextPtr = textMgr->stringWordWrap(leadInTextPtr, 40); // ?? not absolutely sure
- // SGEO: display input char
- state->_vm->_gfx->printCharacter((col + len), row, state->cursorChar, state->colorFg, state->colorBg);
+ textMgr->displayText(leadInTextPtr);
}
- do {
- state->_vm->mainCycle();
- } while (state->inputMode == INPUT_GETSTRING && !(state->_vm->shouldQuit() || state->_vm->_restartGame));
+ state->_vm->cycleInnerLoopActive(CYCLE_INNERLOOP_GETSTRING);
+
+ textMgr->stringSet("");
+ textMgr->stringEdit(stringMaxLen);
+
+ // copy string to destination
+ // TODO: not sure if set all the time or only when ENTER is pressed
+ Common::strlcpy(&state->_vm->_game.strings[stringDestNr][0], (char *)textMgr->_inputString, MAX_STRINGLEN);
+
+ textMgr->charPos_Pop();
+
+ if (!previousEditState) {
+ textMgr->inputEditOff();
+ }
}
-void cmdGetNum(AgiGame *state, uint8 *p) {
- debugC(4, kDebugLevelScripts, "%d %d", p0, p1);
+void cmdGetNum(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ TextMgr *textMgr = state->_vm->_text;
+ int16 leadInTextNr = parameter[0] - 1;
+ int16 numberDestVarNr = parameter[1];
+ const char *leadInTextPtr = nullptr;
+ byte number = 0;
+
+ debugC(4, kDebugLevelScripts, "%d %d", leadInTextNr, numberDestVarNr);
- state->_vm->newInputMode(INPUT_GETSTRING);
+ textMgr->inputEditOn();
+ textMgr->charPos_Set(textMgr->promptRow_Get(), 0);
- if (state->_curLogic->texts != NULL && state->_curLogic->numTexts >= (p0 - 1)) {
- int len = strlen(state->_curLogic->texts[p0 - 1]);
+ if (state->_curLogic->texts && state->_curLogic->numTexts >= leadInTextNr) {
+ leadInTextPtr = state->_curLogic->texts[leadInTextNr];
- state->_vm->printText(state->_curLogic->texts[p0 - 1], 0, 0, 22, len, state->colorFg, state->colorBg);
- state->_vm->getString(len - 1, 22, 3, MAX_STRINGS);
+ leadInTextPtr = textMgr->stringPrintf(leadInTextPtr);
+ leadInTextPtr = textMgr->stringWordWrap(leadInTextPtr, 40); // ?? not absolutely sure
- // CM: display input char
- state->_vm->_gfx->printCharacter((p3 + len), 22, state->cursorChar, state->colorFg, state->colorBg);
+ textMgr->displayText(leadInTextPtr);
}
- do {
- state->_vm->mainCycle();
- } while (state->inputMode == INPUT_GETSTRING && !(state->_vm->shouldQuit() || state->_vm->_restartGame));
+ textMgr->inputEditOff();
+
+ state->_vm->cycleInnerLoopActive(CYCLE_INNERLOOP_GETNUMBER);
- _v[p1] = atoi(state->strings[MAX_STRINGS]);
+ textMgr->stringSet("");
+ textMgr->stringEdit(3);
- debugC(4, kDebugLevelScripts, "[%s] -> %d", state->strings[MAX_STRINGS], _v[p1]);
+ textMgr->promptRedraw();
- state->_vm->clearLines(22, 22, state->colorBg);
- state->_vm->flushLines(22, 22);
+ number = atoi((char *)textMgr->_inputString);
+ vm->setVar(numberDestVarNr, number);
+
+ debugC(4, kDebugLevelScripts, "[%s] -> %d", state->strings[MAX_STRINGS], number);
}
-void cmdSetCursorChar(AgiGame *state, uint8 *p) {
- if (state->_curLogic->texts != NULL && (p0 - 1) <= state->_curLogic->numTexts) {
- state->cursorChar = *state->_curLogic->texts[p0 - 1];
+void cmdSetCursorChar(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ TextMgr *textMgr = state->_vm->_text;
+ uint16 textNr = parameter[0] - 1;
+
+ if (state->_curLogic->texts != NULL && textNr <= state->_curLogic->numTexts) {
+ textMgr->inputSetCursorChar(*state->_curLogic->texts[textNr]);
} else {
// default
- state->cursorChar = '_';
+ textMgr->inputSetCursorChar('_');
}
}
-void cmdSetKey(AgiGame *state, uint8 *p) {
- int key = 256 * p1 + p0;
- int slot = -1;
+void cmdSetKey(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 key = parameter[0] + (parameter[1] << 8);
+ uint16 controllerSlot = parameter[2];
+ int16 keyMappingSlot = -1;
- for (int i = 0; i < MAX_CONTROLLERS; i++) {
- if (slot == -1 && !state->controllers[i].keycode)
- slot = i;
+ for (int i = 0; i < MAX_CONTROLLER_KEYMAPPINGS; i++) {
+ if (keyMappingSlot == -1 && !state->controllerKeyMapping[i].keycode)
+ keyMappingSlot = i;
- if (state->controllers[i].keycode == key && state->controllers[i].controller == p2)
+ if (state->controllerKeyMapping[i].keycode == key && state->controllerKeyMapping[i].controllerSlot == controllerSlot)
return;
}
- if (slot == -1) {
- warning("Number of set.keys exceeded %d", MAX_CONTROLLERS);
+ if (keyMappingSlot == -1) {
+ warning("Number of set.keys exceeded %d", MAX_CONTROLLER_KEYMAPPINGS);
return;
}
- debugC(4, kDebugLevelScripts, "cmdSetKey: %d %d %d", p0, p1, p2);
- state->controllers[slot].keycode = key;
- state->controllers[slot].controller = p2;
+ debugC(4, kDebugLevelScripts, "cmdSetKey: %d %d %d", parameter[0], parameter[1], controllerSlot);
+ state->controllerKeyMapping[keyMappingSlot].keycode = key;
+ state->controllerKeyMapping[keyMappingSlot].controllerSlot = controllerSlot;
- state->controllerOccured[p2] = false;
+ state->controllerOccured[controllerSlot] = false;
}
-void cmdSetString(AgiGame *state, uint8 *p) {
+void cmdSetString(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 stringNr = parameter[0];
+ uint16 textNr = parameter[1] - 1;
// CM: to avoid crash in Groza (str = 150)
- if (p0 > MAX_STRINGS)
+ if (stringNr > MAX_STRINGS)
return;
- strcpy(state->strings[p0], state->_curLogic->texts[p1 - 1]);
+ Common::strlcpy(state->strings[stringNr], state->_curLogic->texts[textNr], MAX_STRINGLEN);
}
-void cmdDisplay(AgiGame *state, uint8 *p) {
+void cmdDisplay(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
// V1 has 4 args
- int t = (getVersion() >= 0x2000 ? p2 : p3);
- int len = 40;
-
- char *s = state->_vm->wordWrapString(state->_curLogic->texts[t - 1], &len);
-
- state->_vm->printText(s, p1, 0, p0, 40, state->colorFg, state->colorBg);
-
- free(s);
-}
+ int16 textNr = (getVersion() >= 0x2000 ? parameter[2] : parameter[3]);
+ int16 textRow = parameter[0];
+ int16 textColumn = parameter[1];
-void cmdDisplayF(AgiGame *state, uint8 *p) {
- state->_vm->printText(state->_curLogic->texts[_v[p2] - 1], _v[p1], 0, _v[p0], 40, state->colorFg, state->colorBg);
+ state->_vm->_text->display(textNr, textRow, textColumn);
}
-void cmdClearTextRect(AgiGame *state, uint8 *p) {
- int c, x1, y1, x2, y2;
+void cmdDisplayF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ int16 textRow = vm->getVar(parameter[0]);
+ int16 textColumn = vm->getVar(parameter[1]);
+ int16 textNr = vm->getVar(parameter[2]);
- if ((c = p4) != 0)
- c = 15;
-
- x1 = p1 * CHAR_COLS;
- y1 = p0 * CHAR_LINES;
- x2 = (p3 + 1) * CHAR_COLS - 1;
- y2 = (p2 + 1) * CHAR_LINES - 1;
+ state->_vm->_text->display(textNr, textRow, textColumn);
+}
- // Added to prevent crash with x2 = 40 in the iigs demo
- if (x1 > GFX_WIDTH)
- x1 = GFX_WIDTH - 1;
- if (x2 > GFX_WIDTH)
- x2 = GFX_WIDTH - 1;
- if (y1 > GFX_HEIGHT)
- y1 = GFX_HEIGHT - 1;
- if (y2 > GFX_HEIGHT)
- y2 = GFX_HEIGHT - 1;
+void cmdClearTextRect(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ int16 textUpperRow = parameter[0];
+ int16 textUpperColumn = parameter[1];
+ int16 textLowerRow = parameter[2];
+ int16 textLowerColumn = parameter[3];
+ int16 color = state->_vm->_text->calculateTextBackground(parameter[4]);
- state->_vm->_gfx->drawRectangle(x1, y1, x2, y2, c);
- state->_vm->_gfx->flushBlock(x1, y1, x2, y2);
+ state->_vm->_text->clearBlock(textUpperRow, textUpperColumn, textLowerRow, textLowerColumn, color);
}
-void cmdToggleMonitor(AgiGame *state, uint8 *p) {
+void cmdToggleMonitor(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
debug(0, "toggle.monitor");
}
-void cmdEchoLine(AgiGame *state, uint8 *p) {
- strcpy((char *)state->inputBuffer, (const char *)state->echoBuffer);
- state->cursorPos = strlen((char *)state->inputBuffer);
- state->hasPrompt = 0;
-}
-
-void cmdClearLines(AgiGame *state, uint8 *p) {
- uint8 l;
+void cmdClearLines(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ int16 textRowUpper = parameter[0];
+ int16 textRowLower = parameter[1];
+ int16 color = state->_vm->_text->calculateTextBackground(parameter[2]);
// Residence 44 calls clear.lines(24,0,0), see Sarien bug #558423
- l = p1 ? p1 : p0;
-
// Agent06 incorrectly calls clear.lines(1,150,0), see ScummVM bugs
// #1935838 and #1935842
- l = (l <= 24) ? l : 24;
-
- state->_vm->clearLines(p0, l, p2);
- state->_vm->flushLines(p0, l);
+ if (textRowUpper > textRowLower) {
+ warning("cmdClearLines: RowUpper higher than RowLower");
+ textRowLower = textRowUpper;
+ }
+ state->_vm->_text->clearLines(textRowUpper, textRowLower, color);
}
-void cmdPrint(AgiGame *state, uint8 *p) {
- int n = p0 < 1 ? 1 : p0;
+void cmdPrint(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ int16 textNr = parameter[0];
- state->_vm->print(state->_curLogic->texts[n - 1], 0, 0, 0);
+ state->_vm->_text->print(textNr);
}
-void cmdPrintF(AgiGame *state, uint8 *p) {
- int n = _v[p0] < 1 ? 1 : _v[p0];
+void cmdPrintF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ int16 textNr = vm->getVar(parameter[0]);
- state->_vm->print(state->_curLogic->texts[n - 1], 0, 0, 0);
+ state->_vm->_text->print(textNr);
}
-void cmdPrintAt(AgiGame *state, uint8 *p) {
- int n = p0 < 1 ? 1 : p0;
+void cmdPrintAt(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ int16 textNr = parameter[0];
+ int16 textRow = parameter[1];
+ int16 textColumn = parameter[2];
+ int16 textWidth = parameter[3];
- debugC(4, kDebugLevelScripts, "%d %d %d %d", p0, p1, p2, p3);
+ debugC(4, kDebugLevelScripts, "%d %d %d %d", textNr, textRow, textColumn, textWidth);
- state->_vm->print(state->_curLogic->texts[n - 1], p1, p2, p3);
+ state->_vm->_text->printAt(textNr, textRow, textColumn, textWidth);
}
-void cmdPrintAtV(AgiGame *state, uint8 *p) {
- int n = _v[p0] < 1 ? 1 : _v[p0];
+void cmdPrintAtV(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ int16 textNr = vm->getVar(parameter[0]);
+ int16 textRow = parameter[1];
+ int16 textColumn = parameter[2];
+ int16 textWidth = parameter[3];
+
+ debugC(4, kDebugLevelScripts, "%d %d %d %d", textNr, textRow, textColumn, textWidth);
- state->_vm->print(state->_curLogic->texts[n - 1], p1, p2, p3);
+ state->_vm->_text->printAt(textNr, textRow, textColumn, textWidth);
}
-void cmdPushScript(AgiGame *state, uint8 *p) {
+// push.script was not available until 2.425, and also not available in 2.440
+void cmdPushScript(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
// We run AGIMOUSE always as a side effect
//if (getFeatures() & GF_AGIMOUSE || true) {
- state->vars[27] = state->_vm->_mouse.button;
- state->vars[28] = state->_vm->_mouse.x / 2;
- state->vars[29] = state->_vm->_mouse.y;
+ vm->setVar(VM_VAR_MOUSE_BUTTONSTATE, state->_vm->_mouse.button);
+ vm->setVar(VM_VAR_MOUSE_X, vm->_mouse.pos.x / 2);
+ vm->setVar(VM_VAR_MOUSE_Y, vm->_mouse.pos.y);
/*} else {
- if (getVersion() >= 0x2915) {
- debug(0, "push.script");
- }
+ if (getVersion() >= 0x2915) {
+ debug(0, "push.script");
+ }
}*/
}
-void cmdSetPriBase(AgiGame *state, uint8 *p) {
- int i, x, pri;
+void cmdSetPriBase(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ if ((getVersion() != 0x2425) && (getVersion() < 0x2936)) {
+ // was only available in the 2.425 interpreter and from 2.936 (last AGI2 version) onwards
+ // Called during KQ3 (Apple IIgs):
+ // - picking up chicken (parameter = 50)
+ // - opening store/tavern door (parameter = 19)
+ // - when pirates say "Land Ho" (parameter = 16)
+ // - when killing the dragon (parameter = 4)
+ // Also called by SQ2 (Apple IIgs):
+ // - in Vohaul's lair (SQ2 currently gets this call through, which breaks some priority)
+ // TODO: Figure out what's going on
+ warning("set.pri.base called, although not available for current AGI version");
+ return;
+ }
- debug(0, "Priority base set to %d", p0);
+ uint16 priorityBase = parameter[0];
- // state->alt_pri = true;
- x = (_HEIGHT - p0) * _HEIGHT / 10;
+ debug(0, "Priority base set to %d", priorityBase);
- for (i = 0; i < _HEIGHT; i++) {
- pri = (i - p0) < 0 ? 4 : (i - p0) * _HEIGHT / x + 5;
- if (pri > 15)
- pri = 15;
- state->priTable[i] = pri;
- }
+ state->_vm->_gfx->setPriorityTable(priorityBase);
}
-void cmdMousePosn(AgiGame *state, uint8 *p) {
- _v[p0] = WIN_TO_PIC_X(state->_vm->_mouse.x);
- _v[p1] = WIN_TO_PIC_Y(state->_vm->_mouse.y);
+void cmdMousePosn(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 destVarNr1 = parameter[0];
+ uint16 destVarNr2 = parameter[1];
+ int16 mouseX = vm->_mouse.pos.x;
+ int16 mouseY = vm->_mouse.pos.y;
+
+ vm->_gfx->translateDisplayPosToGameScreen(mouseX, mouseY);
+
+ vm->setVar(destVarNr1, mouseX);
+ vm->setVar(destVarNr2, mouseY);
}
-void cmdShakeScreen(AgiGame *state, uint8 *p) {
- int i;
+void cmdShakeScreen(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 shakeCount = parameter[0];
// AGIPAL uses shake.screen values between 100 and 109 to set the palette
// (Checked the original AGIPAL-hack's shake.screen-routine's disassembly).
- if (p0 >= 100 && p0 < 110) {
+ if (shakeCount >= 100 && shakeCount < 110) {
if (getFeatures() & GF_AGIPAL) {
- state->_vm->_gfx->setAGIPal(p0);
+ state->_vm->_gfx->setAGIPal(shakeCount);
return;
} else {
warning("It looks like GF_AGIPAL flag is missing");
}
}
- // Disables input while shaking to prevent bug
- // #1678230: AGI: Entering text while screen is shaking
- bool originalValue = state->inputEnabled;
- state->inputEnabled = false;
-
- state->_vm->_gfx->shakeStart();
-
- state->_vm->_sprites->commitBoth(); // Fixes SQ1 demo
- for (i = 4 * p0; i; i--) {
- state->_vm->_gfx->shakeScreen(i & 1);
- state->_vm->_gfx->flushBlock(0, 0, GFX_WIDTH - 1, GFX_HEIGHT - 1);
- state->_vm->mainCycle();
- }
- state->_vm->_gfx->shakeEnd();
-
- // Sets input back to what it was
- state->inputEnabled = originalValue;
+ state->_vm->_gfx->shakeScreen(shakeCount);
}
-void cmdSetSpeed(AgiGame *state, uint8 *p) {
+void cmdSetSpeed(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
// V1 command
(void)state;
- (void)p;
+ (void)parameter;
// speed = _v[p0];
}
-void cmdSetItemView(AgiGame *state, uint8 *p) {
+void cmdSetItemView(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
// V1 command
(void)state;
- (void)p;
+ (void)parameter;
}
-void cmdCallV1(AgiGame *state, uint8 *p) {
- state->_vm->agiLoadResource(rLOGIC, p0);
+void cmdCallV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 resourceNr = parameter[0];
+
+ state->_vm->agiLoadResource(RESOURCETYPE_LOGIC, resourceNr);
// FIXME: The following instruction looks incomplete.
// Maybe something is meant to be assigned to, or read from,
// the logic_list entry?
// state->logic_list[++state->max_logics];
// For now, just do the increment, to silence a clang warning
++state->max_logics;
- _v[13] = 1;
+ vm->setVar(13, 1); // ???? maybe create another enum vor VM Vars
}
-void cmdNewRoomV1(AgiGame *state, uint8 *p) {
+void cmdNewRoomV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 resourceNr = parameter[0];
+
warning("cmdNewRoomV1()");
- state->_vm->agiLoadResource(rLOGIC, p0);
+ state->_vm->agiLoadResource(RESOURCETYPE_LOGIC, resourceNr);
state->max_logics = 1;
- state->logic_list[1] = p0;
- _v[13] = 1;
+ state->logic_list[1] = resourceNr;
+ vm->setVar(13, 1);
}
-void cmdNewRoomVV1(AgiGame *state, uint8 *p) {
+void cmdNewRoomVV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 resourceNr = vm->getVar(parameter[0]);
+
warning("cmdNewRoomVV1()");
- state->_vm->agiLoadResource(rLOGIC, _v[p0]);
+ state->_vm->agiLoadResource(RESOURCETYPE_LOGIC, resourceNr);
state->max_logics = 1;
- state->logic_list[1] = _v[p0];
- _v[13] = 1;
+ state->logic_list[1] = resourceNr;
+ vm->setVar(13, 1);
}
-void cmdUnknown(AgiGame *state, uint8 *p) {
- warning("Skipping unknown opcode %2X", *(code + ip - 1));
+void cmdUnknown(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ warning("Skipping unknown opcode %2X", *(state->_curLogic->data + state->_curLogic->cIP - 1));
}
/**
* Execute a logic script
* @param n Number of the logic resource to execute
*/
-int AgiEngine::runLogic(int n) {
+int AgiEngine::runLogic(int16 logicNr) {
AgiGame *state = &_game;
uint8 op = 0;
uint8 p[CMD_BSIZE] = { 0 };
@@ -1747,25 +2316,26 @@ int AgiEngine::runLogic(int n) {
state->max_logics = 0;
debugC(2, kDebugLevelScripts, "=================");
- debugC(2, kDebugLevelScripts, "runLogic(%d)", n);
+ debugC(2, kDebugLevelScripts, "runLogic(%d)", logicNr);
- sp.script = n;
+ sp.script = logicNr;
sp.curIP = 0;
_game.execStack.push_back(sp);
// If logic not loaded, load it
- if (~_game.dirLogic[n].flags & RES_LOADED) {
- debugC(4, kDebugLevelScripts, "logic %d not loaded!", n);
- agiLoadResource(rLOGIC, n);
+ if (~_game.dirLogic[logicNr].flags & RES_LOADED) {
+ debugC(4, kDebugLevelScripts, "logic %d not loaded!", logicNr);
+ agiLoadResource(RESOURCETYPE_LOGIC, logicNr);
}
- _game.lognum = n;
- _game._curLogic = &_game.logics[_game.lognum];
+ _game.curLogicNr = logicNr;
+ _game._curLogic = &_game.logics[_game.curLogicNr];
_game._curLogic->cIP = _game._curLogic->sIP;
- _timerHack = 0;
- while (ip < _game.logics[n].size && !(shouldQuit() || _restartGame)) {
+ while (state->_curLogic->cIP < _game.logics[logicNr].size && !(shouldQuit() || _restartGame)) {
+ // TODO: old code, needs to be adjusted
+#if 0
if (_debug.enabled) {
if (_debug.steps > 0) {
if (_debug.logic0 || n) {
@@ -1778,35 +2348,31 @@ int AgiEngine::runLogic(int n) {
do {
mainCycle();
} while (!_debug.steps && _debug.enabled);
- _sprites->eraseBoth();
+ _sprites->eraseAllSprites();
}
}
+#endif
- _game.execStack.back().curIP = ip;
+ // Just a counter for every instruction, that got executed
+ _instructionCounter++;
+
+ _game.execStack.back().curIP = state->_curLogic->cIP;
char st[101];
int sz = MIN(_game.execStack.size(), 100u);
memset(st, '.', sz);
st[sz] = 0;
- switch (op = *(code + ip++)) {
- case 0xff: // if (open/close)
- testIfCode(n);
+ switch (op = *(state->_curLogic->data + state->_curLogic->cIP++)) {
+ case 0xff: // if (open/close)
+ testIfCode(logicNr);
break;
- case 0xfe: // goto
+ case 0xfe: // goto
// +2 covers goto size
- ip += 2 + ((int16)READ_LE_UINT16(code + ip));
-
- // timer must keep running even in goto loops,
- // but AGI engine can't do that :(
- if (_timerHack > 20) {
- pollTimer();
- updateTimer();
- _timerHack = 0;
- }
+ state->_curLogic->cIP += 2 + ((int16)READ_LE_UINT16(state->_curLogic->data + state->_curLogic->cIP));
break;
- case 0x00: // return
- debugC(2, kDebugLevelScripts, "%sreturn() // Logic %d", st, n);
+ case 0x00: // return
+ debugC(2, kDebugLevelScripts, "%sreturn() // Logic %d", st, logicNr);
debugC(2, kDebugLevelScripts, "=================");
// if (getVersion() < 0x2000) {
@@ -1825,20 +2391,20 @@ int AgiEngine::runLogic(int n) {
return 1;
default:
num = logicNamesCmd[op].argumentsLength();
- memmove(p, code + ip, num);
+ memmove(p, state->_curLogic->data + state->_curLogic->cIP, num);
memset(p + num, 0, CMD_BSIZE - num);
debugC(2, kDebugLevelScripts, "%s%s(%d %d %d)", st, logicNamesCmd[op].name, p[0], p[1], p[2]);
- _agiCommands[op](&_game, p);
- ip += num;
+ _agiCommands[op](&_game, this, p);
+ state->_curLogic->cIP += num;
}
// if ((op == 0x0B || op == 0x3F || op == 0x40) && logic_index < state->max_logics) {
// n = state->logic_list[++logic_index];
// state->_curLogic = &state->logics[n];
// state->lognum = n;
-// ip = 2;
+// state->_curLogic_cIP = 2;
// warning("running logic %d\n", n);
// }
@@ -1848,13 +2414,13 @@ int AgiEngine::runLogic(int n) {
_game.execStack.pop_back();
- return 0; // after executing new.room()
+ return 0; // after executing new.room()
}
void AgiEngine::executeAgiCommand(uint8 op, uint8 *p) {
debugC(2, kDebugLevelScripts, "%s(%d %d %d)", logicNamesCmd[op].name, p[0], p[1], p[2]);
- _agiCommands[op](&_game, p);
+ _agiCommands[op](&_game, this, p);
}
} // End of namespace Agi
diff --git a/engines/agi/op_dbg.cpp b/engines/agi/op_dbg.cpp
index 997da9db7d..c57782acd5 100644
--- a/engines/agi/op_dbg.cpp
+++ b/engines/agi/op_dbg.cpp
@@ -25,14 +25,14 @@
namespace Agi {
-#define ip (_game.logics[lognum].cIP)
-#define code (_game.logics[lognum].data)
+#define ip (_game.logics[lognum].cIP)
+#define code (_game.logics[lognum].data)
AgiInstruction logicNamesIf[] = {
- { "OR", "", NULL },
- { "NOT", "", NULL },
- { "ELSE", "", NULL },
- { "IF", "", NULL }
+ { "OR", "", NULL },
+ { "NOT", "", NULL },
+ { "ELSE", "", NULL },
+ { "IF", "", NULL }
};
void AgiEngine::debugConsole(int lognum, int mode, const char *str) {
@@ -56,18 +56,18 @@ void AgiEngine::debugConsole(int lognum, int mode, const char *str) {
if (_debug.opcodes) {
debugN(0, "%02X %02X %02X %02X %02X %02X %02X %02X %02X\n"
- " ",
- (uint8)*(code + (0 + ip)) & 0xFF,
- (uint8)*(code + (1 + ip)) & 0xFF,
- (uint8)*(code + (2 + ip)) & 0xFF,
- (uint8)*(code + (3 + ip)) & 0xFF,
- (uint8)*(code + (4 + ip)) & 0xFF,
- (uint8)*(code + (5 + ip)) & 0xFF,
- (uint8)*(code + (6 + ip)) & 0xFF,
- (uint8)*(code + (7 + ip)) & 0xFF,
- (uint8)*(code + (8 + ip)) & 0xFF);
+ " ",
+ (uint8) * (code + (0 + ip)) & 0xFF,
+ (uint8) * (code + (1 + ip)) & 0xFF,
+ (uint8) * (code + (2 + ip)) & 0xFF,
+ (uint8) * (code + (3 + ip)) & 0xFF,
+ (uint8) * (code + (4 + ip)) & 0xFF,
+ (uint8) * (code + (5 + ip)) & 0xFF,
+ (uint8) * (code + (6 + ip)) & 0xFF,
+ (uint8) * (code + (7 + ip)) & 0xFF,
+ (uint8) * (code + (8 + ip)) & 0xFF);
}
- debugN(0, "%s ", (x + *(code + ip) - 0xFC)->name);
+ debugN(0, "%s ", (x + * (code + ip) - 0xFC)->name);
break;
default:
x = mode == lCOMMAND_MODE ? logicNamesCmd : logicNamesTest;
@@ -76,24 +76,24 @@ void AgiEngine::debugConsole(int lognum, int mode, const char *str) {
if (_debug.opcodes) {
debugN(0, "%02X %02X %02X %02X %02X %02X %02X %02X %02X\n"
- " ",
- (uint8)*(code + (0 + ip)) & 0xFF,
- (uint8)*(code + (1 + ip)) & 0xFF,
- (uint8)*(code + (2 + ip)) & 0xFF,
- (uint8)*(code + (3 + ip)) & 0xFF,
- (uint8)*(code + (4 + ip)) & 0xFF,
- (uint8)*(code + (5 + ip)) & 0xFF,
- (uint8)*(code + (6 + ip)) & 0xFF,
- (uint8)*(code + (7 + ip)) & 0xFF,
- (uint8)*(code + (8 + ip)) & 0xFF);
+ " ",
+ (uint8) * (code + (0 + ip)) & 0xFF,
+ (uint8) * (code + (1 + ip)) & 0xFF,
+ (uint8) * (code + (2 + ip)) & 0xFF,
+ (uint8) * (code + (3 + ip)) & 0xFF,
+ (uint8) * (code + (4 + ip)) & 0xFF,
+ (uint8) * (code + (5 + ip)) & 0xFF,
+ (uint8) * (code + (6 + ip)) & 0xFF,
+ (uint8) * (code + (7 + ip)) & 0xFF,
+ (uint8) * (code + (8 + ip)) & 0xFF);
}
- debugN(0, "%s ", (x + *(code + ip))->name);
+ debugN(0, "%s ", (x + * (code + ip))->name);
for (z = 1; a > 0;) {
if (*c == 'n') {
debugN(0, "%d", *(code + (ip + z)));
} else {
- debugN(0, "v%d[%d]", *(code + (ip + z)), getvar(*(code + (ip + z))));
+ debugN(0, "v%d[%d]", *(code + (ip + z)), getVar(*(code + (ip + z))));
}
c++;
z++;
diff --git a/engines/agi/op_test.cpp b/engines/agi/op_test.cpp
index 9839f0ec90..4505668fd1 100644
--- a/engines/agi/op_test.cpp
+++ b/engines/agi/op_test.cpp
@@ -22,7 +22,10 @@
#include "agi/agi.h"
+#include "agi/graphics.h"
#include "agi/opcodes.h"
+#include "agi/words.h"
+
#include "common/endian.h"
namespace Agi {
@@ -30,170 +33,195 @@ namespace Agi {
#define ip (state->_curLogic->cIP)
#define code (state->_curLogic->data)
-#define getvar(a) state->_vm->getvar(a)
-#define getflag(a) state->_vm->getflag(a)
-
-#define testEqual(v1, v2) (getvar(v1) == (v2))
-#define testLess(v1, v2) (getvar(v1) < (v2))
-#define testGreater(v1, v2) (getvar(v1) > (v2))
-#define testIsSet(flag) (getflag(flag))
-#define testHas(obj) (state->_vm->objectGetLocation(obj) == EGO_OWNED)
-#define testHasV1(obj) (state->_vm->objectGetLocation(obj) == EGO_OWNED_V1)
-#define testObjInRoom(obj, v) (state->_vm->objectGetLocation(obj) == getvar(v))
-
-void condEqual(AgiGame *state, uint8 *p) {
- if (p[0] == 11)
- state->_vm->_timerHack++;
- state->testResult = testEqual(p[0], p[1]);
+void condEqual(AgiGame *state, AgiEngine *vm, uint8 *p) {
+ uint16 varNr1 = p[0];
+ uint16 varVal1 = vm->getVar(varNr1);
+ uint16 value2 = p[1];
+ state->testResult = (varVal1 == value2);
}
-void condEqualV(AgiGame *state, uint8 *p) {
- if (p[0] == 11 || p[1] == 11)
- state->_vm->_timerHack++;
- state->testResult = testEqual(p[0], getvar(p[1]));
+void condEqualV(AgiGame *state, AgiEngine *vm, uint8 *p) {
+ uint16 varNr1 = p[0];
+ uint16 varNr2 = p[1];
+ uint16 varVal1 = vm->getVar(varNr1);
+ uint16 varVal2 = vm->getVar(varNr2);
+ state->testResult = (varVal1 == varVal2);
}
-void condLess(AgiGame *state, uint8 *p) {
- if (p[0] == 11)
- state->_vm->_timerHack++;
- state->testResult = testLess(p[0], p[1]);
+void condLess(AgiGame *state, AgiEngine *vm, uint8 *p) {
+ uint16 varNr1 = p[0];
+ uint16 varVal1 = vm->getVar(varNr1);
+ uint16 value2 = p[1];
+ state->testResult = (varVal1 < value2);
}
-void condLessV(AgiGame *state, uint8 *p) {
- if (p[0] == 11 || p[1] == 11)
- state->_vm->_timerHack++;
- state->testResult = testLess(p[0], getvar(p[1]));
+void condLessV(AgiGame *state, AgiEngine *vm, uint8 *p) {
+ uint16 varNr1 = p[0];
+ uint16 varNr2 = p[1];
+ uint16 varVal1 = vm->getVar(varNr1);
+ uint16 varVal2 = vm->getVar(varNr2);
+ state->testResult = (varVal1 < varVal2);
}
-void condGreater(AgiGame *state, uint8 *p) {
- if (p[0] == 11)
- state->_vm->_timerHack++;
- state->testResult = testGreater(p[0], p[1]);
+void condGreater(AgiGame *state, AgiEngine *vm, uint8 *p) {
+ uint16 varNr1 = p[0];
+ uint16 varVal1 = vm->getVar(varNr1);
+ uint16 value2 = p[1];
+ state->testResult = (varVal1 > value2);
}
-void condGreaterV(AgiGame *state, uint8 *p) {
- if (p[0] == 11 || p[1] == 11)
- state->_vm->_timerHack++;
- state->testResult = testGreater(p[0], getvar(p[1]));
+void condGreaterV(AgiGame *state, AgiEngine *vm, uint8 *p) {
+ uint16 varNr1 = p[0];
+ uint16 varNr2 = p[1];
+ uint16 varVal1 = vm->getVar(varNr1);
+ uint16 varVal2 = vm->getVar(varNr2);
+ state->testResult = (varVal1 > varVal2);
}
-void condIsSet(AgiGame *state, uint8 *p) {
- state->testResult = testIsSet(p[0]);
+void condIsSet(AgiGame *state, AgiEngine *vm, uint8 *p) {
+ state->testResult = vm->getFlag(p[0]);
}
-void condIsSetV(AgiGame *state, uint8 *p) {
- state->testResult = testIsSet(getvar(p[0]));
+void condIsSetV(AgiGame *state, AgiEngine *vm, uint8 *p) {
+ uint16 varNr = p[0];
+ uint16 varVal = vm->getVar(varNr);
+ state->testResult = vm->getFlag(varVal);
}
-void condIsSetV1(AgiGame *state, uint8 *p) {
- state->testResult = getvar(p[0]) > 0;
+void condIsSetV1(AgiGame *state, AgiEngine *vm, uint8 *p) {
+ uint16 varNr = p[0];
+ uint16 varVal = vm->getVar(varNr);
+ state->testResult = varVal > 0;
}
-void condHas(AgiGame *state, uint8 *p) {
- state->testResult = testHas(p[0]);
+void condHas(AgiGame *state, AgiEngine *vm, uint8 *p) {
+ uint16 objectNr = p[0];
+ state->testResult = (vm->objectGetLocation(objectNr) == EGO_OWNED);
}
-void condHasV1(AgiGame *state, uint8 *p) {
- state->testResult = testHasV1(p[0]);
+void condHasV1(AgiGame *state, AgiEngine *vm, uint8 *p) {
+ uint16 objectNr = p[0];
+ state->testResult = (vm->objectGetLocation(objectNr) == EGO_OWNED_V1);
}
-void condObjInRoom(AgiGame *state, uint8 *p) {
- state->testResult = testObjInRoom(p[0], p[1]);
+void condObjInRoom(AgiGame *state, AgiEngine *vm, uint8 *p) {
+ uint16 objectNr = p[0];
+ uint16 varNr = p[1];
+ uint16 varVal = vm->getVar(varNr);
+ state->testResult = (vm->objectGetLocation(objectNr) == varVal);
}
-void condPosn(AgiGame *state, uint8 *p) {
- state->testResult = state->_vm->testPosn(p[0], p[1], p[2], p[3], p[4]);
+void condPosn(AgiGame *state, AgiEngine *vm, uint8 *p) {
+ state->testResult = vm->testPosn(p[0], p[1], p[2], p[3], p[4]);
}
-void condController(AgiGame *state, uint8 *p) {
- state->testResult = state->_vm->testController(p[0]);
+void condController(AgiGame *state, AgiEngine *vm, uint8 *p) {
+ state->testResult = vm->testController(p[0]);
}
-void condHaveKey(AgiGame *state, uint8 *p) {
- state->testResult = state->_vm->testKeypressed();
+void condHaveKey(AgiGame *state, AgiEngine *vm, uint8 *p) {
+ // Only check for key when there is not already one set by scripts
+ if (vm->getVar(VM_VAR_KEY)) {
+ state->testResult = 1;
+ return;
+ }
+ // we are not really an inner loop, but we stop processAGIEvents() from doing regular cycle work by setting it up
+ vm->cycleInnerLoopActive(CYCLE_INNERLOOP_HAVEKEY);
+ uint16 key = vm->processAGIEvents();
+ vm->cycleInnerLoopInactive();
+ if (key) {
+ debugC(5, kDebugLevelScripts | kDebugLevelInput, "keypress = %02x", key);
+ vm->setVar(VM_VAR_KEY, key);
+ state->testResult = 1;
+ return;
+ }
+ state->testResult = 0;
}
-void condSaid(AgiGame *state, uint8 *p) {
- int ec = state->_vm->testSaid(p[0], p + 1);
+void condSaid(AgiGame *state, AgiEngine *vm, uint8 *p) {
+ int ec = vm->testSaid(p[0], p + 1);
state->testResult = ec;
}
-void condSaid1(AgiGame *state, uint8 *p) {
+void condSaid1(AgiGame *state, AgiEngine *vm, uint8 *p) {
state->testResult = false;
- if (!getflag(fEnteredCli))
+ if (!vm->getFlag(VM_FLAG_ENTERED_CLI))
return;
int id0 = READ_LE_UINT16(p);
- if ((id0 == 1 || id0 == state->egoWords[0].id))
+ if ((id0 == 1 || id0 == vm->_words->getEgoWordId(0)))
state->testResult = true;
}
-void condSaid2(AgiGame *state, uint8 *p) {
+void condSaid2(AgiGame *state, AgiEngine *vm, uint8 *p) {
state->testResult = false;
- if (!getflag(fEnteredCli))
+ if (!vm->getFlag(VM_FLAG_ENTERED_CLI))
return;
int id0 = READ_LE_UINT16(p);
int id1 = READ_LE_UINT16(p + 2);
- if ((id0 == 1 || id0 == state->egoWords[0].id) &&
- (id1 == 1 || id1 == state->egoWords[1].id))
+ if ((id0 == 1 || id0 == vm->_words->getEgoWordId(0)) &&
+ (id1 == 1 || id1 == vm->_words->getEgoWordId(1)))
state->testResult = true;
}
-void condSaid3(AgiGame *state, uint8 *p) {
+void condSaid3(AgiGame *state, AgiEngine *vm, uint8 *p) {
state->testResult = false;
- if (!getflag(fEnteredCli))
+ if (!vm->getFlag(VM_FLAG_ENTERED_CLI))
return;
int id0 = READ_LE_UINT16(p);
int id1 = READ_LE_UINT16(p + 2);
int id2 = READ_LE_UINT16(p + 4);
- if ((id0 == 1 || id0 == state->egoWords[0].id) &&
- (id1 == 1 || id1 == state->egoWords[1].id) &&
- (id2 == 1 || id2 == state->egoWords[2].id))
+ if ((id0 == 1 || id0 == vm->_words->getEgoWordId(0)) &&
+ (id1 == 1 || id1 == vm->_words->getEgoWordId(1)) &&
+ (id2 == 1 || id2 == vm->_words->getEgoWordId(2)))
state->testResult = true;
}
-void condBit(AgiGame *state, uint8 *p) {
- state->testResult = (getvar(p[1]) >> p[0]) & 1;
+void condBit(AgiGame *state, AgiEngine *vm, uint8 *p) {
+ uint16 value1 = p[0];
+ uint16 varNr2 = p[1];
+ uint16 varVal2 = vm->getVar(varNr2);
+ state->testResult = (varVal2 >> value1) & 1;
}
-void condCompareStrings(AgiGame *state, uint8 *p) {
+void condCompareStrings(AgiGame *state, AgiEngine *vm, uint8 *p) {
debugC(7, kDebugLevelScripts, "comparing [%s], [%s]", state->strings[p[0]], state->strings[p[1]]);
- state->testResult = state->_vm->testCompareStrings(p[0], p[1]);
+ state->testResult = vm->testCompareStrings(p[0], p[1]);
}
-void condObjInBox(AgiGame *state, uint8 *p) {
- state->testResult = state->_vm->testObjInBox(p[0], p[1], p[2], p[3], p[4]);
+void condObjInBox(AgiGame *state, AgiEngine *vm, uint8 *p) {
+ state->testResult = vm->testObjInBox(p[0], p[1], p[2], p[3], p[4]);
}
-void condCenterPosn(AgiGame *state, uint8 *p) {
- state->testResult = state->_vm->testObjCenter(p[0], p[1], p[2], p[3], p[4]);
+void condCenterPosn(AgiGame *state, AgiEngine *vm, uint8 *p) {
+ state->testResult = vm->testObjCenter(p[0], p[1], p[2], p[3], p[4]);
}
-void condRightPosn(AgiGame *state, uint8 *p) {
- state->testResult = state->_vm->testObjRight(p[0], p[1], p[2], p[3], p[4]);
+void condRightPosn(AgiGame *state, AgiEngine *vm, uint8 *p) {
+ state->testResult = vm->testObjRight(p[0], p[1], p[2], p[3], p[4]);
}
-void condUnknown13(AgiGame *state, uint8 *p) {
+void condUnknown13(AgiGame *state, AgiEngine *vm, uint8 *p) {
// My current theory is that this command checks whether the ego is currently moving
// and that that movement has been caused using the mouse and not using the keyboard.
// I base this theory on the game's behavior on an Amiga emulator, not on disassembly.
// This command is used at least in the Amiga version of Gold Rush! v2.05 1989-03-09
// (AGI 2.316) in logics 1, 3, 5, 6, 137 and 192 (Logic.192 revealed this command's nature).
// TODO: Check this command's implementation using disassembly just to be sure.
- int ec = state->viewTable[0].flags & fAdjEgoXY;
+ int ec = state->screenObjTable[SCREENOBJECTS_EGO_ENTRY].flags & fAdjEgoXY;
debugC(7, kDebugLevelScripts, "op_test: in.motion.using.mouse = %s (Amiga-specific testcase 19)", ec ? "true" : "false");
state->testResult = ec;
}
-void condUnknown(AgiGame *state, uint8 *p) {
+void condUnknown(AgiGame *state, AgiEngine *vm, uint8 *p) {
warning("Skipping unknown test command %2X", *(code + ip - 1));
state->testResult = false;
}
@@ -203,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++) {
@@ -221,7 +249,7 @@ uint8 AgiEngine::testCompareStrings(uint8 s1, uint8 s2) {
break;
default:
- ms1[j++] = toupper(ms1[k]);
+ ms1[j++] = tolower(ms1[k]);
break;
}
}
@@ -242,7 +270,7 @@ uint8 AgiEngine::testCompareStrings(uint8 s1, uint8 s2) {
break;
default:
- ms2[j++] = toupper(ms2[k]);
+ ms2[j++] = tolower(ms2[k]);
break;
}
}
@@ -251,35 +279,12 @@ uint8 AgiEngine::testCompareStrings(uint8 s1, uint8 s2) {
return !strcmp(ms1, ms2);
}
-uint8 AgiEngine::testKeypressed() {
- int x = _game.keypress;
-
- _game.keypress = 0;
- if (!x) {
- InputMode mode = _game.inputMode;
-
- _game.inputMode = INPUT_NONE;
- // Only check for events here, without updating the game cycle,
- // otherwise the animations in some games are drawn too quickly
- // like, for example, Manannan's lightnings in the intro of KQ3
- // and the bullets opened in the logo of PQ1, during its intro.
- // Fixes bug #3600733
- mainCycle(true);
- _game.inputMode = mode;
- }
-
- if (x)
- debugC(5, kDebugLevelScripts | kDebugLevelInput, "keypress = %02x", x);
-
- return x;
-}
-
uint8 AgiEngine::testController(uint8 cont) {
- return (_game.controllerOccured[cont] ? 1 : 0);
+ return (_game.controllerOccured[cont] ? true : false);
}
uint8 AgiEngine::testPosn(uint8 n, uint8 x1, uint8 y1, uint8 x2, uint8 y2) {
- VtEntry *v = &_game.viewTable[n];
+ ScreenObjEntry *v = &_game.screenObjTable[n];
uint8 r;
r = v->xPos >= x1 && v->yPos >= y1 && v->xPos <= x2 && v->yPos <= y2;
@@ -290,35 +295,37 @@ uint8 AgiEngine::testPosn(uint8 n, uint8 x1, uint8 y1, uint8 x2, uint8 y2) {
}
uint8 AgiEngine::testObjInBox(uint8 n, uint8 x1, uint8 y1, uint8 x2, uint8 y2) {
- VtEntry *v = &_game.viewTable[n];
+ ScreenObjEntry *v = &_game.screenObjTable[n];
return v->xPos >= x1 &&
- v->yPos >= y1 && v->xPos + v->xSize - 1 <= x2 && v->yPos <= y2;
+ v->yPos >= y1 && v->xPos + v->xSize - 1 <= x2 && v->yPos <= y2;
}
// if n is in center of box
uint8 AgiEngine::testObjCenter(uint8 n, uint8 x1, uint8 y1, uint8 x2, uint8 y2) {
- VtEntry *v = &_game.viewTable[n];
+ ScreenObjEntry *v = &_game.screenObjTable[n];
return v->xPos + v->xSize / 2 >= x1 &&
- v->xPos + v->xSize / 2 <= x2 && v->yPos >= y1 && v->yPos <= y2;
+ v->xPos + v->xSize / 2 <= x2 && v->yPos >= y1 && v->yPos <= y2;
}
// if nect N is in right corner
uint8 AgiEngine::testObjRight(uint8 n, uint8 x1, uint8 y1, uint8 x2, uint8 y2) {
- VtEntry *v = &_game.viewTable[n];
+ ScreenObjEntry *v = &_game.screenObjTable[n];
return v->xPos + v->xSize - 1 >= x1 &&
- v->xPos + v->xSize - 1 <= x2 && v->yPos >= y1 && v->yPos <= y2;
+ v->xPos + v->xSize - 1 <= x2 && v->yPos >= y1 && v->yPos <= y2;
}
// When player has entered something, it is parsed elsewhere
uint8 AgiEngine::testSaid(uint8 nwords, uint8 *cc) {
AgiGame *state = &_game;
- int c, n = _game.numEgoWords;
+ AgiEngine *vm = state->_vm;
+ Words *words = vm->_words;
+ int c, n = words->getEgoWordCount();
int z = 0;
- if (getflag(fSaidAcceptedInput) || !getflag(fEnteredCli))
+ if (vm->getFlag(VM_FLAG_SAID_ACCEPTED_INPUT) || !vm->getFlag(VM_FLAG_ENTERED_CLI))
return false;
// FR:
@@ -343,13 +350,13 @@ uint8 AgiEngine::testSaid(uint8 nwords, uint8 *cc) {
cc += 2;
switch (z) {
- case 9999: // rest of line (empty string counts to...)
+ case 9999: // rest of line (empty string counts to...)
nwords = 1;
break;
- case 1: // any word
+ case 1: // any word
break;
default:
- if (_game.egoWords[c].id != z)
+ if (words->getEgoWordId(c) != z)
return false;
break;
}
@@ -364,7 +371,7 @@ uint8 AgiEngine::testSaid(uint8 nwords, uint8 *cc) {
if (nwords != 0 && READ_LE_UINT16(cc) != 9999)
return false;
- setflag(fSaidAcceptedInput, true);
+ setFlag(VM_FLAG_SAID_ACCEPTED_INPUT, true);
return true;
}
@@ -411,7 +418,7 @@ int AgiEngine::testIfCode(int lognum) {
default:
// Evaluate the command and skip the rest of the instruction
- _agiCondCommands[op](state, p);
+ _agiCondCommands[op](state, this, p);
skipInstruction(op);
// NOT mode is enabled only for one instruction
diff --git a/engines/agi/opcodes.cpp b/engines/agi/opcodes.cpp
index 621fbb8e82..472917de77 100644
--- a/engines/agi/opcodes.cpp
+++ b/engines/agi/opcodes.cpp
@@ -29,333 +29,333 @@ AgiInstruction *logicNamesTest;
AgiInstruction *logicNamesCmd;
AgiInstruction insV1Test[] = {
- { "", "", &condUnknown }, // 00
- { "equaln", "vn", &condEqual }, // 01
- { "equalv", "vv", &condEqualV }, // 02
- { "lessn", "vn", &condLess }, // 03
- { "lessv", "vv", &condLessV }, // 04
- { "greatern", "vn", &condGreater }, // 05
- { "greaterv", "vv", &condGreaterV }, // 06
- { "isset", "v", &condIsSetV1 }, // 07
- { "has", "n", &condHasV1 }, // 08
- { "said", "nnnn", &condSaid2 }, // 09
- { "posn", "nnnnn", &condPosn }, // 0A
- { "controller", "n", &condController }, // 0B
- { "obj.in.room", "nv", &condObjInRoom }, // 0C
- { "said", "nnnnnn", &condSaid3 }, // 0D
- { "have.key", "", &condHaveKey }, // 0E
- { "said", "nn", &condSaid1 }, // 0F
- { "bit", "nv", &condBit }, // 10
+ { "", "", &condUnknown }, // 00
+ { "equaln", "vn", &condEqual }, // 01
+ { "equalv", "vv", &condEqualV }, // 02
+ { "lessn", "vn", &condLess }, // 03
+ { "lessv", "vv", &condLessV }, // 04
+ { "greatern", "vn", &condGreater }, // 05
+ { "greaterv", "vv", &condGreaterV }, // 06
+ { "isset", "v", &condIsSetV1 }, // 07
+ { "has", "n", &condHasV1 }, // 08
+ { "said", "nnnn", &condSaid2 }, // 09
+ { "posn", "nnnnn", &condPosn }, // 0A
+ { "controller", "n", &condController }, // 0B
+ { "obj.in.room", "nv", &condObjInRoom }, // 0C
+ { "said", "nnnnnn", &condSaid3 }, // 0D
+ { "have.key", "", &condHaveKey }, // 0E
+ { "said", "nn", &condSaid1 }, // 0F
+ { "bit", "nv", &condBit }, // 10
};
AgiInstruction insV1[] = {
- { "return", "", NULL }, // 00
- { "increment", "v", &cmdIncrement }, // 01
- { "decrement", "v", &cmdDecrement }, // 02
- { "assignn", "vn", &cmdAssignN }, // 03
- { "assignv", "vv", &cmdAssignV }, // 04
- { "addn", "vn", &cmdAddN }, // 05
- { "addv", "vv", &cmdAddV }, // 06
- { "subn", "vn", &cmdSubN }, // 07
- { "subv", "vv", &cmdSubV }, // 08
- { "load.view", "n", &cmdLoadView }, // 09
- { "animate.obj", "n", &cmdAnimateObj }, // 0A
- { "new.room", "n", &cmdNewRoomV1 }, // 0B
- { "draw.pic", "v", &cmdDrawPicV1 }, // 0C
- { "print", "s", &cmdPrint }, // 0D TODO
- { "status", "", &cmdStatus }, // 0E TODO
- { "save.game", "", &cmdSaveGame }, // 0F TODO
- { "restore.game", "", &cmdLoadGame }, // 10 TODO
- { "init.disk", "", &cmdInitDisk }, // 11 TODO
- { "restart.game", "", &cmdRestartGame }, // 12 TODO
- { "random", "v", &cmdRandomV1 }, // 13
- { "get", "n", &cmdGetV1 }, // 14
- { "drop", "n", &cmdDrop }, // 15
- { "draw", "n", &cmdDraw }, // 16 TODO
- { "erase", "n", &cmdErase }, // 17 TODO
- { "position", "nnn", &cmdPositionV1 }, // 18
- { "position.v", "nvv", &cmdPositionFV1 }, // 19
- { "get.posn", "nvv", &cmdGetPosn }, // 1A
- { "set.cel", "nn", &cmdSetCel }, // 1B
- { "set.loop", "nn", &cmdSetLoop }, // 1C
- { "end.of.loop", "nn", &cmdEndOfLoopV1 }, // 1D
- { "reverse.loop", "nn", &cmdReverseLoopV1 }, // 1E
- { "move.obj", "nnnnn", &cmdMoveObj }, // 1F
- { "set.view", "nn", &cmdSetView }, // 20
- { "follow.ego", "nnn", &cmdFollowEgo }, // 21
- { "block", "", &cmdBlock }, // 22
- { "unblock", "", &cmdUnblock }, // 23
- { "ignore.blocks", "n", &cmdIgnoreBlocks }, // 24
- { "observe.blocks", "n", &cmdObserveBlocks }, // 25
- { "wander", "n", &cmdWander }, // 26
- { "reposition", "nvv", &cmdRepositionV1 }, // 27
- { "stop.motion", "n", &cmdStopMotionV1 }, // 28
- { "start.motion", "n", &cmdStartMotionV1 }, // 29
- { "stop.cycling", "n", &cmdStopCycling }, // 2A
- { "start.cycling", "n", &cmdStartCycling }, // 2B
- { "stop.update", "n", &cmdStopUpdate }, // 2C
- { "start.update", "n", &cmdStartUpdate }, // 2D
- { "program.control", "", &cmdProgramControl }, // 2E
- { "player.control", "", &cmdPlayerControl }, // 2F
- { "set.priority", "nn", &cmdSetPriority }, // 30
- { "release.priority", "n", &cmdReleasePriority }, // 31
- { "add.to.pic", "nnnnnn", &cmdAddToPicV1 }, // 32
- { "set.horizon", "n", &cmdSetHorizon }, // 33
- { "ignore.horizon", "n", &cmdIgnoreHorizon }, // 34
- { "observe.horizon", "n", &cmdObserveHorizon }, // 35
- { "load.logics", "n", &cmdLoadLogic }, // 36 TODO
- { "object.on.water", "n", &cmdObjectOnWater }, // 37
- { "load.pic", "v", &cmdLoadPicV1 }, // 38
- { "load.sound", "n", &cmdLoadSound }, // 39
- { "sound", "nn", &cmdSound }, // 3A
- { "stop.sound", "", &cmdStopSound }, // 3B
- { "set.v", "v", &cmdSetV }, // 3C
- { "reset.v", "v", &cmdResetV }, // 3D
- { "toggle.v", "v", &cmdToggleV }, // 3E
- { "new.room.v", "v", &cmdNewRoomVV1 }, // 3F TODO
- { "call", "n", &cmdCallV1 }, // 40 TODO
- { "quit", "", &cmdQuitV1 }, // 41
- { "set.speed", "v", &cmdSetSpeed }, // 42
- { "move.obj.v", "nvvvv", &cmdMoveObjF }, // 43
- { "...", "nn", &cmdUnknown }, // 44
- { "get.v", "v", &cmdUnknown }, // 45
- { "assign.v", "vv", &cmdUnknown }, // 46
- { "...", "n", &cmdUnknown }, // 47 # printvar.v
- { "get.priority", "nv", &cmdGetPriority }, // 48
- { "ignore.objs", "n", &cmdIgnoreObjs }, // 49
- { "observe.objs", "n", &cmdObserveObjs }, // 4A
- { "distance", "nnv", &cmdDistance }, // 4B
- { "object.on.land", "n", &cmdObjectOnLand }, // 4C
- { "...", "nv", &cmdUnknown }, // 4D # set.priority.f
- { "...", "", &cmdUnknown }, // 4E # show.obj
- { "load.logics", "n", &cmdLoadLogic }, // 4F # load.global.logics
- { "display", "nnns", &cmdDisplay }, // 50 TODO: 4 vs 3 args
- { "prevent.input???", "", &cmdUnknown }, // 51
- { "...", "", &cmdUnknown }, // 52 # nop
- { "...", "n", &cmdUnknown }, // 53 # text.screen
- { "...", "", &cmdUnknown }, // 54 ???
- { "stop.motion", "", &cmdStopMotion }, // 55 or force.update??
- { "discard.view", "n", &cmdDiscardView }, // 56
- { "discard.pic", "v", &cmdDiscardPic }, // 57
- { "set.item.view", "nn", &cmdSetItemView }, // 58
- { "...", "", &cmdUnknown }, // 59 # reverse.cycle
- { "last.cel", "nv", &cmdLastCel }, // 5A
- { "set.cel.v", "nv", &cmdSetCelF }, // 5B
- { "...", "", &cmdUnknown }, // 5C # normal.cycle
- { "load.view", "n", &cmdLoadView }, // 5D
- { "...", "", &cmdUnknown }, // 5E
- { "...", "", &cmdUnknown }, // 5F
- { "setbit", "nv", &cmdUnknown }, // 60
- { "...", "nv", &cmdUnknown }, // 61 # clearbit
+ { "return", "", NULL }, // 00
+ { "increment", "v", &cmdIncrement }, // 01
+ { "decrement", "v", &cmdDecrement }, // 02
+ { "assignn", "vn", &cmdAssignN }, // 03
+ { "assignv", "vv", &cmdAssignV }, // 04
+ { "addn", "vn", &cmdAddN }, // 05
+ { "addv", "vv", &cmdAddV }, // 06
+ { "subn", "vn", &cmdSubN }, // 07
+ { "subv", "vv", &cmdSubV }, // 08
+ { "load.view", "n", &cmdLoadView }, // 09
+ { "animate.obj", "n", &cmdAnimateObj }, // 0A
+ { "new.room", "n", &cmdNewRoom }, // 0B
+ { "draw.pic", "v", &cmdDrawPicV1 }, // 0C
+ { "print", "s", &cmdPrint }, // 0D TODO
+ { "status", "", &cmdStatus }, // 0E TODO
+ { "save.game", "", &cmdSaveGame }, // 0F TODO
+ { "restore.game", "", &cmdLoadGame }, // 10 TODO
+ { "init.disk", "", &cmdInitDisk }, // 11 TODO
+ { "restart.game", "", &cmdRestartGame }, // 12 TODO
+ { "random", "v", &cmdRandomV1 }, // 13
+ { "get", "n", &cmdGetV1 }, // 14
+ { "drop", "n", &cmdDrop }, // 15
+ { "draw", "n", &cmdDraw }, // 16 TODO
+ { "erase", "n", &cmdErase }, // 17 TODO
+ { "position", "nnn", &cmdPositionV1 }, // 18
+ { "position.v", "nvv", &cmdPositionFV1 }, // 19
+ { "get.posn", "nvv", &cmdGetPosn }, // 1A
+ { "set.cel", "nn", &cmdSetCel }, // 1B
+ { "set.loop", "nn", &cmdSetLoop }, // 1C
+ { "end.of.loop", "nn", &cmdEndOfLoopV1 }, // 1D
+ { "reverse.loop", "nn", &cmdReverseLoopV1 }, // 1E
+ { "move.obj", "nnnnn", &cmdMoveObj }, // 1F
+ { "set.view", "nn", &cmdSetView }, // 20
+ { "follow.ego", "nnn", &cmdFollowEgo }, // 21
+ { "block", "", &cmdBlock }, // 22
+ { "unblock", "", &cmdUnblock }, // 23
+ { "ignore.blocks", "n", &cmdIgnoreBlocks }, // 24
+ { "observe.blocks", "n", &cmdObserveBlocks }, // 25
+ { "wander", "n", &cmdWander }, // 26
+ { "reposition", "nvv", &cmdRepositionV1 }, // 27
+ { "stop.motion", "n", &cmdStopMotionV1 }, // 28
+ { "start.motion", "n", &cmdStartMotionV1 }, // 29
+ { "stop.cycling", "n", &cmdStopCycling }, // 2A
+ { "start.cycling", "n", &cmdStartCycling }, // 2B
+ { "stop.update", "n", &cmdStopUpdate }, // 2C
+ { "start.update", "n", &cmdStartUpdate }, // 2D
+ { "program.control", "", &cmdProgramControl }, // 2E
+ { "player.control", "", &cmdPlayerControl }, // 2F
+ { "set.priority", "nn", &cmdSetPriority }, // 30
+ { "release.priority", "n", &cmdReleasePriority }, // 31
+ { "add.to.pic", "nnnnnn", &cmdAddToPicV1 }, // 32
+ { "set.horizon", "n", &cmdSetHorizon }, // 33
+ { "ignore.horizon", "n", &cmdIgnoreHorizon }, // 34
+ { "observe.horizon", "n", &cmdObserveHorizon }, // 35
+ { "load.logics", "n", &cmdLoadLogic }, // 36 TODO
+ { "object.on.water", "n", &cmdObjectOnWater }, // 37
+ { "load.pic", "v", &cmdLoadPicV1 }, // 38
+ { "load.sound", "n", &cmdLoadSound }, // 39
+ { "sound", "nn", &cmdSound }, // 3A
+ { "stop.sound", "", &cmdStopSound }, // 3B
+ { "set.v", "v", &cmdSetV }, // 3C
+ { "reset.v", "v", &cmdResetV }, // 3D
+ { "toggle.v", "v", &cmdToggleV }, // 3E
+ { "new.room.v", "v", &cmdNewRoom }, // 3F
+ { "call", "n", &cmdCallV1 }, // 40 TODO
+ { "quit", "", &cmdQuitV1 }, // 41
+ { "set.speed", "v", &cmdSetSpeed }, // 42
+ { "move.obj.v", "nvvvv", &cmdMoveObjF }, // 43
+ { "...", "nn", &cmdUnknown }, // 44
+ { "get.v", "v", &cmdUnknown }, // 45
+ { "assign.v", "vv", &cmdUnknown }, // 46
+ { "...", "n", &cmdUnknown }, // 47 # printvar.v
+ { "get.priority", "nv", &cmdGetPriority }, // 48
+ { "ignore.objs", "n", &cmdIgnoreObjs }, // 49
+ { "observe.objs", "n", &cmdObserveObjs }, // 4A
+ { "distance", "nnv", &cmdDistance }, // 4B
+ { "object.on.land", "n", &cmdObjectOnLand }, // 4C
+ { "...", "nv", &cmdUnknown }, // 4D # set.priority.f
+ { "...", "", &cmdUnknown }, // 4E # show.obj
+ { "load.logics", "n", &cmdLoadLogic }, // 4F # load.global.logics
+ { "display", "nnns", &cmdDisplay }, // 50 TODO: 4 vs 3 args
+ { "prevent.input???", "", &cmdUnknown }, // 51
+ { "...", "", &cmdUnknown }, // 52 # nop
+ { "...", "n", &cmdUnknown }, // 53 # text.screen
+ { "...", "", &cmdUnknown }, // 54 ???
+ { "stop.motion", "", &cmdStopMotion }, // 55 or force.update??
+ { "discard.view", "n", &cmdDiscardView }, // 56
+ { "discard.pic", "v", &cmdDiscardPic }, // 57
+ { "set.item.view", "nn", &cmdSetItemView }, // 58
+ { "...", "", &cmdUnknown }, // 59 # reverse.cycle
+ { "last.cel", "nv", &cmdLastCel }, // 5A
+ { "set.cel.v", "nv", &cmdSetCelF }, // 5B
+ { "...", "", &cmdUnknown }, // 5C # normal.cycle
+ { "load.view", "n", &cmdLoadView }, // 5D
+ { "...", "", &cmdUnknown }, // 5E
+ { "...", "", &cmdUnknown }, // 5F
+ { "setbit", "nv", &cmdUnknown }, // 60
+ { "...", "nv", &cmdUnknown }, // 61 # clearbit
};
AgiInstruction insV2Test[] = {
- { "", "", &condUnknown }, // 00
- { "equaln", "vn", &condEqual }, // 01
- { "equalv", "vv", &condEqualV }, // 02
- { "lessn", "vn", &condLess }, // 03
- { "lessv", "vv", &condLessV }, // 04
- { "greatern", "vn", &condGreater }, // 05
- { "greaterv", "vv", &condGreaterV }, // 06
- { "isset", "n", &condIsSet }, // 07
- { "issetv", "v", &condIsSetV }, // 08
- { "has", "n", &condHas }, // 09
- { "obj.in.room", "nv", &condObjInRoom}, // 0A
- { "posn", "nnnnn", &condPosn }, // 0B
- { "controller", "n", &condController }, // 0C
- { "have.key", "", &condHaveKey}, // 0D
- { "said", "", &condSaid }, // 0E
- { "compare.strings", "ss", &condCompareStrings }, // 0F
- { "obj.in.box", "nnnnn", &condObjInBox }, // 10
- { "center.posn", "nnnnn", &condCenterPosn }, // 11
- { "right.posn", "nnnnn", &condRightPosn }, // 12
- { "in.motion.using.mouse", "", &condUnknown13 } // 13
+ { "", "", &condUnknown }, // 00
+ { "equaln", "vn", &condEqual }, // 01
+ { "equalv", "vv", &condEqualV }, // 02
+ { "lessn", "vn", &condLess }, // 03
+ { "lessv", "vv", &condLessV }, // 04
+ { "greatern", "vn", &condGreater }, // 05
+ { "greaterv", "vv", &condGreaterV }, // 06
+ { "isset", "n", &condIsSet }, // 07
+ { "issetv", "v", &condIsSetV }, // 08
+ { "has", "n", &condHas }, // 09
+ { "obj.in.room", "nv", &condObjInRoom}, // 0A
+ { "posn", "nnnnn", &condPosn }, // 0B
+ { "controller", "n", &condController }, // 0C
+ { "have.key", "", &condHaveKey}, // 0D
+ { "said", "", &condSaid }, // 0E
+ { "compare.strings", "ss", &condCompareStrings }, // 0F
+ { "obj.in.box", "nnnnn", &condObjInBox }, // 10
+ { "center.posn", "nnnnn", &condCenterPosn }, // 11
+ { "right.posn", "nnnnn", &condRightPosn }, // 12
+ { "in.motion.using.mouse", "", &condUnknown13 } // 13
};
AgiInstruction insV2[] = {
- { "return", "", NULL },
- { "increment", "v", &cmdIncrement },
- { "decrement", "v", &cmdDecrement },
- { "assignn", "vn", &cmdAssignN },
- { "assignv", "vv", &cmdAssignV },
- { "addn", "vn", &cmdAddN },
- { "addv", "vv", &cmdAddV },
- { "subn", "vn", &cmdSubN },
- { "subv", "vv", &cmdSubV },
- { "lindirectv", "vv", &cmdLindirectV },
- { "lindirect", "vv", &cmdRindirect },
- { "lindirectn", "vn", &cmdLindirectN },
- { "set", "n", &cmdSet },
- { "reset", "n", &cmdReset },
- { "toggle", "n", &cmdToggle },
- { "set.v", "v", &cmdSetV },
- { "reset.v", "v", &cmdResetV },
- { "toggle.v", "v", &cmdToggleV },
- { "new.room", "n", &cmdNewRoom },
- { "new.room.v", "v", &cmdNewRoomF },
- { "load.logics", "n", &cmdLoadLogic },
- { "load.logics.v", "v", &cmdLoadLogicF },
- { "call", "n", &cmdCall },
- { "call.v", "v", &cmdCallF },
- { "load.pic", "v", &cmdLoadPic },
- { "draw.pic", "v", &cmdDrawPic },
- { "show.pic", "", &cmdShowPic },
- { "discard.pic", "v", &cmdDiscardPic },
- { "overlay.pic", "v", &cmdOverlayPic },
- { "show.pri.screen", "", &cmdShowPriScreen },
- { "load.view", "n", &cmdLoadView },
- { "load.view.v", "v", &cmdLoadViewF },
- { "discard.view", "n", &cmdDiscardView },
- { "animate.obj", "n", &cmdAnimateObj },
- { "unanimate.all", "", &cmdUnanimateAll },
- { "draw", "n", &cmdDraw },
- { "erase", "n", &cmdErase },
- { "position", "nnn", &cmdPosition },
- { "position.v", "nvv", &cmdPositionF },
- { "get.posn", "nvv", &cmdGetPosn },
- { "reposition", "nvv", &cmdReposition },
- { "set.view", "nn", &cmdSetView },
- { "set.view.v", "nv", &cmdSetViewF },
- { "set.loop", "nn", &cmdSetLoop },
- { "set.loop.v", "nv", &cmdSetLoopF },
- { "fix.loop", "n", &cmdFixLoop },
- { "release.loop", "n", &cmdReleaseLoop },
- { "set.cel", "nn", &cmdSetCel },
- { "set.cel.v", "nv", &cmdSetCelF },
- { "last.cel", "nv", &cmdLastCel },
- { "current.cel", "nv", &cmdCurrentCel },
- { "current.loop", "nv", &cmdCurrentLoop },
- { "current.view", "nv", &cmdCurrentView },
- { "number.of.loops", "nv", &cmdNumberOfLoops },
- { "set.priority", "nn", &cmdSetPriority },
- { "set.priority.v", "nv", &cmdSetPriorityF },
- { "release.priority", "n", &cmdReleasePriority },
- { "get.priority", "nn", &cmdGetPriority },
- { "stop.update", "n", &cmdStopUpdate },
- { "start.update", "n", &cmdStartUpdate },
- { "force.update", "n", &cmdForceUpdate },
- { "ignore.horizon", "n", &cmdIgnoreHorizon },
- { "observe.horizon", "n", &cmdObserveHorizon },
- { "set.horizon", "n", &cmdSetHorizon },
- { "object.on.water", "n", &cmdObjectOnWater },
- { "object.on.land", "n", &cmdObjectOnLand },
- { "object.on.anything", "n", &cmdObjectOnAnything },
- { "ignore.objs", "n", &cmdIgnoreObjs },
- { "observe.objs", "n", &cmdObserveObjs },
- { "distance", "nnv", &cmdDistance },
- { "stop.cycling", "n", &cmdStopCycling },
- { "start.cycling", "n", &cmdStartCycling },
- { "normal.cycle", "n", &cmdNormalCycle },
- { "end.of.loop", "nn", &cmdEndOfLoop },
- { "reverse.cycle", "n", &cmdReverseCycle },
- { "reverse.loop", "nn", &cmdReverseLoop },
- { "cycle.time", "nv", &cmdCycleTime },
- { "stop.motion", "n", &cmdStopMotion },
- { "start.motion", "n", &cmdStartMotion },
- { "step.size", "nv", &cmdStepSize },
- { "step.time", "nv", &cmdStepTime },
- { "move.obj", "nnnnn", &cmdMoveObj },
- { "move.obj.v", "nvvvv", &cmdMoveObjF },
- { "follow.ego", "nnn", &cmdFollowEgo },
- { "wander", "n", &cmdWander },
- { "normal.motion", "n", &cmdNormalMotion },
- { "set.dir", "nv", &cmdSetDir },
- { "get.dir", "nv", &cmdGetDir },
- { "ignore.blocks", "n", &cmdIgnoreBlocks },
- { "observe.blocks", "n", &cmdObserveBlocks },
- { "block", "nnnn", &cmdBlock },
- { "unblock", "", &cmdUnblock },
- { "get", "n", &cmdGet },
- { "get.v", "v", &cmdGetF },
- { "drop", "n", &cmdDrop },
- { "put", "nn", &cmdPut },
- { "put.v", "vv", &cmdPutF },
- { "get.room.v", "vv", &cmdGetRoomF },
- { "load.sound", "n", &cmdLoadSound },
- { "sound", "nn", &cmdSound },
- { "stop.sound", "", &cmdStopSound },
- { "print", "s", &cmdPrint },
- { "print.v", "v", &cmdPrintF },
- { "display", "nns", &cmdDisplay },
- { "display.v", "vvv", &cmdDisplayF },
- { "clear.lines", "nns", &cmdClearLines },
- { "text.screen", "", &cmdTextScreen },
- { "graphics", "", &cmdGraphics },
- { "set.cursor.char", "s", &cmdSetCursorChar },
- { "set.text.attribute", "nn", &cmdSetTextAttribute },
- { "shake.screen", "n", &cmdShakeScreen },
- { "configure.screen", "nnn", &cmdConfigureScreen },
- { "status.line.on", "", &cmdStatusLineOn },
- { "status.line.off", "", &cmdStatusLineOff },
- { "set.string", "ns", &cmdSetString },
- { "get.string", "nsnnn", &cmdGetString },
- { "word.to.string", "nn", &cmdWordToString },
- { "parse", "n", &cmdParse },
- { "get.num", "nv", &cmdGetNum },
- { "prevent.input", "", &cmdPreventInput },
- { "accept.input", "", &cmdAcceptInput },
- { "set.key", "nnn", &cmdSetKey },
- { "add.to.pic", "nnnnnnn", &cmdAddToPic },
- { "add.to.pic.v", "vvvvvvv", &cmdAddToPicF },
- { "status", "", &cmdStatus },
- { "save.game", "", &cmdSaveGame },
- { "restore.game", "", &cmdLoadGame },
- { "init.disk", "", &cmdInitDisk },
- { "restart.game", "", &cmdRestartGame },
- { "show.obj", "n", &cmdShowObj },
- { "random", "nnv", &cmdRandom },
- { "program.control", "", &cmdProgramControl },
- { "player.control", "", &cmdPlayerControl },
- { "obj.status.v", "v", &cmdObjStatusF },
- { "quit", "n", &cmdQuit }, // 0 args for AGI version 2.089
- { "show.mem", "", &cmdShowMem },
- { "pause", "", &cmdPause },
- { "echo.line", "", &cmdEchoLine },
- { "cancel.line", "", &cmdCancelLine },
- { "init.joy", "", &cmdInitJoy },
- { "toggle.monitor", "", &cmdToggleMonitor },
- { "version", "", &cmdVersion },
- { "script.size", "n", &cmdScriptSize },
- { "set.game.id", "s", &cmdSetGameID },
- { "log", "s", &cmdLog },
- { "set.scan.start", "", &cmdSetScanStart },
- { "reset.scan.start", "", &cmdResetScanStart },
- { "reposition.to", "nnn", &cmdRepositionTo },
- { "reposition.to.v", "nvv", &cmdRepositionToF },
- { "trace.on", "", &cmdTraceOn },
- { "trace.info", "nnn", &cmdTraceInfo },
- { "print.at", "snnn", &cmdPrintAt }, // 3 args for AGI versions before 2.440
- { "print.at.v", "vnnn", &cmdPrintAtV },
- { "discard.view.v", "v", &cmdDiscardView},
- { "clear.text.rect", "nnnnn", &cmdClearTextRect },
- { "set.upper.left", "nn", &cmdSetUpperLeft },
- { "set.menu", "s", &cmdSetMenu },
- { "set.menu.item", "sn", &cmdSetMenuItem },
- { "submit.menu", "", &cmdSubmitMenu },
- { "enable.item", "n", &cmdEnableItem },
- { "disable.item", "n", &cmdDisableItem },
- { "menu.input", "", &cmdMenuInput },
- { "show.obj.v", "v", &cmdShowObjV },
- { "open.dialogue", "", &cmdOpenDialogue },
- { "close.dialogue", "", &cmdCloseDialogue },
- { "mul.n", "vn", &cmdMulN },
- { "mul.v", "vv", &cmdMulV },
- { "div.n", "vn", &cmdDivN },
- { "div.v", "vv", &cmdDivV },
- { "close.window", "", &cmdCloseWindow },
- { "set.simple", "n", &cmdSetSimple },
- { "push.script", "", &cmdPushScript },
- { "pop.script", "", &cmdPopScript },
- { "hold.key", "", &cmdHoldKey },
- { "set.pri.base", "n", &cmdSetPriBase },
- { "discard.sound", "n", &cmdDiscardSound },
- { "hide.mouse", "", &cmdHideMouse }, // 1 arg for AGI version 3.002.086
- { "allow.menu", "n", &cmdAllowMenu },
- { "show.mouse", "", &cmdShowMouse },
- { "fence.mouse", "nnnn", &cmdFenceMouse },
- { "mouse.posn", "vv", &cmdMousePosn },
- { "release.key", "", &cmdReleaseKey }, // 2 args for at least the Amiga GR (v2.05 1989-03-09) using AGI 2.316
- { "adj.ego.move.to.xy", "", &cmdAdjEgoMoveToXY }
+ { "return", "", NULL }, // 00
+ { "increment", "v", &cmdIncrement }, // 01
+ { "decrement", "v", &cmdDecrement }, // 02
+ { "assignn", "vn", &cmdAssignN }, // 03
+ { "assignv", "vv", &cmdAssignV }, // 04
+ { "addn", "vn", &cmdAddN }, // 05
+ { "addv", "vv", &cmdAddV }, // 06
+ { "subn", "vn", &cmdSubN }, // 07
+ { "subv", "vv", &cmdSubV }, // 08
+ { "lindirectv", "vv", &cmdLindirectV }, // 09
+ { "lindirect", "vv", &cmdRindirect }, // 0A
+ { "lindirectn", "vn", &cmdLindirectN }, // 0B
+ { "set", "n", &cmdSet }, // 0C
+ { "reset", "n", &cmdReset }, // 0D
+ { "toggle", "n", &cmdToggle }, // 0E
+ { "set.v", "v", &cmdSetV }, // 0F
+ { "reset.v", "v", &cmdResetV }, // 10
+ { "toggle.v", "v", &cmdToggleV }, // 11
+ { "new.room", "n", &cmdNewRoom }, // 12
+ { "new.room.v", "v", &cmdNewRoomF }, // 13
+ { "load.logics", "n", &cmdLoadLogic }, // 14
+ { "load.logics.v", "v", &cmdLoadLogicF }, // 15
+ { "call", "n", &cmdCall }, // 16
+ { "call.v", "v", &cmdCallF }, // 17
+ { "load.pic", "v", &cmdLoadPic }, // 18
+ { "draw.pic", "v", &cmdDrawPic }, // 19
+ { "show.pic", "", &cmdShowPic }, // 1A
+ { "discard.pic", "v", &cmdDiscardPic }, // 1B
+ { "overlay.pic", "v", &cmdOverlayPic }, // 1C
+ { "show.pri.screen", "", &cmdShowPriScreen }, // 1D
+ { "load.view", "n", &cmdLoadView }, // 1E
+ { "load.view.v", "v", &cmdLoadViewF }, // 1F
+ { "discard.view", "n", &cmdDiscardView }, // 20
+ { "animate.obj", "n", &cmdAnimateObj }, // 21
+ { "unanimate.all", "", &cmdUnanimateAll }, // 22
+ { "draw", "n", &cmdDraw }, // 23
+ { "erase", "n", &cmdErase }, // 24
+ { "position", "nnn", &cmdPosition }, // 25
+ { "position.v", "nvv", &cmdPositionF }, // 26
+ { "get.posn", "nvv", &cmdGetPosn }, // 27
+ { "reposition", "nvv", &cmdReposition }, // 28
+ { "set.view", "nn", &cmdSetView }, // 29
+ { "set.view.v", "nv", &cmdSetViewF }, // 2A
+ { "set.loop", "nn", &cmdSetLoop }, // 2B
+ { "set.loop.v", "nv", &cmdSetLoopF }, // 2C
+ { "fix.loop", "n", &cmdFixLoop }, // 2D
+ { "release.loop", "n", &cmdReleaseLoop }, // 2E
+ { "set.cel", "nn", &cmdSetCel }, // 2F
+ { "set.cel.v", "nv", &cmdSetCelF }, // 30
+ { "last.cel", "nv", &cmdLastCel }, // 31
+ { "current.cel", "nv", &cmdCurrentCel }, // 32
+ { "current.loop", "nv", &cmdCurrentLoop }, // 33
+ { "current.view", "nv", &cmdCurrentView }, // 34
+ { "number.of.loops", "nv", &cmdNumberOfLoops }, // 35
+ { "set.priority", "nn", &cmdSetPriority }, // 36
+ { "set.priority.v", "nv", &cmdSetPriorityF }, // 37
+ { "release.priority", "n", &cmdReleasePriority }, // 38
+ { "get.priority", "nn", &cmdGetPriority }, // 39
+ { "stop.update", "n", &cmdStopUpdate }, // 3A
+ { "start.update", "n", &cmdStartUpdate }, // 3B
+ { "force.update", "n", &cmdForceUpdate }, // 3C
+ { "ignore.horizon", "n", &cmdIgnoreHorizon }, // 3D
+ { "observe.horizon", "n", &cmdObserveHorizon }, // 3E
+ { "set.horizon", "n", &cmdSetHorizon }, // 3F
+ { "object.on.water", "n", &cmdObjectOnWater }, // 40
+ { "object.on.land", "n", &cmdObjectOnLand }, // 41
+ { "object.on.anything", "n", &cmdObjectOnAnything }, // 42
+ { "ignore.objs", "n", &cmdIgnoreObjs }, // 43
+ { "observe.objs", "n", &cmdObserveObjs }, // 44
+ { "distance", "nnv", &cmdDistance }, // 45
+ { "stop.cycling", "n", &cmdStopCycling }, // 46
+ { "start.cycling", "n", &cmdStartCycling }, // 47
+ { "normal.cycle", "n", &cmdNormalCycle }, // 48
+ { "end.of.loop", "nn", &cmdEndOfLoop }, // 49
+ { "reverse.cycle", "n", &cmdReverseCycle }, // 5A
+ { "reverse.loop", "nn", &cmdReverseLoop }, // 5B
+ { "cycle.time", "nv", &cmdCycleTime }, // 5C
+ { "stop.motion", "n", &cmdStopMotion }, // 5D
+ { "start.motion", "n", &cmdStartMotion }, // 5E
+ { "step.size", "nv", &cmdStepSize }, // 5F
+ { "step.time", "nv", &cmdStepTime }, // 60
+ { "move.obj", "nnnnn", &cmdMoveObj }, // 61
+ { "move.obj.v", "nvvvv", &cmdMoveObjF }, // 62
+ { "follow.ego", "nnn", &cmdFollowEgo }, // 63
+ { "wander", "n", &cmdWander }, // 64
+ { "normal.motion", "n", &cmdNormalMotion }, // 65
+ { "set.dir", "nv", &cmdSetDir }, // 66
+ { "get.dir", "nv", &cmdGetDir }, // 67
+ { "ignore.blocks", "n", &cmdIgnoreBlocks }, // 68
+ { "observe.blocks", "n", &cmdObserveBlocks }, // 69
+ { "block", "nnnn", &cmdBlock }, // 6A
+ { "unblock", "", &cmdUnblock }, // 6B
+ { "get", "n", &cmdGet }, // 6C
+ { "get.v", "v", &cmdGetF }, // 6D
+ { "drop", "n", &cmdDrop }, // 6E
+ { "put", "nn", &cmdPut }, // 6F
+ { "put.v", "vv", &cmdPutF }, // 70
+ { "get.room.v", "vv", &cmdGetRoomF }, // 71
+ { "load.sound", "n", &cmdLoadSound }, // 72
+ { "sound", "nn", &cmdSound }, // 73
+ { "stop.sound", "", &cmdStopSound }, // 74
+ { "print", "s", &cmdPrint }, // 75
+ { "print.v", "v", &cmdPrintF }, // 76
+ { "display", "nns", &cmdDisplay }, // 77
+ { "display.v", "vvv", &cmdDisplayF }, // 78
+ { "clear.lines", "nns", &cmdClearLines }, // 79
+ { "text.screen", "", &cmdTextScreen }, // 7A
+ { "graphics", "", &cmdGraphics }, // 7B
+ { "set.cursor.char", "s", &cmdSetCursorChar }, // 7C
+ { "set.text.attribute", "nn", &cmdSetTextAttribute }, // 7D
+ { "shake.screen", "n", &cmdShakeScreen }, // 7E
+ { "configure.screen", "nnn", &cmdConfigureScreen }, // 7F
+ { "status.line.on", "", &cmdStatusLineOn }, // 80
+ { "status.line.off", "", &cmdStatusLineOff }, // 81
+ { "set.string", "ns", &cmdSetString }, // 82
+ { "get.string", "nsnnn", &cmdGetString }, // 83
+ { "word.to.string", "nn", &cmdWordToString }, // 84
+ { "parse", "n", &cmdParse }, // 85
+ { "get.num", "nv", &cmdGetNum }, // 86
+ { "prevent.input", "", &cmdPreventInput }, // 87
+ { "accept.input", "", &cmdAcceptInput }, // 88
+ { "set.key", "nnn", &cmdSetKey }, // 89
+ { "add.to.pic", "nnnnnnn", &cmdAddToPic }, // 8A
+ { "add.to.pic.v", "vvvvvvv", &cmdAddToPicF }, // 8B
+ { "status", "", &cmdStatus }, // 8C
+ { "save.game", "", &cmdSaveGame }, // 8D
+ { "restore.game", "", &cmdLoadGame }, // 8E
+ { "init.disk", "", &cmdInitDisk }, // 8F
+ { "restart.game", "", &cmdRestartGame }, // 90
+ { "show.obj", "n", &cmdShowObj }, // 91
+ { "random", "nnv", &cmdRandom }, // 92
+ { "program.control", "", &cmdProgramControl }, // 93
+ { "player.control", "", &cmdPlayerControl }, // 94
+ { "obj.status.v", "v", &cmdObjStatusF }, // 95
+ { "quit", "n", &cmdQuit }, // 96 0 args for AGI version 2.089
+ { "show.mem", "", &cmdShowMem }, // 97
+ { "pause", "", &cmdPause }, // 98
+ { "echo.line", "", &cmdEchoLine }, // 99
+ { "cancel.line", "", &cmdCancelLine }, // 9A
+ { "init.joy", "", &cmdInitJoy }, // 9B
+ { "toggle.monitor", "", &cmdToggleMonitor }, // 9C
+ { "version", "", &cmdVersion }, // 9D
+ { "script.size", "n", &cmdScriptSize }, // 9E
+ { "set.game.id", "s", &cmdSetGameID }, // 9F
+ { "log", "s", &cmdLog }, // A0
+ { "set.scan.start", "", &cmdSetScanStart }, // A1
+ { "reset.scan.start", "", &cmdResetScanStart }, // A2
+ { "reposition.to", "nnn", &cmdRepositionTo }, // A3
+ { "reposition.to.v", "nvv", &cmdRepositionToF }, // A4
+ { "trace.on", "", &cmdTraceOn }, // A5
+ { "trace.info", "nnn", &cmdTraceInfo }, // A6
+ { "print.at", "snnn", &cmdPrintAt }, // 3 args for AGI versions before 2.440
+ { "print.at.v", "vnnn", &cmdPrintAtV }, // A8
+ { "discard.view.v", "v", &cmdDiscardView}, // A9
+ { "clear.text.rect", "nnnnn", &cmdClearTextRect }, // AA
+ { "set.upper.left", "nn", &cmdSetUpperLeft }, // AB
+ { "set.menu", "s", &cmdSetMenu }, // AC
+ { "set.menu.item", "sn", &cmdSetMenuItem }, // AD
+ { "submit.menu", "", &cmdSubmitMenu }, // AE
+ { "enable.item", "n", &cmdEnableItem }, // AF
+ { "disable.item", "n", &cmdDisableItem }, // B0
+ { "menu.input", "", &cmdMenuInput }, // B1
+ { "show.obj.v", "v", &cmdShowObjV }, // B2
+ { "open.dialogue", "", &cmdOpenDialogue }, // B3
+ { "close.dialogue", "", &cmdCloseDialogue }, // B4
+ { "mul.n", "vn", &cmdMulN }, // B5
+ { "mul.v", "vv", &cmdMulV }, // B6
+ { "div.n", "vn", &cmdDivN }, // B7
+ { "div.v", "vv", &cmdDivV }, // B8
+ { "close.window", "", &cmdCloseWindow }, // B9
+ { "set.simple", "n", &cmdSetSimple }, // BA AGI2.425+, *BUT* not included in AGI2.440
+ { "push.script", "", &cmdPushScript }, // BB
+ { "pop.script", "", &cmdPopScript }, // BC
+ { "hold.key", "", &cmdHoldKey }, // BD
+ { "set.pri.base", "n", &cmdSetPriBase }, // BE AGI2.936+ *AND* also inside AGI2.425
+ { "discard.sound", "n", &cmdDiscardSound }, // BF was skip for PC
+ { "hide.mouse", "", &cmdHideMouse }, // C0 1 arg for AGI version 3.002.086 AGI3+ only starts here
+ { "allow.menu", "n", &cmdAllowMenu }, // C1
+ { "show.mouse", "", &cmdShowMouse }, // C2
+ { "fence.mouse", "nnnn", &cmdFenceMouse }, // C3
+ { "mouse.posn", "vv", &cmdMousePosn }, // C4
+ { "release.key", "", &cmdReleaseKey }, // C5 2 args for at least the Amiga GR (v2.05 1989-03-09) using AGI 2.316
+ { "adj.ego.move.to.xy", "", &cmdAdjEgoMoveToXY } // C6
};
void AgiEngine::setupOpcodes() {
@@ -375,9 +375,9 @@ void AgiEngine::setupOpcodes() {
// The Apple IIGS versions of MH1 and Goldrush both have a parameter for
// show.mouse and hide.mouse. Fixes bugs #3577754 and #3426946.
if ((getGameID() == GID_MH1 || getGameID() == GID_GOLDRUSH) &&
- getPlatform() == Common::kPlatformApple2GS) {
- logicNamesCmd[176].args = "n"; // hide.mouse
- logicNamesCmd[178].args = "n"; // show.mouse
+ getPlatform() == Common::kPlatformApple2GS) {
+ logicNamesCmd[176].args = "n"; // hide.mouse
+ logicNamesCmd[178].args = "n"; // show.mouse
}
} else {
for (int i = 0; i < ARRAYSIZE(insV1Test); ++i)
diff --git a/engines/agi/opcodes.h b/engines/agi/opcodes.h
index 6bd31c339a..aac2756f86 100644
--- a/engines/agi/opcodes.h
+++ b/engines/agi/opcodes.h
@@ -38,236 +38,234 @@ struct AgiInstruction {
extern AgiInstruction *logicNamesTest;
extern AgiInstruction *logicNamesCmd;
-void cmdIncrement(AgiGame *state, uint8 *p);
-void cmdDecrement(AgiGame *state, uint8 *p);
-void cmdAssignN(AgiGame *state, uint8 *p);
-void cmdAssignV(AgiGame *state, uint8 *p);
-void cmdAddN(AgiGame *state, uint8 *p);
-void cmdAddV(AgiGame *state, uint8 *p);
-void cmdSubN(AgiGame *state, uint8 *p);
-void cmdSubV(AgiGame *state, uint8 *p); // 0x08
-void cmdLindirectV(AgiGame *state, uint8 *p);
-void cmdRindirect(AgiGame *state, uint8 *p);
-void cmdLindirectN(AgiGame *state, uint8 *p);
-void cmdSet(AgiGame *state, uint8 *p);
-void cmdReset(AgiGame *state, uint8 *p);
-void cmdToggle(AgiGame *state, uint8 *p);
-void cmdSetV(AgiGame *state, uint8 *p);
-void cmdResetV(AgiGame *state, uint8 *p); // 0x10
-void cmdToggleV(AgiGame *state, uint8 *p);
-void cmdNewRoom(AgiGame *state, uint8 *p);
-void cmdNewRoomF(AgiGame *state, uint8 *p);
-void cmdLoadLogic(AgiGame *state, uint8 *p);
-void cmdLoadLogicF(AgiGame *state, uint8 *p);
-void cmdCall(AgiGame *state, uint8 *p);
-void cmdCallF(AgiGame *state, uint8 *p);
-void cmdLoadPic(AgiGame *state, uint8 *p); // 0x18
-void cmdLoadPicV1(AgiGame *state, uint8 *p);
-void cmdDrawPic(AgiGame *state, uint8 *p);
-void cmdDrawPicV1(AgiGame *state, uint8 *p);
-void cmdShowPic(AgiGame *state, uint8 *p);
-void cmdDiscardPic(AgiGame *state, uint8 *p);
-void cmdOverlayPic(AgiGame *state, uint8 *p);
-void cmdShowPriScreen(AgiGame *state, uint8 *p);
-void cmdLoadView(AgiGame *state, uint8 *p);
-void cmdLoadViewF(AgiGame *state, uint8 *p);
-void cmdDiscardView(AgiGame *state, uint8 *p); // 0x20
-void cmdAnimateObj(AgiGame *state, uint8 *p);
-void cmdUnanimateAll(AgiGame *state, uint8 *p);
-void cmdDraw(AgiGame *state, uint8 *p);
-void cmdErase(AgiGame *state, uint8 *p);
-void cmdPosition(AgiGame *state, uint8 *p);
-void cmdPositionV1(AgiGame *state, uint8 *p);
-void cmdPositionF(AgiGame *state, uint8 *p);
-void cmdPositionFV1(AgiGame *state, uint8 *p);
-void cmdGetPosn(AgiGame *state, uint8 *p);
-void cmdReposition(AgiGame *state, uint8 *p); // 0x28
-void cmdRepositionV1(AgiGame *state, uint8 *p); // 0x28
-void cmdSetView(AgiGame *state, uint8 *p);
-void cmdSetViewF(AgiGame *state, uint8 *p);
-void cmdSetLoop(AgiGame *state, uint8 *p);
-void cmdSetLoopF(AgiGame *state, uint8 *p);
-void cmdFixLoop(AgiGame *state, uint8 *p);
-void cmdReleaseLoop(AgiGame *state, uint8 *p);
-void cmdSetCel(AgiGame *state, uint8 *p);
-void cmdSetCelF(AgiGame *state, uint8 *p); // 0x30
-void cmdLastCel(AgiGame *state, uint8 *p);
-void cmdCurrentCel(AgiGame *state, uint8 *p);
-void cmdCurrentLoop(AgiGame *state, uint8 *p);
-void cmdCurrentView(AgiGame *state, uint8 *p);
-void cmdNumberOfLoops(AgiGame *state, uint8 *p);
-void cmdSetPriority(AgiGame *state, uint8 *p);
-void cmdSetPriorityF(AgiGame *state, uint8 *p);
-void cmdReleasePriority(AgiGame *state, uint8 *p); // 0x38
-void cmdGetPriority(AgiGame *state, uint8 *p);
-void cmdStopUpdate(AgiGame *state, uint8 *p);
-void cmdStartUpdate(AgiGame *state, uint8 *p);
-void cmdForceUpdate(AgiGame *state, uint8 *p);
-void cmdIgnoreHorizon(AgiGame *state, uint8 *p);
-void cmdObserveHorizon(AgiGame *state, uint8 *p);
-void cmdSetHorizon(AgiGame *state, uint8 *p);
-void cmdObjectOnWater(AgiGame *state, uint8 *p); // 0x40
-void cmdObjectOnLand(AgiGame *state, uint8 *p);
-void cmdObjectOnAnything(AgiGame *state, uint8 *p);
-void cmdIgnoreObjs(AgiGame *state, uint8 *p);
-void cmdObserveObjs(AgiGame *state, uint8 *p);
-void cmdDistance(AgiGame *state, uint8 *p);
-void cmdStopCycling(AgiGame *state, uint8 *p);
-void cmdStartCycling(AgiGame *state, uint8 *p);
-void cmdNormalCycle(AgiGame *state, uint8 *p); // 0x48
-void cmdEndOfLoop(AgiGame *state, uint8 *p);
-void cmdEndOfLoopV1(AgiGame *state, uint8 *p);
-void cmdReverseCycle(AgiGame *state, uint8 *p);
-void cmdReverseLoop(AgiGame *state, uint8 *p);
-void cmdReverseLoopV1(AgiGame *state, uint8 *p);
-void cmdCycleTime(AgiGame *state, uint8 *p);
-void cmdStopMotion(AgiGame *state, uint8 *p);
-void cmdStopMotionV1(AgiGame *state, uint8 *p);
-void cmdStartMotion(AgiGame *state, uint8 *p);
-void cmdStartMotionV1(AgiGame *state, uint8 *p);
-void cmdStepSize(AgiGame *state, uint8 *p);
-void cmdStepTime(AgiGame *state, uint8 *p); // 0x50
-void cmdMoveObj(AgiGame *state, uint8 *p);
-void cmdMoveObjF(AgiGame *state, uint8 *p);
-void cmdFollowEgo(AgiGame *state, uint8 *p);
-void cmdWander(AgiGame *state, uint8 *p);
-void cmdNormalMotion(AgiGame *state, uint8 *p);
-void cmdSetDir(AgiGame *state, uint8 *p);
-void cmdGetDir(AgiGame *state, uint8 *p);
-void cmdIgnoreBlocks(AgiGame *state, uint8 *p); // 0x58
-void cmdObserveBlocks(AgiGame *state, uint8 *p);
-void cmdBlock(AgiGame *state, uint8 *p);
-void cmdUnblock(AgiGame *state, uint8 *p);
-void cmdGet(AgiGame *state, uint8 *p);
-void cmdGetV1(AgiGame *state, uint8 *p);
-void cmdGetF(AgiGame *state, uint8 *p);
-void cmdDrop(AgiGame *state, uint8 *p);
-void cmdPut(AgiGame *state, uint8 *p);
-void cmdPutF(AgiGame *state, uint8 *p); // 0x60
-void cmdGetRoomF(AgiGame *state, uint8 *p);
-void cmdLoadSound(AgiGame *state, uint8 *p);
-void cmdSound(AgiGame *state, uint8 *p);
-void cmdStopSound(AgiGame *state, uint8 *p);
-void cmdPrint(AgiGame *state, uint8 *p);
-void cmdPrintF(AgiGame *state, uint8 *p);
-void cmdDisplay(AgiGame *state, uint8 *p);
-void cmdDisplayF(AgiGame *state, uint8 *p); // 0x68
-void cmdClearLines(AgiGame *state, uint8 *p);
-void cmdTextScreen(AgiGame *state, uint8 *p);
-void cmdGraphics(AgiGame *state, uint8 *p);
-void cmdSetCursorChar(AgiGame *state, uint8 *p);
-void cmdSetTextAttribute(AgiGame *state, uint8 *p);
-void cmdShakeScreen(AgiGame *state, uint8 *p);
-void cmdConfigureScreen(AgiGame *state, uint8 *p);
-void cmdStatusLineOn(AgiGame *state, uint8 *p); // 0x70
-void cmdStatusLineOff(AgiGame *state, uint8 *p);
-void cmdSetString(AgiGame *state, uint8 *p);
-void cmdGetString(AgiGame *state, uint8 *p);
-void cmdWordToString(AgiGame *state, uint8 *p);
-void cmdParse(AgiGame *state, uint8 *p);
-void cmdGetNum(AgiGame *state, uint8 *p);
-void cmdPreventInput(AgiGame *state, uint8 *p);
-void cmdAcceptInput(AgiGame *state, uint8 *p); // 0x78
-void cmdSetKey(AgiGame *state, uint8 *p);
-void cmdAddToPic(AgiGame *state, uint8 *p);
-void cmdAddToPicV1(AgiGame *state, uint8 *p);
-void cmdAddToPicF(AgiGame *state, uint8 *p);
-void cmdStatus(AgiGame *state, uint8 *p);
-void cmdSaveGame(AgiGame *state, uint8 *p);
-void cmdLoadGame(AgiGame *state, uint8 *p);
-void cmdInitDisk(AgiGame *state, uint8 *p);
-void cmdRestartGame(AgiGame *state, uint8 *p); // 0x80
-void cmdShowObj(AgiGame *state, uint8 *p);
-void cmdRandom(AgiGame *state, uint8 *p);
-void cmdRandomV1(AgiGame *state, uint8 *p);
-void cmdProgramControl(AgiGame *state, uint8 *p);
-void cmdPlayerControl(AgiGame *state, uint8 *p);
-void cmdObjStatusF(AgiGame *state, uint8 *p);
-void cmdQuit(AgiGame *state, uint8 *p);
-void cmdQuitV1(AgiGame *state, uint8 *p);
-void cmdShowMem(AgiGame *state, uint8 *p);
-void cmdPause(AgiGame *state, uint8 *p); // 0x88
-void cmdEchoLine(AgiGame *state, uint8 *p);
-void cmdCancelLine(AgiGame *state, uint8 *p);
-void cmdInitJoy(AgiGame *state, uint8 *p);
-void cmdToggleMonitor(AgiGame *state, uint8 *p);
-void cmdVersion(AgiGame *state, uint8 *p);
-void cmdScriptSize(AgiGame *state, uint8 *p);
-void cmdSetGameID(AgiGame *state, uint8 *p);
-void cmdLog(AgiGame *state, uint8 *p); // 0x90
-void cmdSetScanStart(AgiGame *state, uint8 *p);
-void cmdResetScanStart(AgiGame *state, uint8 *p);
-void cmdRepositionTo(AgiGame *state, uint8 *p);
-void cmdRepositionToF(AgiGame *state, uint8 *p);
-void cmdTraceOn(AgiGame *state, uint8 *p);
-void cmdTraceInfo(AgiGame *state, uint8 *p);
-void cmdPrintAt(AgiGame *state, uint8 *p);
-void cmdPrintAtV(AgiGame *state, uint8 *p); // 0x98
-//void cmdDiscardView(AgiGame *state, uint8 *p); // Opcode repeated from 0x20 ?
-void cmdClearTextRect(AgiGame *state, uint8 *p);
-void cmdSetUpperLeft(AgiGame *state, uint8 *p);
-void cmdSetMenu(AgiGame *state, uint8 *p);
-void cmdSetMenuItem(AgiGame *state, uint8 *p);
-void cmdSubmitMenu(AgiGame *state, uint8 *p);
-void cmdEnableItem(AgiGame *state, uint8 *p);
-void cmdDisableItem(AgiGame *state, uint8 *p); // 0xa0
-void cmdMenuInput(AgiGame *state, uint8 *p);
-void cmdShowObjV(AgiGame *state, uint8 *p);
-void cmdOpenDialogue(AgiGame *state, uint8 *p);
-void cmdCloseDialogue(AgiGame *state, uint8 *p);
-void cmdMulN(AgiGame *state, uint8 *p);
-void cmdMulV(AgiGame *state, uint8 *p);
-void cmdDivN(AgiGame *state, uint8 *p);
-void cmdDivV(AgiGame *state, uint8 *p); // 0xa8
-void cmdCloseWindow(AgiGame *state, uint8 *p);
-void cmdSetSimple(AgiGame *state, uint8 *p);
-void cmdPushScript(AgiGame *state, uint8 *p);
-void cmdPopScript(AgiGame *state, uint8 *p);
-void cmdHoldKey(AgiGame *state, uint8 *p);
-void cmdSetPriBase(AgiGame *state, uint8 *p);
-void cmdDiscardSound(AgiGame *state, uint8 *p);
-void cmdHideMouse(AgiGame *state, uint8 *p); // 0xb0
-void cmdAllowMenu(AgiGame *state, uint8 *p);
-void cmdShowMouse(AgiGame *state, uint8 *p);
-void cmdFenceMouse(AgiGame *state, uint8 *p);
-void cmdMousePosn(AgiGame *state, uint8 *p);
-void cmdReleaseKey(AgiGame *state, uint8 *p);
-void cmdAdjEgoMoveToXY(AgiGame *state, uint8 *p);
+void cmdIncrement(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdDecrement(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdAssignN(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdAssignV(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdAddN(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdAddV(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdSubN(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdSubV(AgiGame *state, AgiEngine *vm, uint8 *p); // 0x08
+void cmdLindirectV(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdRindirect(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdLindirectN(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdSet(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdReset(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdToggle(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdSetV(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdResetV(AgiGame *state, AgiEngine *vm, uint8 *p); // 0x10
+void cmdToggleV(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdNewRoom(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdNewRoomF(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdLoadLogic(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdLoadLogicF(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdCall(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdCallF(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdLoadPic(AgiGame *state, AgiEngine *vm, uint8 *p); // 0x18
+void cmdLoadPicV1(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdDrawPic(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdDrawPicV1(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdShowPic(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdDiscardPic(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdOverlayPic(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdShowPriScreen(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdLoadView(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdLoadViewF(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdDiscardView(AgiGame *state, AgiEngine *vm, uint8 *p); // 0x20
+void cmdAnimateObj(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdUnanimateAll(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdDraw(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdErase(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdPosition(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdPositionV1(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdPositionF(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdPositionFV1(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdGetPosn(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdReposition(AgiGame *state, AgiEngine *vm, uint8 *p); // 0x28
+void cmdRepositionV1(AgiGame *state, AgiEngine *vm, uint8 *p); // 0x28
+void cmdSetView(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdSetViewF(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdSetLoop(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdSetLoopF(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdFixLoop(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdReleaseLoop(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdSetCel(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdSetCelF(AgiGame *state, AgiEngine *vm, uint8 *p); // 0x30
+void cmdLastCel(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdCurrentCel(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdCurrentLoop(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdCurrentView(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdNumberOfLoops(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdSetPriority(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdSetPriorityF(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdReleasePriority(AgiGame *state, AgiEngine *vm, uint8 *p); // 0x38
+void cmdGetPriority(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdStopUpdate(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdStartUpdate(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdForceUpdate(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdIgnoreHorizon(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdObserveHorizon(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdSetHorizon(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdObjectOnWater(AgiGame *state, AgiEngine *vm, uint8 *p); // 0x40
+void cmdObjectOnLand(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdObjectOnAnything(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdIgnoreObjs(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdObserveObjs(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdDistance(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdStopCycling(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdStartCycling(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdNormalCycle(AgiGame *state, AgiEngine *vm, uint8 *p); // 0x48
+void cmdEndOfLoop(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdEndOfLoopV1(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdReverseCycle(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdReverseLoop(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdReverseLoopV1(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdCycleTime(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdStopMotion(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdStopMotionV1(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdStartMotion(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdStartMotionV1(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdStepSize(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdStepTime(AgiGame *state, AgiEngine *vm, uint8 *p); // 0x50
+void cmdMoveObj(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdMoveObjF(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdFollowEgo(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdWander(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdNormalMotion(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdSetDir(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdGetDir(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdIgnoreBlocks(AgiGame *state, AgiEngine *vm, uint8 *p); // 0x58
+void cmdObserveBlocks(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdBlock(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdUnblock(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdGet(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdGetV1(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdGetF(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdDrop(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdPut(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdPutF(AgiGame *state, AgiEngine *vm, uint8 *p); // 0x60
+void cmdGetRoomF(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdLoadSound(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdSound(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdStopSound(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdPrint(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdPrintF(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdDisplay(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdDisplayF(AgiGame *state, AgiEngine *vm, uint8 *p); // 0x68
+void cmdClearLines(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdTextScreen(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdGraphics(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdSetCursorChar(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdSetTextAttribute(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdShakeScreen(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdConfigureScreen(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdStatusLineOn(AgiGame *state, AgiEngine *vm, uint8 *p); // 0x70
+void cmdStatusLineOff(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdSetString(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdGetString(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdWordToString(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdParse(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdGetNum(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdPreventInput(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdAcceptInput(AgiGame *state, AgiEngine *vm, uint8 *p); // 0x78
+void cmdSetKey(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdAddToPic(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdAddToPicV1(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdAddToPicF(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdStatus(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdSaveGame(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdLoadGame(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdInitDisk(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdRestartGame(AgiGame *state, AgiEngine *vm, uint8 *p); // 0x80
+void cmdShowObj(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdRandom(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdRandomV1(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdProgramControl(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdPlayerControl(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdObjStatusF(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdQuit(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdQuitV1(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdShowMem(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdPause(AgiGame *state, AgiEngine *vm, uint8 *p); // 0x88
+void cmdEchoLine(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdCancelLine(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdInitJoy(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdToggleMonitor(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdVersion(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdScriptSize(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdSetGameID(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdLog(AgiGame *state, AgiEngine *vm, uint8 *p); // 0x90
+void cmdSetScanStart(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdResetScanStart(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdRepositionTo(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdRepositionToF(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdTraceOn(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdTraceInfo(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdPrintAt(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdPrintAtV(AgiGame *state, AgiEngine *vm, uint8 *p); // 0x98
+//void cmdDiscardView(AgiGame *state, AgiEngine *vm, uint8 *p); // Opcode repeated from 0x20 ?
+void cmdClearTextRect(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdSetUpperLeft(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdSetMenu(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdSetMenuItem(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdSubmitMenu(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdEnableItem(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdDisableItem(AgiGame *state, AgiEngine *vm, uint8 *p); // 0xa0
+void cmdMenuInput(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdShowObjV(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdOpenDialogue(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdCloseDialogue(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdMulN(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdMulV(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdDivN(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdDivV(AgiGame *state, AgiEngine *vm, uint8 *p); // 0xa8
+void cmdCloseWindow(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdSetSimple(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdPushScript(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdPopScript(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdHoldKey(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdSetPriBase(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdDiscardSound(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdHideMouse(AgiGame *state, AgiEngine *vm, uint8 *p); // 0xb0
+void cmdAllowMenu(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdShowMouse(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdFenceMouse(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdMousePosn(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdReleaseKey(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdAdjEgoMoveToXY(AgiGame *state, AgiEngine *vm, uint8 *p);
-void cmdSetSpeed(AgiGame *state, uint8 *p);
-void cmdSetItemView(AgiGame *state, uint8 *p);
-void cmdCallV1(AgiGame *state, uint8 *p);
-void cmdNewRoomV1(AgiGame *state, uint8 *p);
-void cmdNewRoomVV1(AgiGame *state, uint8 *p);
-void cmdUnknown(AgiGame *state, uint8 *p);
+void cmdSetSpeed(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdSetItemView(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdCallV1(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdUnknown(AgiGame *state, AgiEngine *vm, uint8 *p);
-void condEqual(AgiGame *state, uint8 *p);
-void condEqualV(AgiGame *state, uint8 *p);
-void condLess(AgiGame *state, uint8 *p);
-void condLessV(AgiGame *state, uint8 *p);
-void condGreater(AgiGame *state, uint8 *p);
-void condGreaterV(AgiGame *state, uint8 *p);
-void condIsSet(AgiGame *state, uint8 *p);
-void condIsSetV(AgiGame *state, uint8 *p);
-void condHas(AgiGame *state, uint8 *p);
-void condHasV1(AgiGame *state, uint8 *p);
-void condObjInRoom(AgiGame *state, uint8 *p);
-void condPosn(AgiGame *state, uint8 *p);
-void condController(AgiGame *state, uint8 *p);
-void condHaveKey(AgiGame *state, uint8 *p);
-void condSaid(AgiGame *state, uint8 *p);
-void condCompareStrings(AgiGame *state, uint8 *p);
-void condObjInBox(AgiGame *state, uint8 *p);
-void condCenterPosn(AgiGame *state, uint8 *p);
-void condRightPosn(AgiGame *state, uint8 *p);
-void condUnknown13(AgiGame *state, uint8 *p);
-void condUnknown(AgiGame *state, uint8 *p);
+void condEqual(AgiGame *state, AgiEngine *vm, uint8 *p);
+void condEqualV(AgiGame *state, AgiEngine *vm, uint8 *p);
+void condLess(AgiGame *state, AgiEngine *vm, uint8 *p);
+void condLessV(AgiGame *state, AgiEngine *vm, uint8 *p);
+void condGreater(AgiGame *state, AgiEngine *vm, uint8 *p);
+void condGreaterV(AgiGame *state, AgiEngine *vm, uint8 *p);
+void condIsSet(AgiGame *state, AgiEngine *vm, uint8 *p);
+void condIsSetV(AgiGame *state, AgiEngine *vm, uint8 *p);
+void condHas(AgiGame *state, AgiEngine *vm, uint8 *p);
+void condHasV1(AgiGame *state, AgiEngine *vm, uint8 *p);
+void condObjInRoom(AgiGame *state, AgiEngine *vm, uint8 *p);
+void condPosn(AgiGame *state, AgiEngine *vm, uint8 *p);
+void condController(AgiGame *state, AgiEngine *vm, uint8 *p);
+void condHaveKey(AgiGame *state, AgiEngine *vm, uint8 *p);
+void condSaid(AgiGame *state, AgiEngine *vm, uint8 *p);
+void condCompareStrings(AgiGame *state, AgiEngine *vm, uint8 *p);
+void condObjInBox(AgiGame *state, AgiEngine *vm, uint8 *p);
+void condCenterPosn(AgiGame *state, AgiEngine *vm, uint8 *p);
+void condRightPosn(AgiGame *state, AgiEngine *vm, uint8 *p);
+void condUnknown13(AgiGame *state, AgiEngine *vm, uint8 *p);
+void condUnknown(AgiGame *state, AgiEngine *vm, uint8 *p);
-void condIsSetV1(AgiGame *state, uint8 *p);
-void condSaid1(AgiGame *state, uint8 *p);
-void condSaid2(AgiGame *state, uint8 *p);
-void condSaid3(AgiGame *state, uint8 *p);
-void condBit(AgiGame *state, uint8 *p);
+void condIsSetV1(AgiGame *state, AgiEngine *vm, uint8 *p);
+void condSaid1(AgiGame *state, AgiEngine *vm, uint8 *p);
+void condSaid2(AgiGame *state, AgiEngine *vm, uint8 *p);
+void condSaid3(AgiGame *state, AgiEngine *vm, uint8 *p);
+void condBit(AgiGame *state, AgiEngine *vm, uint8 *p);
} // End of namespace Agi
diff --git a/engines/agi/palette.h b/engines/agi/palette.h
new file mode 100644
index 0000000000..40c31da425
--- /dev/null
+++ b/engines/agi/palette.h
@@ -0,0 +1,406 @@
+/* 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 AGI_PALETTE_H
+#define AGI_PALETTE_H
+
+namespace Agi {
+
+/**
+ * 16 color RGB palette.
+ * This array contains the 6-bit RGB values of the EGA palette exported
+ * to the console drivers.
+ */
+static const uint8 PALETTE_EGA[16 * 3] = {
+ 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x2a,
+ 0x00, 0x2a, 0x00,
+ 0x00, 0x2a, 0x2a,
+ 0x2a, 0x00, 0x00,
+ 0x2a, 0x00, 0x2a,
+ 0x2a, 0x15, 0x00,
+ 0x2a, 0x2a, 0x2a,
+ 0x15, 0x15, 0x15,
+ 0x15, 0x15, 0x3f,
+ 0x15, 0x3f, 0x15,
+ 0x15, 0x3f, 0x3f,
+ 0x3f, 0x15, 0x15,
+ 0x3f, 0x15, 0x3f,
+ 0x3f, 0x3f, 0x15,
+ 0x3f, 0x3f, 0x3f
+};
+
+/**
+ * 4 color CGA palette.
+ */
+static const uint8 PALETTE_CGA[4 * 3] = {
+ 0x00, 0x00, 0x00, // black
+ 0x55, 0xff, 0xff, // cyan
+ 0xff, 0x55, 0xff, // magenta
+ 0xff, 0xff, 0xff
+};
+
+/**
+ * 2 color Hercules (green) palette. Using 8-bit RGB values.
+ */
+static const uint8 PALETTE_HERCULES_GREEN[2 * 3] = {
+ 0x00, 0x00, 0x00, // black
+ 0x00, 0xdc, 0x28 // green
+};
+
+/**
+ * 2 color Hercules (amber) palette. Using 8-bit RGB values.
+ */
+static const uint8 PALETTE_HERCULES_AMBER[2 * 3] = {
+ 0x00, 0x00, 0x00, // black
+ 0xdc, 0xb4, 0x00 // amber
+};
+
+/**
+ * Atari ST AGI palette.
+ * Used by all of the tested Atari ST AGI games
+ * from Donald Duck's Playground (1986) to Manhunter II (1989).
+ * 16 RGB colors. 3 bits per color component.
+ */
+static const uint8 PALETTE_ATARI_ST[16 * 3] = {
+ 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x7,
+ 0x0, 0x4, 0x0,
+ 0x0, 0x5, 0x4,
+ 0x5, 0x0, 0x0,
+ 0x5, 0x3, 0x6,
+ 0x4, 0x3, 0x0,
+ 0x5, 0x5, 0x5,
+ 0x3, 0x3, 0x2,
+ 0x0, 0x5, 0x7,
+ 0x0, 0x6, 0x0,
+ 0x0, 0x7, 0x6,
+ 0x7, 0x2, 0x3,
+ 0x7, 0x4, 0x7,
+ 0x7, 0x7, 0x4,
+ 0x7, 0x7, 0x7
+};
+
+/**
+ * Second generation Apple IIGS AGI palette.
+ * A 16-color, 12-bit RGB palette.
+ *
+ * Used by at least the following Apple IIGS AGI versions:
+ * 1.003 (Leisure Suit Larry I v1.0E, intro says 1987)
+ * 1.005 (AGI Demo 2 1987-06-30?)
+ * 1.006 (King's Quest I v1.0S 1988-02-23)
+ * 1.007 (Police Quest I v2.0B 1988-04-21 8:00am)
+ * 1.013 (King's Quest II v2.0A 1988-06-16 (CE))
+ * 1.013 (Mixed-Up Mother Goose v2.0A 1988-05-31 10:00am)
+ * 1.014 (King's Quest III v2.0A 1988-08-28 (CE))
+ * 1.014 (Space Quest II v2.0A, LOGIC.141 says 1988)
+ * 2.004 (Manhunter I v2.0E 1988-10-05 (CE))
+ * 2.006 (King's Quest IV v1.0K 1988-11-22 (CE))
+ * 3.001 (Black Cauldron v1.0O 1989-02-24 (CE))
+ * 3.003 (Gold Rush! v1.0M 1989-02-28 (CE))
+ */
+// *NOT* identical to Amiga generation 2 palette
+static const uint8 PALETTE_APPLE_II_GS[16 * 3] = {
+ 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0xF,
+ 0x0, 0x8, 0x0,
+ 0x0, 0xD, 0xB,
+ 0xC, 0x0, 0x0,
+ 0xB, 0x7, 0xD,
+ 0x8, 0x5, 0x0,
+ 0xB, 0xB, 0xB,
+ 0x7, 0x7, 0x7,
+ 0x0, 0xB, 0xF,
+ 0x0, 0xE, 0x0,
+ 0x0, 0xF, 0xD,
+ 0xF, 0x9, 0x8,
+ 0xD, 0x9, 0xF, // difference between Amiga v2 palette and Apple II GS palette, gotten from emulator (SQ2)
+ 0xE, 0xE, 0x0,
+ 0xF, 0xF, 0xF
+};
+
+// Re-use Amiga v1 palette for Apple IIgs Space Quest 1
+#define PALETTE_APPLE_II_GS_SQ1 PALETTE_AMIGA_V1
+
+/**
+ * First generation Amiga & Apple IIGS AGI palette.
+ * A 16-color, 12-bit RGB palette.
+ *
+ * Used by at least the following Amiga AGI versions:
+ * 2.082 (King's Quest I v1.0U 1986)
+ * 2.082 (Space Quest I v1.2 1986)
+ * 2.090 (King's Quest III v1.01 1986-11-08)
+ * 2.107 (King's Quest II v2.0J 1987-01-29)
+ * x.yyy (Black Cauldron v2.00 1987-06-14)
+ * x.yyy (Larry I v1.05 1987-06-26)
+ *
+ * Also used by at least the following Apple IIGS AGI versions:
+ * 1.002 (Space Quest I, intro says v2.2 1987)
+ */
+static const uint8 PALETTE_AMIGA_V1[16 * 3] = {
+ 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0xF,
+ 0x0, 0x8, 0x0,
+ 0x0, 0xD, 0xB,
+ 0xC, 0x0, 0x0,
+ 0xB, 0x7, 0xD,
+ 0x8, 0x5, 0x0,
+ 0xB, 0xB, 0xB,
+ 0x7, 0x7, 0x7,
+ 0x0, 0xB, 0xF,
+ 0x0, 0xE, 0x0,
+ 0x0, 0xF, 0xD,
+ 0xF, 0x9, 0x8,
+ 0xF, 0x7, 0x0,
+ 0xE, 0xE, 0x0,
+ 0xF, 0xF, 0xF
+};
+
+/**
+ * Second generation Amiga AGI palette.
+ * A 16-color, 12-bit RGB palette.
+ *
+ * Used by at least the following Amiga AGI versions:
+ * 2.202 (Space Quest II v2.0F. Intro says 1988. ScummVM 0.10.0 detects as 1986-12-09)
+ */
+static const uint8 PALETTE_AMIGA_V2[16 * 3] = {
+ 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0xF,
+ 0x0, 0x8, 0x0,
+ 0x0, 0xD, 0xB,
+ 0xC, 0x0, 0x0,
+ 0xB, 0x7, 0xD,
+ 0x8, 0x5, 0x0,
+ 0xB, 0xB, 0xB,
+ 0x7, 0x7, 0x7,
+ 0x0, 0xB, 0xF,
+ 0x0, 0xE, 0x0,
+ 0x0, 0xF, 0xD,
+ 0xF, 0x9, 0x8,
+ 0xD, 0x0, 0xF,
+ 0xE, 0xE, 0x0,
+ 0xF, 0xF, 0xF
+};
+
+/**
+ * Third generation Amiga AGI palette.
+ * A 16-color, 12-bit RGB palette.
+ *
+ * Used by at least the following Amiga AGI versions:
+ * 2.310 (Police Quest I v2.0B 1989-02-22)
+ * 2.316 (Gold Rush! v2.05 1989-03-09)
+ * x.yyy (Manhunter I v1.06 1989-03-18)
+ * 2.333 (Manhunter II v3.06 1989-08-17)
+ * 2.333 (King's Quest III v2.15 1989-11-15)
+ */
+static const uint8 PALETTE_AMIGA_V3[16 * 3] = {
+ 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0xB,
+ 0x0, 0xB, 0x0,
+ 0x0, 0xB, 0xB,
+ 0xB, 0x0, 0x0,
+ 0xB, 0x0, 0xB,
+ 0xC, 0x7, 0x0,
+ 0xB, 0xB, 0xB,
+ 0x7, 0x7, 0x7,
+ 0x0, 0x0, 0xF,
+ 0x0, 0xF, 0x0,
+ 0x0, 0xF, 0xF,
+ 0xF, 0x0, 0x0,
+ 0xF, 0x0, 0xF,
+ 0xF, 0xF, 0x0,
+ 0xF, 0xF, 0xF
+};
+
+/**
+ * 16 color amiga-ish palette.
+ */
+static const uint8 PALETTE_AMIGA_ALT[16 * 3] = {
+ 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f,
+ 0x00, 0x2A, 0x00,
+ 0x00, 0x2A, 0x2A,
+ 0x33, 0x00, 0x00,
+ 0x2f, 0x1c, 0x37,
+ 0x23, 0x14, 0x00,
+ 0x2f, 0x2f, 0x2f,
+ 0x15, 0x15, 0x15,
+ 0x00, 0x2f, 0x3f,
+ 0x00, 0x33, 0x15,
+ 0x15, 0x3F, 0x3F,
+ 0x3f, 0x27, 0x23,
+ 0x3f, 0x15, 0x3f,
+ 0x3b, 0x3b, 0x00,
+ 0x3F, 0x3F, 0x3F
+};
+
+/**
+ * 16 color Macintosh palette (CLUT format).
+ *
+ * Used by at least the following Macintosh AGI versions:
+ * ?.??? (Police Quest 1 v1.50 23.03.1988)
+ * ?.??? (King's Quest 3 v1.52 11.04.1988)
+ */
+static const uint16 PALETTE_MACINTOSH_CLUT[16 * 3] = {
+ 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0xC000,
+ 0x0000, 0xA800, 0x0000,
+ 0x0000, 0xA000, 0xA000,
+ 0xCE50, 0x0000, 0x0000,
+ 0xC080, 0x0000, 0xFFFF,
+ 0xD000, 0x6130, 0x32D0,
+ 0xC000, 0xC000, 0xC000,
+ 0x6000, 0x6000, 0x6000,
+ 0x6800, 0x6800, 0xFFFF,
+ 0x0000, 0xFFFF, 0x0000,
+ 0x0000, 0xFFFF, 0xFFFF,
+ 0xFFFF, 0x5390, 0x64B0,
+ 0xFFFF, 0x8000, 0x0000,
+ 0xFFFF, 0xFFFF, 0x0000,
+ 0xFFFF, 0xFFFF, 0xFFFF
+};
+
+/**
+ * 16 color Macintosh palette (CLUT format).
+ *
+ * Used by at least the following Macintosh AGI versions:
+ * ?.??? (Gold Rush v1.78 28.07.1989)
+ */
+static const uint16 PALETTE_MACINTOSH_CLUT2[16 * 3] = {
+ 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0xC000,
+ 0x6524, 0xC2FF, 0x0000,
+ 0x0000, 0xA000, 0xA000,
+ 0xDD6B, 0x08C2, 0x06A2,
+ 0x8000, 0x0000, 0xFFFF,
+ 0x93FF, 0x281A, 0x12CC,
+ 0xC000, 0xC000, 0xC000,
+ 0x8000, 0x8000, 0x8000,
+ 0x0000, 0x0000, 0xD400,
+ 0x0000, 0xFFFF, 0x04F1,
+ 0x0241, 0xAB54, 0xEAFF,
+ 0xFFFF, 0xC3DC, 0x8160,
+ 0xFFFF, 0x648A, 0x028C,
+ 0xFC00, 0xF37D, 0x052F,
+ 0xFFFF, 0xFFFF, 0xFFFF
+};
+
+/**
+ * 16 color Macintosh palette (CLUT format).
+ *
+ * Used by at least the following Macintosh AGI versions:
+ * ?.??? (Space Quest 2 v1.51 04.04.1988)
+ */
+static const uint16 PALETTE_MACINTOSH_CLUT3[16 * 3] = {
+ 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0xC000,
+ 0x0000, 0xA7FF, 0x0000,
+ 0x0000, 0x9FFF, 0x9FFF,
+ 0xCE50, 0x0000, 0x0000,
+ 0xC079, 0x0000, 0xFFFF,
+ 0xCFFF, 0x6130, 0x32D0,
+ 0xC000, 0xC000, 0xC000,
+ 0x6000, 0x6000, 0x6000,
+ 0x6800, 0x6800, 0xFFFF,
+ 0x0000, 0xFFFF, 0x0000,
+ 0x0000, 0xFFFF, 0xFFFF,
+ 0xFFFF, 0x538C, 0x64B1,
+ 0xFDCE, 0x1AC0, 0xFFFF,
+ 0xFFFF, 0xFFFF, 0x0000,
+ 0xFFFF, 0xFFFF, 0xFFFF,
+};
+
+/**
+ * 256 color palette used with AGI256 and AGI256-2 games.
+ * Uses full 8 bits per color component.
+ * This is NOT the standard VGA palette.
+ */
+static const uint8 PALETTE_VGA[256 * 3] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x00, 0xA8, 0x00, 0x00, 0xA8, 0xA8,
+ 0xA8, 0x00, 0x00, 0xA8, 0x00, 0xA8, 0xA8, 0x54, 0x00, 0xA8, 0xA8, 0xA8,
+ 0x54, 0x54, 0x54, 0x54, 0x54, 0xFC, 0x54, 0xFC, 0x54, 0x54, 0xFC, 0xFC,
+ 0xFC, 0x54, 0x54, 0xFC, 0x54, 0xFC, 0xFC, 0xFC, 0x54, 0xFC, 0xFC, 0xFC,
+ 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0x20, 0x20, 0x20, 0x2C, 0x2C, 0x2C,
+ 0x38, 0x38, 0x38, 0x44, 0x44, 0x44, 0x50, 0x50, 0x50, 0x60, 0x60, 0x60,
+ 0x70, 0x70, 0x70, 0x80, 0x80, 0x80, 0x90, 0x90, 0x90, 0xA0, 0xA0, 0xA0,
+ 0xB4, 0xB4, 0xB4, 0xC8, 0xC8, 0xC8, 0xE0, 0xE0, 0xE0, 0xFC, 0xFC, 0xFC,
+ 0x00, 0x00, 0xFC, 0x40, 0x00, 0xFC, 0x7C, 0x00, 0xFC, 0xBC, 0x00, 0xFC,
+ 0xFC, 0x00, 0xFC, 0xFC, 0x00, 0xBC, 0xFC, 0x00, 0x7C, 0xFC, 0x00, 0x40,
+ 0xFC, 0x00, 0x00, 0xFC, 0x40, 0x00, 0xFC, 0x7C, 0x00, 0xFC, 0xBC, 0x00,
+ 0xFC, 0xFC, 0x00, 0xBC, 0xFC, 0x00, 0x7C, 0xFC, 0x00, 0x40, 0xFC, 0x00,
+ 0x00, 0xFC, 0x00, 0x00, 0xFC, 0x40, 0x00, 0xFC, 0x7C, 0x00, 0xFC, 0xBC,
+ 0x00, 0xFC, 0xFC, 0x00, 0xBC, 0xFC, 0x00, 0x7C, 0xFC, 0x00, 0x40, 0xFC,
+ 0x7C, 0x7C, 0xFC, 0x9C, 0x7C, 0xFC, 0xBC, 0x7C, 0xFC, 0xDC, 0x7C, 0xFC,
+ 0xFC, 0x7C, 0xFC, 0xFC, 0x7C, 0xDC, 0xFC, 0x7C, 0xBC, 0xFC, 0x7C, 0x9C,
+ 0xFC, 0x7C, 0x7C, 0xFC, 0x9C, 0x7C, 0xFC, 0xBC, 0x7C, 0xFC, 0xDC, 0x7C,
+ 0xFC, 0xFC, 0x7C, 0xDC, 0xFC, 0x7C, 0xBC, 0xFC, 0x7C, 0x9C, 0xFC, 0x7C,
+ 0x7C, 0xFC, 0x7C, 0x7C, 0xFC, 0x9C, 0x7C, 0xFC, 0xBC, 0x7C, 0xFC, 0xDC,
+ 0x7C, 0xFC, 0xFC, 0x7C, 0xDC, 0xFC, 0x7C, 0xBC, 0xFC, 0x7C, 0x9C, 0xFC,
+ 0xB4, 0xB4, 0xFC, 0xC4, 0xB4, 0xFC, 0xD8, 0xB4, 0xFC, 0xE8, 0xB4, 0xFC,
+ 0xFC, 0xB4, 0xFC, 0xFC, 0xB4, 0xE8, 0xFC, 0xB4, 0xD8, 0xFC, 0xB4, 0xC4,
+ 0xFC, 0xB4, 0xB4, 0xFC, 0xC4, 0xB4, 0xFC, 0xD8, 0xB4, 0xFC, 0xE8, 0xB4,
+ 0xFC, 0xFC, 0xB4, 0xE8, 0xFC, 0xB4, 0xD8, 0xFC, 0xB4, 0xC4, 0xFC, 0xB4,
+ 0xB4, 0xFC, 0xB4, 0xB4, 0xFC, 0xC4, 0xB4, 0xFC, 0xD8, 0xB4, 0xFC, 0xE8,
+ 0xB4, 0xFC, 0xFC, 0xB4, 0xE8, 0xFC, 0xB4, 0xD8, 0xFC, 0xB4, 0xC4, 0xFC,
+ 0x00, 0x00, 0x70, 0x1C, 0x00, 0x70, 0x38, 0x00, 0x70, 0x54, 0x00, 0x70,
+ 0x70, 0x00, 0x70, 0x70, 0x00, 0x54, 0x70, 0x00, 0x38, 0x70, 0x00, 0x1C,
+ 0x70, 0x00, 0x00, 0x70, 0x1C, 0x00, 0x70, 0x38, 0x00, 0x70, 0x54, 0x00,
+ 0x70, 0x70, 0x00, 0x54, 0x70, 0x00, 0x38, 0x70, 0x00, 0x1C, 0x70, 0x00,
+ 0x00, 0x70, 0x00, 0x00, 0x70, 0x1C, 0x00, 0x70, 0x38, 0x00, 0x70, 0x54,
+ 0x00, 0x70, 0x70, 0x00, 0x54, 0x70, 0x00, 0x38, 0x70, 0x00, 0x1C, 0x70,
+ 0x38, 0x38, 0x70, 0x44, 0x38, 0x70, 0x54, 0x38, 0x70, 0x60, 0x38, 0x70,
+ 0x70, 0x38, 0x70, 0x70, 0x38, 0x60, 0x70, 0x38, 0x54, 0x70, 0x38, 0x44,
+ 0x70, 0x38, 0x38, 0x70, 0x44, 0x38, 0x70, 0x54, 0x38, 0x70, 0x60, 0x38,
+ 0x70, 0x70, 0x38, 0x60, 0x70, 0x38, 0x54, 0x70, 0x38, 0x44, 0x70, 0x38,
+ 0x38, 0x70, 0x38, 0x38, 0x70, 0x44, 0x38, 0x70, 0x54, 0x38, 0x70, 0x60,
+ 0x38, 0x70, 0x70, 0x38, 0x60, 0x70, 0x38, 0x54, 0x70, 0x38, 0x44, 0x70,
+ 0x50, 0x50, 0x70, 0x58, 0x50, 0x70, 0x60, 0x50, 0x70, 0x68, 0x50, 0x70,
+ 0x70, 0x50, 0x70, 0x70, 0x50, 0x68, 0x70, 0x50, 0x60, 0x70, 0x50, 0x58,
+ 0x70, 0x50, 0x50, 0x70, 0x58, 0x50, 0x70, 0x60, 0x50, 0x70, 0x68, 0x50,
+ 0x70, 0x70, 0x50, 0x68, 0x70, 0x50, 0x60, 0x70, 0x50, 0x58, 0x70, 0x50,
+ 0x50, 0x70, 0x50, 0x50, 0x70, 0x58, 0x50, 0x70, 0x60, 0x50, 0x70, 0x68,
+ 0x50, 0x70, 0x70, 0x50, 0x68, 0x70, 0x50, 0x60, 0x70, 0x50, 0x58, 0x70,
+ 0x00, 0x00, 0x40, 0x10, 0x00, 0x40, 0x20, 0x00, 0x40, 0x30, 0x00, 0x40,
+ 0x40, 0x00, 0x40, 0x40, 0x00, 0x30, 0x40, 0x00, 0x20, 0x40, 0x00, 0x10,
+ 0x40, 0x00, 0x00, 0x40, 0x10, 0x00, 0x40, 0x20, 0x00, 0x40, 0x30, 0x00,
+ 0x40, 0x40, 0x00, 0x30, 0x40, 0x00, 0x20, 0x40, 0x00, 0x10, 0x40, 0x00,
+ 0x00, 0x40, 0x00, 0x00, 0x40, 0x10, 0x00, 0x40, 0x20, 0x00, 0x40, 0x30,
+ 0x00, 0x40, 0x40, 0x00, 0x30, 0x40, 0x00, 0x20, 0x40, 0x00, 0x10, 0x40,
+ 0x20, 0x20, 0x40, 0x28, 0x20, 0x40, 0x30, 0x20, 0x40, 0x38, 0x20, 0x40,
+ 0x40, 0x20, 0x40, 0x40, 0x20, 0x38, 0x40, 0x20, 0x30, 0x40, 0x20, 0x28,
+ 0x40, 0x20, 0x20, 0x40, 0x28, 0x20, 0x40, 0x30, 0x20, 0x40, 0x38, 0x20,
+ 0x40, 0x40, 0x20, 0x38, 0x40, 0x20, 0x30, 0x40, 0x20, 0x28, 0x40, 0x20,
+ 0x20, 0x40, 0x20, 0x20, 0x40, 0x28, 0x20, 0x40, 0x30, 0x20, 0x40, 0x38,
+ 0x20, 0x40, 0x40, 0x20, 0x38, 0x40, 0x20, 0x30, 0x40, 0x20, 0x28, 0x40,
+ 0x2C, 0x2C, 0x40, 0x30, 0x2C, 0x40, 0x34, 0x2C, 0x40, 0x3C, 0x2C, 0x40,
+ 0x40, 0x2C, 0x40, 0x40, 0x2C, 0x3C, 0x40, 0x2C, 0x34, 0x40, 0x2C, 0x30,
+ 0x40, 0x2C, 0x2C, 0x40, 0x30, 0x2C, 0x40, 0x34, 0x2C, 0x40, 0x3C, 0x2C,
+ 0x40, 0x40, 0x2C, 0x3C, 0x40, 0x2C, 0x34, 0x40, 0x2C, 0x30, 0x40, 0x2C,
+ 0x2C, 0x40, 0x2C, 0x2C, 0x40, 0x30, 0x2C, 0x40, 0x34, 0x2C, 0x40, 0x3C,
+ 0x2C, 0x40, 0x40, 0x2C, 0x3C, 0x40, 0x2C, 0x34, 0x40, 0x2C, 0x30, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+} // End of namespace Agi
+
+#endif /* AGI_PALETTE_H */
diff --git a/engines/agi/picture.cpp b/engines/agi/picture.cpp
index 58dfb9db68..2b3bba89db 100644
--- a/engines/agi/picture.cpp
+++ b/engines/agi/picture.cpp
@@ -31,8 +31,11 @@ PictureMgr::PictureMgr(AgiBase *agi, GfxMgr *gfx) {
_vm = agi;
_gfx = gfx;
+ _resourceNr = 0;
_data = NULL;
- _flen = _foffs = 0;
+ _dataSize = 0;
+ _dataOffset = 0;
+ _dataOffsetNibble = false;
_patCode = _patNum = _priOn = _scrOn = _scrColor = _priColor = 0;
_xOffset = _yOffset = 0;
@@ -41,260 +44,43 @@ PictureMgr::PictureMgr(AgiBase *agi, GfxMgr *gfx) {
_minCommand = 0xf0;
_flags = 0;
_currentStep = 0;
+
+ _width = _height = 0;
}
void PictureMgr::putVirtPixel(int x, int y) {
- uint8 *p;
-
- x += _xOffset;
- y += _yOffset;
+ byte drawMask = 0;
if (x < 0 || y < 0 || x >= _width || y >= _height)
return;
- p = &_vm->_game.sbuf16c[y * _width + x];
+ x += _xOffset;
+ y += _yOffset;
if (_priOn)
- *p = (_priColor << 4) | (*p & 0x0f);
+ drawMask |= GFX_SCREEN_MASK_PRIORITY;
if (_scrOn)
- *p = _scrColor | (*p & 0xf0);
-}
+ drawMask |= GFX_SCREEN_MASK_VISUAL;
-#if 0
-static void drawProc(int x, int y, int c, void *data) {
- ((PictureMgr *)data)->putVirtPixel(x, y);
+ _gfx->putPixel(x, y, drawMask, _scrColor, _priColor);
}
-#endif
-
-/**
- * Draw an AGI line.
- * A line drawing routine sent by Joshua Neal, modified by Stuart George
- * (fixed >>2 to >>1 and some other bugs like x1 instead of y1, etc.)
- * @param x1 x coordinate of start point
- * @param y1 y coordinate of start point
- * @param x2 x coordinate of end point
- * @param y2 y coordinate of end point
- */
-void PictureMgr::drawLine(int x1, int y1, int x2, int y2) {
- x1 = CLIP(x1, 0, _width - 1);
- x2 = CLIP(x2, 0, _width - 1);
- y1 = CLIP(y1, 0, _height - 1);
- y2 = CLIP(y2, 0, _height - 1);
-
-#if 0
- Graphics::drawLine(x1, y1, x2, y2, 0, drawProc, this);
-#else
- int i, x, y, deltaX, deltaY, stepX, stepY, errorX, errorY, detdelta;
-
- // Vertical line
-
- if (x1 == x2) {
- if (y1 > y2) {
- SWAP(y1, y2);
- }
-
- for (; y1 <= y2; y1++)
- putVirtPixel(x1, y1);
-
- return;
- }
- // Horizontal line
-
- if (y1 == y2) {
- if (x1 > x2) {
- SWAP(x1, x2);
- }
- for (; x1 <= x2; x1++)
- putVirtPixel(x1, y1);
- return;
- }
-
- y = y1;
- x = x1;
-
- stepY = 1;
- deltaY = y2 - y1;
- if (deltaY < 0) {
- stepY = -1;
- deltaY = -deltaY;
- }
-
- stepX = 1;
- deltaX = x2 - x1;
- if (deltaX < 0) {
- stepX = -1;
- deltaX = -deltaX;
- }
-
- if (deltaY > deltaX) {
- i = deltaY;
- detdelta = deltaY;
- errorX = deltaY / 2;
- errorY = 0;
+byte PictureMgr::getNextByte() {
+ if (!_dataOffsetNibble) {
+ return _data[_dataOffset++];
} else {
- i = deltaX;
- detdelta = deltaX;
- errorX = 0;
- errorY = deltaX / 2;
- }
-
- putVirtPixel(x, y);
-
- do {
- errorY += deltaY;
- if (errorY >= detdelta) {
- errorY -= detdelta;
- y += stepY;
- }
-
- errorX += deltaX;
- if (errorX >= detdelta) {
- errorX -= detdelta;
- x += stepX;
- }
-
- putVirtPixel(x, y);
- i--;
- } while (i > 0);
-#endif
-}
-
-/**
- * Draw a relative AGI line.
- * Draws short lines relative to last position. (drawing action 0xF7)
- */
-void PictureMgr::dynamicDrawLine() {
- int x1, y1, disp, dx, dy;
-
- if ((x1 = nextByte()) >= _minCommand ||
- (y1 = nextByte()) >= _minCommand) {
- _foffs--;
- return;
- }
-
- putVirtPixel(x1, y1);
-
- for (;;) {
- if ((disp = nextByte()) >= _minCommand)
- break;
-
- dx = ((disp & 0xf0) >> 4) & 0x0f;
- dy = (disp & 0x0f);
-
- if (dx & 0x08)
- dx = -(dx & 0x07);
- if (dy & 0x08)
- dy = -(dy & 0x07);
-
- drawLine(x1, y1, x1 + dx, y1 + dy);
- x1 += dx;
- y1 += dy;
- }
- _foffs--;
-}
-
-/**************************************************************************
-** absoluteLine
-**
-** Draws long lines to actual locations (cf. relative) (drawing action 0xF6)
-**************************************************************************/
-void PictureMgr::absoluteDrawLine() {
- int x1, y1, x2, y2;
-
- if ((x1 = nextByte()) >= _minCommand ||
- (y1 = nextByte()) >= _minCommand) {
- _foffs--;
- return;
- }
-
- putVirtPixel(x1, y1);
-
- for (;;) {
- if ((x2 = nextByte()) >= _minCommand)
- break;
-
- if ((y2 = nextByte()) >= _minCommand)
- break;
-
- drawLine(x1, y1, x2, y2);
- x1 = x2;
- y1 = y2;
+ byte curByte = _data[_dataOffset++] << 4;
+ return (_data[_dataOffset] >> 4) | curByte;
}
- _foffs--;
}
-/**************************************************************************
-** okToFill
-**************************************************************************/
-int PictureMgr::isOkFillHere(int x, int y) {
- uint8 p;
-
- x += _xOffset;
- y += _yOffset;
-
- if (x < 0 || x >= _width || y < 0 || y >= _height)
- return false;
-
- p = _vm->_game.sbuf16c[y * _width + x];
-
- if (_flags & kPicFTrollMode)
- return ((p & 0x0f) != 11 && (p & 0x0f) != _scrColor);
-
- if (!_priOn && _scrOn && _scrColor != 15)
- return (p & 0x0f) == 15;
-
- if (_priOn && !_scrOn && _priColor != 4)
- return (p >> 4) == 4;
-
- return (_scrOn && (p & 0x0f) == 15 && _scrColor != 15);
-}
-
-/**************************************************************************
-** agi_fill
-**************************************************************************/
-void PictureMgr::agiFill(unsigned int x, unsigned int y) {
- if (!_scrOn && !_priOn)
- return;
-
- // Push initial pixel on the stack
- Common::Stack<Common::Point> stack;
- stack.push(Common::Point(x,y));
-
- // Exit if stack is empty
- while (!stack.empty()) {
- Common::Point p = stack.pop();
- unsigned int c;
- int newspanUp, newspanDown;
-
- if (!isOkFillHere(p.x, p.y))
- continue;
-
- // Scan for left border
- for (c = p.x - 1; isOkFillHere(c, p.y); c--)
- ;
-
- newspanUp = newspanDown = 1;
- for (c++; isOkFillHere(c, p.y); c++) {
- putVirtPixel(c, p.y);
- if (isOkFillHere(c, p.y - 1)) {
- if (newspanUp) {
- stack.push(Common::Point(c,p.y-1));
- newspanUp = 0;
- }
- } else {
- newspanUp = 1;
- }
-
- if (isOkFillHere(c, p.y + 1)) {
- if (newspanDown) {
- stack.push(Common::Point(c,p.y+1));
- newspanDown = 0;
- }
- } else {
- newspanDown = 1;
- }
- }
+byte PictureMgr::getNextNibble() {
+ if (!_dataOffsetNibble) {
+ _dataOffsetNibble = true;
+ return _data[_dataOffset] >> 4;
+ } else {
+ _dataOffsetNibble = false;
+ return _data[_dataOffset++] & 0x0F;
}
}
@@ -303,43 +89,43 @@ void PictureMgr::agiFill(unsigned int x, unsigned int y) {
**
** Draws an xCorner (drawing action 0xF5)
**************************************************************************/
-void PictureMgr::xCorner(bool skipOtherCoords) {
+void PictureMgr::draw_xCorner(bool skipOtherCoords) {
int x1, x2, y1, y2;
- if ((x1 = nextByte()) >= _minCommand ||
- (y1 = nextByte()) >= _minCommand) {
- _foffs--;
+ if ((x1 = getNextByte()) >= _minCommand ||
+ (y1 = getNextByte()) >= _minCommand) {
+ _dataOffset--;
return;
}
putVirtPixel(x1, y1);
for (;;) {
- x2 = nextByte();
+ x2 = getNextByte();
if (x2 >= _minCommand)
break;
if (skipOtherCoords)
- if (nextByte() >= _minCommand)
+ if (getNextByte() >= _minCommand)
break;
- drawLine(x1, y1, x2, y1);
+ draw_Line(x1, y1, x2, y1);
x1 = x2;
if (skipOtherCoords)
- if (nextByte() >= _minCommand)
+ if (getNextByte() >= _minCommand)
break;
- y2 = nextByte();
+ y2 = getNextByte();
if (y2 >= _minCommand)
break;
- drawLine(x1, y1, x1, y2);
+ draw_Line(x1, y1, x1, y2);
y1 = y2;
}
- _foffs--;
+ _dataOffset--;
}
/**************************************************************************
@@ -350,9 +136,9 @@ void PictureMgr::xCorner(bool skipOtherCoords) {
void PictureMgr::yCorner(bool skipOtherCoords) {
int x1, x2, y1, y2;
- if ((x1 = nextByte()) >= _minCommand ||
- (y1 = nextByte()) >= _minCommand) {
- _foffs--;
+ if ((x1 = getNextByte()) >= _minCommand ||
+ (y1 = getNextByte()) >= _minCommand) {
+ _dataOffset--;
return;
}
@@ -360,44 +146,30 @@ void PictureMgr::yCorner(bool skipOtherCoords) {
for (;;) {
if (skipOtherCoords)
- if (nextByte() >= _minCommand)
+ if (getNextByte() >= _minCommand)
break;
- y2 = nextByte();
+ y2 = getNextByte();
if (y2 >= _minCommand)
break;
- drawLine(x1, y1, x1, y2);
+ draw_Line(x1, y1, x1, y2);
y1 = y2;
- x2 = nextByte();
+ x2 = getNextByte();
if (x2 >= _minCommand)
break;
if (skipOtherCoords)
- if (nextByte() >= _minCommand)
+ if (getNextByte() >= _minCommand)
break;
- drawLine(x1, y1, x2, y1);
+ draw_Line(x1, y1, x2, y1);
x1 = x2;
}
- _foffs--;
-}
-
-/**************************************************************************
-** fill
-**
-** AGI flood fill. (drawing action 0xF8)
-**************************************************************************/
-void PictureMgr::fill() {
- int x1, y1;
-
- while ((x1 = nextByte()) < _minCommand && (y1 = nextByte()) < _minCommand)
- agiFill(x1, y1);
-
- _foffs--;
+ _dataOffset--;
}
/**************************************************************************
@@ -406,22 +178,26 @@ void PictureMgr::fill() {
** Draws pixels, circles, squares, or splatter brush patterns depending
** on the pattern code.
**************************************************************************/
-
void PictureMgr::plotPattern(int x, int y) {
- static const uint16 binary_list[] = {0x8000, 0x4000, 0x2000, 0x1000, 0x800, 0x400, 0x200, 0x100,
- 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1};
+ static const uint16 binary_list[] = {
+ 0x8000, 0x4000, 0x2000, 0x1000, 0x800, 0x400, 0x200, 0x100,
+ 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1
+ };
- static const uint8 circle_list[] = {0, 1, 4, 9, 16, 25, 37, 50};
+ static const uint8 circle_list[] = {
+ 0, 1, 4, 9, 16, 25, 37, 50
+ };
- static uint16 circle_data[] =
- {0x8000,
+ static uint16 circle_data[] = {
+ 0x8000,
0xE000, 0xE000, 0xE000,
0x7000, 0xF800, 0x0F800, 0x0F800, 0x7000,
0x3800, 0x7C00, 0x0FE00, 0x0FE00, 0x0FE00, 0x7C00, 0x3800,
0x1C00, 0x7F00, 0x0FF80, 0x0FF80, 0x0FF80, 0x0FF80, 0x0FF80, 0x7F00, 0x1C00,
0x0E00, 0x3F80, 0x7FC0, 0x7FC0, 0x0FFE0, 0x0FFE0, 0x0FFE0, 0x7FC0, 0x7FC0, 0x3F80, 0x1F00, 0x0E00,
0x0F80, 0x3FE0, 0x7FF0, 0x7FF0, 0x0FFF8, 0x0FFF8, 0x0FFF8, 0x0FFF8, 0x0FFF8, 0x7FF0, 0x7FF0, 0x3FE0, 0x0F80,
- 0x07C0, 0x1FF0, 0x3FF8, 0x7FFC, 0x7FFC, 0x0FFFE, 0x0FFFE, 0x0FFFE, 0x0FFFE, 0x0FFFE, 0x7FFC, 0x7FFC, 0x3FF8, 0x1FF0, 0x07C0};
+ 0x07C0, 0x1FF0, 0x3FF8, 0x7FFC, 0x7FFC, 0x0FFFE, 0x0FFFE, 0x0FFFE, 0x0FFFE, 0x0FFFE, 0x7FFC, 0x7FFC, 0x3FF8, 0x1FF0, 0x07C0
+ };
uint16 circle_word;
const uint16 *circle_ptr;
@@ -434,10 +210,10 @@ void PictureMgr::plotPattern(int x, int y) {
uint8 temp8;
uint16 temp16;
- int pen_x = x;
- int pen_y = y;
- uint16 texture_num = 0;
- uint16 pen_size = (_patCode & 0x07);
+ int pen_x = x;
+ int pen_y = y;
+ uint16 texture_num = 0;
+ uint16 pen_size = (_patCode & 0x07);
circle_ptr = &circle_data[circle_list[pen_size]];
@@ -458,7 +234,7 @@ void PictureMgr::plotPattern(int x, int y) {
pen_x = temp16;
pen_x /= 2;
- pen_final_x = pen_x; // original starting point?? -> used in plotrelated
+ pen_final_x = pen_x; // original starting point?? -> used in plotrelated
// Setup the Y Position
// = pen_y - pen.size
@@ -469,16 +245,16 @@ void PictureMgr::plotPattern(int x, int y) {
if (pen_y >= temp16)
pen_y = temp16;
- pen_final_y = pen_y; // used in plotrelated
+ pen_final_y = pen_y; // used in plotrelated
- t = (uint8)(texture_num | 0x01); // even
+ t = (uint8)(texture_num | 0x01); // even
// new purpose for temp16
- temp16 = (pen_size << 1) + 1; // pen size
- pen_final_y += temp16; // the last row of this shape
+ temp16 = (pen_size << 1) + 1; // pen size
+ pen_final_y += temp16; // the last row of this shape
temp16 = temp16 << 1;
- pen_width = temp16; // width of shape?
+ pen_width = temp16; // width of shape?
bool circleCond;
int counterStep;
@@ -501,7 +277,7 @@ void PictureMgr::plotPattern(int x, int y) {
circle_word = *circle_ptr++;
for (counter = 0; counter <= pen_width; counter += counterStep) {
- if (circleCond || ((binary_list[counter>>1] & circle_word) != 0)) {
+ if (circleCond || ((binary_list[counter >> 1] & circle_word) != 0)) {
if ((_patCode & 0x20) != 0) {
temp8 = t % 2;
t = t >> 1;
@@ -532,267 +308,600 @@ void PictureMgr::plotBrush() {
for (;;) {
if (_patCode & 0x20) {
- if ((_patNum = nextByte()) >= _minCommand)
+ if ((_patNum = getNextByte()) >= _minCommand)
break;
_patNum = (_patNum >> 1) & 0x7f;
}
- if ((x1 = nextByte()) >= _minCommand)
+ if ((x1 = getNextByte()) >= _minCommand)
break;
- if ((y1 = nextByte()) >= _minCommand)
+ if ((y1 = getNextByte()) >= _minCommand)
break;
plotPattern(x1, y1);
}
- _foffs--;
+ _dataOffset--;
}
/**************************************************************************
** Draw AGI picture
**************************************************************************/
-
void PictureMgr::drawPicture() {
- uint8 act;
- int drawing;
- int iteration = 0;
-
_patCode = 0;
_patNum = 0;
- _priOn = _scrOn = false;
- _scrColor = (_pictureVersion == AGIPIC_C64) ? 0x0 : 0xf;
- _priColor = 0x4;
+ _priOn = false;
+ _scrOn = false;
+ _scrColor = 15;
+ _priColor = 4;
+
+ switch (_pictureVersion) {
+ case AGIPIC_C64:
+ drawPictureC64();
+ break;
+ case AGIPIC_V1:
+ drawPictureV1();
+ break;
+ case AGIPIC_V15:
+ drawPictureV15();
+ break;
+ case AGIPIC_V2:
+ drawPictureV2();
+ break;
+ case AGIPIC_256:
+ drawPictureAGI256();
+ break;
+ default:
+ break;
+ }
+}
+
+void PictureMgr::drawPictureC64() {
+ byte curByte;
- drawing = 1;
+ debugC(8, kDebugLevelMain, "Drawing C64 picture");
- debugC(8, kDebugLevelMain, "Drawing v2 picture");
- for (drawing = 1; drawing && _foffs < _flen;) {
- act = nextByte();
+ _scrColor = 0x0;
- if (_pictureVersion == AGIPIC_C64 && act >= 0xf0 && act <= 0xfe) {
- _scrColor = act - 0xf0;
+ while (_dataOffset < _dataSize) {
+ curByte = getNextByte();
+
+ if ((curByte >= 0xF0) && (curByte <= 0xFE)) {
+ _scrColor = curByte & 0x0F;
continue;
}
- switch (act) {
- case 0xe0: // x-corner (C64)
- xCorner();
+ switch (curByte) {
+ case 0xe0: // x-corner
+ draw_xCorner();
break;
- case 0xe1: // y-corner (C64)
+ case 0xe1: // y-corner
yCorner();
break;
- case 0xe2: // dynamic draw lines (C64)
- dynamicDrawLine();
+ case 0xe2: // dynamic draw lines
+ draw_LineShort();
break;
- case 0xe3: // absolute draw lines (C64)
- absoluteDrawLine();
+ case 0xe3: // absolute draw lines
+ draw_LineAbsolute();
break;
- case 0xe4: // fill (C64)
- _scrColor = nextByte();
- _scrColor &= 0xF; // for v3 drawing diff
- fill();
+ case 0xe4: // fill
+ draw_SetColor();
+ draw_Fill();
break;
- case 0xe5: // enable screen drawing (C64)
+ case 0xe5: // enable screen drawing
_scrOn = true;
break;
- case 0xe6: // plot brush (C64)
- _patCode = nextByte();
+ case 0xe6: // plot brush
+ _patCode = getNextByte();
plotBrush();
break;
- case 0xf0: // set color on screen (AGI pic v2)
- if (_pictureVersion == AGIPIC_V15)
- break;
+ case 0xff: // end of data
+ return;
+ default:
+ warning("Unknown picture opcode (%x) at (%x)", curByte, _dataOffset - 1);
+ break;
+ }
+ }
+}
+
+void PictureMgr::drawPictureV1() {
+ byte curByte;
+
+ debugC(8, kDebugLevelMain, "Drawing V1 picture");
+
+ while (_dataOffset < _dataSize) {
+ curByte = getNextByte();
- _scrColor = nextByte();
- _scrColor &= 0xF; // for v3 drawing diff
+ switch (curByte) {
+ case 0xf1:
+ draw_SetColor();
_scrOn = true;
+ _priOn = false;
break;
- case 0xf1:
- if (_pictureVersion == AGIPIC_V1) {
- _scrColor = nextByte();
- _scrColor &= 0xF; // for v3 drawing diff
- _scrOn = true;
- _priOn = false;
- } else if (_pictureVersion == AGIPIC_V15) { // set color on screen
- _scrColor = nextByte();
- _scrColor &= 0xF;
- _scrOn = true;
- } else if (_pictureVersion == AGIPIC_V2) { // disable screen drawing
- _scrOn = false;
- }
+ case 0xf3:
+ draw_SetColor();
+ _scrOn = true;
+ draw_SetPriority();
+ _priOn = true;
break;
- case 0xf2: // set color on priority (AGI pic v2)
- if (_pictureVersion == AGIPIC_V15)
- break;
-
- _priColor = nextByte();
- _priColor &= 0xf; // for v3 drawing diff
+ case 0xfa:
+ _scrOn = false;
_priOn = true;
+ draw_LineAbsolute();
+ _scrOn = true;
+ _priOn = false;
break;
- case 0xf3:
- if (_pictureVersion == AGIPIC_V1) {
- _scrColor = nextByte();
- _scrColor &= 0xF; // for v3 drawing diff
- _scrOn = true;
- _priColor = nextByte();
- _priColor &= 0xf; // for v3 drawing diff
- _priOn = true;
- }
+ case 0xfb:
+ draw_LineShort();
+ break;
+ case 0xff: // end of data
+ return;
+ default:
+ warning("Unknown picture opcode (%x) at (%x)", curByte, _dataOffset - 1);
+ break;
+ }
+ }
+}
- if (_pictureVersion == AGIPIC_V15 && (_flags & kPicFf3Stop))
- drawing = 0;
+void PictureMgr::drawPictureV15() {
+ byte curByte;
- if (_pictureVersion == AGIPIC_V2) // disable priority screen
- _priOn = false;
- break;
- case 0xf4: // y-corner
- if (_pictureVersion == AGIPIC_V15)
- break;
+ debugC(8, kDebugLevelMain, "Drawing V1.5 picture");
- yCorner();
- break;
- case 0xf5: // x-corner
- if (_pictureVersion == AGIPIC_V15)
- break;
+ while (_dataOffset < _dataSize) {
+ curByte = getNextByte();
- xCorner();
+ switch (curByte) {
+ case 0xf0:
+ // happens in all Troll's Tale pictures
+ // TODO: figure out what it was meant for
break;
- case 0xf6: // absolute draw lines
- if (_pictureVersion == AGIPIC_V15)
- break;
-
- absoluteDrawLine();
+ case 0xf1:
+ draw_SetColor();
+ _scrOn = true;
break;
- case 0xf7: // dynamic draw lines
- if (_pictureVersion == AGIPIC_V15)
- break;
-
- dynamicDrawLine();
+ case 0xf3:
+ if (_flags & kPicFf3Stop)
+ return;
break;
- case 0xf8: // fill
- if (_pictureVersion == AGIPIC_V15) {
- yCorner(true);
- } else if (_pictureVersion == AGIPIC_V2) {
- fill();
- }
+ case 0xf8:
+ yCorner(true);
+ break;
+ case 0xf9:
+ draw_xCorner(true);
+ break;
+ case 0xfa:
+ // TODO: is this really correct?
+ draw_LineAbsolute();
break;
- case 0xf9: // set pattern
- if (_pictureVersion == AGIPIC_V15) {
- xCorner(true);
- } else if (_pictureVersion == AGIPIC_V2) {
- _patCode = nextByte();
+ case 0xfb:
+ // TODO: is this really correct?
+ draw_LineAbsolute();
+ break;
+ case 0xfe:
+ draw_SetColor();
+ _scrOn = true;
+ draw_Fill();
+ break;
+ case 0xff: // end of data
+ return;
+ default:
+ warning("Unknown picture opcode (%x) at (%x)", curByte, _dataOffset - 1);
+ break;
+ }
+ }
+}
+
+void PictureMgr::drawPictureV2() {
+ byte curByte;
+ bool nibbleMode = false;
+ bool mickeyCrystalAnimation = false;
+ int mickeyIteration = 0;
+
+ debugC(8, kDebugLevelMain, "Drawing V2/V3 picture");
+
+ if (_vm->_game.dirPic[_resourceNr].flags & RES_PICTURE_V3_NIBBLE_PARM) {
+ // check, if this resource uses nibble mode (0xF0 + 0xF2 commands take nibbles instead of bytes)
+ nibbleMode = true;
+ }
+
+ if ((_flags & kPicFStep) && _vm->getGameType() == GType_PreAGI) {
+ mickeyCrystalAnimation = true;
+ }
+
+ while (_dataOffset < _dataSize) {
+ curByte = getNextByte();
- if (_vm->getGameType() == GType_PreAGI)
- plotBrush();
+ switch (curByte) {
+ case 0xf0:
+ if (!nibbleMode) {
+ draw_SetColor();
+ } else {
+ draw_SetNibbleColor();
}
+ _scrOn = true;
break;
- case 0xfa: // plot brush
- if (_pictureVersion == AGIPIC_V1) {
- _scrOn = false;
- _priOn = true;
- absoluteDrawLine();
- _scrOn = true;
- _priOn = false;
- } else if (_pictureVersion == AGIPIC_V15) {
- absoluteDrawLine();
- } else if (_pictureVersion == AGIPIC_V2) {
- plotBrush();
- }
+ case 0xf1:
+ _scrOn = false;
break;
- case 0xfb:
- if (_pictureVersion == AGIPIC_V1) {
- dynamicDrawLine();
- } else if (_pictureVersion == AGIPIC_V15) {
- absoluteDrawLine();
+ case 0xf2:
+ if (!nibbleMode) {
+ draw_SetPriority();
+ } else {
+ draw_SetNibblePriority();
}
+ _priOn = true;
break;
- case 0xfc: // fill (AGI pic v1)
- if (_pictureVersion == AGIPIC_V15)
- break;
+ case 0xf3:
+ _priOn = false;
+ break;
+ case 0xf4:
+ yCorner();
+ break;
+ case 0xf5:
+ draw_xCorner();
+ break;
+ case 0xf6:
+ draw_LineAbsolute();
+ break;
+ case 0xf7:
+ draw_LineShort();
+ break;
+ case 0xf8:
+ draw_Fill();
+ break;
+ case 0xf9:
+ _patCode = getNextByte();
- _scrColor = nextByte();
- _scrColor &= 0xF;
- _priColor = nextByte();
- _priColor &= 0xf;
- fill();
+ if (_vm->getGameType() == GType_PreAGI)
+ plotBrush();
break;
- case 0xfe: // fill (AGI pic v1.5)
- _scrColor = nextByte();
- _scrColor &= 0xF;
- _scrOn = true;
- fill();
+ case 0xfa:
+ plotBrush();
break;
- case 0xff: // end of pic data
- drawing = 0;
+ case 0xfc:
+ draw_SetColor();
+ draw_SetPriority();
+ draw_Fill();
break;
+ case 0xff: // end of data
+ return;
default:
- warning("Unknown picture opcode (%x) at (%x)", act, _foffs - 1);
+ warning("Unknown picture opcode (%x) at (%x)", curByte, _dataOffset - 1);
+ break;
}
// This is used by Mickey for the crystal animation
// One frame of the crystal animation is shown on each iteration, based on _currentStep
- if ((_flags & kPicFStep) && _vm->getGameType() == GType_PreAGI && _currentStep == iteration) {
- int storedXOffset = _xOffset;
- int storedYOffset = _yOffset;
- // Note that picture coordinates are correct for Mickey only
- showPic(10, 0, _width, _height);
- _xOffset = storedXOffset;
- _yOffset = storedYOffset;
- _currentStep++;
- if (_currentStep > 14) // crystal animation is 15 frames
- _currentStep = 0;
- // reset the picture step flag - it will be set when the next frame of the crystal animation is drawn
- _flags &= ~kPicFStep;
- return; // return back to the game loop
+ if (mickeyCrystalAnimation) {
+ if (_currentStep == mickeyIteration) {
+ int storedXOffset = _xOffset;
+ int storedYOffset = _yOffset;
+ // Note that picture coordinates are correct for Mickey only
+ showPic(10, 0, _width, _height);
+ _xOffset = storedXOffset;
+ _yOffset = storedYOffset;
+ _currentStep++;
+ if (_currentStep > 14) // crystal animation is 15 frames
+ _currentStep = 0;
+ // reset the picture step flag - it will be set when the next frame of the crystal animation is drawn
+ _flags &= ~kPicFStep;
+ return; // return back to the game loop
+ }
+ mickeyIteration++;
+ }
+ }
+}
+
+void PictureMgr::drawPictureAGI256() {
+ const uint32 maxFlen = _width * _height;
+ int16 x = 0;
+ int16 y = 0;
+ byte *dataPtr = _data;
+ byte *dataEndPtr = _data + _dataSize;
+ byte color = 0;
+
+ debugC(8, kDebugLevelMain, "Drawing AGI256 picture");
+
+ while (dataPtr < dataEndPtr) {
+ color = *dataPtr++;
+ _gfx->putPixel(x, y, GFX_SCREEN_MASK_VISUAL, color, 0);
+
+ x++;
+ if (x >= _width) {
+ x = 0;
+ y++;
+ if (y >= _height) {
+ break;
+ }
+ }
+ }
+
+ if (_dataSize < maxFlen) {
+ warning("Undersized AGI256 picture resource %d, using it anyway. Filling rest with white.", _resourceNr);
+ while (_dataSize < maxFlen) {
+ x++;
+ if (x >= _width) {
+ x = 0;
+ y++;
+ if (y >= _height)
+ break;
+ }
+ _gfx->putPixel(x, y, GFX_SCREEN_MASK_VISUAL, 15, 0);
}
+ } else if (_dataSize > maxFlen)
+ warning("Oversized AGI256 picture resource %d, decoding only %ux%u part of it", _resourceNr, _width, _height);
+}
+
+void PictureMgr::draw_SetColor() {
+ _scrColor = getNextByte();
- iteration++;
+ // For CGA, replace the color with its mixture color
+ switch (_vm->_renderMode) {
+ case Common::kRenderCGA:
+ _scrColor = _gfx->getCGAMixtureColor(_scrColor);
+ break;
+ default:
+ break;
}
}
+void PictureMgr::draw_SetPriority() {
+ _priColor = getNextByte();
+}
+
+// this gets a nibble instead of a full byte
+// used by some V3 games, special resource flag RES_PICTURE_V3_NIBBLE_PARM is set
+void PictureMgr::draw_SetNibbleColor() {
+ _scrColor = getNextNibble();
+
+ // For CGA, replace the color with its mixture color
+ switch (_vm->_renderMode) {
+ case Common::kRenderCGA:
+ _scrColor = _gfx->getCGAMixtureColor(_scrColor);
+ break;
+ default:
+ break;
+ }
+}
+
+void PictureMgr::draw_SetNibblePriority() {
+ _priColor = getNextNibble();
+}
+
/**
- * convert AGI v3 format picture to AGI v2 format
+ * Draw an AGI line.
+ * A line drawing routine sent by Joshua Neal, modified by Stuart George
+ * (fixed >>2 to >>1 and some other bugs like x1 instead of y1, etc.)
+ * @param x1 x coordinate of start point
+ * @param y1 y coordinate of start point
+ * @param x2 x coordinate of end point
+ * @param y2 y coordinate of end point
*/
-uint8 *PictureMgr::convertV3Pic(uint8 *src, uint32 len) {
- uint8 d, old = 0, x, *in, *xdata, *out, mode = 0;
- uint32 i, ulen;
+void PictureMgr::draw_Line(int16 x1, int16 y1, int16 x2, int16 y2) {
+ x1 = CLIP<int16>(x1, 0, _width - 1);
+ x2 = CLIP<int16>(x2, 0, _width - 1);
+ y1 = CLIP<int16>(y1, 0, _height - 1);
+ y2 = CLIP<int16>(y2, 0, _height - 1);
- xdata = (uint8 *)malloc(len + len / 2);
+ int i, x, y, deltaX, deltaY, stepX, stepY, errorX, errorY, detdelta;
- out = xdata;
- in = src;
+ // Vertical line
- for (i = ulen = 0; i < len; i++, ulen++) {
- d = *in++;
+ if (x1 == x2) {
+ if (y1 > y2) {
+ SWAP(y1, y2);
+ }
- *out++ = x = mode ? ((d & 0xF0) >> 4) + ((old & 0x0F) << 4) : d;
+ for (; y1 <= y2; y1++)
+ putVirtPixel(x1, y1);
- if (x == 0xFF) {
- ulen++;
- break;
+ return;
+ }
+
+ // Horizontal line
+
+ if (y1 == y2) {
+ if (x1 > x2) {
+ SWAP(x1, x2);
+ }
+ for (; x1 <= x2; x1++)
+ putVirtPixel(x1, y1);
+ return;
+ }
+
+ y = y1;
+ x = x1;
+
+ stepY = 1;
+ deltaY = y2 - y1;
+ if (deltaY < 0) {
+ stepY = -1;
+ deltaY = -deltaY;
+ }
+
+ stepX = 1;
+ deltaX = x2 - x1;
+ if (deltaX < 0) {
+ stepX = -1;
+ deltaX = -deltaX;
+ }
+
+ if (deltaY > deltaX) {
+ i = deltaY;
+ detdelta = deltaY;
+ errorX = deltaY / 2;
+ errorY = 0;
+ } else {
+ i = deltaX;
+ detdelta = deltaX;
+ errorX = 0;
+ errorY = deltaX / 2;
+ }
+
+ putVirtPixel(x, y);
+
+ do {
+ errorY += deltaY;
+ if (errorY >= detdelta) {
+ errorY -= detdelta;
+ y += stepY;
+ }
+
+ errorX += deltaX;
+ if (errorX >= detdelta) {
+ errorX -= detdelta;
+ x += stepX;
}
- if (x == 0xf0 || x == 0xf2) {
- if (mode) {
- *out++ = d & 0x0F;
- ulen++;
+ putVirtPixel(x, y);
+ i--;
+ } while (i > 0);
+}
+
+/**
+ * Draw a relative AGI line.
+ * Draws short lines relative to last position. (drawing action 0xF7)
+ */
+void PictureMgr::draw_LineShort() {
+ int x1, y1, disp, dx, dy;
+
+ if ((x1 = getNextByte()) >= _minCommand ||
+ (y1 = getNextByte()) >= _minCommand) {
+ _dataOffset--;
+ return;
+ }
+
+ putVirtPixel(x1, y1);
+
+ for (;;) {
+ if ((disp = getNextByte()) >= _minCommand)
+ break;
+
+ dx = ((disp & 0xf0) >> 4) & 0x0f;
+ dy = (disp & 0x0f);
+
+ if (dx & 0x08)
+ dx = -(dx & 0x07);
+ if (dy & 0x08)
+ dy = -(dy & 0x07);
+
+ draw_Line(x1, y1, x1 + dx, y1 + dy);
+ x1 += dx;
+ y1 += dy;
+ }
+ _dataOffset--;
+}
+
+/**************************************************************************
+** absoluteLine
+**
+** Draws long lines to actual locations (cf. relative) (drawing action 0xF6)
+**************************************************************************/
+void PictureMgr::draw_LineAbsolute() {
+ int16 x1, y1, x2, y2;
+
+ if ((x1 = getNextByte()) >= _minCommand ||
+ (y1 = getNextByte()) >= _minCommand) {
+ _dataOffset--;
+ return;
+ }
+
+ putVirtPixel(x1, y1);
+
+ for (;;) {
+ if ((x2 = getNextByte()) >= _minCommand)
+ break;
+
+ if ((y2 = getNextByte()) >= _minCommand)
+ break;
+
+ draw_Line(x1, y1, x2, y2);
+ x1 = x2;
+ y1 = y2;
+ }
+ _dataOffset--;
+}
+
+// flood fill
+void PictureMgr::draw_Fill() {
+ int16 x1, y1;
+
+ while ((x1 = getNextByte()) < _minCommand && (y1 = getNextByte()) < _minCommand)
+ draw_Fill(x1, y1);
+
+ _dataOffset--;
+}
+
+void PictureMgr::draw_Fill(int16 x, int16 y) {
+ if (!_scrOn && !_priOn)
+ return;
+
+ // Push initial pixel on the stack
+ Common::Stack<Common::Point> stack;
+ stack.push(Common::Point(x, y));
+
+ // Exit if stack is empty
+ while (!stack.empty()) {
+ Common::Point p = stack.pop();
+ unsigned int c;
+ bool newspanUp, newspanDown;
+
+ if (!draw_FillCheck(p.x, p.y))
+ continue;
+
+ // Scan for left border
+ for (c = p.x - 1; draw_FillCheck(c, p.y); c--)
+ ;
+
+ newspanUp = newspanDown = true;
+ for (c++; draw_FillCheck(c, p.y); c++) {
+ putVirtPixel(c, p.y);
+ if (draw_FillCheck(c, p.y - 1)) {
+ if (newspanUp) {
+ stack.push(Common::Point(c, p.y - 1));
+ newspanUp = false;
+ }
} else {
- d = *in++;
- *out++ = (d & 0xF0) >> 4;
- i++, ulen++;
+ newspanUp = true;
}
- mode = !mode;
+ if (draw_FillCheck(c, p.y + 1)) {
+ if (newspanDown) {
+ stack.push(Common::Point(c, p.y + 1));
+ newspanDown = false;
+ }
+ } else {
+ newspanDown = true;
+ }
}
-
- old = d;
}
+}
+
+int PictureMgr::draw_FillCheck(int16 x, int16 y) {
+ byte screenColor;
+ byte screenPriority;
- free(src);
- xdata = (uint8 *)realloc(xdata, ulen);
+ if (x < 0 || x >= _width || y < 0 || y >= _height)
+ return false;
+
+ x += _xOffset;
+ y += _yOffset;
+
+ screenColor = _gfx->getColor(x, y);
+ screenPriority = _gfx->getPriority(x, y);
+
+ if (_flags & kPicFTrollMode)
+ return ((screenColor != 11) && (screenColor != _scrColor));
- return xdata;
+ if (!_priOn && _scrOn && _scrColor != 15)
+ return (screenColor == 15);
+
+ if (_priOn && !_scrOn && _priColor != 4)
+ return screenPriority == 4;
+
+ return (_scrOn && screenColor == 15 && _scrColor != 15);
}
/**
@@ -804,8 +913,8 @@ uint8 *PictureMgr::convertV3Pic(uint8 *src, uint32 len) {
* @param clear clear AGI screen before drawing
* @param agi256 load an AGI256 picture resource
*/
-int PictureMgr::decodePicture(int n, int clr, bool agi256, int pic_width, int pic_height) {
- debugC(8, kDebugLevelResources, "(%d)", n);
+int PictureMgr::decodePicture(int16 resourceNr, bool clearScreen, bool agi256, int16 pic_width, int16 pic_height) {
+ debugC(8, kDebugLevelResources, "(%d)", resourceNr);
_patCode = 0;
_patNum = 0;
@@ -813,32 +922,28 @@ int PictureMgr::decodePicture(int n, int clr, bool agi256, int pic_width, int pi
_scrColor = 0xF;
_priColor = 0x4;
- _data = _vm->_game.pictures[n].rdata;
- _flen = _vm->_game.dirPic[n].len;
- _foffs = 0;
+ _resourceNr = resourceNr;
+ _data = _vm->_game.pictures[resourceNr].rdata;
+ _dataSize = _vm->_game.dirPic[resourceNr].len;
+ _dataOffset = 0;
+ _dataOffsetNibble = false;
_width = pic_width;
_height = pic_height;
- if (clr && !agi256) // 256 color pictures should always fill the whole screen, so no clearing for them.
- memset(_vm->_game.sbuf16c, 0x4f, _width * _height); // Clear 16 color AGI screen (Priority 4, color white).
+ if (clearScreen && !agi256) { // 256 color pictures should always fill the whole screen, so no clearing for them.
+ _gfx->clear(15, 4); // Clear 16 color AGI screen (Priority 4, color white).
+ }
if (!agi256) {
drawPicture(); // Draw 16 color picture.
} else {
- const uint32 maxFlen = _width * _height;
- memcpy(_vm->_game.sbuf256c, _data, MIN(_flen, maxFlen)); // Draw 256 color picture.
-
- if (_flen < maxFlen) {
- warning("Undersized AGI256 picture resource %d, using it anyway. Filling rest with white.", n);
- memset(_vm->_game.sbuf256c + _flen, 0x0f, maxFlen - _flen); // Fill missing area with white.
- } else if (_flen > maxFlen)
- warning("Oversized AGI256 picture resource %d, decoding only %ux%u part of it", n, _width, _height);
+ drawPictureAGI256();
}
- if (clr)
+ if (clearScreen)
_vm->clearImageStack();
- _vm->recordImageStackCall(ADD_PIC, n, clr, agi256, 0, 0, 0, 0);
+ _vm->recordImageStackCall(ADD_PIC, resourceNr, clearScreen, agi256, 0, 0, 0, 0);
return errOK;
}
@@ -852,7 +957,7 @@ int PictureMgr::decodePicture(int n, int clr, bool agi256, int pic_width, int pi
* @param length the size of the picture data buffer
* @param clear clear AGI screen before drawing
*/
-int PictureMgr::decodePicture(byte* data, uint32 length, int clr, int pic_width, int pic_height) {
+int PictureMgr::decodePicture(byte *data, uint32 length, int clr, int pic_width, int pic_height) {
_patCode = 0;
_patNum = 0;
_priOn = _scrOn = false;
@@ -860,14 +965,15 @@ int PictureMgr::decodePicture(byte* data, uint32 length, int clr, int pic_width,
_priColor = 0x4;
_data = data;
- _flen = length;
- _foffs = 0;
+ _dataSize = length;
+ _dataOffset = 0;
+ _dataOffsetNibble = false;
_width = pic_width;
_height = pic_height;
if (clr) // 256 color pictures should always fill the whole screen, so no clearing for them.
- memset(_vm->_game.sbuf16c, 0x4f, _width * _height); // Clear 16 color AGI screen (Priority 4, color white).
+ clear();
drawPicture(); // Draw 16 color picture.
@@ -891,29 +997,65 @@ int PictureMgr::unloadPicture(int n) {
}
void PictureMgr::clear() {
- memset(_vm->_game.sbuf16c, 0x4f, _width * _height);
+ _gfx->clear(15, 4); // Clear 16 color AGI screen (Priority 4, color white).
+}
+
+void PictureMgr::showPic() {
+ debugC(8, kDebugLevelMain, "Show picture!");
+
+ _gfx->render_Block(0, 0, SCRIPT_WIDTH, SCRIPT_HEIGHT);
}
/**
* Show AGI picture.
* This function copies a ``hidden'' AGI picture to the output device.
*/
-void PictureMgr::showPic(int x, int y, int pic_width, int pic_height) {
- int i, y1;
- int offset;
+void PictureMgr::showPic(int16 x, int16 y, int16 pic_width, int16 pic_height) {
_width = pic_width;
_height = pic_height;
debugC(8, kDebugLevelMain, "Show picture!");
- i = 0;
- offset = _vm->_game.lineMinPrint * CHAR_LINES;
- for (y1 = y; y1 < y + _height; y1++) {
- _gfx->putPixelsA(x, y1 + offset, _width, &_vm->_game.sbuf16c[i]);
- i += _width;
+ _gfx->render_Block(x, y, pic_width, pic_height);
+}
+
+void PictureMgr::showPicWithTransition() {
+ _width = SCRIPT_WIDTH;
+ _height = SCRIPT_HEIGHT;
+
+ debugC(8, kDebugLevelMain, "Show picture!");
+
+ if (!_vm->_game.automaticRestoreGame) {
+ // only do transitions when we are not restoring a saved game
+
+ if (!_vm->_game.gfxMode) {
+ // if we are not yet in graphics mode, set graphics mode palette now
+ // TODO: maybe change text mode to use different colors for drawing
+ // so that we don't have to change palettes at all
+ _gfx->setPalette(true);
+ }
+
+ switch (_vm->_renderMode) {
+ case Common::kRenderAmiga:
+ case Common::kRenderApple2GS:
+ // Platform Amiga/Apple II GS -> render and do Amiga transition
+ _gfx->render_Block(0, 0, SCRIPT_WIDTH, SCRIPT_HEIGHT, false);
+ _gfx->transition_Amiga();
+ return;
+ break;
+ case Common::kRenderAtariST:
+ // Platform Atari ST used a different transition, looks "high-res" (full 320x168)
+ _gfx->render_Block(0, 0, SCRIPT_WIDTH, SCRIPT_HEIGHT, false);
+ _gfx->transition_AtariSt();
+ return;
+ default:
+ // Platform PC -> render directly
+ // Macintosh AGI also doesn't seem to have any transitions
+ break;
+ }
}
- _gfx->flushScreen();
+ _gfx->render_Block(0, 0, SCRIPT_WIDTH, SCRIPT_HEIGHT);
}
// preagi needed functions (for plotPattern)
@@ -933,8 +1075,9 @@ void PictureMgr::setPictureVersion(AgiPictureVersion version) {
void PictureMgr::setPictureData(uint8 *data, int len) {
_data = data;
- _flen = len;
- _foffs = 0;
+ _dataSize = len;
+ _dataOffset = 0;
+ _dataOffsetNibble = false;
_flags = 0;
}
diff --git a/engines/agi/picture.h b/engines/agi/picture.h
index 9ff1e742f4..dfc505d8d0 100644
--- a/engines/agi/picture.h
+++ b/engines/agi/picture.h
@@ -25,15 +25,15 @@
namespace Agi {
-#define _DEFAULT_WIDTH 160
-#define _DEFAULT_HEIGHT 168
+#define _DEFAULT_WIDTH 160
+#define _DEFAULT_HEIGHT 168
/**
* AGI picture resource.
*/
struct AgiPicture {
- uint32 flen; /**< size of raw data */
- uint8 *rdata; /**< raw vector image data */
+ uint32 flen; /**< size of raw data */
+ uint8 *rdata; /**< raw vector image data */
};
// AGI picture version
@@ -41,7 +41,8 @@ enum AgiPictureVersion {
AGIPIC_C64,
AGIPIC_V1,
AGIPIC_V15,
- AGIPIC_V2
+ AGIPIC_V2,
+ AGIPIC_256
};
enum AgiPictureFlags {
@@ -60,34 +61,52 @@ class PictureMgr {
AgiBase *_vm;
GfxMgr *_gfx;
-private:
+public:
+ PictureMgr(AgiBase *agi, GfxMgr *gfx);
- void drawLine(int x1, int y1, int x2, int y2);
- void dynamicDrawLine();
- void absoluteDrawLine();
- int isOkFillHere(int x, int y);
- void agiFill(unsigned int x, unsigned int y);
- void xCorner(bool skipOtherCoords = false);
+private:
+ void draw_xCorner(bool skipOtherCoords = false);
void yCorner(bool skipOtherCoords = false);
- void fill();
int plotPatternPoint(int x, int y, int bitpos);
void plotBrush();
- uint8 nextByte() { return _data[_foffs++]; }
+ byte getNextByte();
+ byte getNextNibble();
public:
- PictureMgr(AgiBase *agi, GfxMgr *gfx);
-
void putVirtPixel(int x, int y);
- int decodePicture(int n, int clear, bool agi256 = false, int pic_width = _DEFAULT_WIDTH, int pic_height = _DEFAULT_HEIGHT);
- int decodePicture(byte* data, uint32 length, int clear, int pic_width = _DEFAULT_WIDTH, int pic_height = _DEFAULT_HEIGHT);
+ int decodePicture(int16 resourceNr, bool clearScreen, bool agi256 = false, int16 pic_width = _DEFAULT_WIDTH, int16 pic_height = _DEFAULT_HEIGHT);
+ int decodePicture(byte *data, uint32 length, int clear, int pic_width = _DEFAULT_WIDTH, int pic_height = _DEFAULT_HEIGHT);
int unloadPicture(int);
void drawPicture();
- void showPic(int x = 0, int y = 0, int pic_width = _DEFAULT_WIDTH, int pic_height = _DEFAULT_HEIGHT);
+private:
+ void drawPictureC64();
+ void drawPictureV1();
+ void drawPictureV15();
+ void drawPictureV2();
+ void drawPictureAGI256();
+
+ void draw_SetColor();
+ void draw_SetPriority();
+ void draw_SetNibbleColor();
+ void draw_SetNibblePriority();
+
+ void draw_Line(int16 x1, int16 y1, int16 x2, int16 y2);
+ void draw_LineShort();
+ void draw_LineAbsolute();
+
+ int draw_FillCheck(int16 x, int16 y);
+ void draw_Fill(int16 x, int16 y);
+ void draw_Fill();
+
+public:
+ void showPic(); // <-- for regular AGI games
+ void showPic(int16 x, int16 y, int16 pic_width, int16 pic_height); // <-- for preAGI games
+ void showPicWithTransition();
uint8 *convertV3Pic(uint8 *src, uint32 len);
- void plotPattern(int x, int y); // public because it's used directly by preagi
+ void plotPattern(int x, int y); // public because it's used directly by preagi
void setPattern(uint8 code, uint8 num);
@@ -108,19 +127,12 @@ public:
_height = h;
}
- void putPixel(int x, int y, uint8 color) {
- _scrColor = color;
- _priOn = false;
- _scrOn = true;
- putVirtPixel(x, y);
- }
-
- bool isPictureLoaded() { return _data != NULL; }
-
private:
+ int16 _resourceNr;
uint8 *_data;
- uint32 _flen;
- uint32 _foffs;
+ uint32 _dataSize;
+ uint32 _dataOffset;
+ bool _dataOffsetNibble;
uint8 _patCode;
uint8 _patNum;
@@ -132,8 +144,8 @@ private:
uint8 _minCommand;
AgiPictureVersion _pictureVersion;
- int _width, _height;
- int _xOffset, _yOffset;
+ int16 _width, _height;
+ int16 _xOffset, _yOffset;
int _flags;
int _currentStep;
diff --git a/engines/agi/preagi.cpp b/engines/agi/preagi.cpp
index c368c7b195..f8630db0b6 100644
--- a/engines/agi/preagi.cpp
+++ b/engines/agi/preagi.cpp
@@ -20,15 +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"
namespace Agi {
@@ -51,47 +51,39 @@ 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() {
initRenderMode();
- _gfx = new GfxMgr(this);
+ _font = new GfxFont(this);
+ _gfx = new GfxMgr(this, _font);
_picture = new PictureMgr(this, _gfx);
- if (getGameID() == GID_MICKEY) {
- _fontData = fontData_Mickey;
- } else {
- _fontData = fontData_IBM;
- }
-
- _gfx->initMachine();
+ _font->init();
_game.gameFlags = 0;
- _game.colorFg = 15;
- _game.colorBg = 0;
+ //_game._vm->_text->charAttrib_Set(15, 0);
_defaultColor = 0xF;
_game.name[0] = '\0';
- _game.sbufOrig = (uint8 *)calloc(_WIDTH, _HEIGHT * 2); // Allocate space for two AGI screens vertically
- _game.sbuf16c = _game.sbufOrig + SBUF16_OFFSET; // Make sbuf16c point to the 16 color (+control line & priority info) AGI screen
- _game.sbuf = _game.sbuf16c; // Make sbuf point to the 16 color (+control line & priority info) AGI screen by default
-
- _game.lineMinPrint = 0; // hardcoded
+ //_game._vm->_text->configureScreen(0); // hardcoded
_gfx->initVideo();
_speakerStream = new Audio::PCSpeaker(_mixer->getOutputRate());
- _mixer->playStream(Audio::Mixer::kSFXSoundType, &_speakerHandle,
- _speakerStream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, _speakerHandle,
+ _speakerStream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
debugC(2, kDebugLevelMain, "Detect game");
// clear all resources and events
- for (int i = 0; i < MAX_DIRS; i++) {
+ for (int i = 0; i < MAX_DIRECTORY_ENTRIES; i++) {
memset(&_game.pictures[i], 0, sizeof(struct AgiPicture));
memset(&_game.sounds[i], 0, sizeof(class AgiSound *)); // _game.sounds contains pointers now
memset(&_game.dirPic[i], 0, sizeof(struct AgiDir));
@@ -100,8 +92,13 @@ void PreAgiEngine::initialize() {
}
PreAgiEngine::~PreAgiEngine() {
- _mixer->stopHandle(_speakerHandle);
+ _mixer->stopHandle(*_speakerHandle);
delete _speakerStream;
+ delete _speakerHandle;
+
+ delete _picture;
+ delete _gfx;
+ delete _font;
}
int PreAgiEngine::rnd(int hi) {
@@ -113,11 +110,11 @@ void PreAgiEngine::clearScreen(int attr, bool overrideDefault) {
if (overrideDefault)
_defaultColor = attr;
- _gfx->clearScreen((attr & 0xF0) / 0x10);
+ _gfx->clearDisplay((attr & 0xF0) / 0x10);
}
void PreAgiEngine::clearGfxScreen(int attr) {
- _gfx->drawRectangle(0, 0, GFX_WIDTH - 1, IDI_MAX_ROW_PIC * 8 -1, (attr & 0xF0) / 0x10);
+ _gfx->drawDisplayRect(0, 0, DISPLAY_DEFAULT_WIDTH - 1, IDI_MAX_ROW_PIC * 8 - 1, (attr & 0xF0) / 0x10);
}
// String functions
@@ -143,7 +140,7 @@ void PreAgiEngine::drawStr(int row, int col, int attr, const char *buffer) {
break;
default:
- _gfx->putTextCharacter(1, col * 8 , row * 8, static_cast<char>(code), attr & 0x0f, (attr & 0xf0) / 0x10, false, _fontData);
+ _gfx->drawCharacter(row, col, code, attr & 0x0f, attr >> 4, false);
if (++col == 320 / 8) {
col = 0;
@@ -154,7 +151,7 @@ void PreAgiEngine::drawStr(int row, int col, int attr, const char *buffer) {
}
void PreAgiEngine::drawStrMiddle(int row, int attr, const char *buffer) {
- int col = (25 / 2) - (strlen(buffer) / 2); // 25 = 320 / 8 (maximum column)
+ int col = (25 / 2) - (strlen(buffer) / 2); // 25 = 320 / 8 (maximum column)
drawStr(row, col, attr, buffer);
}
@@ -170,13 +167,13 @@ void PreAgiEngine::clearTextArea() {
}
void PreAgiEngine::clearRow(int row) {
- drawStr(row, 0, IDA_DEFAULT, " "); // 40 spaces
+ drawStr(row, 0, IDA_DEFAULT, " "); // 40 spaces
}
-void PreAgiEngine::printStr(const char* szMsg) {
+void PreAgiEngine::printStr(const char *szMsg) {
clearTextArea();
drawStr(21, 0, IDA_DEFAULT, szMsg);
- _gfx->doUpdate();
+ g_system->updateScreen();
}
void PreAgiEngine::XOR80(char *buffer) {
@@ -274,7 +271,7 @@ void PreAgiEngine::waitForTimer(int msec_delay) {
uint32 start_time = _system->getMillis();
while (_system->getMillis() < start_time + msec_delay) {
- _gfx->doUpdate();
+ g_system->updateScreen();
_system->delayMillis(10);
}
}
diff --git a/engines/agi/preagi.h b/engines/agi/preagi.h
index c2962b09b3..6950aa30cd 100644
--- a/engines/agi/preagi.h
+++ b/engines/agi/preagi.h
@@ -25,20 +25,23 @@
#include "agi/agi.h"
-#include "audio/softsynth/pcspk.h"
+namespace Audio {
+class SoundHandle;
+class PCSpeaker;
+}
namespace Agi {
// default attributes
-#define IDA_DEFAULT 0x0F
-#define IDA_DEFAULT_REV 0xF0
+#define IDA_DEFAULT 0x0F
+#define IDA_DEFAULT_REV 0xF0
-#define IDI_SND_OSCILLATOR_FREQUENCY 1193180
-#define IDI_SND_TIMER_RESOLUTION 0.0182
+#define IDI_SND_OSCILLATOR_FREQUENCY 1193180
+#define IDI_SND_TIMER_RESOLUTION 0.0182
#define kColorDefault 0x1337
-#define IDI_MAX_ROW_PIC 20
+#define IDI_MAX_ROW_PIC 20
enum SelectionTypes {
kSelYesNo,
@@ -69,9 +72,9 @@ protected:
void clearImageStack() {}
void recordImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3,
- int16 p4, int16 p5, int16 p6, int16 p7) {}
+ int16 p4, int16 p5, int16 p6, int16 p7) {}
void replayImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3,
- int16 p4, int16 p5, int16 p6, int16 p7) {}
+ int16 p4, int16 p5, int16 p6, int16 p7) {}
void releaseImageStack() {}
int saveGame(const Common::String &fileName, const Common::String &saveName) { return -1; }
int loadGame(const Common::String &fileName, bool checkId = true) { return -1; }
@@ -99,7 +102,7 @@ protected:
void printStrXOR(char *szMsg);
// Saved Games
- Common::SaveFileManager* getSaveFileMan() { return _saveFileMan; }
+ Common::SaveFileManager *getSaveFileMan() { return _saveFileMan; }
void playNote(int16 frequency, int32 length);
void waitForTimer(int msec_delay);
@@ -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 883107a957..0584aab683 100644
--- a/engines/agi/preagi_mickey.cpp
+++ b/engines/agi/preagi_mickey.cpp
@@ -90,7 +90,7 @@ void MickeyEngine::readOfsData(int offset, int iItem, uint8 *buffer, long buflen
memcpy(ofs, buffer, sizeof(ofs));
for (int i = 0; i < 256; i++)
- ofs[i] = buffer[i*2] + 256 * buffer[i*2+1];
+ ofs[i] = buffer[i * 2] + 256 * buffer[i * 2 + 1];
readExe(ofs[iItem] + IDI_MSA_OFS_EXE, buffer, buflen);
}
@@ -102,8 +102,10 @@ bool MickeyEngine::chooseY_N(int ofsPrompt, bool fErrorMsg) {
while (!shouldQuit()) {
switch (getSelection(kSelYesNo)) {
- case 0: return false;
- case 1: return true;
+ case 0:
+ return false;
+ case 1:
+ return true;
default:
if (fErrorMsg) {
printExeStr(IDO_MSA_PRESS_YES_OR_NO);
@@ -149,7 +151,7 @@ void MickeyEngine::printStr(char *buffer) {
}
// Show the string on screen
- _gfx->doUpdate();
+ _gfx->updateScreen();
}
void MickeyEngine::printLine(const char *buffer) {
@@ -158,7 +160,7 @@ void MickeyEngine::printLine(const char *buffer) {
drawStr(22, 18 - strlen(buffer) / 2, IDA_DEFAULT, buffer);
// Show the string on screen
- _gfx->doUpdate();
+ _gfx->updateScreen();
waitAnyKey(true);
}
@@ -253,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;
@@ -276,15 +278,15 @@ void MickeyEngine::drawMenu(MSA_MENU menu, int sel0, int sel1) {
attr = IDA_DEFAULT;
drawStr(IDI_MSA_ROW_MENU_0 + iRow, menu.row[iRow].entry[iWord].x0,
- attr, (char *)menu.row[iRow].entry[iWord].szText);
+ attr, (char *)menu.row[iRow].entry[iWord].szText);
}
}
// Menu created, show it on screen
- _gfx->doUpdate();
+ _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;
@@ -303,15 +305,15 @@ void MickeyEngine::getMouseMenuSelRow(MSA_MENU menu, int *sel0, int *sel1, int i
for (iWord = 0; iWord < menu.row[iRow].count; iWord++) {
if ((x >= menu.row[iRow].entry[iWord].x0) &&
- (x < (int)(menu.row[iRow].entry[iWord].x0 +
- strlen((char *)menu.row[iRow].entry[iWord].szText)))) {
- *sel = iWord;
- break;
+ (x < (int)(menu.row[iRow].entry[iWord].x0 +
+ strlen((char *)menu.row[iRow].entry[iWord].szText)))) {
+ *sel = iWord;
+ break;
}
}
}
-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;
@@ -330,24 +332,24 @@ bool MickeyEngine::getMenuSelRow(MSA_MENU menu, int *sel0, int *sel1, int iRow)
_clickToMove = false;
for (int i = 0; i <= menu.row[0].count; i++)
- if (menu.row[0].entry[i].szText[0] == 71 && menu.row[0].entry[i].szText[1] == 79) // GO
+ if (menu.row[0].entry[i].szText[0] == 71 && menu.row[0].entry[i].szText[1] == 79) // GO
goIndex = i;
if (goIndex >= 0) {
for (int j = 0; j <= menu.row[1].count; j++) {
if (menu.row[1].entry[j].szText[0] == 78 && menu.row[1].entry[j].szText[1] == 79 &&
- menu.row[1].entry[j].szText[2] == 82 && menu.row[1].entry[j].szText[3] == 84 &&
- menu.row[1].entry[j].szText[4] == 72)
+ menu.row[1].entry[j].szText[2] == 82 && menu.row[1].entry[j].szText[3] == 84 &&
+ menu.row[1].entry[j].szText[4] == 72)
northIndex = j;
if (menu.row[1].entry[j].szText[0] == 83 && menu.row[1].entry[j].szText[1] == 79 &&
- menu.row[1].entry[j].szText[2] == 85 && menu.row[1].entry[j].szText[3] == 84 &&
- menu.row[1].entry[j].szText[4] == 72)
+ menu.row[1].entry[j].szText[2] == 85 && menu.row[1].entry[j].szText[3] == 84 &&
+ menu.row[1].entry[j].szText[4] == 72)
southIndex = j;
if (menu.row[1].entry[j].szText[0] == 69 && menu.row[1].entry[j].szText[1] == 65 &&
- menu.row[1].entry[j].szText[2] == 83 && menu.row[1].entry[j].szText[3] == 84)
+ menu.row[1].entry[j].szText[2] == 83 && menu.row[1].entry[j].szText[3] == 84)
eastIndex = j;
if (menu.row[1].entry[j].szText[0] == 87 && menu.row[1].entry[j].szText[1] == 69 &&
- menu.row[1].entry[j].szText[2] == 83 && menu.row[1].entry[j].szText[3] == 84)
+ menu.row[1].entry[j].szText[2] == 83 && menu.row[1].entry[j].szText[3] == 84)
westIndex = j;
}
}
@@ -372,62 +374,68 @@ bool MickeyEngine::getMenuSelRow(MSA_MENU menu, int *sel0, int *sel1, int iRow)
// Change cursor
if (northIndex >= 0 && (event.mouse.x >= 20 && event.mouse.x <= (IDI_MSA_PIC_WIDTH + 10) * 2) &&
- (event.mouse.y >= 0 && event.mouse.y <= 10)) {
- _gfx->setCursorPalette(true);
+ (event.mouse.y >= 0 && event.mouse.y <= 10)) {
+ //_gfx->setCursorPalette(true);
+ // TODO:?????
} else if (southIndex >= 0 && (event.mouse.x >= 20 && event.mouse.x <= (IDI_MSA_PIC_WIDTH + 10) * 2) &&
- (event.mouse.y >= IDI_MSA_PIC_HEIGHT - 10 && event.mouse.y <= IDI_MSA_PIC_HEIGHT)) {
- _gfx->setCursorPalette(true);
+ (event.mouse.y >= IDI_MSA_PIC_HEIGHT - 10 && event.mouse.y <= IDI_MSA_PIC_HEIGHT)) {
+ //_gfx->setCursorPalette(true);
} else if (westIndex >= 0 && (event.mouse.y >= 0 && event.mouse.y <= IDI_MSA_PIC_HEIGHT) &&
- (event.mouse.x >= 20 && event.mouse.x <= 30)) {
- _gfx->setCursorPalette(true);
+ (event.mouse.x >= 20 && event.mouse.x <= 30)) {
+ //_gfx->setCursorPalette(true);
} else if (eastIndex >= 0 && (event.mouse.y >= 0 && event.mouse.y <= IDI_MSA_PIC_HEIGHT) &&
- (event.mouse.x >= IDI_MSA_PIC_WIDTH * 2 && event.mouse.x <= (IDI_MSA_PIC_WIDTH + 10) * 2)) {
- _gfx->setCursorPalette(true);
+ (event.mouse.x >= IDI_MSA_PIC_WIDTH * 2 && event.mouse.x <= (IDI_MSA_PIC_WIDTH + 10) * 2)) {
+ //_gfx->setCursorPalette(true);
} else {
- _gfx->setCursorPalette(false);
+ //_gfx->setCursorPalette(false);
}
}
break;
case Common::EVENT_LBUTTONUP:
// Click to move
if (northIndex >= 0 && (event.mouse.x >= 20 && event.mouse.x <= (IDI_MSA_PIC_WIDTH + 10) * 2) &&
- (event.mouse.y >= 0 && event.mouse.y <= 10)) {
+ (event.mouse.y >= 0 && event.mouse.y <= 10)) {
*sel0 = goIndex;
*sel1 = northIndex;
drawMenu(menu, *sel0, *sel1);
- _gfx->setCursorPalette(false);
+ //_gfx->setCursorPalette(false);
+ // TODO???
_clickToMove = true;
} else if (southIndex >= 0 && (event.mouse.x >= 20 && event.mouse.x <= (IDI_MSA_PIC_WIDTH + 10) * 2) &&
- (event.mouse.y >= IDI_MSA_PIC_HEIGHT - 10 && event.mouse.y <= IDI_MSA_PIC_HEIGHT)) {
+ (event.mouse.y >= IDI_MSA_PIC_HEIGHT - 10 && event.mouse.y <= IDI_MSA_PIC_HEIGHT)) {
*sel0 = goIndex;
*sel1 = southIndex;
drawMenu(menu, *sel0, *sel1);
- _gfx->setCursorPalette(false);
+ //_gfx->setCursorPalette(false);
+ // TODO???
_clickToMove = true;
} else if (westIndex >= 0 && (event.mouse.y >= 0 && event.mouse.y <= IDI_MSA_PIC_HEIGHT) &&
- (event.mouse.x >= 20 && event.mouse.x <= 30)) {
+ (event.mouse.x >= 20 && event.mouse.x <= 30)) {
*sel0 = goIndex;
*sel1 = westIndex;
drawMenu(menu, *sel0, *sel1);
- _gfx->setCursorPalette(false);
+ //_gfx->setCursorPalette(false);
+ // TODO???
_clickToMove = true;
} else if (eastIndex >= 0 && (event.mouse.y >= 0 && event.mouse.y <= IDI_MSA_PIC_HEIGHT) &&
- (event.mouse.x >= IDI_MSA_PIC_WIDTH * 2 && event.mouse.x <= (IDI_MSA_PIC_WIDTH + 10) * 2)) {
+ (event.mouse.x >= IDI_MSA_PIC_WIDTH * 2 && event.mouse.x <= (IDI_MSA_PIC_WIDTH + 10) * 2)) {
*sel0 = goIndex;
*sel1 = eastIndex;
drawMenu(menu, *sel0, *sel1);
- _gfx->setCursorPalette(false);
+ //_gfx->setCursorPalette(false);
+ // TODO???
_clickToMove = true;
} else {
- _gfx->setCursorPalette(false);
+ //_gfx->setCursorPalette(false);
+ // TODO???
}
return true;
case Common::EVENT_RBUTTONUP:
@@ -486,7 +494,7 @@ bool MickeyEngine::getMenuSelRow(MSA_MENU menu, int *sel0, int *sel1, int iRow)
return false;
case Common::KEYCODE_s:
- flipflag(fSoundOn);
+ flipFlag(VM_FLAG_SOUND_ON);
break;
case Common::KEYCODE_c:
inventory();
@@ -594,7 +602,7 @@ void MickeyEngine::centerMenu(MSA_MENU *menu) {
w += strlen((char *)menu->row[iRow].entry[iWord].szText);
}
w += menu->row[iRow].count - 1;
- x = (40 - w) / 2; // FIX
+ x = (40 - w) / 2; // FIX
for (iWord = 0; iWord < menu->row[iRow].count; iWord++) {
menu->row[iRow].entry[iWord].x0 = x;
@@ -625,9 +633,9 @@ void MickeyEngine::patchMenu(MSA_MENU *menu) {
// read patches
readOfsData(
- IDOFS_MSA_MENU_PATCHES,
- _gameStateMickey.nRmMenu[_gameStateMickey.iRoom] + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] - 1,
- buffer, sizeof(buffer)
+ IDOFS_MSA_MENU_PATCHES,
+ _gameStateMickey.nRmMenu[_gameStateMickey.iRoom] + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] - 1,
+ buffer, sizeof(buffer)
);
// get number of patches
@@ -659,14 +667,14 @@ void MickeyEngine::printDatMessage(int iStr) {
void MickeyEngine::playNote(MSA_SND_NOTE note) {
if (!note.counter) {
// Pause
- _system->delayMillis((uint) (note.length / IDI_SND_TIMER_RESOLUTION));
+ _system->delayMillis((uint)(note.length / IDI_SND_TIMER_RESOLUTION));
} else {
- PreAgiEngine::playNote(IDI_SND_OSCILLATOR_FREQUENCY / note.counter, (int32) (note.length / IDI_SND_TIMER_RESOLUTION));
+ PreAgiEngine::playNote(IDI_SND_OSCILLATOR_FREQUENCY / note.counter, (int32)(note.length / IDI_SND_TIMER_RESOLUTION));
}
}
void MickeyEngine::playSound(ENUM_MSA_SOUND iSound) {
- if (!getflag(fSoundOn))
+ if (!getFlag(VM_FLAG_SOUND_ON))
return;
Common::Event event;
@@ -727,7 +735,7 @@ void MickeyEngine::drawObj(ENUM_MSA_OBJECT iObj, int x0, int y0) {
if (!file.open(szFile))
return;
- uint8* buffer = new uint8[4096];
+ uint8 *buffer = new uint8[4096];
uint32 size = file.size();
file.read(buffer, size);
file.close();
@@ -749,13 +757,15 @@ void MickeyEngine::drawPic(int iPic) {
if (!file.open(szFile))
return;
- uint8* buffer = new uint8[4096];
+ uint8 *buffer = new uint8[4096];
uint32 size = file.size();
file.read(buffer, size);
file.close();
// Note that decodePicture clears the screen
+ _picture->setOffset(10, 0);
_picture->decodePicture(buffer, size, true, IDI_MSA_PIC_WIDTH, IDI_MSA_PIC_HEIGHT);
+ _picture->setOffset(0, 0);
_picture->showPic(10, 0, IDI_MSA_PIC_WIDTH, IDI_MSA_PIC_HEIGHT);
}
@@ -781,36 +791,35 @@ void MickeyEngine::drawRoomAnimation() {
case IDI_MSA_PIC_SHIP_PLUTO:
case IDI_MSA_PIC_SHIP_JUPITER:
case IDI_MSA_PIC_SHIP_MARS:
- case IDI_MSA_PIC_SHIP_URANUS:
- {
- // draw blinking ship lights
+ case IDI_MSA_PIC_SHIP_URANUS: {
+ // draw blinking ship lights
- uint8 iColor = 0;
+ uint8 iColor = 0;
- _picture->setPattern(2, 0);
+ _picture->setPattern(2, 0);
- for (int i = 0; i < 12; i++) {
- iColor = _gameStateMickey.nFrame + i;
- if (iColor > 15)
- iColor -= 15;
+ for (int i = 0; i < 12; i++) {
+ iColor = _gameStateMickey.nFrame + i;
+ if (iColor > 15)
+ iColor -= 15;
- objLight[1] = iColor;
- objLight[4] += 7;
+ objLight[1] = iColor;
+ objLight[4] += 7;
- _picture->setPictureData(objLight);
- _picture->setPictureFlags(kPicFCircle);
- _picture->drawPicture();
- }
- _picture->showPic(10, 0, IDI_MSA_PIC_WIDTH, IDI_MSA_PIC_HEIGHT);
+ _picture->setPictureData(objLight);
+ _picture->setPictureFlags(kPicFCircle);
+ _picture->drawPicture();
+ }
+ _picture->showPic(10, 0, IDI_MSA_PIC_WIDTH, IDI_MSA_PIC_HEIGHT);
- _gameStateMickey.nFrame--;
- if (_gameStateMickey.nFrame < 0)
- _gameStateMickey.nFrame = 15;
+ _gameStateMickey.nFrame--;
+ if (_gameStateMickey.nFrame < 0)
+ _gameStateMickey.nFrame = 15;
- playSound(IDI_MSA_SND_PRESS_BLUE);
- }
- break;
+ playSound(IDI_MSA_SND_PRESS_BLUE);
+ }
+ break;
case IDI_MSA_PIC_SHIP_CONTROLS:
@@ -836,9 +845,9 @@ void MickeyEngine::drawRoomAnimation() {
break;
default:
drawObj(
- IDI_MSA_OBJECT_CRYSTAL,
- IDI_MSA_XTAL_ROOM_XY[_gameStateMickey.iPlanet][1],
- IDI_MSA_XTAL_ROOM_XY[_gameStateMickey.iPlanet][2]
+ IDI_MSA_OBJECT_CRYSTAL,
+ IDI_MSA_XTAL_ROOM_XY[_gameStateMickey.iPlanet][1],
+ IDI_MSA_XTAL_ROOM_XY[_gameStateMickey.iPlanet][2]
);
break;
}
@@ -878,7 +887,7 @@ void MickeyEngine::drawRoom() {
if (_gameStateMickey.iRmObj[_gameStateMickey.iRoom] != IDI_MSA_OBJECT_NONE) {
readOfsData(IDO_MSA_ROOM_OBJECT_XY_OFFSETS,
- _gameStateMickey.iRmObj[_gameStateMickey.iRoom], buffer, sizeof(buffer));
+ _gameStateMickey.iRmObj[_gameStateMickey.iRoom], buffer, sizeof(buffer));
nObjs = buffer[pBuf++];
@@ -892,75 +901,65 @@ void MickeyEngine::drawRoom() {
drawRoomAnimation();
}
-#if 0
-const uint8 colorBCG[16][2] = {
- { 0x00, 0x00 }, // 0 (black, black)
- { 0, 0 },
- { 0x00, 0x0D }, // 2 (black, purple)
- { 0x00, 0xFF }, // 3 (black, white)
- { 0, 0 },
- { 0, 0 },
- { 0, 0 },
- { 0, 0 },
- { 0x0D, 0x00 }, // 8 (purple, black)
- { 0, 0 },
- { 0x0D, 0x0D }, // A (purple, purple)
- { 0, 0 },
- { 0xFF, 0x00 }, // C (white, black)
- { 0, 0 },
- { 0, 0 },
- { 0xFF, 0xFF } // F (white, white)
+// Straight mapping, CGA colors to CGA
+const byte BCGColorMappingCGAToCGA[4] = {
+ 0, 1, 2, 3
+};
+
+// Mapping table to map CGA colors to EGA
+const byte BCGColorMappingCGAToEGA[4] = {
+ 0, 11, 13, 15
};
-#endif
void MickeyEngine::drawLogo() {
- // TODO: clean this up and make it work properly, the logo is drawn way off to the right
-#if 0
- char szFile[256] = {0};
- uint8 *buffer = new uint8[16384];
- const int w = 150;
- const int h = 80;
- const int xoffset = 30; // FIXME: remove this
- uint8 bitmap[w][h];
- uint8 color, color2, color3, color4;
-
- // read in logos.bcg
- sprintf(szFile, IDS_MSA_PATH_LOGO);
+ const int width = 80;
+ const int height = 85 * 2;
+ byte color1, color2, color3, color4;
+ byte *fileBuffer = nullptr;
+ uint32 fileBufferSize = 0;
+ byte *dataBuffer;
+ byte curByte;
+ const byte *BCGColorMapping = BCGColorMappingCGAToEGA;
+
+ // disable color mapping in case we are in CGA mode
+ if (_renderMode == Common::kRenderCGA)
+ BCGColorMapping = BCGColorMappingCGAToCGA;
+
+ // read logos.bcg
Common::File infile;
- if (!infile.open(szFile))
+ if (!infile.open(IDS_MSA_PATH_LOGO))
return;
- infile.read(buffer, infile.size());
+ fileBufferSize = infile.size();
+ fileBuffer = new byte[fileBufferSize];
+ infile.read(fileBuffer, fileBufferSize);
infile.close();
- // draw logo bitmap
- memcpy(bitmap, buffer, sizeof(bitmap));
-
- _picture->setDimensions(w, h);
+ if (fileBufferSize < (width * height / 4))
+ error("logos.bcg: unexpected end of file");
// Show BCG picture
- for (int y = 0; y < h; y++) {
- for (int x = xoffset; x < w; x++) {
- color = colorBCG[(bitmap[y][x] & 0xf0) / 0x10][0]; // background
- color2 = colorBCG[(bitmap[y][x] & 0xf0) / 0x10][1]; // background
- color3 = colorBCG[ bitmap[y][x] & 0x0f][0]; // foreground
- color4 = colorBCG[ bitmap[y][x] & 0x0f][1]; // foreground
-
- _picture->putPixel(x * 4 - xoffset, y, color);
- _picture->putPixel(x * 4 + 1 - xoffset, y, color2);
- _picture->putPixel(x * 4 + 2 - xoffset, y, color3);
- _picture->putPixel(x * 4 + 3 - xoffset, y, color4);
- _picture->putPixel(x * 4 - xoffset, y + 1, color);
- _picture->putPixel(x * 4 + 1 - xoffset, y + 1, color2);
- _picture->putPixel(x * 4 + 2 - xoffset, y + 1, color3);
- _picture->putPixel(x * 4 + 3 - xoffset, y + 1, color4);
+ // It's basically uncompressed CGA 4-color data (4 pixels per byte)
+ dataBuffer = fileBuffer;
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ curByte = *dataBuffer++;
+
+ color1 = BCGColorMapping[(curByte >> 6) & 0x03];
+ color2 = BCGColorMapping[(curByte >> 4) & 0x03];
+ color3 = BCGColorMapping[(curByte >> 2) & 0x03];
+ color4 = BCGColorMapping[(curByte >> 0) & 0x03];
+
+ _gfx->putPixelOnDisplay(x * 4 + 0, y, color1);
+ _gfx->putPixelOnDisplay(x * 4 + 1, y, color2);
+ _gfx->putPixelOnDisplay(x * 4 + 2, y, color3);
+ _gfx->putPixelOnDisplay(x * 4 + 3, y, color4);
}
}
- _picture->showPic(10, 10, w, h);
+ _gfx->copyDisplayToScreen();
- delete[] buffer;
-#endif
+ delete[] fileBuffer;
}
void MickeyEngine::animate() {
@@ -1000,7 +999,7 @@ bool MickeyEngine::loadGame() {
if (getSelection(kSelAnyKey) == 0)
return false;
} else {
- if (infile->readUint32BE() != MKTAG('M','I','C','K')) {
+ if (infile->readUint32BE() != MKTAG('M', 'I', 'C', 'K')) {
warning("MickeyEngine::loadGame wrong save game format");
return false;
}
@@ -1080,7 +1079,7 @@ bool MickeyEngine::loadGame() {
}
void MickeyEngine::saveGame() {
- Common::OutSaveFile* outfile;
+ Common::OutSaveFile *outfile;
char szFile[256] = {0};
bool diskerror = true;
int sel;
@@ -1117,7 +1116,7 @@ void MickeyEngine::saveGame() {
if (getSelection(kSelAnyKey) == 0)
return;
} else {
- outfile->writeUint32BE(MKTAG('M','I','C','K')); // header
+ outfile->writeUint32BE(MKTAG('M', 'I', 'C', 'K')); // header
outfile->writeByte(MSA_SAVEGAME_VERSION);
outfile->writeByte(_gameStateMickey.iRoom);
@@ -1206,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;
}
@@ -1214,15 +1213,15 @@ 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;
}
waitAnyKey();
//Set back to black
- _gfx->clearScreen(0);
- _gfx->doUpdate();
+ _gfx->clearDisplay(0);
+ _gfx->updateScreen();
drawRoom();
@@ -1319,11 +1318,11 @@ void MickeyEngine::flipSwitch() {
iPlanet = rnd(IDI_MSA_MAX_PLANET - 2);
} while (planetIsAlreadyAssigned(iPlanet));
} else {
- iPlanet = IDI_MSA_PLANET_URANUS; // Uranus is always last
+ iPlanet = IDI_MSA_PLANET_URANUS; // Uranus is always last
}
_gameStateMickey.iPlanetXtal[i] = iPlanet;
- iHint = rnd(5) - 1; // clues are 0-4
+ iHint = rnd(5) - 1; // clues are 0-4
_gameStateMickey.iClue[i] = IDO_MSA_NEXT_PIECE[iPlanet][iHint];
}
@@ -1399,8 +1398,8 @@ void MickeyEngine::inventory() {
void MickeyEngine::intro() {
// Draw Sierra logo
- //drawLogo(); // Original does not even show this, so we skip it too
- //waitAnyKey(); // Not in the original, but needed so that the logo is visible
+ drawLogo(); // Original does not even show this, so we skip it too
+ waitAnyKey(); // Not in the original, but needed so that the logo is visible
// draw title picture
_gameStateMickey.iRoom = IDI_MSA_PIC_TITLE;
@@ -1448,14 +1447,14 @@ void MickeyEngine::intro() {
playSound(IDI_MSA_SND_PRESS_BLUE);
//Set screen to white
- _gfx->clearScreen(15);
- _gfx->doUpdate();
+ _gfx->clearDisplay(15);
+ _gfx->updateScreen();
_system->delayMillis(IDI_MSA_ANIM_DELAY);
//Set back to black
- _gfx->clearScreen(0);
- _gfx->doUpdate();
+ _gfx->clearDisplay(0);
+ _gfx->updateScreen();
drawRoom();
printDesc(_gameStateMickey.iRoom);
@@ -2032,7 +2031,7 @@ bool MickeyEngine::parse(int cmd, int arg) {
}
break;
case IDI_MSA_ACTION_PRESS_BUTTON:
- if (_gameStateMickey.fShipDoorOpen) { // inner door open
+ if (_gameStateMickey.fShipDoorOpen) { // inner door open
if (_gameStateMickey.iPlanet && !_gameStateMickey.fSuit) {
printDatMessage(arg);
} else {
@@ -2120,7 +2119,7 @@ bool MickeyEngine::parse(int cmd, int arg) {
printDatString(22);
drawStr(IDI_MSA_ROW_PLANET, IDI_MSA_COL_PLANET, IDA_DEFAULT,
- (const char *)IDS_MSA_PLANETS[_gameStateMickey.iPlanet]);
+ (const char *)IDS_MSA_PLANETS[_gameStateMickey.iPlanet]);
waitAnyKey(true);
@@ -2201,7 +2200,7 @@ void MickeyEngine::waitAnyKey(bool anim) {
Common::Event event;
if (!anim)
- _gfx->doUpdate();
+ _gfx->updateScreen();
while (!shouldQuit()) {
while (_system->getEventManager()->pollEvent(event)) {
@@ -2219,10 +2218,9 @@ void MickeyEngine::waitAnyKey(bool anim) {
if (anim) {
animate();
- _gfx->doUpdate();
}
- _system->updateScreen();
+ _gfx->updateScreen();
_system->delayMillis(10);
}
}
@@ -2264,7 +2262,7 @@ void MickeyEngine::init() {
readExe(IDO_MSA_ROOM_TEXT_OFFSETS, buffer, sizeof(buffer));
memcpy(_gameStateMickey.oRmTxt, buffer, sizeof(_gameStateMickey.oRmTxt));
for (int i = 0; i < IDI_MSA_MAX_ROOM; i++)
- _gameStateMickey.oRmTxt[i] = buffer[i*2] + 256 * buffer[i*2+1];
+ _gameStateMickey.oRmTxt[i] = buffer[i * 2] + 256 * buffer[i * 2 + 1];
// read room object indices
//readExe(IDO_MSA_ROOM_OBJECT, buffer, sizeof(buffer));
@@ -2300,7 +2298,7 @@ void MickeyEngine::init() {
#endif
- setflag(fSoundOn, true); // enable sound
+ setFlag(VM_FLAG_SOUND_ON, true); // enable sound
}
Common::Error MickeyEngine::go() {
@@ -2341,7 +2339,7 @@ Common::Error MickeyEngine::go() {
}
}
} else {
- _gameStateMickey.nAir = 50; // max air supply
+ _gameStateMickey.nAir = 50; // max air supply
}
done = checkMenu();
diff --git a/engines/agi/preagi_mickey.h b/engines/agi/preagi_mickey.h
index 55b3633c8c..066880d324 100644
--- a/engines/agi/preagi_mickey.h
+++ b/engines/agi/preagi_mickey.h
@@ -25,16 +25,16 @@
namespace Agi {
-#define MSA_SAVEGAME_VERSION 2
+#define MSA_SAVEGAME_VERSION 2
// strings
-#define IDS_MSA_PATH_DAT "dat/%s"
-#define IDS_MSA_PATH_OBJ "obj/%s.ooo"
-#define IDS_MSA_PATH_PIC "%d.pic"
-#define IDS_MSA_PATH_LOGO "logos.bcg"
+#define IDS_MSA_PATH_DAT "dat/%s"
+#define IDS_MSA_PATH_OBJ "obj/%s.ooo"
+#define IDS_MSA_PATH_PIC "%d.pic"
+#define IDS_MSA_PATH_LOGO "logos.bcg"
-#define IDS_MSA_INVENTORY "MICKEY IS CARRYING THE FOLLOWING:"
-#define IDS_MSA_CRYSTALS "%s CRYSTALS"
+#define IDS_MSA_INVENTORY "MICKEY IS CARRYING THE FOLLOWING:"
+#define IDS_MSA_CRYSTALS "%s CRYSTALS"
const char IDS_MSA_CRYSTAL_NO[][3] = {
"NO", " 1", " 2", " 3", " 4", " 5", " 6", " 7", " 8", " 9"
@@ -68,221 +68,221 @@ const char IDS_MSA_INSERT_DISK[][40] = {
// max values
-#define IDI_MSA_MAX_PLANET 9
-#define IDI_MSA_MAX_DAT 10
-#define IDI_MSA_MAX_PIC_ROOM 224
-#define IDI_MSA_MAX_ROOM 160
+#define IDI_MSA_MAX_PLANET 9
+#define IDI_MSA_MAX_DAT 10
+#define IDI_MSA_MAX_PIC_ROOM 224
+#define IDI_MSA_MAX_ROOM 160
-#define IDI_MSA_MAX_BUTTON 6
-#define IDI_MSA_MAX_ITEM 11
+#define IDI_MSA_MAX_BUTTON 6
+#define IDI_MSA_MAX_ITEM 11
-#define IDI_MSA_ANIM_DELAY 25
+#define IDI_MSA_ANIM_DELAY 25
-#define IDI_MSA_LEN_STORY 1372
+#define IDI_MSA_LEN_STORY 1372
// rows
-#define IDI_MSA_ROW_MENU_0 20
-#define IDI_MSA_ROW_MENU_1 21
-#define IDI_MSA_ROW_INV_TITLE 2
-#define IDI_MSA_ROW_INV_CRYSTALS 4
-#define IDI_MSA_ROW_INV_ITEMS 5
-#define IDI_MSA_ROW_TEMPERATURE 21
-#define IDI_MSA_ROW_PLANET 22
-#define IDI_MSA_ROW_INSERT_DISK 23
+#define IDI_MSA_ROW_MENU_0 20
+#define IDI_MSA_ROW_MENU_1 21
+#define IDI_MSA_ROW_INV_TITLE 2
+#define IDI_MSA_ROW_INV_CRYSTALS 4
+#define IDI_MSA_ROW_INV_ITEMS 5
+#define IDI_MSA_ROW_TEMPERATURE 21
+#define IDI_MSA_ROW_PLANET 22
+#define IDI_MSA_ROW_INSERT_DISK 23
-#define IDI_MSA_COL_INV_TITLE 4
-#define IDI_MSA_COL_INV_ITEMS 15
-#define IDI_MSA_COL_PLANET 28
-#define IDI_MSA_COL_INSERT_DISK 1
+#define IDI_MSA_COL_INV_TITLE 4
+#define IDI_MSA_COL_INV_ITEMS 15
+#define IDI_MSA_COL_PLANET 28
+#define IDI_MSA_COL_INSERT_DISK 1
// screen
-#define IDI_MSA_PIC_WIDTH 140
-#define IDI_MSA_PIC_HEIGHT 159
+#define IDI_MSA_PIC_WIDTH 140
+#define IDI_MSA_PIC_HEIGHT 159
// pictures
-#define IDI_MSA_PIC_EARTH_TIRE_SWING 1
-#define IDI_MSA_PIC_EARTH_TIRE_SWING_1 200 // rope taken, swing on ground
-#define IDI_MSA_PIC_EARTH_DOGHOUSE 2
-#define IDI_MSA_PIC_EARTH_IN_DOGHOUSE 154
-#define IDI_MSA_PIC_EARTH_TREE 3
-#define IDI_MSA_PIC_EARTH_GARDEN 4
-#define IDI_MSA_PIC_EARTH_FRONT_HOUSE 5
-#define IDI_MSA_PIC_EARTH_HAMMOCK 6
-#define IDI_MSA_PIC_EARTH_BUTTERFLY 7
-#define IDI_MSA_PIC_EARTH_MAILBOX 8
-#define IDI_MSA_PIC_EARTH_ROAD_0 9
-#define IDI_MSA_PIC_EARTH_ROAD_1 10
-#define IDI_MSA_PIC_EARTH_ROAD_2 11
-#define IDI_MSA_PIC_EARTH_ROAD_3 12
-#define IDI_MSA_PIC_EARTH_ROAD_4 13 // starting room
-#define IDI_MSA_PIC_EARTH_ROAD_5 14
-#define IDI_MSA_PIC_EARTH_ROAD_6 15
-#define IDI_MSA_PIC_EARTH_ROAD_7 18
-#define IDI_MSA_PIC_EARTH_UNDER_TREE 16
-#define IDI_MSA_PIC_EARTH_UP_IN_TREE 155 // CRYSTAL
-#define IDI_MSA_PIC_EARTH_SHIP 17
-#define IDI_MSA_PIC_EARTH_LIVING_ROOM 19
-#define IDI_MSA_PIC_EARTH_KITCHEN 20
-#define IDI_MSA_PIC_EARTH_KITCHEN_1 159 // cupboard open
-#define IDI_MSA_PIC_EARTH_GARAGE 21
-#define IDI_MSA_PIC_EARTH_GARAGE_1 160 // cabinet open
-#define IDI_MSA_PIC_EARTH_BEDROOM 22
-#define IDI_MSA_PIC_EARTH_BEDROOM_1 161 // closet open
-#define IDI_MSA_PIC_EARTH_BATHROOM 23 // WEIGH MICKEY
-#define IDI_MSA_PIC_EARTH_SHIP_LEAVING 24
-#define IDI_MSA_PIC_EARTH_MINNIE 25
-
-#define IDI_MSA_PIC_SHIP_AIRLOCK 25
-#define IDI_MSA_PIC_SHIP_AIRLOCK_0 201 // door closed
-#define IDI_MSA_PIC_SHIP_AIRLOCK_1 202 // door open
-#define IDI_MSA_PIC_SHIP_AIRLOCK_2 203 // door closed, spacesuits on
-#define IDI_MSA_PIC_SHIP_AIRLOCK_3 204 // door open, spacesuits on
-#define IDI_MSA_PIC_SHIP_BEDROOM 29
-#define IDI_MSA_PIC_SHIP_CONTROLS 26
-#define IDI_MSA_PIC_SHIP_CORRIDOR 27
-#define IDI_MSA_PIC_SHIP_KITCHEN 28
-#define IDI_MSA_PIC_SHIP_KITCHEN_1 172 // cabinet open
-
-#define IDI_MSA_PIC_SHIP_VENUS 146
-#define IDI_MSA_PIC_SHIP_NEPTUNE 147
-#define IDI_MSA_PIC_SHIP_MERCURY 148
-#define IDI_MSA_PIC_SHIP_SATURN 149
-#define IDI_MSA_PIC_SHIP_PLUTO 150
-#define IDI_MSA_PIC_SHIP_JUPITER 151
-#define IDI_MSA_PIC_SHIP_MARS 152
-#define IDI_MSA_PIC_SHIP_URANUS 153
-
-#define IDI_MSA_PIC_VENUS_0 30
-#define IDI_MSA_PIC_VENUS_1 31
-#define IDI_MSA_PIC_VENUS_2 32
-#define IDI_MSA_PIC_VENUS_3 34
-#define IDI_MSA_PIC_VENUS_4 36
-#define IDI_MSA_PIC_VENUS_5 38
-#define IDI_MSA_PIC_VENUS_CHASM 35
-#define IDI_MSA_PIC_VENUS_CHASM_1 183 // rope lowered
-#define IDI_MSA_PIC_VENUS_PROBE 39 // CRYSTAL, USE WRENCH
-#define IDI_MSA_PIC_VENUS_PROBE_1 184 // hatch open
-#define IDI_MSA_PIC_VENUS_SHIP 33
-#define IDI_MSA_PIC_VENUS_WEIGH 37 // WEIGH MICKEY
-
-#define IDI_MSA_PIC_NEPTUNE_0 40
-#define IDI_MSA_PIC_NEPTUNE_1 42
-#define IDI_MSA_PIC_NEPTUNE_2 43
-#define IDI_MSA_PIC_NEPTUNE_3 44
-#define IDI_MSA_PIC_NEPTUNE_4 45
-#define IDI_MSA_PIC_NEPTUNE_5 48
-#define IDI_MSA_PIC_NEPTUNE_6 50
-#define IDI_MSA_PIC_NEPTUNE_7 52
-#define IDI_MSA_PIC_NEPTUNE_8 53
-#define IDI_MSA_PIC_NEPTUNE_9 54
-#define IDI_MSA_PIC_NEPTUNE_10 55
-#define IDI_MSA_PIC_NEPTUNE_11 56
-#define IDI_MSA_PIC_NEPTUNE_BABIES 61
-#define IDI_MSA_PIC_NEPTUNE_CASTLE_0 46
-#define IDI_MSA_PIC_NEPTUNE_CASTLE_1 51
-#define IDI_MSA_PIC_NEPTUNE_CASTLE_2 57
-#define IDI_MSA_PIC_NEPTUNE_CASTLE_3 58
-#define IDI_MSA_PIC_NEPTUNE_CASTLE_4 59
-#define IDI_MSA_PIC_NEPTUNE_CASTLE_5 60
-#define IDI_MSA_PIC_NEPTUNE_CASTLE_6 66
-#define IDI_MSA_PIC_NEPTUNE_CASTLE_7 67
-#define IDI_MSA_PIC_NEPTUNE_CASTLE_8 68
-#define IDI_MSA_PIC_NEPTUNE_EATING_AREA 62
-#define IDI_MSA_PIC_NEPTUNE_ENTRANCE 47
-#define IDI_MSA_PIC_NEPTUNE_ENTRANCE_1 185 // entrance open
-#define IDI_MSA_PIC_NEPTUNE_ENTRYWAY 63
-#define IDI_MSA_PIC_NEPTUNE_GUARD 69
-#define IDI_MSA_PIC_NEPTUNE_LEADER 64 // CRYSTAL, GIVE SCARF
-#define IDI_MSA_PIC_NEPTUNE_SHIP 49
-#define IDI_MSA_PIC_NEPTUNE_SLEEP_AREA 65
-#define IDI_MSA_PIC_NEPTUNE_WEIGH 41
-
-#define IDI_MSA_PIC_MERCURY_0 71
-#define IDI_MSA_PIC_MERCURY_1 73
-#define IDI_MSA_PIC_MERCURY_2 75
-#define IDI_MSA_PIC_MERCURY_3 77
-#define IDI_MSA_PIC_MERCURY_4 80
-#define IDI_MSA_PIC_MERCURY_ALIEN_0 72 // CRYSTAL, GIVE SUNGLASSES
-#define IDI_MSA_PIC_MERCURY_ALIEN_1 74
-#define IDI_MSA_PIC_MERCURY_ALIEN_2 81
-#define IDI_MSA_PIC_MERCURY_CAVE_0 70 // hidden feature, press '2' here
-#define IDI_MSA_PIC_MERCURY_CAVE_1 78
-#define IDI_MSA_PIC_MERCURY_CAVE_2 79
-#define IDI_MSA_PIC_MERCURY_SHIP 76
-#define IDI_MSA_PIC_MERCURY_WEIGH 82
-
-#define IDI_MSA_PIC_SATURN_0 84
-#define IDI_MSA_PIC_SATURN_1 86
-#define IDI_MSA_PIC_SATURN_2 90
-#define IDI_MSA_PIC_SATURN_3 91
-#define IDI_MSA_PIC_SATURN_ISLAND 89 // CRYSTAL
-#define IDI_MSA_PIC_SATURN_LAKE_0 85 // USE MATTRESS
-#define IDI_MSA_PIC_SATURN_LAKE_1 88 // USE MATTRESS
-#define IDI_MSA_PIC_SATURN_LAKE_2 92 // USE MATTRESS
-#define IDI_MSA_PIC_SATURN_SHIP 87
-#define IDI_MSA_PIC_SATURN_WEIGH 83 // WEIGH MICKEY
-
-#define IDI_MSA_PIC_PLUTO_0 93
-#define IDI_MSA_PIC_PLUTO_1 96
-#define IDI_MSA_PIC_PLUTO_2 97
-#define IDI_MSA_PIC_PLUTO_3 98
-#define IDI_MSA_PIC_PLUTO_4 101
-#define IDI_MSA_PIC_PLUTO_ALIENS 100 // CRYSTAL, GIVE BONE
-#define IDI_MSA_PIC_PLUTO_CAVE_0 99
-#define IDI_MSA_PIC_PLUTO_CAVE_1 103
-#define IDI_MSA_PIC_PLUTO_CRATER 102
-#define IDI_MSA_PIC_PLUTO_SHIP 95
-#define IDI_MSA_PIC_PLUTO_WEIGH 94 // WEIGH MICKEY
-
-#define IDI_MSA_PIC_JUPITER_0 106
-#define IDI_MSA_PIC_JUPITER_1 107
-#define IDI_MSA_PIC_JUPITER_2 108
-#define IDI_MSA_PIC_JUPITER_3 109
-#define IDI_MSA_PIC_JUPITER_4 113
-#define IDI_MSA_PIC_JUPITER_5 116
-#define IDI_MSA_PIC_JUPITER_6 117
-#define IDI_MSA_PIC_JUPITER_7 120
-#define IDI_MSA_PIC_JUPITER_CRACK 114
-#define IDI_MSA_PIC_JUPITER_LAVA 110 // CRYSTAL, THROW ROCK
-#define IDI_MSA_PIC_JUPITER_ROCK_0 112 // GET ROCK
-#define IDI_MSA_PIC_JUPITER_ROCK_1 119 // GET ROCK
-#define IDI_MSA_PIC_JUPITER_SHIP 115
-#define IDI_MSA_PIC_JUPITER_WEIGH 118 // WEIGH MICKEY
-
-#define IDI_MSA_PIC_MARS_0 121
-#define IDI_MSA_PIC_MARS_1 124
-#define IDI_MSA_PIC_MARS_2 125
-#define IDI_MSA_PIC_MARS_3 126
-#define IDI_MSA_PIC_MARS_4 127
-#define IDI_MSA_PIC_MARS_5 128
-#define IDI_MSA_PIC_MARS_6 130
-#define IDI_MSA_PIC_MARS_SHIP 123
-#define IDI_MSA_PIC_MARS_TUBE_0 129
-#define IDI_MSA_PIC_MARS_TUBE_1 131
-#define IDI_MSA_PIC_MARS_VOLCANO 132 // CRYSTAL, DIG PLUTO
-#define IDI_MSA_PIC_MARS_WEIGH 122 // WEIGH MICKEY
-
-#define IDI_MSA_PIC_URANUS_0 133
-#define IDI_MSA_PIC_URANUS_1 134
-#define IDI_MSA_PIC_URANUS_2 135
-#define IDI_MSA_PIC_URANUS_3 138
-#define IDI_MSA_PIC_URANUS_4 139
-#define IDI_MSA_PIC_URANUS_5 140
-#define IDI_MSA_PIC_URANUS_6 142
-#define IDI_MSA_PIC_URANUS_CHAMBER 145 // CRYSTAL, USE CROWBAR
-#define IDI_MSA_PIC_URANUS_SHIP 137
-#define IDI_MSA_PIC_URANUS_STEPS 144
-#define IDI_MSA_PIC_URANUS_ENTRANCE 141 // ENTER TEMPLE
-#define IDI_MSA_PIC_URANUS_TEMPLE 143 // USE CRYSTAL, ENTER DOOR
-#define IDI_MSA_PIC_URANUS_TEMPLE_1 206 // crystal used
-#define IDI_MSA_PIC_URANUS_TEMPLE_2 207 // door open
-#define IDI_MSA_PIC_URANUS_WEIGH 136 // WEIGH MICKEY
-
-#define IDI_MSA_PIC_STAR_MAP 165
-#define IDI_MSA_PIC_TITLE 240
+#define IDI_MSA_PIC_EARTH_TIRE_SWING 1
+#define IDI_MSA_PIC_EARTH_TIRE_SWING_1 200 // rope taken, swing on ground
+#define IDI_MSA_PIC_EARTH_DOGHOUSE 2
+#define IDI_MSA_PIC_EARTH_IN_DOGHOUSE 154
+#define IDI_MSA_PIC_EARTH_TREE 3
+#define IDI_MSA_PIC_EARTH_GARDEN 4
+#define IDI_MSA_PIC_EARTH_FRONT_HOUSE 5
+#define IDI_MSA_PIC_EARTH_HAMMOCK 6
+#define IDI_MSA_PIC_EARTH_BUTTERFLY 7
+#define IDI_MSA_PIC_EARTH_MAILBOX 8
+#define IDI_MSA_PIC_EARTH_ROAD_0 9
+#define IDI_MSA_PIC_EARTH_ROAD_1 10
+#define IDI_MSA_PIC_EARTH_ROAD_2 11
+#define IDI_MSA_PIC_EARTH_ROAD_3 12
+#define IDI_MSA_PIC_EARTH_ROAD_4 13 // starting room
+#define IDI_MSA_PIC_EARTH_ROAD_5 14
+#define IDI_MSA_PIC_EARTH_ROAD_6 15
+#define IDI_MSA_PIC_EARTH_ROAD_7 18
+#define IDI_MSA_PIC_EARTH_UNDER_TREE 16
+#define IDI_MSA_PIC_EARTH_UP_IN_TREE 155 // CRYSTAL
+#define IDI_MSA_PIC_EARTH_SHIP 17
+#define IDI_MSA_PIC_EARTH_LIVING_ROOM 19
+#define IDI_MSA_PIC_EARTH_KITCHEN 20
+#define IDI_MSA_PIC_EARTH_KITCHEN_1 159 // cupboard open
+#define IDI_MSA_PIC_EARTH_GARAGE 21
+#define IDI_MSA_PIC_EARTH_GARAGE_1 160 // cabinet open
+#define IDI_MSA_PIC_EARTH_BEDROOM 22
+#define IDI_MSA_PIC_EARTH_BEDROOM_1 161 // closet open
+#define IDI_MSA_PIC_EARTH_BATHROOM 23 // WEIGH MICKEY
+#define IDI_MSA_PIC_EARTH_SHIP_LEAVING 24
+#define IDI_MSA_PIC_EARTH_MINNIE 25
+
+#define IDI_MSA_PIC_SHIP_AIRLOCK 25
+#define IDI_MSA_PIC_SHIP_AIRLOCK_0 201 // door closed
+#define IDI_MSA_PIC_SHIP_AIRLOCK_1 202 // door open
+#define IDI_MSA_PIC_SHIP_AIRLOCK_2 203 // door closed, spacesuits on
+#define IDI_MSA_PIC_SHIP_AIRLOCK_3 204 // door open, spacesuits on
+#define IDI_MSA_PIC_SHIP_BEDROOM 29
+#define IDI_MSA_PIC_SHIP_CONTROLS 26
+#define IDI_MSA_PIC_SHIP_CORRIDOR 27
+#define IDI_MSA_PIC_SHIP_KITCHEN 28
+#define IDI_MSA_PIC_SHIP_KITCHEN_1 172 // cabinet open
+
+#define IDI_MSA_PIC_SHIP_VENUS 146
+#define IDI_MSA_PIC_SHIP_NEPTUNE 147
+#define IDI_MSA_PIC_SHIP_MERCURY 148
+#define IDI_MSA_PIC_SHIP_SATURN 149
+#define IDI_MSA_PIC_SHIP_PLUTO 150
+#define IDI_MSA_PIC_SHIP_JUPITER 151
+#define IDI_MSA_PIC_SHIP_MARS 152
+#define IDI_MSA_PIC_SHIP_URANUS 153
+
+#define IDI_MSA_PIC_VENUS_0 30
+#define IDI_MSA_PIC_VENUS_1 31
+#define IDI_MSA_PIC_VENUS_2 32
+#define IDI_MSA_PIC_VENUS_3 34
+#define IDI_MSA_PIC_VENUS_4 36
+#define IDI_MSA_PIC_VENUS_5 38
+#define IDI_MSA_PIC_VENUS_CHASM 35
+#define IDI_MSA_PIC_VENUS_CHASM_1 183 // rope lowered
+#define IDI_MSA_PIC_VENUS_PROBE 39 // CRYSTAL, USE WRENCH
+#define IDI_MSA_PIC_VENUS_PROBE_1 184 // hatch open
+#define IDI_MSA_PIC_VENUS_SHIP 33
+#define IDI_MSA_PIC_VENUS_WEIGH 37 // WEIGH MICKEY
+
+#define IDI_MSA_PIC_NEPTUNE_0 40
+#define IDI_MSA_PIC_NEPTUNE_1 42
+#define IDI_MSA_PIC_NEPTUNE_2 43
+#define IDI_MSA_PIC_NEPTUNE_3 44
+#define IDI_MSA_PIC_NEPTUNE_4 45
+#define IDI_MSA_PIC_NEPTUNE_5 48
+#define IDI_MSA_PIC_NEPTUNE_6 50
+#define IDI_MSA_PIC_NEPTUNE_7 52
+#define IDI_MSA_PIC_NEPTUNE_8 53
+#define IDI_MSA_PIC_NEPTUNE_9 54
+#define IDI_MSA_PIC_NEPTUNE_10 55
+#define IDI_MSA_PIC_NEPTUNE_11 56
+#define IDI_MSA_PIC_NEPTUNE_BABIES 61
+#define IDI_MSA_PIC_NEPTUNE_CASTLE_0 46
+#define IDI_MSA_PIC_NEPTUNE_CASTLE_1 51
+#define IDI_MSA_PIC_NEPTUNE_CASTLE_2 57
+#define IDI_MSA_PIC_NEPTUNE_CASTLE_3 58
+#define IDI_MSA_PIC_NEPTUNE_CASTLE_4 59
+#define IDI_MSA_PIC_NEPTUNE_CASTLE_5 60
+#define IDI_MSA_PIC_NEPTUNE_CASTLE_6 66
+#define IDI_MSA_PIC_NEPTUNE_CASTLE_7 67
+#define IDI_MSA_PIC_NEPTUNE_CASTLE_8 68
+#define IDI_MSA_PIC_NEPTUNE_EATING_AREA 62
+#define IDI_MSA_PIC_NEPTUNE_ENTRANCE 47
+#define IDI_MSA_PIC_NEPTUNE_ENTRANCE_1 185 // entrance open
+#define IDI_MSA_PIC_NEPTUNE_ENTRYWAY 63
+#define IDI_MSA_PIC_NEPTUNE_GUARD 69
+#define IDI_MSA_PIC_NEPTUNE_LEADER 64 // CRYSTAL, GIVE SCARF
+#define IDI_MSA_PIC_NEPTUNE_SHIP 49
+#define IDI_MSA_PIC_NEPTUNE_SLEEP_AREA 65
+#define IDI_MSA_PIC_NEPTUNE_WEIGH 41
+
+#define IDI_MSA_PIC_MERCURY_0 71
+#define IDI_MSA_PIC_MERCURY_1 73
+#define IDI_MSA_PIC_MERCURY_2 75
+#define IDI_MSA_PIC_MERCURY_3 77
+#define IDI_MSA_PIC_MERCURY_4 80
+#define IDI_MSA_PIC_MERCURY_ALIEN_0 72 // CRYSTAL, GIVE SUNGLASSES
+#define IDI_MSA_PIC_MERCURY_ALIEN_1 74
+#define IDI_MSA_PIC_MERCURY_ALIEN_2 81
+#define IDI_MSA_PIC_MERCURY_CAVE_0 70 // hidden feature, press '2' here
+#define IDI_MSA_PIC_MERCURY_CAVE_1 78
+#define IDI_MSA_PIC_MERCURY_CAVE_2 79
+#define IDI_MSA_PIC_MERCURY_SHIP 76
+#define IDI_MSA_PIC_MERCURY_WEIGH 82
+
+#define IDI_MSA_PIC_SATURN_0 84
+#define IDI_MSA_PIC_SATURN_1 86
+#define IDI_MSA_PIC_SATURN_2 90
+#define IDI_MSA_PIC_SATURN_3 91
+#define IDI_MSA_PIC_SATURN_ISLAND 89 // CRYSTAL
+#define IDI_MSA_PIC_SATURN_LAKE_0 85 // USE MATTRESS
+#define IDI_MSA_PIC_SATURN_LAKE_1 88 // USE MATTRESS
+#define IDI_MSA_PIC_SATURN_LAKE_2 92 // USE MATTRESS
+#define IDI_MSA_PIC_SATURN_SHIP 87
+#define IDI_MSA_PIC_SATURN_WEIGH 83 // WEIGH MICKEY
+
+#define IDI_MSA_PIC_PLUTO_0 93
+#define IDI_MSA_PIC_PLUTO_1 96
+#define IDI_MSA_PIC_PLUTO_2 97
+#define IDI_MSA_PIC_PLUTO_3 98
+#define IDI_MSA_PIC_PLUTO_4 101
+#define IDI_MSA_PIC_PLUTO_ALIENS 100 // CRYSTAL, GIVE BONE
+#define IDI_MSA_PIC_PLUTO_CAVE_0 99
+#define IDI_MSA_PIC_PLUTO_CAVE_1 103
+#define IDI_MSA_PIC_PLUTO_CRATER 102
+#define IDI_MSA_PIC_PLUTO_SHIP 95
+#define IDI_MSA_PIC_PLUTO_WEIGH 94 // WEIGH MICKEY
+
+#define IDI_MSA_PIC_JUPITER_0 106
+#define IDI_MSA_PIC_JUPITER_1 107
+#define IDI_MSA_PIC_JUPITER_2 108
+#define IDI_MSA_PIC_JUPITER_3 109
+#define IDI_MSA_PIC_JUPITER_4 113
+#define IDI_MSA_PIC_JUPITER_5 116
+#define IDI_MSA_PIC_JUPITER_6 117
+#define IDI_MSA_PIC_JUPITER_7 120
+#define IDI_MSA_PIC_JUPITER_CRACK 114
+#define IDI_MSA_PIC_JUPITER_LAVA 110 // CRYSTAL, THROW ROCK
+#define IDI_MSA_PIC_JUPITER_ROCK_0 112 // GET ROCK
+#define IDI_MSA_PIC_JUPITER_ROCK_1 119 // GET ROCK
+#define IDI_MSA_PIC_JUPITER_SHIP 115
+#define IDI_MSA_PIC_JUPITER_WEIGH 118 // WEIGH MICKEY
+
+#define IDI_MSA_PIC_MARS_0 121
+#define IDI_MSA_PIC_MARS_1 124
+#define IDI_MSA_PIC_MARS_2 125
+#define IDI_MSA_PIC_MARS_3 126
+#define IDI_MSA_PIC_MARS_4 127
+#define IDI_MSA_PIC_MARS_5 128
+#define IDI_MSA_PIC_MARS_6 130
+#define IDI_MSA_PIC_MARS_SHIP 123
+#define IDI_MSA_PIC_MARS_TUBE_0 129
+#define IDI_MSA_PIC_MARS_TUBE_1 131
+#define IDI_MSA_PIC_MARS_VOLCANO 132 // CRYSTAL, DIG PLUTO
+#define IDI_MSA_PIC_MARS_WEIGH 122 // WEIGH MICKEY
+
+#define IDI_MSA_PIC_URANUS_0 133
+#define IDI_MSA_PIC_URANUS_1 134
+#define IDI_MSA_PIC_URANUS_2 135
+#define IDI_MSA_PIC_URANUS_3 138
+#define IDI_MSA_PIC_URANUS_4 139
+#define IDI_MSA_PIC_URANUS_5 140
+#define IDI_MSA_PIC_URANUS_6 142
+#define IDI_MSA_PIC_URANUS_CHAMBER 145 // CRYSTAL, USE CROWBAR
+#define IDI_MSA_PIC_URANUS_SHIP 137
+#define IDI_MSA_PIC_URANUS_STEPS 144
+#define IDI_MSA_PIC_URANUS_ENTRANCE 141 // ENTER TEMPLE
+#define IDI_MSA_PIC_URANUS_TEMPLE 143 // USE CRYSTAL, ENTER DOOR
+#define IDI_MSA_PIC_URANUS_TEMPLE_1 206 // crystal used
+#define IDI_MSA_PIC_URANUS_TEMPLE_2 207 // door open
+#define IDI_MSA_PIC_URANUS_WEIGH 136 // WEIGH MICKEY
+
+#define IDI_MSA_PIC_STAR_MAP 165
+#define IDI_MSA_PIC_TITLE 240
// objects
@@ -330,16 +330,16 @@ const char IDS_MSA_NAME_OBJ[][9] = {
};
const int IDI_MSA_XTAL_ROOM_XY[IDI_MSA_MAX_PLANET][3] = {
- // room x y
- {IDI_MSA_PIC_EARTH_UP_IN_TREE, 14, 76},
- {IDI_MSA_PIC_VENUS_PROBE, 74, 80},
- {IDI_MSA_PIC_NEPTUNE_LEADER, 70, 27},
- {IDI_MSA_PIC_MERCURY_ALIEN_0, 123, 64},
- {IDI_MSA_PIC_SATURN_ISLAND, 110, 115},
- {IDI_MSA_PIC_PLUTO_ALIENS, 60, 104},
- {IDI_MSA_PIC_JUPITER_LAVA, 56, 54},
- {IDI_MSA_PIC_MARS_VOLCANO, 107, 100},
- {IDI_MSA_PIC_URANUS_CHAMBER, 90, 4}
+ // room x y
+ {IDI_MSA_PIC_EARTH_UP_IN_TREE, 14, 76},
+ {IDI_MSA_PIC_VENUS_PROBE, 74, 80},
+ {IDI_MSA_PIC_NEPTUNE_LEADER, 70, 27},
+ {IDI_MSA_PIC_MERCURY_ALIEN_0, 123, 64},
+ {IDI_MSA_PIC_SATURN_ISLAND, 110, 115},
+ {IDI_MSA_PIC_PLUTO_ALIENS, 60, 104},
+ {IDI_MSA_PIC_JUPITER_LAVA, 56, 54},
+ {IDI_MSA_PIC_MARS_VOLCANO, 107, 100},
+ {IDI_MSA_PIC_URANUS_CHAMBER, 90, 4}
};
// planets
@@ -411,23 +411,23 @@ const char IDS_MSA_NAME_ITEM[][15] = {
// buttons
-#define IDI_MSA_BUTTON_ORANGE 0x4F // 'O'
-#define IDI_MSA_BUTTON_BLUE 0x42 // 'B'
+#define IDI_MSA_BUTTON_ORANGE 0x4F // 'O'
+#define IDI_MSA_BUTTON_BLUE 0x42 // 'B'
// file structures
struct MSA_TEXT_ENTRY {
- uint8 x0;
- uint8 szText[11];
+ uint8 x0;
+ uint8 szText[11];
};
struct MSA_TEXT_BLOCK {
- uint8 count;
- MSA_TEXT_ENTRY entry[5];
+ uint8 count;
+ MSA_TEXT_ENTRY entry[5];
};
struct MSA_MSG_BLOCK {
- uint8 data[5];
+ uint8 data[5];
};
struct MSA_MENU {
@@ -437,108 +437,108 @@ struct MSA_MENU {
};
struct MSA_DAT_HEADER {
- uint16 filelen;
- uint16 ofsRoom[IDI_MSA_MAX_ROOM];
- uint16 ofsDesc[IDI_MSA_MAX_ROOM];
- uint16 ofsStr[IDI_MSA_MAX_ROOM];
+ uint16 filelen;
+ uint16 ofsRoom[IDI_MSA_MAX_ROOM];
+ uint16 ofsDesc[IDI_MSA_MAX_ROOM];
+ uint16 ofsStr[IDI_MSA_MAX_ROOM];
};
struct MSA_SND_NOTE {
- uint16 counter; // freq = 1193180 / counter
- uint8 length; // msec = length / 0.0182
+ uint16 counter; // freq = 1193180 / counter
+ uint8 length; // msec = length / 0.0182
};
// file offset modifiers
-#define IDI_MSA_OFS_DAT 0x0002
-#define IDI_MSA_OFS_EXE 0x35C0
+#define IDI_MSA_OFS_DAT 0x0002
+#define IDI_MSA_OFS_EXE 0x35C0
// actions
-#define IDI_MSA_ACTION_GOTO_ROOM 0x00
-#define IDI_MSA_ACTION_SHOW_INT_STR 0x01
-#define IDI_MSA_ACTION_UNUSED 0x02
-#define IDI_MSA_ACTION_SHOW_DAT_STR 0x03
-
-#define IDI_MSA_ACTION_GET_ROPE 0x7F
-#define IDI_MSA_ACTION_UNTIE_ROPE 0x80
-#define IDI_MSA_ACTION_GET_BONE 0x81
-#define IDI_MSA_ACTION_GET_XTAL_EARTH 0x82
-#define IDI_MSA_ACTION_LOOK_DESK 0x83
-#define IDI_MSA_ACTION_WRITE_LETTER 0x84
-#define IDI_MSA_ACTION_MAIL_LETTER 0x85
-#define IDI_MSA_ACTION_OPEN_CUPBOARD 0x86
-#define IDI_MSA_ACTION_GET_FLASHLIGHT 0x87
-#define IDI_MSA_ACTION_OPEN_CABINET 0x88
-#define IDI_MSA_ACTION_GET_CROWBAR 0x89
-#define IDI_MSA_ACTION_GET_WRENCH 0x8A
-#define IDI_MSA_ACTION_OPEN_CLOSET 0x8B
-#define IDI_MSA_ACTION_GET_MATTRESS 0x8C
-#define IDI_MSA_ACTION_GET_SCARF 0x8D
-#define IDI_MSA_ACTION_GET_SUNGLASSES 0x8E
-#define IDI_MSA_ACTION_GET_SCALE 0x8F
-#define IDI_MSA_ACTION_GOTO_SPACESHIP 0x90
-
-#define IDI_MSA_ACTION_DOWN_CHASM 0x91
-#define IDI_MSA_ACTION_DOWN_ROPE 0x92
-#define IDI_MSA_ACTION_USE_ROPE 0x93
-#define IDI_MSA_ACTION_OPEN_HATCH 0x94
-#define IDI_MSA_ACTION_USE_WRENCH 0x95
-#define IDI_MSA_ACTION_GET_XTAL_VENUS 0x96
-
-#define IDI_MSA_ACTION_LOOK_CASTLE 0x97
-#define IDI_MSA_ACTION_ENTER_OPENING 0x98
-#define IDI_MSA_ACTION_USE_CROWBAR 0x99
-#define IDI_MSA_ACTION_GET_XTAL_NEPTUNE 0x9A
-#define IDI_MSA_ACTION_TALK_LEADER 0x9B
-#define IDI_MSA_ACTION_GIVE_SCARF 0x9C
-
-#define IDI_MSA_ACTION_GET_XTAL_MERCURY 0x9D
-#define IDI_MSA_ACTION_GIVE_SUNGLASSES 0x9E
-#define IDI_MSA_ACTION_CROSS_LAKE 0x9F
-#define IDI_MSA_ACTION_USE_MATTRESS 0xA0
-#define IDI_MSA_ACTION_GET_XTAL_SATURN 0xA1
-#define IDI_MSA_ACTION_LEAVE_ISLAND 0xA2
-
-#define IDI_MSA_ACTION_GET_XTAL_PLUTO 0xA3
-#define IDI_MSA_ACTION_GIVE_BONE 0xA4
-
-#define IDI_MSA_ACTION_GET_ROCK_0 0xA5
-#define IDI_MSA_ACTION_GET_ROCK_1 0xA6
-#define IDI_MSA_ACTION_GET_XTAL_JUPITER 0xA7
-#define IDI_MSA_ACTION_THROW_ROCK 0xA8
-
-#define IDI_MSA_ACTION_GO_TUBE 0xA9
-#define IDI_MSA_ACTION_USE_FLASHLIGHT 0xAA
-#define IDI_MSA_ACTION_PLUTO_DIG 0xAB
-#define IDI_MSA_ACTION_GET_XTAL_MARS 0xAC
-
-#define IDI_MSA_ACTION_USE_CRYSTAL 0xAD
-#define IDI_MSA_ACTION_OPEN_DOOR 0xAE
-#define IDI_MSA_ACTION_ENTER_DOOR 0xAF
-#define IDI_MSA_ACTION_GET_XTAL_URANUS 0xB0
-#define IDI_MSA_ACTION_USE_CROWBAR_1 0xB1
-
-#define IDI_MSA_ACTION_GO_NORTH 0xB2
-#define IDI_MSA_ACTION_GO_PLANET 0xB3
-#define IDI_MSA_ACTION_PRESS_BUTTON 0xB4
-#define IDI_MSA_ACTION_WEAR_SPACESUIT 0xB5
-#define IDI_MSA_ACTION_READ_GAUGE 0xB6
-#define IDI_MSA_ACTION_PRESS_ORANGE 0xB7
-#define IDI_MSA_ACTION_PRESS_BLUE 0xB8
-#define IDI_MSA_ACTION_FLIP_SWITCH 0xB9
-#define IDI_MSA_ACTION_PUSH_THROTTLE 0xBA
-#define IDI_MSA_ACTION_PULL_THROTTLE 0xBB
-#define IDI_MSA_ACTION_LEAVE_ROOM 0xBC
-#define IDI_MSA_ACTION_OPEN_CABINET_1 0xBD
-#define IDI_MSA_ACTION_READ_MAP 0xBE
-#define IDI_MSA_ACTION_GO_WEST 0xBF
-
-#define IDI_MSA_ACTION_PLANET_INFO 0xC0
-#define IDI_MSA_ACTION_ENTER_TEMPLE 0xC1
-#define IDI_MSA_ACTION_OPEN_MAILBOX 0xC2
-#define IDI_MSA_ACTION_SAVE_GAME 0xC3
-#define IDI_MSA_ACTION_LOOK_MICKEY 0xC4
+#define IDI_MSA_ACTION_GOTO_ROOM 0x00
+#define IDI_MSA_ACTION_SHOW_INT_STR 0x01
+#define IDI_MSA_ACTION_UNUSED 0x02
+#define IDI_MSA_ACTION_SHOW_DAT_STR 0x03
+
+#define IDI_MSA_ACTION_GET_ROPE 0x7F
+#define IDI_MSA_ACTION_UNTIE_ROPE 0x80
+#define IDI_MSA_ACTION_GET_BONE 0x81
+#define IDI_MSA_ACTION_GET_XTAL_EARTH 0x82
+#define IDI_MSA_ACTION_LOOK_DESK 0x83
+#define IDI_MSA_ACTION_WRITE_LETTER 0x84
+#define IDI_MSA_ACTION_MAIL_LETTER 0x85
+#define IDI_MSA_ACTION_OPEN_CUPBOARD 0x86
+#define IDI_MSA_ACTION_GET_FLASHLIGHT 0x87
+#define IDI_MSA_ACTION_OPEN_CABINET 0x88
+#define IDI_MSA_ACTION_GET_CROWBAR 0x89
+#define IDI_MSA_ACTION_GET_WRENCH 0x8A
+#define IDI_MSA_ACTION_OPEN_CLOSET 0x8B
+#define IDI_MSA_ACTION_GET_MATTRESS 0x8C
+#define IDI_MSA_ACTION_GET_SCARF 0x8D
+#define IDI_MSA_ACTION_GET_SUNGLASSES 0x8E
+#define IDI_MSA_ACTION_GET_SCALE 0x8F
+#define IDI_MSA_ACTION_GOTO_SPACESHIP 0x90
+
+#define IDI_MSA_ACTION_DOWN_CHASM 0x91
+#define IDI_MSA_ACTION_DOWN_ROPE 0x92
+#define IDI_MSA_ACTION_USE_ROPE 0x93
+#define IDI_MSA_ACTION_OPEN_HATCH 0x94
+#define IDI_MSA_ACTION_USE_WRENCH 0x95
+#define IDI_MSA_ACTION_GET_XTAL_VENUS 0x96
+
+#define IDI_MSA_ACTION_LOOK_CASTLE 0x97
+#define IDI_MSA_ACTION_ENTER_OPENING 0x98
+#define IDI_MSA_ACTION_USE_CROWBAR 0x99
+#define IDI_MSA_ACTION_GET_XTAL_NEPTUNE 0x9A
+#define IDI_MSA_ACTION_TALK_LEADER 0x9B
+#define IDI_MSA_ACTION_GIVE_SCARF 0x9C
+
+#define IDI_MSA_ACTION_GET_XTAL_MERCURY 0x9D
+#define IDI_MSA_ACTION_GIVE_SUNGLASSES 0x9E
+#define IDI_MSA_ACTION_CROSS_LAKE 0x9F
+#define IDI_MSA_ACTION_USE_MATTRESS 0xA0
+#define IDI_MSA_ACTION_GET_XTAL_SATURN 0xA1
+#define IDI_MSA_ACTION_LEAVE_ISLAND 0xA2
+
+#define IDI_MSA_ACTION_GET_XTAL_PLUTO 0xA3
+#define IDI_MSA_ACTION_GIVE_BONE 0xA4
+
+#define IDI_MSA_ACTION_GET_ROCK_0 0xA5
+#define IDI_MSA_ACTION_GET_ROCK_1 0xA6
+#define IDI_MSA_ACTION_GET_XTAL_JUPITER 0xA7
+#define IDI_MSA_ACTION_THROW_ROCK 0xA8
+
+#define IDI_MSA_ACTION_GO_TUBE 0xA9
+#define IDI_MSA_ACTION_USE_FLASHLIGHT 0xAA
+#define IDI_MSA_ACTION_PLUTO_DIG 0xAB
+#define IDI_MSA_ACTION_GET_XTAL_MARS 0xAC
+
+#define IDI_MSA_ACTION_USE_CRYSTAL 0xAD
+#define IDI_MSA_ACTION_OPEN_DOOR 0xAE
+#define IDI_MSA_ACTION_ENTER_DOOR 0xAF
+#define IDI_MSA_ACTION_GET_XTAL_URANUS 0xB0
+#define IDI_MSA_ACTION_USE_CROWBAR_1 0xB1
+
+#define IDI_MSA_ACTION_GO_NORTH 0xB2
+#define IDI_MSA_ACTION_GO_PLANET 0xB3
+#define IDI_MSA_ACTION_PRESS_BUTTON 0xB4
+#define IDI_MSA_ACTION_WEAR_SPACESUIT 0xB5
+#define IDI_MSA_ACTION_READ_GAUGE 0xB6
+#define IDI_MSA_ACTION_PRESS_ORANGE 0xB7
+#define IDI_MSA_ACTION_PRESS_BLUE 0xB8
+#define IDI_MSA_ACTION_FLIP_SWITCH 0xB9
+#define IDI_MSA_ACTION_PUSH_THROTTLE 0xBA
+#define IDI_MSA_ACTION_PULL_THROTTLE 0xBB
+#define IDI_MSA_ACTION_LEAVE_ROOM 0xBC
+#define IDI_MSA_ACTION_OPEN_CABINET_1 0xBD
+#define IDI_MSA_ACTION_READ_MAP 0xBE
+#define IDI_MSA_ACTION_GO_WEST 0xBF
+
+#define IDI_MSA_ACTION_PLANET_INFO 0xC0
+#define IDI_MSA_ACTION_ENTER_TEMPLE 0xC1
+#define IDI_MSA_ACTION_OPEN_MAILBOX 0xC2
+#define IDI_MSA_ACTION_SAVE_GAME 0xC3
+#define IDI_MSA_ACTION_LOOK_MICKEY 0xC4
// sounds
@@ -584,52 +584,52 @@ const int IDI_MSA_AIR_SUPPLY[] = { 30, 20, 10, 0 };
// planet information
const int IDO_MSA_PLANET_INFO[IDI_MSA_MAX_PLANET][4] = {
- {0x6313, 0x63B2, 0x6449, 0}, // EARTH
- {0x61EB, 0x6288, 0, 0}, // VENUS
- {0x6B64, 0x6C06, 0x6CA3, 0}, // NEPTUNE
- {0x609B, 0x612C, 0x61CA, 0}, // MERCURY
- {0x6879, 0x6916, 0x6984, 0}, // SATURN
- {0x6CCF, 0x6D72, 0x6E10, 0}, // PLUTO
- {0x667C, 0x6714, 0x67B1, 0x684E}, // JUPITER
- {0x6471, 0x650F, 0x65AD, 0x6651}, // MARS
- {0x69C3, 0x6A62, 0x6B00, 0} // URANUS
+ {0x6313, 0x63B2, 0x6449, 0}, // EARTH
+ {0x61EB, 0x6288, 0, 0}, // VENUS
+ {0x6B64, 0x6C06, 0x6CA3, 0}, // NEPTUNE
+ {0x609B, 0x612C, 0x61CA, 0}, // MERCURY
+ {0x6879, 0x6916, 0x6984, 0}, // SATURN
+ {0x6CCF, 0x6D72, 0x6E10, 0}, // PLUTO
+ {0x667C, 0x6714, 0x67B1, 0x684E}, // JUPITER
+ {0x6471, 0x650F, 0x65AD, 0x6651}, // MARS
+ {0x69C3, 0x6A62, 0x6B00, 0} // URANUS
};
// next crystal piece hints
const int IDO_MSA_NEXT_PIECE[IDI_MSA_MAX_PLANET][5] = {
- {0, 0, 0, 0, 0}, // earth
- {0x4DCC, 0x4E20, 0x4E64, 0x4E9E, 0x4F0B}, // venus
- {0x5900, 0x599B, 0x5A07, 0x5A8E, 0x5B07}, // neptune
- {0x4F57, 0x4FA3, 0x4FF1, 0x5056, 0x50BD}, // mercury
- {0x5471, 0x54DF, 0x5548, 0x55C2, 0x562A}, // saturn
- {0x5B78, 0x5BB6, 0x5C29, 0x5C76, 0x5CE1}, // pluto
- {0x526B, 0x52DA, 0x5340, 0x53A1, 0x540C}, // jupiter
- {0x50F6, 0x512C, 0x5170, 0x51D5, 0x5228}, // mars
- {0x56AA, 0x571C, 0x579E, 0x5807, 0x5875} // uranus
+ {0, 0, 0, 0, 0}, // earth
+ {0x4DCC, 0x4E20, 0x4E64, 0x4E9E, 0x4F0B}, // venus
+ {0x5900, 0x599B, 0x5A07, 0x5A8E, 0x5B07}, // neptune
+ {0x4F57, 0x4FA3, 0x4FF1, 0x5056, 0x50BD}, // mercury
+ {0x5471, 0x54DF, 0x5548, 0x55C2, 0x562A}, // saturn
+ {0x5B78, 0x5BB6, 0x5C29, 0x5C76, 0x5CE1}, // pluto
+ {0x526B, 0x52DA, 0x5340, 0x53A1, 0x540C}, // jupiter
+ {0x50F6, 0x512C, 0x5170, 0x51D5, 0x5228}, // mars
+ {0x56AA, 0x571C, 0x579E, 0x5807, 0x5875} // uranus
};
// message offsets
-#define IDO_MSA_COPYRIGHT 0x7801
-#define IDO_MSA_INTRO 0x4679
-#define IDO_MSA_GAME_STORY 0x6E9C
+#define IDO_MSA_COPYRIGHT 0x7801
+#define IDO_MSA_INTRO 0x4679
+#define IDO_MSA_GAME_STORY 0x6E9C
-#define IDO_MSA_PRESS_1_TO_9 0x7530
-#define IDO_MSA_PRESS_YES_OR_NO 0x480D
-#define IDO_MSA_TOO_MANY_BUTTONS_PRESSED 0x5DF7
+#define IDO_MSA_PRESS_1_TO_9 0x7530
+#define IDO_MSA_PRESS_YES_OR_NO 0x480D
+#define IDO_MSA_TOO_MANY_BUTTONS_PRESSED 0x5DF7
-#define IDO_MSA_XL30_SPEAKING 0x4725
-#define IDO_MSA_CRYSTAL_PIECE_FOUND 0x600C
+#define IDO_MSA_XL30_SPEAKING 0x4725
+#define IDO_MSA_CRYSTAL_PIECE_FOUND 0x600C
-#define IDO_MSA_ROOM_TEXT_OFFSETS 0x8B01
-#define IDO_MSA_ROOM_OBJECT_XY_OFFSETS 0x8EA8
-#define IDO_MSA_ROOM_MENU_FIX 0x4a27
+#define IDO_MSA_ROOM_TEXT_OFFSETS 0x8B01
+#define IDO_MSA_ROOM_OBJECT_XY_OFFSETS 0x8EA8
+#define IDO_MSA_ROOM_MENU_FIX 0x4a27
// offsets to offset arrays
-#define IDOFS_MSA_MENU_PATCHES 0x5e7a
-#define IDOFS_MSA_SOUND_DATA 0x9deb
+#define IDOFS_MSA_MENU_PATCHES 0x5e7a
+#define IDOFS_MSA_SOUND_DATA 0x9deb
// game structure
@@ -698,24 +698,24 @@ protected:
bool _clickToMove;
int getDat(int);
- void readExe(int, uint8*, long);
- void getDatFileName(int, char*);
- void readDatHdr(char*, MSA_DAT_HEADER*);
- void readOfsData(int, int, uint8*, long);
+ void readExe(int, uint8 *, long);
+ void getDatFileName(int, char *);
+ void readDatHdr(char *, MSA_DAT_HEADER *);
+ void readOfsData(int, int, uint8 *, long);
bool chooseY_N(int, bool);
int choose1to9(int);
void printStr(char *);
- void printLine(const char*);
+ void printLine(const char *);
void printExeStr(int);
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 getMenuSel(char*, int*, int*);
- void centerMenu(MSA_MENU*);
- void patchMenu(MSA_MENU*);
+ 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 *);
void printDatString(int);
void printDatMessage(int);
void playNote(MSA_SND_NOTE);
@@ -751,7 +751,7 @@ protected:
bool mickeyHasItem(int item) {
if (_gameStateMickey.fItem[item]) {
- printDatMessage(90); // Mickey already has item
+ printDatMessage(90); // Mickey already has item
return true;
} else {
return false;
diff --git a/engines/agi/preagi_troll.cpp b/engines/agi/preagi_troll.cpp
index 2889407c85..7583536c83 100644
--- a/engines/agi/preagi_troll.cpp
+++ b/engines/agi/preagi_troll.cpp
@@ -41,7 +41,7 @@ TrollEngine::~TrollEngine() {
void TrollEngine::pressAnyKey(int col) {
drawStr(24, col, kColorDefault, IDS_TRO_PRESSANYKEY);
- _gfx->doUpdate();
+ g_system->updateScreen();
getSelection(kSelAnyKey);
}
@@ -49,7 +49,7 @@ void TrollEngine::drawMenu(const char *szMenu, int iSel) {
clearTextArea();
drawStr(21, 0, kColorDefault, szMenu);
drawStr(22 + iSel, 0, kColorDefault, " *");
- _gfx->doUpdate();
+ g_system->updateScreen();
}
bool TrollEngine::getMenuSel(const char *szMenu, int *iSel, int nSel) {
@@ -155,8 +155,8 @@ void TrollEngine::drawPic(int iPic, bool f3IsCont, bool clr, bool troll) {
_picture->drawPicture();
- _picture->showPic();
- _gfx->doUpdate();
+ _picture->showPic(); // TODO: *HAVE* to add coordinates + height/width!!
+ g_system->updateScreen();
}
// Game Logic
@@ -223,11 +223,11 @@ void TrollEngine::waitAnyKeyIntro() {
// fall through
case 0:
drawStr(22, 3, kColorDefault, IDS_TRO_INTRO_2);
- _gfx->doUpdate();
+ g_system->updateScreen();
break;
case 100:
drawStr(22, 3, kColorDefault, IDS_TRO_INTRO_3);
- _gfx->doUpdate();
+ g_system->updateScreen();
break;
}
@@ -262,7 +262,7 @@ void TrollEngine::credits() {
drawStr(17, 7, 12, IDS_TRO_CREDITS_5);
drawStr(19, 2, 14, IDS_TRO_CREDITS_6);
- _gfx->doUpdate();
+ g_system->updateScreen();
pressAnyKey();
}
@@ -288,11 +288,11 @@ void TrollEngine::tutorial() {
switch (iSel) {
case IDI_TRO_SEL_OPTION_1:
clearScreen(0x22, false);
- _gfx->doUpdate();
+ g_system->updateScreen();
break;
case IDI_TRO_SEL_OPTION_2:
clearScreen(0x00, false);
- _gfx->doUpdate();
+ g_system->updateScreen();
break;
case IDI_TRO_SEL_OPTION_3:
done = true;
@@ -304,7 +304,7 @@ void TrollEngine::tutorial() {
clearScreen(0x4F);
drawStr(7, 4, kColorDefault, IDS_TRO_TUTORIAL_5);
drawStr(9, 4, kColorDefault, IDS_TRO_TUTORIAL_6);
- _gfx->doUpdate();
+ g_system->updateScreen();
if (!getSelection(kSelYesNo))
break;
@@ -314,37 +314,37 @@ void TrollEngine::tutorial() {
clearScreen(0x5F);
drawStr(4, 1, kColorDefault, IDS_TRO_TUTORIAL_7);
drawStr(5, 1, kColorDefault, IDS_TRO_TUTORIAL_8);
- _gfx->doUpdate();
+ g_system->updateScreen();
pressAnyKey();
clearScreen(0x2F);
drawStr(6, 1, kColorDefault, IDS_TRO_TUTORIAL_9);
- _gfx->doUpdate();
+ g_system->updateScreen();
pressAnyKey();
clearScreen(0x19);
drawStr(7, 1, kColorDefault, IDS_TRO_TUTORIAL_10);
drawStr(8, 1, kColorDefault, IDS_TRO_TUTORIAL_11);
- _gfx->doUpdate();
+ g_system->updateScreen();
pressAnyKey();
clearScreen(0x6E);
drawStr(9, 1, kColorDefault, IDS_TRO_TUTORIAL_12);
drawStr(10, 1, kColorDefault, IDS_TRO_TUTORIAL_13);
- _gfx->doUpdate();
+ g_system->updateScreen();
pressAnyKey();
clearScreen(0x4C);
drawStr(11, 1, kColorDefault, IDS_TRO_TUTORIAL_14);
drawStr(12, 1, kColorDefault, IDS_TRO_TUTORIAL_15);
- _gfx->doUpdate();
+ g_system->updateScreen();
pressAnyKey();
clearScreen(0x5D);
drawStr(13, 1, kColorDefault, IDS_TRO_TUTORIAL_16);
drawStr(14, 1, kColorDefault, IDS_TRO_TUTORIAL_17);
drawStr(15, 1, kColorDefault, IDS_TRO_TUTORIAL_18);
- _gfx->doUpdate();
+ g_system->updateScreen();
pressAnyKey();
// show treasures
@@ -353,7 +353,7 @@ void TrollEngine::tutorial() {
for (int i = 0; i < IDI_TRO_MAX_TREASURE; i++)
drawStr(19 - i, 11, kColorDefault, _items[i].name);
- _gfx->doUpdate();
+ g_system->updateScreen();
pressAnyKey();
}
@@ -363,7 +363,7 @@ void TrollEngine::intro() {
clearScreen(0x2F);
drawStr(9, 10, kColorDefault, IDS_TRO_INTRO_0);
drawStr(14, 15, kColorDefault, IDS_TRO_INTRO_1);
- _gfx->doUpdate();
+ g_system->updateScreen();
_system->delayMillis(3200);
CursorMan.showMouse(true);
@@ -371,7 +371,7 @@ void TrollEngine::intro() {
// Draw logo
setDefaultTextColor(0x0f);
drawPic(45, false, true);
- _gfx->doUpdate();
+ g_system->updateScreen();
// wait for keypress and alternate message
waitAnyKeyIntro();
@@ -379,7 +379,7 @@ void TrollEngine::intro() {
// have you played this game before?
drawStr(22, 3, kColorDefault, IDS_TRO_INTRO_4);
drawStr(23, 6, kColorDefault, IDS_TRO_INTRO_5);
- _gfx->doUpdate();
+ g_system->updateScreen();
if (!getSelection(kSelYesNo))
tutorial();
@@ -411,7 +411,7 @@ void TrollEngine::gameOver() {
sprintf(szMoves, IDS_TRO_GAMEOVER_0, _moves);
drawStr(21, 1, kColorDefault, szMoves);
drawStr(22, 1, kColorDefault, IDS_TRO_GAMEOVER_1);
- _gfx->doUpdate();
+ g_system->updateScreen();
pressAnyKey();
}
@@ -443,7 +443,7 @@ int TrollEngine::drawRoom(char *menu) {
}
drawPic(_currentRoom, contFlag, true);
- _gfx->doUpdate();
+ g_system->updateScreen();
if (_currentRoom == 42) {
drawPic(44, false, false); // don't clear
@@ -454,7 +454,7 @@ int TrollEngine::drawRoom(char *menu) {
}
}
- _gfx->doUpdate();
+ g_system->updateScreen();
char tmp[10];
strncat(menu, (char *)_gameData + _locMessagesIdx[_currentRoom], 39);
@@ -464,7 +464,7 @@ int TrollEngine::drawRoom(char *menu) {
sprintf(tmp, "\n %d.", i);
strcat(menu, tmp);
- strncat(menu, (char *)_gameData + _options[_roomDescs[_roomPicture - 1].options[i]- 1], 35);
+ strncat(menu, (char *)_gameData + _options[_roomDescs[_roomPicture - 1].options[i] - 1], 35);
n = i + 1;
}
@@ -498,7 +498,7 @@ void TrollEngine::pickupTreasure(int treasureId) {
if (_currentRoom != 24) {
clearTextArea();
drawPic(_currentRoom, false, true);
- _gfx->doUpdate();
+ g_system->updateScreen();
}
printUserMessage(treasureId + 16);
@@ -546,7 +546,7 @@ void TrollEngine::printUserMessage(int msgId) {
void TrollEngine::gameLoop() {
bool done = false;
- char menu[160+5];
+ char menu[160 + 5];
int currentOption, numberOfOptions;
int roomParam;
int haveFlashlight;
@@ -584,7 +584,7 @@ void TrollEngine::gameLoop() {
printUserMessage(13);
break;
}
- // fall down
+ // fall down
case OT_GO:
_currentRoom = roomParam;
_roomPicture = _roomPicStartIdx[_currentRoom];
@@ -618,7 +618,7 @@ void TrollEngine::gameLoop() {
haveFlashlight = true;
_locMessagesIdx[_currentRoom] = IDO_TRO_LOCMESSAGES +
- (roomParam + 42) * 39;
+ (roomParam + 42) * 39;
pickupTreasure(roomParam);
}
@@ -730,10 +730,11 @@ void TrollEngine::init() {
//SetScreenPar(320, 200, (char *)ibm_fontdata);
const int gaps[] = { 0x3A40, 0x4600, 0x4800, 0x5800, 0x5a00, 0x6a00,
- 0x6c00, 0x7400, 0x7600, 0x7c00, 0x7e00, 0x8e00,
- 0x9000, 0xa000, 0xa200, 0xb200, 0xb400, 0xc400,
- 0xc600, 0xd600, 0xd800, 0xe800, 0xea00, 0xfa00,
- 0xfc00, 0x10c00, 0x10e00, 0x11e00, 0x12000, 0x13000 };
+ 0x6c00, 0x7400, 0x7600, 0x7c00, 0x7e00, 0x8e00,
+ 0x9000, 0xa000, 0xa200, 0xb200, 0xb400, 0xc400,
+ 0xc600, 0xd600, 0xd800, 0xe800, 0xea00, 0xfa00,
+ 0xfc00, 0x10c00, 0x10e00, 0x11e00, 0x12000, 0x13000
+ };
Common::File infile;
if (!infile.open(IDA_TRO_BINNAME))
diff --git a/engines/agi/preagi_troll.h b/engines/agi/preagi_troll.h
index 41ddbea166..4f2be7056b 100644
--- a/engines/agi/preagi_troll.h
+++ b/engines/agi/preagi_troll.h
@@ -27,87 +27,87 @@ namespace Agi {
// strings
-#define IDS_TRO_DISK "ERROR ERROR !"
-#define IDS_TRO_PATH_PIC "%s"
-
-#define IDS_TRO_PRESSANYKEY "PRESS ANY KEY TO CONTINUE:"
-
-#define IDS_TRO_INTRO_0 "SIERRA ON-LINE INC."
-#define IDS_TRO_INTRO_1 "Presents :"
-#define IDS_TRO_INTRO_2 "Copyright 1984 Sierra On-Line Inc."
-#define IDS_TRO_INTRO_3 " Press any key to continue. "
-#define IDS_TRO_INTRO_4 "HAVE YOU PLAYED THIS GAME BEFORE ?"
-#define IDS_TRO_INTRO_5 "PRESS <Y> OR <N>"
-
-#define IDS_TRO_TUTORIAL_0 " First press the <space bar>.\n 1. Turn the screen GREEN.\n 2. Turn the screen BLACK.\n *3. SEE a SURPRISE, and then more."
-#define IDS_TRO_TUTORIAL_1 " Press <return> to make your choice.\n 1. Turn the screen GREEN.\n 2. Turn the screen BLACK.\n 3. SEE a SURPRISE, and then more."
-//#define IDS_TRO_TUTORIAL_0 "First press the <space bar>."
-//#define IDS_TRO_TUTORIAL_1 "1. Turn the screen GREEN."
-//#define IDS_TRO_TUTORIAL_2 "2. Turn the screen BLACK."
-//#define IDS_TRO_TUTORIAL_3 "3. SEE a SURPRISE, and then more."
-//#define IDS_TRO_TUTORIAL_4 "Press <return> to make your choice."
-#define IDS_TRO_TUTORIAL_5 "Would you like more practice ?"
-#define IDS_TRO_TUTORIAL_6 "Press <Y> for yes, <N> for no."
-#define IDS_TRO_TUTORIAL_7 "The evil TROLL has hidden all the"
-#define IDS_TRO_TUTORIAL_8 "Treasures of MARK, the Dwarf King."
-#define IDS_TRO_TUTORIAL_9 "Help KING MARK find his Treasures."
-#define IDS_TRO_TUTORIAL_10 "You can't take a Treasure if the TROLL"
-#define IDS_TRO_TUTORIAL_11 "is in the same picture as the Treasure."
-#define IDS_TRO_TUTORIAL_12 "To make the TROLL go away you have to"
-#define IDS_TRO_TUTORIAL_13 "make the picture change."
-#define IDS_TRO_TUTORIAL_14 "During the game see the Treasures you"
-#define IDS_TRO_TUTORIAL_15 "have already found by pressing <F>."
-#define IDS_TRO_TUTORIAL_16 "During the game you can turn the sound"
-#define IDS_TRO_TUTORIAL_17 "on or off by pressing the <S> key "
-#define IDS_TRO_TUTORIAL_18 "while holding down the <Ctrl> key."
-#define IDS_TRO_TUTORIAL_19 "The TROLL has hidden these Treasures:"
-
-#define IDS_TRO_CREDITS_0 "Prepare to enter the world of . . ."
-#define IDS_TRO_CREDITS_1 "TROLL'S TALE (tm)"
-#define IDS_TRO_CREDITS_2 "------------"
-#define IDS_TRO_CREDITS_3 "Written by MIKE MACCHESNEY"
-#define IDS_TRO_CREDITS_4 "Conversion by PETER OLIPHANT"
-#define IDS_TRO_CREDITS_5 "Graphic Art by DOUG MACNEILL"
-#define IDS_TRO_CREDITS_6 "Original Version by AL LOWE"
-
-#define IDS_TRO_TREASURE_0 "TREASURES FOUND"
-#define IDS_TRO_TREASURE_1 "---------------"
-#define IDS_TRO_TREASURE_2 "NONE"
-#define IDS_TRO_TREASURE_3 "THERE ARE STILL %d TREASURES TO FIND"
-#define IDS_TRO_TREASURE_4 "%d TREASURES TO FIND"
-#define IDS_TRO_TREASURE_5 "%d TREASURE TO FIND"
-#define IDS_TRO_TREASURE_6 "YOU HAVE FOUND ALL OF THE TREASURES!!"
-#define IDS_TRO_TREASURE_7 "THERE'S ONLY ONE MORE TREASURE TO FIND."
-#define IDS_TRO_TREASURE_8 "GREAT!! YOU HAVE FOUND EVERY TREASURE."
-#define IDS_TRO_TREASURE_9 "TAKE THE TREASURES TO THE GUARD."
-
-#define IDS_TRO_GAMEOVER_0 "You took %d moves to complete TROLL'S"
-#define IDS_TRO_GAMEOVER_1 "TALE. Do you think you can do better?"
+#define IDS_TRO_DISK "ERROR ERROR !"
+#define IDS_TRO_PATH_PIC "%s"
+
+#define IDS_TRO_PRESSANYKEY "PRESS ANY KEY TO CONTINUE:"
+
+#define IDS_TRO_INTRO_0 "SIERRA ON-LINE INC."
+#define IDS_TRO_INTRO_1 "Presents :"
+#define IDS_TRO_INTRO_2 "Copyright 1984 Sierra On-Line Inc."
+#define IDS_TRO_INTRO_3 " Press any key to continue. "
+#define IDS_TRO_INTRO_4 "HAVE YOU PLAYED THIS GAME BEFORE ?"
+#define IDS_TRO_INTRO_5 "PRESS <Y> OR <N>"
+
+#define IDS_TRO_TUTORIAL_0 " First press the <space bar>.\n 1. Turn the screen GREEN.\n 2. Turn the screen BLACK.\n *3. SEE a SURPRISE, and then more."
+#define IDS_TRO_TUTORIAL_1 " Press <return> to make your choice.\n 1. Turn the screen GREEN.\n 2. Turn the screen BLACK.\n 3. SEE a SURPRISE, and then more."
+//#define IDS_TRO_TUTORIAL_0 "First press the <space bar>."
+//#define IDS_TRO_TUTORIAL_1 "1. Turn the screen GREEN."
+//#define IDS_TRO_TUTORIAL_2 "2. Turn the screen BLACK."
+//#define IDS_TRO_TUTORIAL_3 "3. SEE a SURPRISE, and then more."
+//#define IDS_TRO_TUTORIAL_4 "Press <return> to make your choice."
+#define IDS_TRO_TUTORIAL_5 "Would you like more practice ?"
+#define IDS_TRO_TUTORIAL_6 "Press <Y> for yes, <N> for no."
+#define IDS_TRO_TUTORIAL_7 "The evil TROLL has hidden all the"
+#define IDS_TRO_TUTORIAL_8 "Treasures of MARK, the Dwarf King."
+#define IDS_TRO_TUTORIAL_9 "Help KING MARK find his Treasures."
+#define IDS_TRO_TUTORIAL_10 "You can't take a Treasure if the TROLL"
+#define IDS_TRO_TUTORIAL_11 "is in the same picture as the Treasure."
+#define IDS_TRO_TUTORIAL_12 "To make the TROLL go away you have to"
+#define IDS_TRO_TUTORIAL_13 "make the picture change."
+#define IDS_TRO_TUTORIAL_14 "During the game see the Treasures you"
+#define IDS_TRO_TUTORIAL_15 "have already found by pressing <F>."
+#define IDS_TRO_TUTORIAL_16 "During the game you can turn the sound"
+#define IDS_TRO_TUTORIAL_17 "on or off by pressing the <S> key "
+#define IDS_TRO_TUTORIAL_18 "while holding down the <Ctrl> key."
+#define IDS_TRO_TUTORIAL_19 "The TROLL has hidden these Treasures:"
+
+#define IDS_TRO_CREDITS_0 "Prepare to enter the world of . . ."
+#define IDS_TRO_CREDITS_1 "TROLL'S TALE (tm)"
+#define IDS_TRO_CREDITS_2 "------------"
+#define IDS_TRO_CREDITS_3 "Written by MIKE MACCHESNEY"
+#define IDS_TRO_CREDITS_4 "Conversion by PETER OLIPHANT"
+#define IDS_TRO_CREDITS_5 "Graphic Art by DOUG MACNEILL"
+#define IDS_TRO_CREDITS_6 "Original Version by AL LOWE"
+
+#define IDS_TRO_TREASURE_0 "TREASURES FOUND"
+#define IDS_TRO_TREASURE_1 "---------------"
+#define IDS_TRO_TREASURE_2 "NONE"
+#define IDS_TRO_TREASURE_3 "THERE ARE STILL %d TREASURES TO FIND"
+#define IDS_TRO_TREASURE_4 "%d TREASURES TO FIND"
+#define IDS_TRO_TREASURE_5 "%d TREASURE TO FIND"
+#define IDS_TRO_TREASURE_6 "YOU HAVE FOUND ALL OF THE TREASURES!!"
+#define IDS_TRO_TREASURE_7 "THERE'S ONLY ONE MORE TREASURE TO FIND."
+#define IDS_TRO_TREASURE_8 "GREAT!! YOU HAVE FOUND EVERY TREASURE."
+#define IDS_TRO_TREASURE_9 "TAKE THE TREASURES TO THE GUARD."
+
+#define IDS_TRO_GAMEOVER_0 "You took %d moves to complete TROLL'S"
+#define IDS_TRO_GAMEOVER_1 "TALE. Do you think you can do better?"
// picture
#define IDI_TRO_PICNUM 47
-#define IDI_TRO_PIC_WIDTH 160
-#define IDI_TRO_PIC_HEIGHT 168
-#define IDI_TRO_PIC_X0 0
-#define IDI_TRO_PIC_Y0 0
-#define IDI_TRO_PIC_FLAGS IDF_AGI_PIC_V15
+#define IDI_TRO_PIC_WIDTH 160
+#define IDI_TRO_PIC_HEIGHT 168
+#define IDI_TRO_PIC_X0 0
+#define IDI_TRO_PIC_Y0 0
+#define IDI_TRO_PIC_FLAGS IDF_AGI_PIC_V15
// max values
-#define IDI_TRO_MAX_TREASURE 16
-#define IDI_TRO_MAX_OPTION 3
+#define IDI_TRO_MAX_TREASURE 16
+#define IDI_TRO_MAX_OPTION 3
-#define IDI_TRO_SEL_OPTION_1 0
-#define IDI_TRO_SEL_OPTION_2 1
-#define IDI_TRO_SEL_OPTION_3 2
+#define IDI_TRO_SEL_OPTION_1 0
+#define IDI_TRO_SEL_OPTION_2 1
+#define IDI_TRO_SEL_OPTION_3 2
-#define IDI_TRO_MAX_ROW_PIC 21
+#define IDI_TRO_MAX_ROW_PIC 21
-#define IDI_TRO_NUM_ROOMDESCS 65
-#define IDI_TRO_NUM_OPTIONS 129
-#define IDI_TRO_NUM_NUMROOMS 43
+#define IDI_TRO_NUM_ROOMDESCS 65
+#define IDI_TRO_NUM_OPTIONS 129
+#define IDI_TRO_NUM_NUMROOMS 43
#define IDI_TRO_NUM_USERMSGS 34
@@ -120,7 +120,7 @@ namespace Agi {
#define IDA_TRO_BINNAME "troll.img"
#define IDO_TRO_DATA_START 0x3A40
-#define IDO_TRO_PIC_START 0x3EF5
+#define IDO_TRO_PIC_START 0x3EF5
#define IDO_TRO_LOCMESSAGES 0x1F7C
#define IDO_TRO_USERMESSAGES 0x34A4
#define IDO_TRO_ROOMDESCS 0x0082
@@ -198,7 +198,7 @@ private:
void playTune(int tune, int len);
- bool getMenuSel(const char*, int*, int);
+ bool getMenuSel(const char *, int *, int);
void drawMenu(const char *szMenu, int iSel);
diff --git a/engines/agi/preagi_winnie.cpp b/engines/agi/preagi_winnie.cpp
index a91ad24fc6..8fb9daca5e 100644
--- a/engines/agi/preagi_winnie.cpp
+++ b/engines/agi/preagi_winnie.cpp
@@ -134,7 +134,7 @@ uint32 WinnieEngine::readObj(int iObj, uint8 *buffer) {
Common::File file;
if (!file.open(fileName)) {
- warning ("Could not open file \'%s\'", fileName.c_str());
+ warning("Could not open file \'%s\'", fileName.c_str());
return 0;
}
@@ -192,16 +192,16 @@ void WinnieEngine::randomize() {
void WinnieEngine::intro() {
drawPic(IDS_WTP_FILE_LOGO);
printStr(IDS_WTP_INTRO_0);
- _gfx->doUpdate();
+ g_system->updateScreen();
_system->delayMillis(0x640);
if (getPlatform() == Common::kPlatformAmiga)
- _gfx->clearScreen(0);
+ _gfx->clearDisplay(0);
drawPic(IDS_WTP_FILE_TITLE);
printStr(IDS_WTP_INTRO_1);
- _gfx->doUpdate();
+ g_system->updateScreen();
_system->delayMillis(0x640);
if (!playSound(IDI_WTP_SND_POOH_0))
@@ -226,11 +226,11 @@ void WinnieEngine::setTakeDrop(int fCanSel[]) {
fCanSel[IDI_WTP_SEL_DROP] = _gameStateWinnie.iObjHave;
}
-void WinnieEngine::setFlag(int iFlag) {
+void WinnieEngine::setWinnieFlag(int iFlag) {
_gameStateWinnie.fGame[iFlag] = 1;
}
-void WinnieEngine::clearFlag(int iFlag) {
+void WinnieEngine::clearWinnieFlag(int iFlag) {
_gameStateWinnie.fGame[iFlag] = 0;
}
@@ -274,9 +274,10 @@ int WinnieEngine::parser(int pc, int index, uint8 *buffer) {
memset(fCanSel, 0, sizeof(fCanSel));
// check if NSEW directions should be displayed
- if (hdr.roomNew[0])
+ if (hdr.roomNew[0]) {
fCanSel[IDI_WTP_SEL_NORTH] = fCanSel[IDI_WTP_SEL_SOUTH] =
fCanSel[IDI_WTP_SEL_EAST] = fCanSel[IDI_WTP_SEL_WEST] = true;
+ }
// check if object in room or player carrying one
setTakeDrop(fCanSel);
@@ -291,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:
@@ -404,11 +405,11 @@ int WinnieEngine::parser(int pc, int index, uint8 *buffer) {
break;
case IDO_WTP_FLAG_CLEAR:
opcode = *(buffer + pc++);
- clearFlag(opcode);
+ clearWinnieFlag(opcode);
break;
case IDO_WTP_FLAG_SET:
opcode = *(buffer + pc++);
- setFlag(opcode);
+ setWinnieFlag(opcode);
break;
case IDO_WTP_GAME_OVER:
gameOver();
@@ -452,7 +453,7 @@ int WinnieEngine::parser(int pc, int index, uint8 *buffer) {
if (iBlock == 1)
return IDI_WTP_PAR_OK;
- _gfx->doUpdate();
+ g_system->updateScreen();
}
return IDI_WTP_PAR_OK;
@@ -477,7 +478,7 @@ void WinnieEngine::inventory() {
Common::String missing = Common::String::format(IDS_WTP_INVENTORY_1, _gameStateWinnie.nObjMiss);
drawStr(IDI_WTP_ROW_OPTION_4, IDI_WTP_COL_MENU, IDA_DEFAULT, missing.c_str());
- _gfx->doUpdate();
+ g_system->updateScreen();
getSelection(kSelAnyKey);
}
@@ -494,7 +495,7 @@ void WinnieEngine::printObjStr(int iObj, int iStr) {
bool WinnieEngine::isRightObj(int iRoom, int iObj, int *iCode) {
WTP_ROOM_HDR roomhdr;
- WTP_OBJ_HDR objhdr;
+ WTP_OBJ_HDR objhdr;
uint8 *roomdata = (uint8 *)malloc(4096);
uint8 *objdata = (uint8 *)malloc(2048);
@@ -755,7 +756,7 @@ void WinnieEngine::drawMenu(char *szMenu, int iSel, int fCanSel[]) {
break;
}
drawStr(iRow, iCol - 1, IDA_DEFAULT, ">");
- _gfx->doUpdate();
+ g_system->updateScreen();
}
void WinnieEngine::incMenuSel(int *iSel, int fCanSel[]) {
@@ -777,7 +778,7 @@ void WinnieEngine::getMenuMouseSel(int *iSel, int fCanSel[], int x, int y) {
case IDI_WTP_ROW_OPTION_1:
case IDI_WTP_ROW_OPTION_2:
case IDI_WTP_ROW_OPTION_3:
- if (fCanSel[y - IDI_WTP_ROW_OPTION_1]) *iSel = y - IDI_WTP_ROW_OPTION_1;
+ if (fCanSel[y - IDI_WTP_ROW_OPTION_1]) *iSel = y - IDI_WTP_ROW_OPTION_1;
break;
case IDI_WTP_ROW_OPTION_4:
if (fCanSel[IDI_WTP_SEL_NORTH] && (x > IDI_WTP_COL_NORTH - 1) && (x < 6)) *iSel = IDI_WTP_SEL_NORTH;
@@ -821,15 +822,16 @@ void WinnieEngine::getMenuSel(char *szMenu, int *iSel, int fCanSel[]) {
// Change cursor
if (fCanSel[IDI_WTP_SEL_NORTH] && hotspotNorth.contains(event.mouse.x, event.mouse.y)) {
- _gfx->setCursorPalette(true);
+ //_gfx->setCursorPalette(true);
+ // ????
} else if (fCanSel[IDI_WTP_SEL_SOUTH] && hotspotSouth.contains(event.mouse.x, event.mouse.y)) {
- _gfx->setCursorPalette(true);
+ //_gfx->setCursorPalette(true);
} else if (fCanSel[IDI_WTP_SEL_WEST] && hotspotWest.contains(event.mouse.x, event.mouse.y)) {
- _gfx->setCursorPalette(true);
+ //_gfx->setCursorPalette(true);
} else if (fCanSel[IDI_WTP_SEL_EAST] && hotspotEast.contains(event.mouse.x, event.mouse.y)) {
- _gfx->setCursorPalette(true);
+ //_gfx->setCursorPalette(true);
} else {
- _gfx->setCursorPalette(false);
+ //_gfx->setCursorPalette(false);
}
break;
@@ -838,47 +840,52 @@ void WinnieEngine::getMenuSel(char *szMenu, int *iSel, int fCanSel[]) {
if (fCanSel[IDI_WTP_SEL_NORTH] && hotspotNorth.contains(event.mouse.x, event.mouse.y)) {
*iSel = IDI_WTP_SEL_NORTH;
makeSel(iSel, fCanSel);
- _gfx->setCursorPalette(false);
+ //_gfx->setCursorPalette(false);
+ // TODO???
return;
} else if (fCanSel[IDI_WTP_SEL_SOUTH] && hotspotSouth.contains(event.mouse.x, event.mouse.y)) {
*iSel = IDI_WTP_SEL_SOUTH;
makeSel(iSel, fCanSel);
- _gfx->setCursorPalette(false);
+ //_gfx->setCursorPalette(false);
+ // TODO???
return;
} else if (fCanSel[IDI_WTP_SEL_WEST] && hotspotWest.contains(event.mouse.x, event.mouse.y)) {
*iSel = IDI_WTP_SEL_WEST;
makeSel(iSel, fCanSel);
- _gfx->setCursorPalette(false);
+ //_gfx->setCursorPalette(false);
+ // TODO???
return;
} else if (fCanSel[IDI_WTP_SEL_EAST] && hotspotEast.contains(event.mouse.x, event.mouse.y)) {
*iSel = IDI_WTP_SEL_EAST;
makeSel(iSel, fCanSel);
- _gfx->setCursorPalette(false);
+ //_gfx->setCursorPalette(false);
+ // TODO???
return;
} else {
- _gfx->setCursorPalette(false);
+ //_gfx->setCursorPalette(false);
+ // TODO???
}
switch (*iSel) {
- case IDI_WTP_SEL_OPT_1:
- case IDI_WTP_SEL_OPT_2:
- case IDI_WTP_SEL_OPT_3:
- for (int iSel2 = 0; iSel2 < IDI_WTP_MAX_OPTION; iSel2++) {
- if (*iSel == (fCanSel[iSel2 + IDI_WTP_SEL_REAL_OPT_1] - 1)) {
- *iSel = iSel2;
- // Menu selection made, hide the mouse cursor
- CursorMan.showMouse(false);
- return;
- }
- }
- break;
- default:
- if (fCanSel[*iSel]) {
+ case IDI_WTP_SEL_OPT_1:
+ case IDI_WTP_SEL_OPT_2:
+ case IDI_WTP_SEL_OPT_3:
+ for (int iSel2 = 0; iSel2 < IDI_WTP_MAX_OPTION; iSel2++) {
+ if (*iSel == (fCanSel[iSel2 + IDI_WTP_SEL_REAL_OPT_1] - 1)) {
+ *iSel = iSel2;
// Menu selection made, hide the mouse cursor
CursorMan.showMouse(false);
return;
}
- break;
+ }
+ break;
+ default:
+ if (fCanSel[*iSel]) {
+ // Menu selection made, hide the mouse cursor
+ CursorMan.showMouse(false);
+ return;
+ }
+ break;
}
break;
case Common::EVENT_RBUTTONUP:
@@ -941,7 +948,7 @@ void WinnieEngine::getMenuSel(char *szMenu, int *iSel, int fCanSel[]) {
break;
case Common::KEYCODE_s:
if (event.kbd.flags & Common::KBD_CTRL) {
- flipflag(fSoundOn);
+ flipFlag(VM_FLAG_SOUND_ON);
} else {
*iSel = IDI_WTP_SEL_SOUTH;
makeSel(iSel, fCanSel);
@@ -987,7 +994,7 @@ void WinnieEngine::getMenuSel(char *szMenu, int *iSel, int fCanSel[]) {
}
break;
default:
- if (!event.kbd.flags) { // if the control/alt/shift keys are not pressed
+ if (!event.kbd.flags) { // if the control/alt/shift keys are not pressed
keyHelp();
clrMenuSel(iSel, fCanSel);
}
@@ -1016,7 +1023,7 @@ void WinnieEngine::gameLoop() {
readRoom(_room, roomdata, hdr);
drawRoomPic();
- _gfx->doUpdate();
+ g_system->updateScreen();
decodePhase = 1;
}
@@ -1064,7 +1071,7 @@ void WinnieEngine::drawPic(const char *szName) {
Common::File file;
if (!file.open(fileName)) {
- warning ("Could not open file \'%s\'", fileName.c_str());
+ warning("Could not open file \'%s\'", fileName.c_str());
return;
}
@@ -1083,7 +1090,7 @@ void WinnieEngine::drawObjPic(int iObj, int x0, int y0) {
if (!iObj)
return;
- WTP_OBJ_HDR objhdr;
+ WTP_OBJ_HDR objhdr;
uint8 *buffer = (uint8 *)malloc(2048);
uint32 objSize = readObj(iObj, buffer);
parseObjHeader(&objhdr, buffer, sizeof(WTP_OBJ_HDR));
@@ -1102,7 +1109,7 @@ void WinnieEngine::drawRoomPic() {
int iObj = getObjInRoom(_room);
// clear gfx screen
- _gfx->clearScreen(0);
+ _gfx->clearDisplay(0);
// read room picture
readRoom(_room, buffer, roomhdr);
@@ -1175,7 +1182,8 @@ void WinnieEngine::clrMenuSel(int *iSel, int fCanSel[]) {
while (!fCanSel[*iSel]) {
*iSel += 1;
}
- _gfx->setCursorPalette(false);
+ //_gfx->setCursorPalette(false);
+ // TODO???
}
void WinnieEngine::printRoomStr(int iRoom, int iStr) {
@@ -1209,7 +1217,7 @@ void WinnieEngine::saveGame() {
if (!outfile)
return;
- outfile->writeUint32BE(MKTAG('W','I','N','N')); // header
+ outfile->writeUint32BE(MKTAG('W', 'I', 'N', 'N')); // header
outfile->writeByte(WTP_SAVEGAME_VERSION);
outfile->writeByte(_gameStateWinnie.fSound);
@@ -1244,7 +1252,7 @@ void WinnieEngine::loadGame() {
if (!infile)
return;
- if (infile->readUint32BE() == MKTAG('W','I','N','N')) {
+ if (infile->readUint32BE() == MKTAG('W', 'I', 'N', 'N')) {
saveVersion = infile->readByte();
if (saveVersion != WTP_SAVEGAME_VERSION)
warning("Old save game version (%d, current version is %d). Will try and read anyway, but don't be surprised if bad things happen", saveVersion, WTP_SAVEGAME_VERSION);
@@ -1262,25 +1270,25 @@ void WinnieEngine::loadGame() {
// Since we read the save file data as little-endian, we skip the first byte of each
// variable
- infile->seek(0); // Jump back to the beginning of the file
+ infile->seek(0); // Jump back to the beginning of the file
- infile->readUint16LE(); // skip unused field
- infile->readByte(); // first 8 bits of fSound
+ infile->readUint16LE(); // skip unused field
+ infile->readByte(); // first 8 bits of fSound
_gameStateWinnie.fSound = infile->readByte();
- infile->readByte(); // first 8 bits of nMoves
+ infile->readByte(); // first 8 bits of nMoves
_gameStateWinnie.nMoves = infile->readByte();
- infile->readByte(); // first 8 bits of nObjMiss
+ infile->readByte(); // first 8 bits of nObjMiss
_gameStateWinnie.nObjMiss = infile->readByte();
- infile->readByte(); // first 8 bits of nObjRet
+ infile->readByte(); // first 8 bits of nObjRet
_gameStateWinnie.nObjRet = infile->readByte();
- infile->readUint16LE(); // skip unused field
- infile->readUint16LE(); // skip unused field
- infile->readUint16LE(); // skip unused field
- infile->readByte(); // first 8 bits of iObjHave
+ infile->readUint16LE(); // skip unused field
+ infile->readUint16LE(); // skip unused field
+ infile->readUint16LE(); // skip unused field
+ infile->readByte(); // first 8 bits of iObjHave
_gameStateWinnie.iObjHave = infile->readByte();
- infile->readUint16LE(); // skip unused field
- infile->readUint16LE(); // skip unused field
- infile->readUint16LE(); // skip unused field
+ infile->readUint16LE(); // skip unused field
+ infile->readUint16LE(); // skip unused field
+ infile->readUint16LE(); // skip unused field
}
for (i = 0; i < IDI_WTP_MAX_FLAG; i++)
@@ -1322,7 +1330,7 @@ WinnieEngine::~WinnieEngine() {
void WinnieEngine::init() {
// Initialize sound
- switch (MidiDriver::getMusicType(MidiDriver::detectDevice(MDT_PCSPK|MDT_PCJR))) {
+ switch (MidiDriver::getMusicType(MidiDriver::detectDevice(MDT_PCSPK | MDT_PCJR))) {
case MT_PCSPK:
_soundemu = SOUND_EMU_PC;
break;
@@ -1335,7 +1343,7 @@ void WinnieEngine::init() {
}
_sound = new SoundMgr(this, _mixer);
- setflag(fSoundOn, true); // enable sound
+ setFlag(VM_FLAG_SOUND_ON, true); // enable sound
memset(&_gameStateWinnie, 0, sizeof(_gameStateWinnie));
_gameStateWinnie.fSound = 1;
diff --git a/engines/agi/preagi_winnie.h b/engines/agi/preagi_winnie.h
index b5e8b8d10b..7175c282e8 100644
--- a/engines/agi/preagi_winnie.h
+++ b/engines/agi/preagi_winnie.h
@@ -25,123 +25,123 @@
namespace Agi {
-#define WTP_SAVEGAME_VERSION 1
-#define IDI_XOR_KEY 0x80
+#define WTP_SAVEGAME_VERSION 1
+#define IDI_XOR_KEY 0x80
// strings
-#define IDS_WTP_ROOM_DOS "rooms/rm.%02d"
-#define IDS_WTP_ROOM_AMIGA "room.%d"
-#define IDS_WTP_ROOM_C64 "room%02d"
-#define IDS_WTP_ROOM_APPLE "room%d.obj"
-#define IDS_WTP_OBJ_DOS "obj.%02d"
-#define IDS_WTP_OBJ_AMIGA "object.%d"
-#define IDS_WTP_OBJ_C64 "object%02d"
-#define IDS_WTP_OBJ_APPLE "object%d.obj"
-#define IDS_WTP_SND_DOS "snd.%02d"
-#define IDS_WTP_SND_AMIGA "Sounds"
-#define IDS_WTP_SND_C64 "sound.obj"
-#define IDS_WTP_SND_APPLE "sound.obj"
-
-#define IDS_WTP_FILE_LOGO "logo"
-#define IDS_WTP_FILE_TITLE "title"
-#define IDS_WTP_FILE_SAVEGAME "savegame"
-#define IDS_WTP_FILE_RND "rnd"
-
-#define IDS_WTP_DISK_ERROR "There is a problem with your disk drive.Please make sure your Winnie-the-Pooh disk is in the drive correctly."
-
-#define IDS_WTP_INTRO_0 " PRESENT"
-#define IDS_WTP_INTRO_1 " TM designates trademark of\n Sierra On-Line, Inc.\n (c) 1985 Walt Disney Productions"
-
-#define IDS_WTP_HELP_0 "The <SPACE BAR> moves the pointer. Press <RETURN> when it is by the choice you want. Press the <Backspace> key to see what you just finished reading."
-#define IDS_WTP_HELP_1 "Press <C> to see what you are carrying. <Ctrl-S> turns the sound off and on. <ESC> takes you to the playroom (in caseyou get lost or want to save the game)."
-
-#define IDS_WTP_GAME_OVER_0 "Congratulations!! You did it! You returned everything that was lost. Now,Christopher Robin invites you to a Hero party."
-#define IDS_WTP_GAME_OVER_1 "The good news is: YOU are the Hero!! The bad news is: you have to find the party by yourself. Good luck!"
-
-#define IDS_WTP_OWL_0 "\"For example, that object you are carrying now is interesting. I know I've seen it before. Hmmm. Let me think about this . . .\""
-#define IDS_WTP_OWL_1 "\"You know, this object here beside me isfamiliar. I'm sure I could give you some sort of clue about it. Let me see. . .\""
-
-#define IDS_WTP_WIND_0 "Oh, no! The Blustery Wind begins to howl. It has returned, and mixed up all the objects in the Wood."
-#define IDS_WTP_WIND_1 "But don't worry. Everyone still has theobjects you returned to them.\n\n (Today must be Winds-day!)"
-#define IDS_WTP_TIGGER "\"Hallooooo, there!!!! It's ME, Tigger! Let's BOUNCE!\""
-#define IDS_WTP_MIST "Oh, look out! The mysterious mist is coming in. It gets so thick that you can't see through it. Just keep walkingand it will soon clear up."
-
-#define IDS_WTP_SONG_0 "Winnie-the-Pooh, Winnie-the-Pooh, Tubby little cubby all stuffed with fluff, He's Winnie-the-Pooh, Winnie-the-Pooh, Willy, nilly, silly, old bear."
-#define IDS_WTP_SONG_1 "Deep in the Hundred Acre Wood, Where Christopher Robin plays, You will find the enchanted neighborhoodof Christopher's childhood days."
-#define IDS_WTP_SONG_2 "A donkey named Eeyore is his friend, and Kanga and little Roo. There's Rabbit and Piglet and there's Owl But most of all Winnie-the-Pooh!"
-
-#define IDS_WTP_NSEW "North South East West"
-#define IDS_WTP_TAKE "Take"
-#define IDS_WTP_DROP "Drop"
-#define IDS_WTP_CANT_GO "\nSorry, but you can't go that way."
-#define IDS_WTP_CANT_TAKE "You can't take it. You can only carry one object at a time."
-#define IDS_WTP_CANT_DROP "You can't drop it. Another object is already here."
-#define IDS_WTP_WRONG_PLACE "\nOk, but it doesn't belong here."
-#define IDS_WTP_OK "\nOk."
-
-#define IDS_WTP_INVENTORY_0 "You are carrying nothing."
-#define IDS_WTP_INVENTORY_1 "Number of objects still missing: %d"
+#define IDS_WTP_ROOM_DOS "rooms/rm.%02d"
+#define IDS_WTP_ROOM_AMIGA "room.%d"
+#define IDS_WTP_ROOM_C64 "room%02d"
+#define IDS_WTP_ROOM_APPLE "room%d.obj"
+#define IDS_WTP_OBJ_DOS "obj.%02d"
+#define IDS_WTP_OBJ_AMIGA "object.%d"
+#define IDS_WTP_OBJ_C64 "object%02d"
+#define IDS_WTP_OBJ_APPLE "object%d.obj"
+#define IDS_WTP_SND_DOS "snd.%02d"
+#define IDS_WTP_SND_AMIGA "Sounds"
+#define IDS_WTP_SND_C64 "sound.obj"
+#define IDS_WTP_SND_APPLE "sound.obj"
+
+#define IDS_WTP_FILE_LOGO "logo"
+#define IDS_WTP_FILE_TITLE "title"
+#define IDS_WTP_FILE_SAVEGAME "savegame"
+#define IDS_WTP_FILE_RND "rnd"
+
+#define IDS_WTP_DISK_ERROR "There is a problem with your disk drive.Please make sure your Winnie-the-Pooh disk is in the drive correctly."
+
+#define IDS_WTP_INTRO_0 " PRESENT"
+#define IDS_WTP_INTRO_1 " TM designates trademark of\n Sierra On-Line, Inc.\n (c) 1985 Walt Disney Productions"
+
+#define IDS_WTP_HELP_0 "The <SPACE BAR> moves the pointer. Press <RETURN> when it is by the choice you want. Press the <Backspace> key to see what you just finished reading."
+#define IDS_WTP_HELP_1 "Press <C> to see what you are carrying. <Ctrl-S> turns the sound off and on. <ESC> takes you to the playroom (in caseyou get lost or want to save the game)."
+
+#define IDS_WTP_GAME_OVER_0 "Congratulations!! You did it! You returned everything that was lost. Now,Christopher Robin invites you to a Hero party."
+#define IDS_WTP_GAME_OVER_1 "The good news is: YOU are the Hero!! The bad news is: you have to find the party by yourself. Good luck!"
+
+#define IDS_WTP_OWL_0 "\"For example, that object you are carrying now is interesting. I know I've seen it before. Hmmm. Let me think about this . . .\""
+#define IDS_WTP_OWL_1 "\"You know, this object here beside me isfamiliar. I'm sure I could give you some sort of clue about it. Let me see. . .\""
+
+#define IDS_WTP_WIND_0 "Oh, no! The Blustery Wind begins to howl. It has returned, and mixed up all the objects in the Wood."
+#define IDS_WTP_WIND_1 "But don't worry. Everyone still has theobjects you returned to them.\n\n (Today must be Winds-day!)"
+#define IDS_WTP_TIGGER "\"Hallooooo, there!!!! It's ME, Tigger! Let's BOUNCE!\""
+#define IDS_WTP_MIST "Oh, look out! The mysterious mist is coming in. It gets so thick that you can't see through it. Just keep walkingand it will soon clear up."
+
+#define IDS_WTP_SONG_0 "Winnie-the-Pooh, Winnie-the-Pooh, Tubby little cubby all stuffed with fluff, He's Winnie-the-Pooh, Winnie-the-Pooh, Willy, nilly, silly, old bear."
+#define IDS_WTP_SONG_1 "Deep in the Hundred Acre Wood, Where Christopher Robin plays, You will find the enchanted neighborhoodof Christopher's childhood days."
+#define IDS_WTP_SONG_2 "A donkey named Eeyore is his friend, and Kanga and little Roo. There's Rabbit and Piglet and there's Owl But most of all Winnie-the-Pooh!"
+
+#define IDS_WTP_NSEW "North South East West"
+#define IDS_WTP_TAKE "Take"
+#define IDS_WTP_DROP "Drop"
+#define IDS_WTP_CANT_GO "\nSorry, but you can't go that way."
+#define IDS_WTP_CANT_TAKE "You can't take it. You can only carry one object at a time."
+#define IDS_WTP_CANT_DROP "You can't drop it. Another object is already here."
+#define IDS_WTP_WRONG_PLACE "\nOk, but it doesn't belong here."
+#define IDS_WTP_OK "\nOk."
+
+#define IDS_WTP_INVENTORY_0 "You are carrying nothing."
+#define IDS_WTP_INVENTORY_1 "Number of objects still missing: %d"
// COMMODORE 64 version strings
-#define IDS_WTP_FILE_SAVEGAME_C64 "saved game"
-#define IDS_WTP_DISK_ERROR_C64 "There is a problem with your disk drive.Please make sure your disk is in the drive correctly."
-#define IDS_WTP_HELP_0_C64 "The <SPACE BAR> moves the pointer. Press <RETURN> when it is by the choice you want. <F1> brings back what you have already read."
-#define IDS_WTP_HELP_1_C64 "<F3> takes you back to the playroom (if you get lost, or want to save the game).<F5> turns the sound off and on. <F7> shows what you're carrying."
-#define IDS_WTP_WRONG_PLACE_C64 "\nOk, but this is not the right place."
+#define IDS_WTP_FILE_SAVEGAME_C64 "saved game"
+#define IDS_WTP_DISK_ERROR_C64 "There is a problem with your disk drive.Please make sure your disk is in the drive correctly."
+#define IDS_WTP_HELP_0_C64 "The <SPACE BAR> moves the pointer. Press <RETURN> when it is by the choice you want. <F1> brings back what you have already read."
+#define IDS_WTP_HELP_1_C64 "<F3> takes you back to the playroom (if you get lost, or want to save the game).<F5> turns the sound off and on. <F7> shows what you're carrying."
+#define IDS_WTP_WRONG_PLACE_C64 "\nOk, but this is not the right place."
// maximum values
-#define IDI_WTP_MAX_OBJ_MISSING 10
-
-#define IDI_WTP_MAX_ROOM 62
-#define IDI_WTP_MAX_OBJ 40
-#define IDI_WTP_MAX_SND 14
-#define IDI_WTP_MAX_PIC 2
-
-#define IDI_WTP_MAX_ROOM_NORMAL 57
-#define IDI_WTP_MAX_ROOM_TELEPORT 30
-#define IDI_WTP_MAX_ROOM_OBJ 42
-#define IDI_WTP_MAX_BLOCK 4
-#define IDI_WTP_MAX_STR 6
-#define IDI_WTP_MAX_OBJ_STR 4
-#define IDI_WTP_MAX_OBJ_STR_END 2
-#define IDI_WTP_MAX_FLAG 40
-#define IDI_WTP_MAX_OPTION 3
-#define IDI_WTP_MAX_DIR 4
-#define IDI_WTP_MAX_MOVES_UNTIL_WIND 150
+#define IDI_WTP_MAX_OBJ_MISSING 10
+
+#define IDI_WTP_MAX_ROOM 62
+#define IDI_WTP_MAX_OBJ 40
+#define IDI_WTP_MAX_SND 14
+#define IDI_WTP_MAX_PIC 2
+
+#define IDI_WTP_MAX_ROOM_NORMAL 57
+#define IDI_WTP_MAX_ROOM_TELEPORT 30
+#define IDI_WTP_MAX_ROOM_OBJ 42
+#define IDI_WTP_MAX_BLOCK 4
+#define IDI_WTP_MAX_STR 6
+#define IDI_WTP_MAX_OBJ_STR 4
+#define IDI_WTP_MAX_OBJ_STR_END 2
+#define IDI_WTP_MAX_FLAG 40
+#define IDI_WTP_MAX_OPTION 3
+#define IDI_WTP_MAX_DIR 4
+#define IDI_WTP_MAX_MOVES_UNTIL_WIND 150
// positions
-#define IDI_WTP_ROW_MENU 21
-#define IDI_WTP_ROW_OPTION_1 21
-#define IDI_WTP_ROW_OPTION_2 22
-#define IDI_WTP_ROW_OPTION_3 23
-#define IDI_WTP_ROW_OPTION_4 24
-
-#define IDI_WTP_COL_MENU 0
-#define IDI_WTP_COL_OPTION 1
-#define IDI_WTP_COL_NSEW 1
-#define IDI_WTP_COL_NORTH 1
-#define IDI_WTP_COL_SOUTH 8
-#define IDI_WTP_COL_EAST 15
-#define IDI_WTP_COL_WEST 21
-#define IDI_WTP_COL_TAKE 29
-#define IDI_WTP_COL_DROP 35
-#define IDI_WTP_COL_PRESENT 17
+#define IDI_WTP_ROW_MENU 21
+#define IDI_WTP_ROW_OPTION_1 21
+#define IDI_WTP_ROW_OPTION_2 22
+#define IDI_WTP_ROW_OPTION_3 23
+#define IDI_WTP_ROW_OPTION_4 24
+
+#define IDI_WTP_COL_MENU 0
+#define IDI_WTP_COL_OPTION 1
+#define IDI_WTP_COL_NSEW 1
+#define IDI_WTP_COL_NORTH 1
+#define IDI_WTP_COL_SOUTH 8
+#define IDI_WTP_COL_EAST 15
+#define IDI_WTP_COL_WEST 21
+#define IDI_WTP_COL_TAKE 29
+#define IDI_WTP_COL_DROP 35
+#define IDI_WTP_COL_PRESENT 17
// data file offset modifiers
-#define IDI_WTP_OFS_ROOM 0x5400
-#define IDI_WTP_OFS_OBJ 0x0800
+#define IDI_WTP_OFS_ROOM 0x5400
+#define IDI_WTP_OFS_OBJ 0x0800
// picture
-#define IDI_WTP_PIC_WIDTH 140
-#define IDI_WTP_PIC_HEIGHT 159
-#define IDI_WTP_PIC_X0 10
-#define IDI_WTP_PIC_Y0 0
-#define IDI_WTP_PIC_FLAGS IDF_AGI_PIC_V2
+#define IDI_WTP_PIC_WIDTH 140
+#define IDI_WTP_PIC_HEIGHT 159
+#define IDI_WTP_PIC_X0 10
+#define IDI_WTP_PIC_Y0 0
+#define IDI_WTP_PIC_FLAGS IDF_AGI_PIC_V2
// selections
@@ -162,7 +162,7 @@ enum {
IDI_WTP_SEL_REAL_OPT_3
};
-#define IDI_WTP_SEL_LAST IDI_WTP_SEL_REAL_OPT_3
+#define IDI_WTP_SEL_LAST IDI_WTP_SEL_REAL_OPT_3
// rooms
@@ -174,13 +174,13 @@ enum {
IDI_WTP_ROOM_WEST
};
-#define IDI_WTP_ROOM_HIDE 0
+#define IDI_WTP_ROOM_HIDE 0
-#define IDI_WTP_ROOM_PICNIC 2
-#define IDI_WTP_ROOM_HOME 28
-#define IDI_WTP_ROOM_PARTY 58
-#define IDI_WTP_ROOM_MIST 59
-#define IDI_WTP_ROOM_TIGGER 61
+#define IDI_WTP_ROOM_PICNIC 2
+#define IDI_WTP_ROOM_HOME 28
+#define IDI_WTP_ROOM_PARTY 58
+#define IDI_WTP_ROOM_MIST 59
+#define IDI_WTP_ROOM_TIGGER 61
// sound
@@ -200,23 +200,23 @@ enum ENUM_WTP_SOUND {
// script opcodes
-#define IDO_WTP_GOTO_ROOM 0x06
-#define IDO_WTP_PRINT_MSG 0x08
-#define IDO_WTP_PRINT_STR 0x0A
-#define IDO_WTP_DROP_OBJ 0x0C
-#define IDO_WTP_FLAG_CLEAR 0x0E
-#define IDO_WTP_FLAG_SET 0x10
-#define IDO_WTP_GAME_OVER 0x12
-#define IDO_WTP_WALK_MIST 0x14
-#define IDO_WTP_PLAY_SOUND 0x16
-#define IDO_WTP_SAVE_GAME 0x18
-#define IDO_WTP_LOAD_GAME 0x1A
-#define IDO_WTP_OWL_HELP 0x1C
-#define IDO_WTP_GOTO_RND 0x1E
-
-#define IDO_WTP_OPTION_0 0x15
-#define IDO_WTP_OPTION_1 0x16
-#define IDO_WTP_OPTION_2 0x17
+#define IDO_WTP_GOTO_ROOM 0x06
+#define IDO_WTP_PRINT_MSG 0x08
+#define IDO_WTP_PRINT_STR 0x0A
+#define IDO_WTP_DROP_OBJ 0x0C
+#define IDO_WTP_FLAG_CLEAR 0x0E
+#define IDO_WTP_FLAG_SET 0x10
+#define IDO_WTP_GAME_OVER 0x12
+#define IDO_WTP_WALK_MIST 0x14
+#define IDO_WTP_PLAY_SOUND 0x16
+#define IDO_WTP_SAVE_GAME 0x18
+#define IDO_WTP_LOAD_GAME 0x1A
+#define IDO_WTP_OWL_HELP 0x1C
+#define IDO_WTP_GOTO_RND 0x1E
+
+#define IDO_WTP_OPTION_0 0x15
+#define IDO_WTP_OPTION_1 0x16
+#define IDO_WTP_OPTION_2 0x17
enum {
IDI_WTP_OBJ_DESC = 0,
@@ -234,49 +234,49 @@ enum {
// room file option block
struct WTP_ROOM_BLOCK {
- uint16 ofsOpt[IDI_WTP_MAX_BLOCK];
+ uint16 ofsOpt[IDI_WTP_MAX_BLOCK];
};
// room file header
struct WTP_ROOM_HDR {
- uint8 roomNumber;
- uint8 objId;
- uint16 ofsPic;
- uint16 fileLen;
- uint16 reserved0;
- int8 roomNew[IDI_WTP_MAX_DIR];
- uint8 objX;
- uint8 objY;
- uint16 reserved1;
- uint16 ofsDesc[IDI_WTP_MAX_BLOCK];
- uint16 ofsBlock[IDI_WTP_MAX_BLOCK];
- uint16 ofsStr[IDI_WTP_MAX_STR];
- uint32 reserved2;
- WTP_ROOM_BLOCK opt[IDI_WTP_MAX_BLOCK];
+ uint8 roomNumber;
+ uint8 objId;
+ uint16 ofsPic;
+ uint16 fileLen;
+ uint16 reserved0;
+ int8 roomNew[IDI_WTP_MAX_DIR];
+ uint8 objX;
+ uint8 objY;
+ uint16 reserved1;
+ uint16 ofsDesc[IDI_WTP_MAX_BLOCK];
+ uint16 ofsBlock[IDI_WTP_MAX_BLOCK];
+ uint16 ofsStr[IDI_WTP_MAX_STR];
+ uint32 reserved2;
+ WTP_ROOM_BLOCK opt[IDI_WTP_MAX_BLOCK];
};
// object file header
struct WTP_OBJ_HDR {
- uint16 fileLen;
- uint16 objId;
- uint16 ofsEndStr[IDI_WTP_MAX_OBJ_STR_END];
- uint16 ofsStr[IDI_WTP_MAX_OBJ_STR];
- uint16 ofsPic;
+ uint16 fileLen;
+ uint16 objId;
+ uint16 ofsEndStr[IDI_WTP_MAX_OBJ_STR_END];
+ uint16 ofsStr[IDI_WTP_MAX_OBJ_STR];
+ uint16 ofsPic;
};
// savegame
struct WTP_SAVE_GAME {
- uint8 fSound;
- uint8 nMoves;
- uint8 nObjMiss;
- uint8 nObjRet;
- uint8 iObjHave;
- uint8 fGame[IDI_WTP_MAX_FLAG];
- uint8 iUsedObj[IDI_WTP_MAX_OBJ_MISSING];
- uint8 iObjRoom[IDI_WTP_MAX_ROOM_OBJ];
+ uint8 fSound;
+ uint8 nMoves;
+ uint8 nObjMiss;
+ uint8 nObjRet;
+ uint8 iObjHave;
+ uint8 fGame[IDI_WTP_MAX_FLAG];
+ uint8 iUsedObj[IDI_WTP_MAX_OBJ_MISSING];
+ uint8 iObjRoom[IDI_WTP_MAX_ROOM_OBJ];
};
class PreAgiEngine;
@@ -298,10 +298,10 @@ private:
WTP_SAVE_GAME _gameStateWinnie;
int _room;
- int _mist;
+ int _mist;
bool _doWind;
bool _winnieEvent;
- int _tiggerMist;
+ int _tiggerMist;
int _roomOffset;
int _objOffset;
@@ -310,40 +310,40 @@ private:
void randomize();
void intro();
- void drawPic(const char*);
+ void drawPic(const char *);
void gameLoop();
void parseRoomHeader(WTP_ROOM_HDR *roomHdr, byte *buffer, int len);
void parseObjHeader(WTP_OBJ_HDR *objHdr, byte *buffer, int len);
- uint32 readRoom(int, uint8*, WTP_ROOM_HDR&);
+ uint32 readRoom(int, uint8 *, WTP_ROOM_HDR &);
void drawRoomPic();
- int parser(int, int, uint8*);
+ int parser(int, int, uint8 *);
int getObjInRoom(int);
bool getSelOkBack();
- void getMenuSel(char*, int*, int[]);
+ void getMenuSel(char *, int *, int[]);
void keyHelp();
- void clrMenuSel(int*, int[]);
- void incMenuSel(int*, int[]);
- void decMenuSel(int*, int[]);
- void drawMenu(char*, int, int[]);
+ void clrMenuSel(int *, int[]);
+ void incMenuSel(int *, int[]);
+ void decMenuSel(int *, int[]);
+ void drawMenu(char *, int, int[]);
void printRoomStr(int, int);
void inventory();
void printObjStr(int, int);
- uint32 readObj(int, uint8*);
+ uint32 readObj(int, uint8 *);
void takeObj(int);
void dropObj(int);
- bool isRightObj(int, int, int*);
+ bool isRightObj(int, int, int *);
void drawObjPic(int, int, int);
- void getMenuMouseSel(int*, int[], int, int);
- void setFlag(int);
- void clearFlag(int);
+ void getMenuMouseSel(int *, int[], int, int);
+ void setWinnieFlag(int);
+ void clearWinnieFlag(int);
void gameOver();
void saveGame();
void loadGame();
void dropObjRnd();
void setTakeDrop(int[]);
- void makeSel(int*, int[]);
+ void makeSel(int *, int[]);
void wind();
void mist();
diff --git a/engines/agi/saveload.cpp b/engines/agi/saveload.cpp
index 41a7a943ff..fc4aea3169 100644
--- a/engines/agi/saveload.cpp
+++ b/engines/agi/saveload.cpp
@@ -38,33 +38,44 @@
#include "agi/agi.h"
#include "agi/graphics.h"
+#include "agi/text.h"
#include "agi/sprite.h"
#include "agi/keyboard.h"
#include "agi/menu.h"
+#include "agi/systemui.h"
+#include "agi/words.h"
-#define SAVEGAME_VERSION 6
+#define SAVEGAME_CURRENT_VERSION 11
//
-// Version 0 (Sarien): view table has 64 entries
-// Version 1 (Sarien): view table has 256 entries (needed in KQ3)
-// Version 2 (ScummVM): first ScummVM version
-// Version 3 (ScummVM): added AGIPAL save/load support
-// Version 4 (ScummVM): added thumbnails and save creation date/time
-// Version 5 (ScummVM): Added game md5
-// Version 6 (ScummVM): Added game played time
-//
+// Version 0 (Sarien): view table has 64 entries
+// Version 1 (Sarien): view table has 256 entries (needed in KQ3)
+// Version 2 (ScummVM): first ScummVM version
+// Version 3 (ScummVM): added AGIPAL save/load support
+// Version 4 (ScummVM): added thumbnails and save creation date/time
+// Version 5 (ScummVM): Added game md5
+// Version 6 (ScummVM): Added game played time
+// Version 7 (ScummVM): Added controller key mappings
+// required for some games for quick-loading from ScummVM main menu
+// for games, that do not set all key mappings right at the start
+// Added automatic save data (for command SetSimple)
+// Version 8 (ScummVM): Added Hold-Key-Mode boolean
+// required for at least Mixed Up Mother Goose
+// gets set at the start of the game only
+// Version 9 (ScummVM): Added seconds to saved game time stamp
+// Version 10 (ScummVM): Added priorityTableSet boolean
namespace Agi {
-static const uint32 AGIflag = MKTAG('A','G','I',':');
+static const uint32 AGIflag = MKTAG('A', 'G', 'I', ':');
-int AgiEngine::saveGame(const Common::String &fileName, const Common::String &description) {
+int AgiEngine::saveGame(const Common::String &fileName, const Common::String &descriptionString) {
char gameIDstring[8] = "gameIDX";
int i;
Common::OutSaveFile *out;
int result = errOK;
- debugC(3, kDebugLevelMain | kDebugLevelSavegame, "AgiEngine::saveGame(%s, %s)", fileName.c_str(), description.c_str());
+ debugC(3, kDebugLevelMain | kDebugLevelSavegame, "AgiEngine::saveGame(%s, %s)", fileName.c_str(), descriptionString.c_str());
if (!(out = _saveFileMan->openForSaving(fileName))) {
warning("Can't create file '%s', game not saved", fileName.c_str());
return errBadFileOpen;
@@ -73,10 +84,17 @@ int AgiEngine::saveGame(const Common::String &fileName, const Common::String &de
}
out->writeUint32BE(AGIflag);
- out->write(description.c_str(), 31);
- out->writeByte(SAVEGAME_VERSION);
- debugC(5, kDebugLevelMain | kDebugLevelSavegame, "Writing save game version (%d)", SAVEGAME_VERSION);
+ // Write description of saved game, limited to SAVEDGAME_DESCRIPTION_LEN characters + terminating NUL
+ char description[SAVEDGAME_DESCRIPTION_LEN + 1];
+
+ memset(description, 0, sizeof(description));
+ strncpy(description, descriptionString.c_str(), SAVEDGAME_DESCRIPTION_LEN);
+ assert(SAVEDGAME_DESCRIPTION_LEN + 1 == 31); // safety
+ out->write(description, 31);
+
+ out->writeByte(SAVEGAME_CURRENT_VERSION);
+ debugC(5, kDebugLevelMain | kDebugLevelSavegame, "Writing save game version (%d)", SAVEGAME_CURRENT_VERSION);
// Thumbnail
Graphics::saveThumbnail(*out);
@@ -93,13 +111,14 @@ int AgiEngine::saveGame(const Common::String &fileName, const Common::String &de
debugC(5, kDebugLevelMain | kDebugLevelSavegame, "Writing save date (%d)", saveDate);
out->writeUint16BE(saveTime);
debugC(5, kDebugLevelMain | kDebugLevelSavegame, "Writing save time (%d)", saveTime);
+ // Version 9+: save seconds of current time as well
+ out->writeByte(curTime.tm_sec & 0xFF);
out->writeUint32BE(playTime);
debugC(5, kDebugLevelMain | kDebugLevelSavegame, "Writing play time (%d)", playTime);
- out->writeByte(_game.state);
- debugC(5, kDebugLevelMain | kDebugLevelSavegame, "Writing game state (%d)", _game.state);
+ 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);
@@ -116,37 +135,56 @@ int AgiEngine::saveGame(const Common::String &fileName, const Common::String &de
out->writeByte(tmp[i]);
}
+ // Version 7+: Save automatic saving state (set.simple opcode)
+ out->writeByte(_game.automaticSave);
+ out->write(_game.automaticSaveDescription, 31);
+
+ // touch VM_VAR_SECONDS, so that it gets updated
+ getVar(VM_VAR_SECONDS);
+
for (i = 0; i < MAX_FLAGS; i++)
out->writeByte(_game.flags[i]);
for (i = 0; i < MAX_VARS; i++)
out->writeByte(_game.vars[i]);
out->writeSint16BE((int8)_game.horizon);
- out->writeSint16BE((int16)_game.lineStatus);
- out->writeSint16BE((int16)_game.lineUserInput);
- out->writeSint16BE((int16)_game.lineMinPrint);
+ out->writeSint16BE((int16)_text->statusRow_Get());
+ out->writeSint16BE((int16)_text->promptRow_Get());
+ out->writeSint16BE((int16)_text->getWindowRowMin());
- out->writeSint16BE((int16)_game.inputMode);
- out->writeSint16BE((int16)_game.lognum);
+ out->writeSint16BE(1); // was _game.inputMode, we set it to 1, which was INPUTMODE_NORMAL
+ out->writeSint16BE((int16)_game.curLogicNr);
out->writeSint16BE((int16)_game.playerControl);
out->writeSint16BE((int16)shouldQuit());
- out->writeSint16BE((int16)_game.statusLine);
- out->writeSint16BE((int16)_game.clockEnabled);
+ if (_text->statusEnabled()) {
+ out->writeSint16BE(0x7FFF);
+ } else {
+ out->writeSint16BE(0);
+ }
+ out->writeSint16BE(1); // was clock enabled
+ // (previous in-game-timer, in-game-timer is always enabled during the regular game, so need to save/load it)
out->writeSint16BE((int16)_game.exitAllLogics);
out->writeSint16BE((int16)_game.pictureShown);
- out->writeSint16BE((int16)_game.hasPrompt);
+ out->writeSint16BE((int16)_text->promptIsEnabled()); // was "_game.hasPrompt", no longer needed
out->writeSint16BE((int16)_game.gameFlags);
- out->writeSint16BE(_game.inputEnabled);
+ if (_text->promptIsEnabled()) {
+ out->writeSint16BE(0x7FFF);
+ } else {
+ out->writeSint16BE(0);
+ }
+
+ for (i = 0; i < SCRIPT_HEIGHT; i++)
+ out->writeByte(_gfx->saveLoadGetPriority(i));
- for (i = 0; i < _HEIGHT; i++)
- out->writeByte(_game.priTable[i]);
+ // Version 10+: Save, if priority table got modified (set.pri.base opcode)
+ out->writeSint16BE((int16)_gfx->saveLoadWasPriorityTableModified());
out->writeSint16BE((int16)_game.gfxMode);
- out->writeByte(_game.cursorChar);
- out->writeSint16BE((int16)_game.colorFg);
- out->writeSint16BE((int16)_game.colorBg);
+ out->writeByte(_text->inputGetCursorChar());
+ out->writeSint16BE((int16)_text->charAttrib_GetForeground());
+ out->writeSint16BE((int16)_text->charAttrib_GetBackground());
// game.hires
// game.sbuf
@@ -157,21 +195,33 @@ int AgiEngine::saveGame(const Common::String &fileName, const Common::String &de
for (i = 0; i < (int16)_game.numObjects; i++)
out->writeSint16BE((int16)objectGetLocation(i));
+ // Version 7+: save controller key mappings
+ // required for games, that do not set all key mappings right at the start
+ // when quick restoring is used from ScummVM menu, only 1 cycle is executed
+ for (i = 0; i < MAX_CONTROLLER_KEYMAPPINGS; i++) {
+ out->writeUint16BE(_game.controllerKeyMapping[i].keycode);
+ out->writeByte(_game.controllerKeyMapping[i].controllerSlot);
+ }
+
+ // Version 8+: hold-key-mode
+ // required for at least Mixed Up Mother Goose
+ out->writeByte(_keyHoldMode);
+
// game.ev_keyp
for (i = 0; i < MAX_STRINGS; i++)
out->write(_game.strings[i], MAX_STRINGLEN);
// record info about loaded resources
- for (i = 0; i < MAX_DIRS; i++) {
+ for (i = 0; i < MAX_DIRECTORY_ENTRIES; i++) {
out->writeByte(_game.dirLogic[i].flags);
out->writeSint16BE((int16)_game.logics[i].sIP);
out->writeSint16BE((int16)_game.logics[i].cIP);
}
- for (i = 0; i < MAX_DIRS; i++)
+ for (i = 0; i < MAX_DIRECTORY_ENTRIES; i++)
out->writeByte(_game.dirPic[i].flags);
- for (i = 0; i < MAX_DIRS; i++)
+ for (i = 0; i < MAX_DIRECTORY_ENTRIES; i++)
out->writeByte(_game.dirView[i].flags);
- for (i = 0; i < MAX_DIRS; i++)
+ for (i = 0; i < MAX_DIRECTORY_ENTRIES; i++)
out->writeByte(_game.dirSound[i].flags);
// game.pictures
@@ -179,51 +229,79 @@ int AgiEngine::saveGame(const Common::String &fileName, const Common::String &de
// game.views
// game.sounds
- for (i = 0; i < MAX_VIEWTABLE; i++) {
- VtEntry *v = &_game.viewTable[i];
+ for (i = 0; i < SCREENOBJECTS_MAX; i++) {
+ ScreenObjEntry *screenObj = &_game.screenObjTable[i];
- out->writeByte(v->stepTime);
- out->writeByte(v->stepTimeCount);
- out->writeByte(v->entry);
- out->writeSint16BE(v->xPos);
- out->writeSint16BE(v->yPos);
- out->writeByte(v->currentView);
+ out->writeByte(screenObj->stepTime);
+ out->writeByte(screenObj->stepTimeCount);
+ out->writeByte(screenObj->objectNr);
+ out->writeSint16BE(screenObj->xPos);
+ out->writeSint16BE(screenObj->yPos);
+ out->writeByte(screenObj->currentViewNr);
// v->view_data
- out->writeByte(v->currentLoop);
- out->writeByte(v->numLoops);
+ out->writeByte(screenObj->currentLoopNr);
+ out->writeByte(screenObj->loopCount);
// v->loop_data
- out->writeByte(v->currentCel);
- out->writeByte(v->numCels);
+ out->writeByte(screenObj->currentCelNr);
+ out->writeByte(screenObj->celCount);
// v->cel_data
// v->cel_data_2
- out->writeSint16BE(v->xPos2);
- out->writeSint16BE(v->yPos2);
+ out->writeSint16BE(screenObj->xPos_prev);
+ out->writeSint16BE(screenObj->yPos_prev);
// v->s
- out->writeSint16BE(v->xSize);
- out->writeSint16BE(v->ySize);
- out->writeByte(v->stepSize);
- out->writeByte(v->cycleTime);
- out->writeByte(v->cycleTimeCount);
- out->writeByte(v->direction);
+ out->writeSint16BE(screenObj->xSize);
+ out->writeSint16BE(screenObj->ySize);
+ out->writeByte(screenObj->stepSize);
+ out->writeByte(screenObj->cycleTime);
+ out->writeByte(screenObj->cycleTimeCount);
+ out->writeByte(screenObj->direction);
- out->writeByte(v->motion);
- out->writeByte(v->cycle);
- out->writeByte(v->priority);
+ out->writeByte(screenObj->motionType);
+ out->writeByte(screenObj->cycle);
+ // Version 11+: loop_flag, was saved previously under vt.parm1
+ out->writeByte(screenObj->loop_flag);
+ out->writeByte(screenObj->priority);
- out->writeUint16BE(v->flags);
+ out->writeUint16BE(screenObj->flags);
- out->writeByte(v->parm1);
- out->writeByte(v->parm2);
- out->writeByte(v->parm3);
- out->writeByte(v->parm4);
+ // this was done so that saved games compatibility isn't broken
+ switch (screenObj->motionType) {
+ case kMotionNormal:
+ out->writeByte(0);
+ out->writeByte(0);
+ out->writeByte(0);
+ out->writeByte(0);
+ break;
+ case kMotionWander:
+ out->writeByte(screenObj->wander_count);
+ out->writeByte(0);
+ out->writeByte(0);
+ out->writeByte(0);
+ break;
+ case kMotionFollowEgo:
+ out->writeByte(screenObj->follow_stepSize);
+ out->writeByte(screenObj->follow_flag);
+ out->writeByte(screenObj->follow_count);
+ out->writeByte(0);
+ break;
+ case kMotionEgo:
+ case kMotionMoveObj:
+ out->writeByte((byte)screenObj->move_x); // problematic! int16 -> byte
+ out->writeByte((byte)screenObj->move_y);
+ out->writeByte(screenObj->move_stepSize);
+ out->writeByte(screenObj->move_flag);
+ break;
+ default:
+ error("unknown motion-type");
+ }
}
// Save image stack
@@ -249,7 +327,7 @@ int AgiEngine::saveGame(const Common::String &fileName, const Common::String &de
warning("Can't write file '%s'. (Disk full?)", fileName.c_str());
result = errIOError;
} else
- debugC(1, kDebugLevelMain | kDebugLevelSavegame, "Saved game %s in file %s", description.c_str(), fileName.c_str());
+ debugC(1, kDebugLevelMain | kDebugLevelSavegame, "Saved game %s in file %s", descriptionString.c_str(), fileName.c_str());
delete out;
debugC(3, kDebugLevelMain | kDebugLevelSavegame, "Closed %s", fileName.c_str());
@@ -260,11 +338,15 @@ int AgiEngine::saveGame(const Common::String &fileName, const Common::String &de
}
int AgiEngine::loadGame(const Common::String &fileName, bool checkId) {
- char description[31], saveVersion, loadId[8];
- int i, vtEntries = MAX_VIEWTABLE;
+ char description[SAVEDGAME_DESCRIPTION_LEN + 1];
+ byte saveVersion = 0;
+ char loadId[8];
+ int i, vtEntries = SCREENOBJECTS_MAX;
uint8 t;
int16 parm[7];
Common::InSaveFile *in;
+ bool totalPlayTimeWasSet = false;
+ byte oldLoopFlag = 0;
debugC(3, kDebugLevelMain | kDebugLevelSavegame, "AgiEngine::loadGame(%s)", fileName.c_str());
@@ -284,30 +366,45 @@ int AgiEngine::loadGame(const Common::String &fileName, bool checkId) {
return errOK;
}
- in->read(description, 31);
+ assert(SAVEDGAME_DESCRIPTION_LEN + 1 == 31); // safety
+ in->read(description, 31); // skip description
+ // check, if there is a terminating NUL inside description
+ uint16 descriptionPos = 0;
+ while (description[descriptionPos]) {
+ descriptionPos++;
+ if (descriptionPos >= sizeof(description))
+ error("saved game description is corrupt");
+ }
debugC(6, kDebugLevelMain | kDebugLevelSavegame, "Description is: %s", description);
saveVersion = in->readByte();
- if (saveVersion < 2) // is the save game pre-ScummVM?
- warning("Old save game version (%d, current version is %d). Will try and read anyway, but don't be surprised if bad things happen", saveVersion, SAVEGAME_VERSION);
+ if (saveVersion < 2) // is the save game pre-ScummVM?
+ warning("Old save game version (%d, current version is %d). Will try and read anyway, but don't be surprised if bad things happen", saveVersion, SAVEGAME_CURRENT_VERSION);
if (saveVersion < 3)
warning("This save game contains no AGIPAL data, if the game is using the AGIPAL hack, it won't work correctly");
+ if (saveVersion > SAVEGAME_CURRENT_VERSION)
+ error("Saved game was created with a newer version of ScummVM. Unable to load.");
+
if (saveVersion >= 4) {
// We don't need the thumbnail here, so just read it and discard it
Graphics::skipThumbnail(*in);
- in->readUint32BE(); // save date
- in->readUint16BE(); // save time
+ in->readUint32BE(); // save date
+ in->readUint16BE(); // save time (hour + minute)
+ if (saveVersion >= 9) {
+ in->readByte(); // save time seconds
+ }
if (saveVersion >= 6) {
uint32 playTime = in->readUint32BE();
- g_engine->setTotalPlayTime(playTime * 1000);
+ inGameTimerReset(playTime * 1000);
+ totalPlayTimeWasSet = true;
}
}
- _game.state = (State)in->readByte();
+ in->readByte(); // was _game.state, not needed anymore
in->read(loadId, 8);
if (strcmp(loadId, _game.id) != 0 && checkId) {
@@ -348,56 +445,93 @@ int AgiEngine::loadGame(const Common::String &fileName, bool checkId) {
}
}
+ if (saveVersion >= 7) {
+ // Restore automatic saving state (set.simple opcode)
+ _game.automaticSave = in->readByte();
+ in->read(_game.automaticSaveDescription, 31);
+ } else {
+ _game.automaticSave = false;
+ _game.automaticSaveDescription[0] = 0;
+ }
+
for (i = 0; i < MAX_FLAGS; i++)
_game.flags[i] = in->readByte();
for (i = 0; i < MAX_VARS; i++)
_game.vars[i] = in->readByte();
- setvar(vFreePages, 180); // Set amount of free memory to realistic value (Overwriting the just loaded value)
+ if (!totalPlayTimeWasSet) {
+ // If we haven't gotten total play time by now, try to calculate it by using VM Variables
+ // This will happen for at least saves before version 6
+ // Direct access because otherwise we would trigger an update to these variables according to ScummVM total play time
+ byte playTimeSeconds = _game.vars[VM_VAR_SECONDS];
+ byte playTimeMinutes = _game.vars[VM_VAR_MINUTES];
+ byte playTimeHours = _game.vars[VM_VAR_HOURS];
+ byte playTimeDays = _game.vars[VM_VAR_DAYS];
+ uint32 playTime = (playTimeSeconds + (playTimeMinutes * 60) + (playTimeHours * 3600) + (playTimeDays * 86400)) * 1000;
+
+ inGameTimerReset(playTime);
+ }
+
+ setVar(VM_VAR_FREE_PAGES, 180); // Set amount of free memory to realistic value (Overwriting the just loaded value)
_game.horizon = in->readSint16BE();
- _game.lineStatus = in->readSint16BE();
- _game.lineUserInput = in->readSint16BE();
- _game.lineMinPrint = in->readSint16BE();
+ _text->statusRow_Set(in->readSint16BE());
+ _text->promptRow_Set(in->readSint16BE());
+ _text->configureScreen(in->readSint16BE());
// These are never saved
- _game.cursorPos = 0;
- _game.inputBuffer[0] = 0;
- _game.echoBuffer[0] = 0;
- _game.keypress = 0;
+ _text->promptReset();
- _game.inputMode = (InputMode)in->readSint16BE();
- _game.lognum = in->readSint16BE();
+ in->readSint16BE(); // was _game.inputMode, not needed anymore
+
+ _game.curLogicNr = in->readSint16BE();
_game.playerControl = in->readSint16BE();
if (in->readSint16BE())
quitGame();
- _game.statusLine = in->readSint16BE();
- _game.clockEnabled = in->readSint16BE();
+ if (in->readSint16BE()) {
+ _text->statusEnable();
+ } else {
+ _text->statusDisable();
+ }
+ in->readSint16BE(); // was clock enabled, no longer needed
_game.exitAllLogics = in->readSint16BE();
- _game.pictureShown = in->readSint16BE();
- _game.hasPrompt = in->readSint16BE();
+ in->readSint16BE(); // was _game.pictureShown
+ in->readSint16BE(); // was _game.hasPrompt, no longer needed
_game.gameFlags = in->readSint16BE();
- _game.inputEnabled = in->readSint16BE();
+ if (in->readSint16BE()) {
+ _text->promptEnable();
+ } else {
+ _text->promptDisable();
+ }
- for (i = 0; i < _HEIGHT; i++)
- _game.priTable[i] = in->readByte();
+ for (i = 0; i < SCRIPT_HEIGHT; i++)
+ _gfx->saveLoadSetPriority(i, in->readByte());
- if (_game.hasWindow)
- closeWindow();
+ if (saveVersion >= 10) {
+ // Version 10+: priority table was modified by scripts
+ int16 priorityTableWasModified = in->readSint16BE();
+
+ if (priorityTableWasModified) {
+ _gfx->saveLoadSetPriorityTableModifiedBool(true);
+ } else {
+ _gfx->saveLoadSetPriorityTableModifiedBool(false);
+ }
+ } else {
+ // Try to figure it out by ourselves
+ _gfx->saveLoadFigureOutPriorityTableModifiedBool();
+ }
+
+ _text->closeWindow();
- _game.msgBoxTicks = 0;
_game.block.active = false;
- // game.window - fixed by close_window()
- // game.has_window - fixed by close_window()
_game.gfxMode = in->readSint16BE();
- _game.cursorChar = in->readByte();
- _game.colorFg = in->readSint16BE();
- _game.colorBg = in->readSint16BE();
+ _text->inputSetCursorChar(in->readByte());
- // game.hires - rebuilt from image stack
- // game.sbuf - rebuilt from image stack
+ int16 textForeground = in->readSint16BE();
+ int16 textBackground = in->readSint16BE();
+ _text->charAttrib_Set(textForeground, textBackground);
// game.ego_words - fixed by clean_input
// game.num_ego_words - fixed by clean_input
@@ -407,41 +541,58 @@ int AgiEngine::loadGame(const Common::String &fileName, bool checkId) {
objectSetLocation(i, in->readSint16BE());
// Those are not serialized
- for (i = 0; i < MAX_DIRS; i++) {
+ for (i = 0; i < MAX_CONTROLLERS; i++) {
_game.controllerOccured[i] = false;
}
+ if (saveVersion >= 7) {
+ // For old saves, we just keep the current controllers
+ for (i = 0; i < MAX_CONTROLLER_KEYMAPPINGS; i++) {
+ _game.controllerKeyMapping[i].keycode = in->readUint16BE();
+ _game.controllerKeyMapping[i].controllerSlot = in->readByte();
+ }
+ }
+
+ if (saveVersion >= 8) {
+ // Version 8+: hold-key-mode
+ if (in->readByte()) {
+ _keyHoldMode = true;
+ } else {
+ _keyHoldMode = false;
+ }
+ }
+
for (i = 0; i < MAX_STRINGS; i++)
in->read(_game.strings[i], MAX_STRINGLEN);
- for (i = 0; i < MAX_DIRS; i++) {
+ for (i = 0; i < MAX_DIRECTORY_ENTRIES; i++) {
if (in->readByte() & RES_LOADED)
- agiLoadResource(rLOGIC, i);
+ agiLoadResource(RESOURCETYPE_LOGIC, i);
else
- agiUnloadResource(rLOGIC, i);
+ agiUnloadResource(RESOURCETYPE_LOGIC, i);
_game.logics[i].sIP = in->readSint16BE();
_game.logics[i].cIP = in->readSint16BE();
}
- for (i = 0; i < MAX_DIRS; i++) {
+ for (i = 0; i < MAX_DIRECTORY_ENTRIES; i++) {
if (in->readByte() & RES_LOADED)
- agiLoadResource(rPICTURE, i);
+ agiLoadResource(RESOURCETYPE_PICTURE, i);
else
- agiUnloadResource(rPICTURE, i);
+ agiUnloadResource(RESOURCETYPE_PICTURE, i);
}
- for (i = 0; i < MAX_DIRS; i++) {
+ for (i = 0; i < MAX_DIRECTORY_ENTRIES; i++) {
if (in->readByte() & RES_LOADED)
- agiLoadResource(rVIEW, i);
+ agiLoadResource(RESOURCETYPE_VIEW, i);
else
- agiUnloadResource(rVIEW, i);
+ agiUnloadResource(RESOURCETYPE_VIEW, i);
}
- for (i = 0; i < MAX_DIRS; i++) {
+ for (i = 0; i < MAX_DIRECTORY_ENTRIES; i++) {
if (in->readByte() & RES_LOADED)
- agiLoadResource(rSOUND, i);
+ agiLoadResource(RESOURCETYPE_SOUND, i);
else
- agiUnloadResource(rSOUND, i);
+ agiUnloadResource(RESOURCETYPE_SOUND, i);
}
// game.pictures - loaded above
@@ -450,78 +601,116 @@ int AgiEngine::loadGame(const Common::String &fileName, bool checkId) {
// game.sounds - loaded above
for (i = 0; i < vtEntries; i++) {
- VtEntry *v = &_game.viewTable[i];
-
- v->stepTime = in->readByte();
- v->stepTimeCount = in->readByte();
- v->entry = in->readByte();
- v->xPos = in->readSint16BE();
- v->yPos = in->readSint16BE();
- v->currentView = in->readByte();
-
- // v->view_data - fixed below
+ ScreenObjEntry *screenObj = &_game.screenObjTable[i];
- v->currentLoop = in->readByte();
- v->numLoops = in->readByte();
+ screenObj->stepTime = in->readByte();
+ screenObj->stepTimeCount = in->readByte();
+ screenObj->objectNr = in->readByte();
+ screenObj->xPos = in->readSint16BE();
+ screenObj->yPos = in->readSint16BE();
+ screenObj->currentViewNr = in->readByte();
- // v->loop_data - fixed below
+ // screenObj->view_data - fixed below
- v->currentCel = in->readByte();
- v->numCels = in->readByte();
+ screenObj->currentLoopNr = in->readByte();
+ screenObj->loopCount = in->readByte();
- // v->cel_data - fixed below
- // v->cel_data_2 - fixed below
+ // screenObj->loop_data - fixed below
- v->xPos2 = in->readSint16BE();
- v->yPos2 = in->readSint16BE();
+ screenObj->currentCelNr = in->readByte();
+ screenObj->celCount = in->readByte();
- // v->s - fixed below
+ // screenObj->cel_data - fixed below
+ // screenObj->cel_data_2 - fixed below
- v->xSize = in->readSint16BE();
- v->ySize = in->readSint16BE();
- v->stepSize = in->readByte();
- v->cycleTime = in->readByte();
- v->cycleTimeCount = in->readByte();
- v->direction = in->readByte();
+ screenObj->xPos_prev = in->readSint16BE();
+ screenObj->yPos_prev = in->readSint16BE();
- v->motion = (MotionType)in->readByte();
- v->cycle = (CycleType)in->readByte();
- v->priority = in->readByte();
+ // screenObj->s - fixed below
- v->flags = in->readUint16BE();
+ screenObj->xSize = in->readSint16BE();
+ screenObj->ySize = in->readSint16BE();
+ screenObj->stepSize = in->readByte();
+ screenObj->cycleTime = in->readByte();
+ screenObj->cycleTimeCount = in->readByte();
+ screenObj->direction = in->readByte();
- v->parm1 = in->readByte();
- v->parm2 = in->readByte();
- v->parm3 = in->readByte();
- v->parm4 = in->readByte();
- }
- for (i = vtEntries; i < MAX_VIEWTABLE; i++) {
- memset(&_game.viewTable[i], 0, sizeof(VtEntry));
+ screenObj->motionType = (MotionType)in->readByte();
+ screenObj->cycle = (CycleType)in->readByte();
+ if (saveVersion >= 11) {
+ // Version 11+: loop_flag, was previously vt.parm1
+ screenObj->loop_flag = in->readByte();
+ }
+ screenObj->priority = in->readByte();
+
+ screenObj->flags = in->readUint16BE();
+
+ // this was done so that saved games compatibility isn't broken
+ switch (screenObj->motionType) {
+ case kMotionNormal:
+ oldLoopFlag = in->readByte();
+ in->readByte();
+ in->readByte();
+ in->readByte();
+ break;
+ case kMotionWander:
+ screenObj->wander_count = in->readByte();
+ in->readByte();
+ in->readByte();
+ in->readByte();
+ oldLoopFlag = screenObj->wander_count;
+ break;
+ case kMotionFollowEgo:
+ screenObj->follow_stepSize = in->readByte();
+ screenObj->follow_flag = in->readByte();
+ screenObj->follow_count = in->readByte();
+ in->readByte();
+ oldLoopFlag = screenObj->follow_stepSize;
+ break;
+ case kMotionEgo:
+ case kMotionMoveObj:
+ screenObj->move_x = in->readByte(); // problematic! int16 -> byte
+ screenObj->move_y = in->readByte();
+ screenObj->move_stepSize = in->readByte();
+ screenObj->move_flag = in->readByte();
+ oldLoopFlag = screenObj->move_x;
+ break;
+ default:
+ error("unknown motion-type");
+ }
+ if (saveVersion < 11) {
+ if (saveVersion < 7) {
+ // Recreate loop_flag from motion-type (was previously vt.parm1)
+ // vt.parm1 was shared for multiple uses
+ screenObj->loop_flag = oldLoopFlag;
+ } else {
+ // for Version 7-10 we can't really do anything, it was not saved
+ screenObj->loop_flag = 0; // set it to 0
+ }
+ }
}
- // Fix some pointers in viewtable
+ // Fix some pointers in screenObjTable
- for (i = 0; i < MAX_VIEWTABLE; i++) {
- VtEntry *v = &_game.viewTable[i];
+ for (i = 0; i < SCREENOBJECTS_MAX; i++) {
+ ScreenObjEntry *screenObj = &_game.screenObjTable[i];
- if (_game.dirView[v->currentView].offset == _EMPTY)
+ if (_game.dirView[screenObj->currentViewNr].offset == _EMPTY)
continue;
- if (!(_game.dirView[v->currentView].flags & RES_LOADED))
- agiLoadResource(rVIEW, v->currentView);
+ if (!(_game.dirView[screenObj->currentViewNr].flags & RES_LOADED))
+ agiLoadResource(RESOURCETYPE_VIEW, screenObj->currentViewNr);
- setView(v, v->currentView); // Fix v->view_data
- setLoop(v, v->currentLoop); // Fix v->loop_data
- setCel(v, v->currentCel); // Fix v->cel_data
- v->celData2 = v->celData;
- v->s = NULL; // not sure if it is used...
+ setView(screenObj, screenObj->currentViewNr); // Fix v->view_data
+ setLoop(screenObj, screenObj->currentLoopNr); // Fix v->loop_data
+ setCel(screenObj, screenObj->currentCelNr); // Fix v->cel_data
}
- _sprites->eraseBoth();
+ _sprites->eraseSprites();
+
+ _game.pictureShown = false;
- // Clear input line
- _gfx->clearScreen(0);
- writeStatus();
+ _gfx->clearDisplay(0, false); // clear display screen, but not copy it to actual screen for now b/c transition
// Recreate background from saved image stack
clearImageStack();
@@ -529,7 +718,7 @@ int AgiEngine::loadGame(const Common::String &fileName, bool checkId) {
for (i = 0; i < 7; i++)
parm[i] = in->readSint16BE();
replayImageStackCall(t, parm[0], parm[1], parm[2],
- parm[3], parm[4], parm[5], parm[6]);
+ parm[3], parm[4], parm[5], parm[6]);
}
// Load AGIPAL Data
@@ -539,259 +728,28 @@ int AgiEngine::loadGame(const Common::String &fileName, bool checkId) {
delete in;
debugC(3, kDebugLevelMain | kDebugLevelSavegame, "Closed %s", fileName.c_str());
- setflag(fRestoreJustRan, true);
-
- _game.hasPrompt = 0; // force input line repaint if necessary
- cleanInput();
-
- _sprites->eraseBoth();
- _sprites->blitBoth();
- _sprites->commitBoth();
- _picture->showPic();
- _gfx->doUpdate();
-
- return errOK;
-}
-
-#define NUM_SLOTS 100
-#define NUM_VISIBLE_SLOTS 12
-
-Common::String AgiEngine::getSavegameFilename(int num) const {
- Common::String saveLoadSlot = _targetName;
- saveLoadSlot += Common::String::format(".%.3d", num);
- return saveLoadSlot;
-}
-
-void AgiEngine::getSavegameDescription(int num, char *buf, bool showEmpty) {
- Common::InSaveFile *in;
- Common::String fileName = getSavegameFilename(num);
-
- debugC(4, kDebugLevelMain | kDebugLevelSavegame, "Current game id is %s", _targetName.c_str());
-
- if (!(in = _saveFileMan->openForLoading(fileName))) {
- debugC(4, kDebugLevelMain | kDebugLevelSavegame, "File %s does not exist", fileName.c_str());
-
- if (showEmpty)
- strcpy(buf, " (empty slot)");
- else
- *buf = 0;
- } else {
- debugC(4, kDebugLevelMain | kDebugLevelSavegame, "Successfully opened %s for reading", fileName.c_str());
-
- uint32 type = in->readUint32BE();
-
- if (type == AGIflag) {
- debugC(6, kDebugLevelMain | kDebugLevelSavegame, "Has AGI flag, good start");
- in->read(buf, 31);
- } else {
- warning("This doesn't appear to be an AGI savegame");
- strcpy(buf, "(corrupt file)");
- }
-
- delete in;
- }
-}
-
-int AgiEngine::selectSlot() {
- int i, key, active = 0;
- int rc = -1;
- int hm = 1, vm = 3; // box margins
- int xmin, xmax, slotClicked;
- char desc[NUM_VISIBLE_SLOTS][40];
- int textCenter, buttonLength, buttonX[2], buttonY;
- const char *buttonText[] = { " OK ", "Cancel", NULL };
-
- _noSaveLoadAllowed = true;
-
- for (i = 0; i < NUM_VISIBLE_SLOTS; i++) {
- getSavegameDescription(_firstSlot + i, desc[i]);
- }
-
- textCenter = GFX_WIDTH / CHAR_LINES / 2;
- buttonLength = 6;
- buttonX[0] = (textCenter - 3 * buttonLength / 2) * CHAR_COLS;
- buttonX[1] = (textCenter + buttonLength / 2) * CHAR_COLS;
- buttonY = (vm + 17) * CHAR_LINES;
-
- for (i = 0; i < 2; i++)
- _gfx->drawCurrentStyleButton(buttonX[i], buttonY, buttonText[i], false, false, i == 0);
-
- AllowSyntheticEvents on(this);
- int oldFirstSlot = _firstSlot + 1;
- int oldActive = active + 1;
- bool exitSelectSlot = false;
- while (!exitSelectSlot && !(shouldQuit() || _restartGame)) {
- int sbPos = 0;
-
- // Use the extreme scrollbar positions only if the extreme
- // slots are in sight. (We have to calculate this even if we
- // don't redraw the save slots, because it's also used for
- // clicking in the scrollbar.
-
- if (_firstSlot == 0)
- sbPos = 1;
- else if (_firstSlot == NUM_SLOTS - NUM_VISIBLE_SLOTS)
- sbPos = NUM_VISIBLE_SLOTS - 2;
- else {
- sbPos = 2 + (_firstSlot * (NUM_VISIBLE_SLOTS - 4)) / (NUM_SLOTS - NUM_VISIBLE_SLOTS - 1);
- if (sbPos >= NUM_VISIBLE_SLOTS - 3)
- sbPos = NUM_VISIBLE_SLOTS - 3;
- }
-
- if (oldFirstSlot != _firstSlot || oldActive != active) {
- char dstr[64];
- for (i = 0; i < NUM_VISIBLE_SLOTS; i++) {
- sprintf(dstr, "[%2d. %-28.28s]", i + _firstSlot, desc[i]);
- printText(dstr, 0, hm + 1, vm + 4 + i,
- (40 - 2 * hm) - 1, i == active ? MSG_BOX_COLOR : MSG_BOX_TEXT,
- i == active ? MSG_BOX_TEXT : MSG_BOX_COLOR);
- }
-
- char upArrow[] = "^";
- char downArrow[] = "v";
- char scrollBar[] = " ";
-
- for (i = 1; i < NUM_VISIBLE_SLOTS - 1; i++)
- printText(scrollBar, 35, hm + 1, vm + 4 + i, 1, MSG_BOX_COLOR, 7, true);
-
- printText(upArrow, 35, hm + 1, vm + 4, 1, 8, 7);
- printText(downArrow, 35, hm + 1, vm + 4 + NUM_VISIBLE_SLOTS - 1, 1, 8, 7);
- printText(scrollBar, 35, hm + 1, vm + 4 + sbPos, 1, MSG_BOX_COLOR, MSG_BOX_TEXT);
-
- oldActive = active;
- oldFirstSlot = _firstSlot;
- }
-
- pollTimer();
- key = doPollKeyboard();
-
- // It may happen that somebody will open GMM while
- // this dialog is open, and load a game
- // We are processing it here, effectively jumping
- // out of the dead loop
- if (getflag(fRestoreJustRan)) {
- rc = -2;
- exitSelectSlot = true;
- }
-
- if (!exitSelectSlot) {
- switch (key) {
- case KEY_ENTER:
- rc = active;
- Common::strlcpy(_game.strings[MAX_STRINGS], desc[i], MAX_STRINGLEN);
- debugC(8, kDebugLevelMain | kDebugLevelInput, "Button pressed: %d", rc);
- exitSelectSlot = true;
- break;
- case KEY_ESCAPE:
- rc = -1;
- exitSelectSlot = true;
- break;
- case BUTTON_LEFT:
- if (_gfx->testButton(buttonX[0], buttonY, buttonText[0])) {
- rc = active;
- strncpy(_game.strings[MAX_STRINGS], desc[i], MAX_STRINGLEN);
- debugC(8, kDebugLevelMain | kDebugLevelInput, "Button pressed: %d", rc);
- exitSelectSlot = true;
- } else if (_gfx->testButton(buttonX[1], buttonY, buttonText[1])) {
- rc = -1;
- exitSelectSlot = true;
- } else {
- slotClicked = ((int)_mouse.y - 1) / CHAR_COLS - (vm + 4);
- xmin = (hm + 1) * CHAR_COLS;
- xmax = xmin + CHAR_COLS * 34;
- if ((int)_mouse.x >= xmin && (int)_mouse.x <= xmax) {
- if (slotClicked >= 0 && slotClicked < NUM_VISIBLE_SLOTS)
- active = slotClicked;
- }
- xmin = (hm + 36) * CHAR_COLS;
- xmax = xmin + CHAR_COLS;
- if ((int)_mouse.x >= xmin && (int)_mouse.x <= xmax) {
- if (slotClicked >= 0 && slotClicked < NUM_VISIBLE_SLOTS) {
- if (slotClicked == 0)
- keyEnqueue(KEY_UP);
- else if (slotClicked == NUM_VISIBLE_SLOTS - 1)
- keyEnqueue(KEY_DOWN);
- else if (slotClicked < sbPos)
- keyEnqueue(KEY_UP_RIGHT);
- else if (slotClicked > sbPos)
- keyEnqueue(KEY_DOWN_RIGHT);
- }
- }
- }
- break;
+ setFlag(VM_FLAG_RESTORE_JUST_RAN, true);
- case KEY_DOWN:
- active++;
- if (active >= NUM_VISIBLE_SLOTS) {
- if (_firstSlot + NUM_VISIBLE_SLOTS < NUM_SLOTS) {
- _firstSlot++;
- for (i = 1; i < NUM_VISIBLE_SLOTS; i++)
- memcpy(desc[i - 1], desc[i], sizeof(desc[0]));
- getSavegameDescription(_firstSlot + NUM_VISIBLE_SLOTS - 1, desc[NUM_VISIBLE_SLOTS - 1]);
- }
- active = NUM_VISIBLE_SLOTS - 1;
- }
- break;
- case KEY_UP:
- active--;
- if (active < 0) {
- active = 0;
- if (_firstSlot > 0) {
- _firstSlot--;
- for (i = NUM_VISIBLE_SLOTS - 1; i > 0; i--)
- memcpy(desc[i], desc[i - 1], sizeof(desc[0]));
- getSavegameDescription(_firstSlot, desc[0]);
- }
- }
- break;
+ _words->clearEgoWords();
- // Page Up/Down and mouse wheel scrolling all leave 'active'
- // unchanged so that a visible slot will remain selected.
+ // don't delay anything right after restoring a game
+ artificialDelay_Reset();
- case WHEEL_DOWN:
- if (_firstSlot < NUM_SLOTS - NUM_VISIBLE_SLOTS) {
- _firstSlot++;
- for (i = 1; i < NUM_VISIBLE_SLOTS; i++)
- memcpy(desc[i - 1], desc[i], sizeof(desc[0]));
- getSavegameDescription(_firstSlot + NUM_VISIBLE_SLOTS - 1, desc[NUM_VISIBLE_SLOTS - 1]);
- }
- break;
- case WHEEL_UP:
- if (_firstSlot > 0) {
- _firstSlot--;
- for (i = NUM_VISIBLE_SLOTS - 1; i > 0; i--)
- memcpy(desc[i], desc[i - 1], sizeof(desc[0]));
- getSavegameDescription(_firstSlot, desc[0]);
- }
- break;
- case KEY_DOWN_RIGHT:
- // This is probably triggered by Page Down.
- _firstSlot += NUM_VISIBLE_SLOTS;
- if (_firstSlot > NUM_SLOTS - NUM_VISIBLE_SLOTS) {
- _firstSlot = NUM_SLOTS - NUM_VISIBLE_SLOTS;
- }
- for (i = 0; i < NUM_VISIBLE_SLOTS; i++)
- getSavegameDescription(_firstSlot + i, desc[i]);
- break;
- case KEY_UP_RIGHT:
- // This is probably triggered by Page Up.
- _firstSlot -= NUM_VISIBLE_SLOTS;
- if (_firstSlot < 0) {
- _firstSlot = 0;
- }
- for (i = 0; i < NUM_VISIBLE_SLOTS; i++)
- getSavegameDescription(_firstSlot + i, desc[i]);
- break;
- }
- }
- _gfx->doUpdate();
- }
+ _sprites->eraseSprites();
+ _sprites->buildAllSpriteLists();
+ _sprites->drawAllSpriteLists();
+ _picture->showPicWithTransition();
+ _game.pictureShown = true;
+ _text->statusDraw();
+ _text->promptRedraw();
- closeWindow();
+ // copy everything over (we should probably only copy over the remaining parts of the screen w/o play screen
+ _gfx->copyDisplayToScreen();
- _noSaveLoadAllowed = false;
+ // Sync volume settings from ScummVM system settings, so that VM volume variable is overwritten
+ setVolumeViaSystemSetting();
- return rc;
+ return errOK;
}
int AgiEngine::scummVMSaveLoadDialog(bool isSave) {
@@ -834,7 +792,8 @@ int AgiEngine::doSave(int slot, const Common::String &desc) {
// Make sure all graphics was blitted to screen. This fixes bug
// #2960567: "AGI: Ego partly erased in Load/Save thumbnails"
- _gfx->doUpdate();
+ _gfx->updateScreen();
+// _gfx->doUpdate();
return saveGame(fileName, desc);
}
@@ -843,162 +802,218 @@ int AgiEngine::doLoad(int slot, bool showMessages) {
Common::String fileName = getSavegameFilename(slot);
debugC(8, kDebugLevelMain | kDebugLevelResources, "file is [%s]", fileName.c_str());
- _sprites->eraseBoth();
+ _sprites->eraseSprites();
_sound->stopSound();
- closeWindow();
+ _text->closeWindow();
int result = loadGame(fileName);
if (result == errOK) {
- if (showMessages)
- messageBox("Game restored.");
- _game.exitAllLogics = 1;
- _menu->enableAll();
+ _game.exitAllLogics = true;
+ _menu->itemEnableAll();
} else {
if (showMessages)
- messageBox("Error restoring game.");
+ _text->messageBox("Error restoring game.");
}
return result;
}
-int AgiEngine::saveGameDialog() {
- if (!ConfMan.getBool("originalsaveload"))
- return scummVMSaveLoadDialog(true);
+SavedGameSlotIdArray AgiEngine::getSavegameSlotIds() {
+ Common::StringArray filenames;
+ int16 numberPos = _targetName.size() + 1;
+ int16 slotId = 0;
+ SavedGameSlotIdArray slotIdArray;
- char *desc;
- const char *buttons[] = { "Do as I say!", "I regret", NULL };
- char dstr[200];
- int rc, slot = 0;
- int hm, vm, hp, vp;
- int w;
-
- hm = 1;
- vm = 3;
- hp = hm * CHAR_COLS;
- vp = vm * CHAR_LINES;
- w = (40 - 2 * hm) - 1;
-
- do {
- drawWindow(hp, vp, GFX_WIDTH - hp, GFX_HEIGHT - vp);
- printText("Select a slot in which you wish to\nsave the game:",
- 0, hm + 1, vm + 1, w, MSG_BOX_TEXT, MSG_BOX_COLOR);
- slot = selectSlot();
- if (slot + _firstSlot == 0)
- messageBox("That slot is for Autosave only.");
- else if (slot < 0)
- return errOK;
- } while (slot + _firstSlot == 0);
-
- drawWindow(hp, vp + 5 * CHAR_LINES, GFX_WIDTH - hp,
- GFX_HEIGHT - vp - 9 * CHAR_LINES);
- printText("Enter a description for this game:",
- 0, hm + 1, vm + 6, w, MSG_BOX_TEXT, MSG_BOX_COLOR);
- _gfx->drawRectangle(3 * CHAR_COLS, 11 * CHAR_LINES - 1,
- 37 * CHAR_COLS, 12 * CHAR_LINES, MSG_BOX_TEXT);
- _gfx->flushBlock(3 * CHAR_COLS, 11 * CHAR_LINES - 1,
- 37 * CHAR_COLS, 12 * CHAR_LINES);
-
- // The description field of the save/restore dialog holds 32 characters
- // but we use four of them for the slot number. The input field is a
- // bit wider than that, so we don't have to worry about leaving space
- // for the cursor.
-
- getString(2, 11, 28, MAX_STRINGS);
-
- // If we're saving over an old slot, show the old description. We can't
- // access that buffer directly, so we have to feed the characters to
- // the input handler one at a time.
-
- char name[40];
- int numChars;
-
- getSavegameDescription(_firstSlot + slot, name, false);
-
- for (numChars = 0; numChars < 28 && name[numChars]; numChars++)
- handleGetstring(name[numChars]);
-
- _gfx->printCharacter(numChars + 3, 11, _game.cursorChar, MSG_BOX_COLOR, MSG_BOX_TEXT);
- do {
- mainCycle();
- } while (_game.inputMode == INPUT_GETSTRING);
- closeWindow();
-
- desc = _game.strings[MAX_STRINGS];
- sprintf(dstr, "Are you sure you want to save the game "
- "described as:\n\n%s\n\nin slot %d?\n\n\n", desc, _firstSlot + slot);
-
- rc = selectionBox(dstr, buttons);
-
- if (rc != 0) {
- messageBox("Game NOT saved.");
- return errOK;
+ // search for saved game filenames...
+ filenames = _saveFileMan->listSavefiles(_targetName + ".###");
+
+ Common::StringArray::iterator it;
+ Common::StringArray::iterator end = filenames.end();
+
+ // convert to lower-case, just to be sure
+ for (it = filenames.begin(); it != end; it++) {
+ it->toLowercase();
}
+ // sort
+ Common::sort(filenames.begin(), filenames.end());
- int result = doSave(_firstSlot + slot, desc);
+ // now extract slot-Ids
+ for (it = filenames.begin(); it != end; it++) {
+ slotId = atoi(it->c_str() + numberPos);
- if (result == errOK)
- messageBox("Game saved.");
- else
- messageBox("Error saving game.");
+ slotIdArray.push_back(slotId);
+ }
+ return slotIdArray;
+}
- return result;
+Common::String AgiEngine::getSavegameFilename(int16 slotId) const {
+ Common::String saveLoadSlot = _targetName;
+ saveLoadSlot += Common::String::format(".%.3d", slotId);
+ return saveLoadSlot;
}
-int AgiEngine::saveGameSimple() {
- if (!ConfMan.getBool("originalsaveload"))
- return scummVMSaveLoadDialog(true);
+bool AgiEngine::getSavegameInformation(int16 slotId, Common::String &saveDescription, uint32 &saveDate, uint32 &saveTime, bool &saveIsValid) {
+ Common::InSaveFile *in;
+ Common::String fileName = getSavegameFilename(slotId);
+ char saveGameDescription[31];
+ int16 curPos = 0;
+ byte saveVersion = 0;
- Common::String fileName = getSavegameFilename(0);
+ saveDescription.clear();
+ saveDate = 0;
+ saveTime = 0;
+ saveIsValid = false;
- int result = saveGame(fileName, "Default savegame");
- if (result != errOK)
- messageBox("Error saving game.");
- return result;
-}
+ debugC(4, kDebugLevelMain | kDebugLevelSavegame, "Current game id is %s", _targetName.c_str());
-int AgiEngine::loadGameDialog() {
- if (!ConfMan.getBool("originalsaveload"))
- return scummVMSaveLoadDialog(false);
+ if (!(in = _saveFileMan->openForLoading(fileName))) {
+ debugC(4, kDebugLevelMain | kDebugLevelSavegame, "File %s does not exist", fileName.c_str());
+ return false;
+
+ } else {
+ debugC(4, kDebugLevelMain | kDebugLevelSavegame, "Successfully opened %s for reading", fileName.c_str());
- int slot = 0;
- int hm, vm, hp, vp; // box margins
- int w;
+ uint32 type = in->readUint32BE();
- hm = 1;
- vm = 3;
- hp = hm * CHAR_COLS;
- vp = vm * CHAR_LINES;
- w = (40 - 2 * hm) - 1;
+ if (type != AGIflag) {
+ warning("This doesn't appear to be an AGI savegame");
+ saveDescription += "[ScummVM: not an AGI save]";
+ delete in;
+ return true;
+ }
- _sprites->eraseBoth();
- _sound->stopSound();
+ debugC(6, kDebugLevelMain | kDebugLevelSavegame, "Has AGI flag, good start");
+ if (in->read(saveGameDescription, 31) != 31) {
+ warning("unexpected EOF");
+ delete in;
+ saveDescription += "[ScummVM: invalid save]";
+ return true;
+ }
- drawWindow(hp, vp, GFX_WIDTH - hp, GFX_HEIGHT - vp);
- printText("Select a game which you wish to\nrestore:",
- 0, hm + 1, vm + 1, w, MSG_BOX_TEXT, MSG_BOX_COLOR);
+ for (curPos = 0; curPos < 31; curPos++) {
+ if (!saveGameDescription[curPos])
+ break;
+ }
+ if (curPos >= 31) {
+ warning("corrupted description");
+ delete in;
+ saveDescription += "[ScummVM: invalid save]";
+ return true;
+ }
- slot = selectSlot();
+ saveVersion = in->readByte();
+ if (saveVersion > SAVEGAME_CURRENT_VERSION) {
+ warning("save from a future ScummVM, not supported");
+ delete in;
+ saveDescription += "[ScummVM: not supported]";
+ return true;
+ }
- if (slot < 0) {
- if (slot == -1) // slot = -2 when GMM was launched
- messageBox("Game NOT restored.");
+ if (saveVersion >= 4) {
+ // We don't need the thumbnail here, so just read it and discard it
+ Graphics::skipThumbnail(*in);
- return errOK;
+ saveDate = in->readUint32BE();
+ saveTime = in->readUint16BE() << 8;
+ if (saveVersion >= 9) {
+ saveTime |= in->readByte(); // add seconds (only available since saved game version 9+)
+ }
+
+ // save date is DDMMYYYY, we need a proper format
+ byte saveDateDay = saveDate >> 24;
+ byte saveDateMonth = (saveDate >> 16) & 0xFF;
+ uint16 saveDateYear = saveDate & 0xFFFF;
+
+ saveDate = (saveDateYear << 16) | (saveDateMonth << 8) | saveDateDay;
+
+ } else {
+ saveDate = 0;
+ saveTime = 0;
+ }
+
+ saveDescription += saveGameDescription;
+ saveIsValid = true;
+
+ delete in;
+ return true;
}
+}
+
+bool AgiEngine::loadGameAutomatic() {
+ int16 automaticRestoreGameSlotId = 0;
- return doLoad(_firstSlot + slot, true);
+ automaticRestoreGameSlotId = _systemUI->figureOutAutomaticRestoreGameSlot(_game.automaticSaveDescription);
+ if (automaticRestoreGameSlotId >= 0) {
+ if (doLoad(automaticRestoreGameSlotId, true) == errOK) {
+ return true;
+ }
+ }
+ return false;
}
-int AgiEngine::loadGameSimple() {
+bool AgiEngine::loadGameDialog() {
+ int16 restoreGameSlotId = 0;
+
if (!ConfMan.getBool("originalsaveload"))
return scummVMSaveLoadDialog(false);
- else
- return doLoad(0, true);
+
+ restoreGameSlotId = _systemUI->askForRestoreGameSlot();
+ if (restoreGameSlotId >= 0) {
+ if (doLoad(restoreGameSlotId, true) == errOK) {
+ return true;
+ }
+ }
+ return errOK;
}
+// Try to figure out either the slot, that is currently using the automatic saved game description
+// or get a new slot.
+// If we fail, return false, so that the regular saved game dialog is called
+// Original AGI was limited to 12 saves, we are effectively limited to 100 saves at the moment.
+//
+// btw. this also means that entering an existant name in Mixed Up Mother Goose will effectively overwrite
+// that saved game. This is also what original AGI did.
+bool AgiEngine::saveGameAutomatic() {
+ int16 automaticSaveGameSlotId = 0;
+
+ automaticSaveGameSlotId = _systemUI->figureOutAutomaticSaveGameSlot(_game.automaticSaveDescription);
+ if (automaticSaveGameSlotId >= 0) {
+ Common::String slotDescription(_game.automaticSaveDescription);
+
+ // WORKAROUND: Remove window in case one is currently shown, otherwise it would get saved in the thumbnail
+ // Happens for Mixed Up Mother Goose. The scripts close the window after saving.
+ // Original interpreter obviously did not do this, but original interpreter also did not save thumbnails.
+ _text->closeWindow();
+
+ if (doSave(automaticSaveGameSlotId, slotDescription) == errOK) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AgiEngine::saveGameDialog() {
+ int16 saveGameSlotId = 0;
+ Common::String slotDescription;
+
+ if (!ConfMan.getBool("originalsaveload"))
+ return scummVMSaveLoadDialog(true);
+
+ saveGameSlotId = _systemUI->askForSaveGameSlot();
+ if (saveGameSlotId >= 0) {
+ if (_systemUI->askForSaveGameDescription(saveGameSlotId, slotDescription)) {
+ if (doSave(saveGameSlotId, slotDescription) == errOK) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
void AgiEngine::recordImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3,
- int16 p4, int16 p5, int16 p6, int16 p7) {
+ int16 p4, int16 p5, int16 p6, int16 p7) {
ImageStackElement pnew;
pnew.type = type;
@@ -1015,15 +1030,15 @@ void AgiEngine::recordImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3,
}
void AgiEngine::replayImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3,
- int16 p4, int16 p5, int16 p6, int16 p7) {
+ int16 p4, int16 p5, int16 p6, int16 p7) {
switch (type) {
case ADD_PIC:
debugC(8, kDebugLevelMain, "--- decoding picture %d ---", p1);
- agiLoadResource(rPICTURE, p1);
+ agiLoadResource(RESOURCETYPE_PICTURE, p1);
_picture->decodePicture(p1, p2, p3 != 0);
break;
case ADD_VIEW:
- agiLoadResource(rVIEW, p1);
+ agiLoadResource(RESOURCETYPE_VIEW, p1);
_sprites->addToPic(p1, p2, p3, p4, p5, p6, p7);
break;
}
@@ -1041,12 +1056,12 @@ void AgiEngine::checkQuickLoad() {
if (ConfMan.hasKey("save_slot")) {
Common::String saveNameBuffer = getSavegameFilename(ConfMan.getInt("save_slot"));
- _sprites->eraseBoth();
+ _sprites->eraseSprites();
_sound->stopSound();
- if (loadGame(saveNameBuffer, false) == errOK) { // Do not check game id
- _game.exitAllLogics = 1;
- _menu->enableAll();
+ if (loadGame(saveNameBuffer, false) == errOK) { // Do not check game id
+ _game.exitAllLogics = true;
+ _menu->itemEnableAll();
}
}
}
@@ -1054,21 +1069,21 @@ void AgiEngine::checkQuickLoad() {
Common::Error AgiEngine::loadGameState(int slot) {
Common::String saveLoadSlot = getSavegameFilename(slot);
- _sprites->eraseBoth();
+ _sprites->eraseSprites();
_sound->stopSound();
if (loadGame(saveLoadSlot) == errOK) {
- _game.exitAllLogics = 1;
- _menu->enableAll();
+ _game.exitAllLogics = true;
+ _menu->itemEnableAll();
return Common::kNoError;
} else {
return Common::kUnknownError;
}
}
-Common::Error AgiEngine::saveGameState(int slot, const Common::String &desc) {
+Common::Error AgiEngine::saveGameState(int slot, const Common::String &description) {
Common::String saveLoadSlot = getSavegameFilename(slot);
- if (saveGame(saveLoadSlot, desc) == errOK)
+ if (saveGame(saveLoadSlot, description) == errOK)
return Common::kNoError;
else
return Common::kUnknownError;
diff --git a/engines/agi/sound.cpp b/engines/agi/sound.cpp
index 8f678cbac9..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
//
@@ -140,7 +150,7 @@ void SoundMgr::startSound(int resnum, int flag) {
if (_vm->getVersion() < 0x2000) {
_vm->_game.vars[_endflag] = 0;
} else {
- _vm->setflag(_endflag, false);
+ _vm->setFlag(_endflag, false);
}
}
@@ -160,7 +170,7 @@ void SoundMgr::stopSound() {
if (_vm->getVersion() < 0x2000) {
_vm->_game.vars[_endflag] = 1;
} else {
- _vm->setflag(_endflag, true);
+ _vm->setFlag(_endflag, true);
}
}
@@ -169,7 +179,7 @@ void SoundMgr::stopSound() {
void SoundMgr::soundIsFinished() {
if (_endflag != -1)
- _vm->setflag(_endflag, true);
+ _vm->setFlag(_endflag, true);
if (_playingSound != -1)
_vm->_game.sounds[_playingSound]->stop();
@@ -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 992feb1186..8aa7a5d1df 100644
--- a/engines/agi/sound.h
+++ b/engines/agi/sound.h
@@ -23,15 +23,18 @@
#ifndef AGI_SOUND_H
#define AGI_SOUND_H
-#include "audio/mixer.h"
+namespace Audio {
+class Mixer;
+class SoundHandle;
+}
namespace Agi {
-#define SOUND_EMU_NONE 0
-#define SOUND_EMU_PC 1
-#define SOUND_EMU_PCJR 2
-#define SOUND_EMU_MAC 3
-#define SOUND_EMU_AMIGA 4
+#define SOUND_EMU_NONE 0
+#define SOUND_EMU_PC 1
+#define SOUND_EMU_PCJR 2
+#define SOUND_EMU_MAC 3
+#define SOUND_EMU_AMIGA 4
#define SOUND_EMU_APPLE2GS 5
#define SOUND_EMU_COCO3 6
#define SOUND_EMU_MIDI 7
@@ -62,20 +65,17 @@ struct AgiNote {
* starts (The first 16-bit little endian word, to be precise).
*/
enum AgiSoundEmuType {
- AGI_SOUND_SAMPLE = 0x0001,
- AGI_SOUND_MIDI = 0x0002,
- AGI_SOUND_4CHN = 0x0008
+ AGI_SOUND_SAMPLE = 0x0001,
+ AGI_SOUND_MIDI = 0x0002,
+ AGI_SOUND_4CHN = 0x0008
};
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 b940eed762..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;
}
@@ -95,21 +96,20 @@ int SoundGen2GS::readBuffer(int16 *buffer, const int numSamples) {
void SoundGen2GS::play(int resnum) {
AgiSoundEmuType type;
- _playingSound = resnum;
-
type = (AgiSoundEmuType)_vm->_game.sounds[resnum]->type();
- assert (type == AGI_SOUND_SAMPLE || type == AGI_SOUND_MIDI);
+ assert(type == AGI_SOUND_SAMPLE || type == AGI_SOUND_MIDI);
if (_vm->_soundemu != SOUND_EMU_APPLE2GS) {
warning("Trying to play sample or MIDI resource but not using Apple IIGS sound emulation mode");
return;
}
+ // FIXME: all sorts of things in here are not thread-safe
haltGenerators();
switch (type) {
case AGI_SOUND_SAMPLE: {
- IIgsSample *sampleRes = (IIgsSample *) _vm->_game.sounds[_playingSound];
+ IIgsSample *sampleRes = (IIgsSample *) _vm->_game.sounds[resnum];
const IIgsSampleHeader &header = sampleRes->getHeader();
_channels[kSfxMidiChannel].setInstrument(&header.instrument);
_channels[kSfxMidiChannel].setVolume(header.volume);
@@ -117,18 +117,20 @@ void SoundGen2GS::play(int resnum) {
break;
}
case AGI_SOUND_MIDI:
- ((IIgsMidi *) _vm->_game.sounds[_playingSound])->rewind();
+ ((IIgsMidi *) _vm->_game.sounds[resnum])->rewind();
_ticks = 0;
break;
default:
break;
}
+
+ _playingSound = resnum;
}
void SoundGen2GS::stop() {
haltGenerators();
_playingSound = -1;
- _playing = 0;
+ _playing = false;
}
/**
@@ -144,26 +146,26 @@ uint SoundGen2GS::generateOutput() {
int16 *p = _out;
int n = _outSize;
while (n--) {
- int outl = 0;
- int outr = 0;
+ int outLeft = 0;
+ int outRight = 0;
for (int k = 0; k < MAX_GENERATORS; k++) {
IIgsGenerator *g = &_generators[k];
- if (!g->ins)
+ if (!g->curInstrument)
continue;
- const IIgsInstrumentHeader *i = g->ins;
+ const IIgsInstrumentHeader *curInstrument = g->curInstrument;
// Advance envelope
int vol = fracToInt(g->a);
- if (g->a <= i->env[g->seg].bp) {
- g->a += i->env[g->seg].inc * ENVELOPE_COEF;
- if (g->a > i->env[g->seg].bp) {
- g->a = i->env[g->seg].bp;
+ if (g->a <= curInstrument->env[g->seg].bp) {
+ g->a += curInstrument->env[g->seg].inc * ENVELOPE_COEF;
+ if (g->a > curInstrument->env[g->seg].bp) {
+ g->a = curInstrument->env[g->seg].bp;
g->seg++;
}
} else {
- g->a -= i->env[g->seg].inc * ENVELOPE_COEF;
- if (g->a < i->env[g->seg].bp) {
- g->a = i->env[g->seg].bp;
+ g->a -= curInstrument->env[g->seg].inc * ENVELOPE_COEF;
+ if (g->a < curInstrument->env[g->seg].bp) {
+ g->a = curInstrument->env[g->seg].bp;
g->seg++;
}
}
@@ -182,10 +184,10 @@ uint SoundGen2GS::generateOutput() {
if ((uint)fracToInt(g->osc[0].p) >= g->osc[0].size) {
g->osc[0].p -= intToFrac(g->osc[0].size);
if (!g->osc[0].loop)
- g->osc[0].halt = 1;
+ g->osc[0].halt = true;
if (g->osc[0].swap) {
- g->osc[0].halt = 1;
- g->osc[1].halt = 0;
+ g->osc[0].halt = true;
+ g->osc[1].halt = false;
}
}
}
@@ -195,42 +197,42 @@ uint SoundGen2GS::generateOutput() {
if ((uint)fracToInt(g->osc[1].p) >= g->osc[1].size) {
g->osc[1].p -= intToFrac(g->osc[1].size);
if (!g->osc[1].loop)
- g->osc[1].halt = 1;
+ g->osc[1].halt = true;
if (g->osc[1].swap) {
- g->osc[0].halt = 0;
- g->osc[1].halt = 1;
+ g->osc[0].halt = false;
+ g->osc[1].halt = true;
}
}
}
// Take envelope and MIDI volume information into account.
// Also amplify.
- s0 *= vol * g->vel / 127 * 80 / 256;
- s1 *= vol * g->vel / 127 * 80 / 256;
+ s0 *= vol * g->velocity / 127 * 80 / 256;
+ s1 *= vol * g->velocity / 127 * 80 / 256;
// Select output channel.
- if (g->osc[0].chn)
- outl += s0;
+ if (g->osc[0].rightChannel)
+ outRight += s0;
else
- outr += s0;
+ outLeft += s0;
- if (g->osc[1].chn)
- outl += s1;
+ if (g->osc[1].rightChannel)
+ outRight += s1;
else
- outr += s1;
+ outLeft += s1;
}
- if (outl > 32768)
- outl = 32768;
- if (outl < -32767)
- outl = -32767;
- if (outr > 32768)
- outr = 32768;
- if (outr < -32767)
- outr = -32767;
-
- *p++ = outl;
- *p++ = outr;
+ if (outLeft > 32768)
+ outLeft = 32768;
+ if (outLeft < -32767)
+ outLeft = -32767;
+ if (outRight > 32768)
+ outRight = 32768;
+ if (outRight < -32767)
+ outRight = -32767;
+
+ *p++ = outLeft;
+ *p++ = outRight;
}
return _outSize * 2;
@@ -345,7 +347,7 @@ void SoundGen2GS::advanceMidiPlayer() {
case MIDI_PITCH_WHEEL:
parm1 = *p++;
parm2 = *p++;
- debugC(3, kDebugLevelSound, "channel %X: pitch wheel (unimplemented)", chn);
+ debugC(3, kDebugLevelSound, "channel %X: pitch wheel (unimplemented) %02X, %02X", chn, parm1, parm2);
break;
default:
@@ -360,8 +362,11 @@ void SoundGen2GS::advanceMidiPlayer() {
void SoundGen2GS::midiNoteOff(int channel, int note, int velocity) {
// Release keys within the given MIDI channel
for (int i = 0; i < MAX_GENERATORS; i++) {
- if (_generators[i].chn == channel && _generators[i].key == note)
- _generators[i].seg = _generators[i].ins->seg;
+ if (_generators[i].channel == channel && _generators[i].key == note) {
+ if (_generators[i].curInstrument) {
+ _generators[i].seg = _generators[i].curInstrument->seg;
+ }
+ }
}
}
@@ -372,9 +377,9 @@ void SoundGen2GS::midiNoteOn(int channel, int note, int velocity) {
}
// Allocate a generator for the note.
- IIgsGenerator* g = allocateGenerator();
- g->ins = _channels[channel].getInstrument();
- const IIgsInstrumentHeader* i = g->ins;
+ IIgsGenerator *generator = allocateGenerator();
+ generator->curInstrument = _channels[channel].getInstrument();
+ const IIgsInstrumentHeader *curInstrument = generator->curInstrument;
// Pass information from the MIDI channel to the generator. Take
// velocity into account, although simplistically.
@@ -382,45 +387,45 @@ void SoundGen2GS::midiNoteOn(int channel, int note, int velocity) {
if (velocity > 127)
velocity = 127;
- g->key = note;
- g->vel = velocity * _channels[channel].getVolume() / 127;
- g->chn = channel;
+ generator->key = note;
+ generator->velocity = velocity * _channels[channel].getVolume() / 127;
+ generator->channel = channel;
// Instruments can define different samples to be used based on
// what the key is. Find the correct samples for our key.
int wa = 0;
int wb = 0;
- while (wa < i->waveCount[0] - 1 && note > i->wave[0][wa].key)
+ while (wa < curInstrument->waveCount[0] - 1 && note > curInstrument->wave[0][wa].key)
wa++;
- while (wb < i->waveCount[1] - 1 && note > i->wave[1][wb].key)
+ while (wb < curInstrument->waveCount[1] - 1 && note > curInstrument->wave[1][wb].key)
wb++;
// Prepare the generator.
- g->osc[0].base = i->base + i->wave[0][wa].offset;
- g->osc[0].size = i->wave[0][wa].size;
- g->osc[0].pd = doubleToFrac(midiKeyToFreq(note, (double)i->wave[0][wa].tune / 256.0) / (double)_sampleRate);
- g->osc[0].p = 0;
- g->osc[0].halt = i->wave[0][wa].halt;
- g->osc[0].loop = i->wave[0][wa].loop;
- g->osc[0].swap = i->wave[0][wa].swap;
- g->osc[0].chn = i->wave[0][wa].chn;
-
- g->osc[1].base = i->base + i->wave[1][wb].offset;
- g->osc[1].size = i->wave[1][wb].size;
- g->osc[1].pd = doubleToFrac(midiKeyToFreq(note, (double)i->wave[1][wb].tune / 256.0) / (double)_sampleRate);
- g->osc[1].p = 0;
- g->osc[1].halt = i->wave[1][wb].halt;
- g->osc[1].loop = i->wave[1][wb].loop;
- g->osc[1].swap = i->wave[1][wb].swap;
- g->osc[1].chn = i->wave[1][wb].chn;
-
- g->seg = 0;
- g->a = 0;
+ generator->osc[0].base = curInstrument->wavetableBase + curInstrument->wave[0][wa].offset;
+ generator->osc[0].size = curInstrument->wave[0][wa].size;
+ generator->osc[0].pd = doubleToFrac(midiKeyToFreq(note, (double)curInstrument->wave[0][wa].tune / 256.0) / (double)_sampleRate);
+ generator->osc[0].p = 0;
+ generator->osc[0].halt = curInstrument->wave[0][wa].halt;
+ generator->osc[0].loop = curInstrument->wave[0][wa].loop;
+ generator->osc[0].swap = curInstrument->wave[0][wa].swap;
+ generator->osc[0].rightChannel = curInstrument->wave[0][wa].rightChannel;
+
+ generator->osc[1].base = curInstrument->wavetableBase + curInstrument->wave[1][wb].offset;
+ generator->osc[1].size = curInstrument->wave[1][wb].size;
+ generator->osc[1].pd = doubleToFrac(midiKeyToFreq(note, (double)curInstrument->wave[1][wb].tune / 256.0) / (double)_sampleRate);
+ generator->osc[1].p = 0;
+ generator->osc[1].halt = curInstrument->wave[1][wb].halt;
+ generator->osc[1].loop = curInstrument->wave[1][wb].loop;
+ generator->osc[1].swap = curInstrument->wave[1][wb].swap;
+ generator->osc[1].rightChannel = curInstrument->wave[1][wb].rightChannel;
+
+ generator->seg = 0;
+ generator->a = 0;
// Print debug messages for instruments with swap mode or vibrato enabled
- if (g->osc[0].swap || g->osc[1].swap)
+ if (generator->osc[0].swap || generator->osc[1].swap)
debugC(2, kDebugLevelSound, "Detected swap mode in a playing instrument. This is rare and is not tested well...");
- if (i->vibDepth > 0)
+ if (curInstrument->vibDepth > 0)
debugC(2, kDebugLevelSound, "Detected vibrato in a playing instrument. Vibrato is not implemented, playing without...");
}
@@ -430,6 +435,9 @@ double SoundGen2GS::midiKeyToFreq(int key, double finetune) {
void SoundGen2GS::haltGenerators() {
for (int i = 0; i < MAX_GENERATORS; i++) {
+ // Reset instrument pointer especially for samples, because samples are deleted on unload/room changes
+ // and not resetting them here would cause those invalidated samples get accessed during generateOutput()
+ _generators[i].curInstrument = nullptr;
_generators[i].osc[0].halt = true;
_generators[i].osc[1].halt = true;
}
@@ -468,13 +476,15 @@ IIgsMidi::IIgsMidi(uint8 *data, uint32 len, int resnum) : AgiSound() {
static bool convertWave(Common::SeekableReadStream &source, int8 *dest, uint length) {
// Convert the wave from 8-bit unsigned to 8-bit signed format
for (uint i = 0; i < length; i++)
- dest[i] = (int8) ((int) source.readByte() - ZERO_OFFSET);
+ dest[i] = (int8)((int)source.readByte() - ZERO_OFFSET);
return !(source.eos() || source.err());
}
-IIgsSample::IIgsSample(uint8 *data, uint32 len, int resnum) : AgiSound() {
+IIgsSample::IIgsSample(uint8 *data, uint32 len, int16 resourceNr) : AgiSound() {
Common::MemoryReadStream stream(data, len, DisposeAfterUse::YES);
+ _sample = nullptr;
+
// Check that the header was read ok and that it's of the correct type
if (_header.read(stream) && _header.type == AGI_SOUND_SAMPLE) { // An Apple IIGS AGI sample resource
uint32 sampleStartPos = stream.pos();
@@ -483,14 +493,14 @@ IIgsSample::IIgsSample(uint8 *data, uint32 len, int resnum) : AgiSound() {
if (tailLen < _header.sampleSize) { // Check if there's no room for the sample data in the stream
// Apple IIGS Manhunter I: Sound resource 16 has only 16074 bytes
// of sample data although header says it should have 16384 bytes.
- warning("Apple IIGS sample (%d) too short (%d bytes. Should be %d bytes). Using the part that's left",
- resnum, tailLen, _header.sampleSize);
+ warning("Apple IIGS sample (%d) expected %d bytes, got %d bytes only",
+ resourceNr, _header.sampleSize, tailLen);
_header.sampleSize = (uint16) tailLen; // Use the part that's left
}
if (_header.pitch > 0x7F) { // Check if the pitch is invalid
- warning("Apple IIGS sample (%d) has too high pitch (0x%02x)", resnum, _header.pitch);
+ warning("Apple IIGS sample (%d) has too high pitch (0x%02x)", resourceNr, _header.pitch);
_header.pitch &= 0x7F; // Apple IIGS AGI probably did it this way too
}
@@ -501,13 +511,16 @@ IIgsSample::IIgsSample(uint8 *data, uint32 len, int resnum) : AgiSound() {
if (_sample != NULL) {
_isValid = convertWave(stream, _sample, _header.sampleSize);
- // Finalize header info using sample data
- _header.finalize(_sample);
+
+ if (_isValid) {
+ // Finalize header info using sample data
+ _header.finalize(_sample);
+ }
}
}
if (!_isValid) // Check for errors
- warning("Error creating Apple IIGS sample from resource %d (Type %d, length %d)", resnum, _header.type, len);
+ warning("Error creating Apple IIGS sample from resource %d (Type %d, length %d)", resourceNr, _header.type, len);
}
@@ -516,74 +529,90 @@ bool IIgsInstrumentHeader::read(Common::SeekableReadStream &stream, bool ignoreA
env[i].bp = intToFrac(stream.readByte());
env[i].inc = intToFrac(stream.readUint16LE()) >> 8;
}
- seg = stream.readByte();
- /*priority =*/ stream.readByte(); // Not needed. 32 in all tested data.
- bend = stream.readByte();
- vibDepth = stream.readByte();
- vibSpeed = stream.readByte();
+ seg = stream.readByte();
+ /*priority =*/ stream.readByte(); // Not needed. 32 in all tested data.
+ bend = stream.readByte();
+ vibDepth = stream.readByte();
+ vibSpeed = stream.readByte();
stream.readByte(); // Not needed? 0 in all tested data.
waveCount[0] = stream.readByte();
waveCount[1] = stream.readByte();
- for (int i = 0; i < 2; i++)
- for (int k = 0; k < waveCount[i]; k++) {
- wave[i][k].key = stream.readByte();
- wave[i][k].offset = stream.readByte() << 8;
- wave[i][k].size = 0x100 << (stream.readByte() & 7);
- uint8 b = stream.readByte();
- wave[i][k].tune = stream.readUint16LE();
-
- // For sample resources we ignore the address.
- if (ignoreAddr)
- wave[i][k].offset = 0;
-
- // Check for samples that extend out of the wavetable.
- if (wave[i][k].offset + wave[i][k].size >= SIERRASTANDARD_SIZE) {
- warning("Invalid data detected in the instrument set of Apple IIGS AGI. Continuing anyway...");
- wave[i][k].size = SIERRASTANDARD_SIZE - wave[i][k].offset;
+ for (int i = 0; i < 2; i++) {
+ for (int k = 0; k < waveCount[i]; k++) {
+ wave[i][k].key = stream.readByte();
+ wave[i][k].offset = stream.readByte() << 8;
+ wave[i][k].size = 0x100 << (stream.readByte() & 7);
+ uint8 b = stream.readByte();
+ wave[i][k].tune = stream.readUint16LE();
+
+ // For sample resources we ignore the address.
+ if (ignoreAddr)
+ wave[i][k].offset = 0;
+
+ // Parse the generator mode byte to separate fields.
+ wave[i][k].halt = b & 0x1; // Bit 0 = HALT
+ wave[i][k].loop = !(b & 0x2); // Bit 1 =!LOOP
+ wave[i][k].swap = (b & 0x6) == 0x6; // Bit 1&2 = SWAP
+ // channels seem to be reversed, verified with emulator + captured apple IIgs music
+ if (b & 0x10) {
+ wave[i][k].rightChannel = true; // Bit 4 set = right channel
+ } else {
+ wave[i][k].rightChannel = false; // Bit 4 not set = left channel
+ }
}
-
- // Parse the generator mode byte to separate fields.
- wave[i][k].halt = b & 0x1; // Bit 0 = HALT
- wave[i][k].loop = !(b & 0x2); // Bit 1 =!LOOP
- wave[i][k].swap = (b & 0x6) == 0x6; // Bit 1&2 = SWAP
- wave[k][k].chn = (b >> 4) > 0; // Output channel (left or right)
}
return !(stream.eos() || stream.err());
}
-bool IIgsInstrumentHeader::finalize(int8 *wavetable) {
- // Calculate final pointers to sample data and detect true sample size
- // in case the sample ends prematurely.
- for (int i = 0; i < 2; i++)
- for (int k = 0; k < waveCount[i]; k++) {
- base = wavetable;
- int8 *p = base + wave[i][k].offset;
- uint trueSize;
- for (trueSize = 0; trueSize < wave[i][k].size; trueSize++)
- if (p[trueSize] == -ZERO_OFFSET)
- break;
- wave[i][k].size = trueSize;
+bool IIgsInstrumentHeader::finalize(int8 *wavetable, uint32 wavetableSize) {
+ wavetableBase = wavetable;
+
+ // Go through all offsets and sizes and make sure, they point to within wavetable
+ for (int i = 0; i < 2; i++) {
+ for (int k = 0; k < waveCount[i]; k++) {
+ uint32 waveOffset = wave[i][k].offset;
+ uint32 waveSize = wave[i][k].size;
+
+ if (waveOffset >= wavetableSize) {
+ error("Apple IIgs sound: sample data points outside of wavetable");
+ }
+
+ if ((waveOffset + waveSize) > wavetableSize) {
+ // fix up size, it's actually saved in a way in the header, that it can't be correct
+ // if we don't fix it here, we would do invalid memory access, which results in potential crashes
+ wave[i][k].size = wavetableSize - waveOffset;
+ }
+
+ // Detect true sample size
+ int8 *sample = wavetableBase + wave[i][k].offset;
+ uint32 trueSize;
+ for (trueSize = 0; trueSize < wave[i][k].size; trueSize++) {
+ if (sample[trueSize] == -ZERO_OFFSET)
+ break;
+ }
+ wave[i][k].size = trueSize;
+ }
}
return true;
}
bool IIgsSampleHeader::read(Common::SeekableReadStream &stream) {
- type = stream.readUint16LE();
- pitch = stream.readByte();
- unknownByte_Ofs3 = stream.readByte();
- volume = stream.readByte();
- unknownByte_Ofs5 = stream.readByte();
- instrumentSize = stream.readUint16LE();
- sampleSize = stream.readUint16LE();
+ type = stream.readUint16LE();
+ pitch = stream.readByte();
+ unknownByte_Ofs3 = stream.readByte();
+ volume = stream.readByte();
+ unknownByte_Ofs5 = stream.readByte();
+ instrumentSize = stream.readUint16LE();
+ sampleSize = stream.readUint16LE();
// Read the instrument header *ignoring* its wave address info
return instrument.read(stream, true);
}
-bool IIgsSampleHeader::finalize(int8 *sample) {
- return instrument.finalize(sample);
+bool IIgsSampleHeader::finalize(int8 *sampleData) {
+ return instrument.finalize(sampleData, sampleSize);
}
//###
@@ -625,22 +654,26 @@ bool SoundGen2GS::loadInstruments() {
/** Older Apple IIGS AGI MIDI program change to instrument number mapping. */
static const IIgsMidiProgramMapping progToInstMappingV1 = {
- {19, 20, 22, 23, 21, 24, 5, 5, 5, 5,
- 6, 7, 10, 9, 11, 9, 15, 8, 5, 5,
- 17, 16, 18, 12, 14, 5, 5, 5, 5, 5,
- 0, 1, 2, 9, 3, 4, 15, 2, 2, 2,
- 25, 13, 13, 25},
+ {
+ 19, 20, 22, 23, 21, 24, 5, 5, 5, 5,
+ 6, 7, 10, 9, 11, 9, 15, 8, 5, 5,
+ 17, 16, 18, 12, 14, 5, 5, 5, 5, 5,
+ 0, 1, 2, 9, 3, 4, 15, 2, 2, 2,
+ 25, 13, 13, 25
+ },
5
};
/** Newer Apple IIGS AGI MIDI program change to instrument number mapping.
FIXME: Some instrument choices sound wrong. */
static const IIgsMidiProgramMapping progToInstMappingV2 = {
- {21, 22, 24, 25, 23, 26, 6, 6, 6, 6,
- 7, 9, 12, 8, 13, 11, 17, 10, 6, 6,
- 19, 18, 20, 14, 16, 6, 6, 6, 6, 6,
- 0, 1, 2, 4, 3, 5, 17, 2, 2, 2,
- 27, 15, 15, 27},
+ {
+ 21, 22, 24, 25, 23, 26, 6, 6, 6, 6,
+ 7, 9, 12, 8, 13, 11, 17, 10, 6, 6,
+ 19, 18, 20, 14, 16, 6, 6, 6, 6, 6,
+ 0, 1, 2, 4, 3, 5, 17, 2, 2, 2,
+ 27, 15, 15, 27
+ },
6
};
@@ -715,7 +748,7 @@ bool SoundGen2GS::loadInstrumentHeaders(Common::String &exePath, const IIgsExeIn
file.open(exePath);
if (file.size() != (int32)exeInfo.exeSize) {
debugC(3, kDebugLevelSound, "Apple IIGS executable (%s) has wrong size (Is %d, should be %d)",
- exePath.c_str(), file.size(), exeInfo.exeSize);
+ exePath.c_str(), file.size(), exeInfo.exeSize);
}
// Read the whole executable file into memory
@@ -736,7 +769,7 @@ bool SoundGen2GS::loadInstrumentHeaders(Common::String &exePath, const IIgsExeIn
uint16 instSetByteCount = data->readUint16LE();
if (instSetByteCount != exeInfo.instSet->byteCount) {
debugC(3, kDebugLevelSound, "Wrong instrument set size (Is %d, should be %d) in Apple IIGS executable (%s)",
- instSetByteCount, exeInfo.instSet->byteCount, exePath.c_str());
+ instSetByteCount, exeInfo.instSet->byteCount, exePath.c_str());
}
// Check instrument set's md5sum
@@ -744,7 +777,7 @@ bool SoundGen2GS::loadInstrumentHeaders(Common::String &exePath, const IIgsExeIn
Common::String md5str = Common::computeStreamMD5AsString(*data, exeInfo.instSet->byteCount);
if (md5str != exeInfo.instSet->md5) {
warning("Unknown Apple IIGS instrument set (md5: %s) in %s, trying to use it nonetheless",
- md5str.c_str(), exePath.c_str());
+ md5str.c_str(), exePath.c_str());
}
// Read in the instrument set one instrument at a time
@@ -757,10 +790,10 @@ bool SoundGen2GS::loadInstrumentHeaders(Common::String &exePath, const IIgsExeIn
for (uint i = 0; i < exeInfo.instSet->instCount; i++) {
if (!instrument.read(*data)) {
warning("Error loading Apple IIGS instrument (%d. of %d) from %s, not loading more instruments",
- i + 1, exeInfo.instSet->instCount, exePath.c_str());
+ i + 1, exeInfo.instSet->instCount, exePath.c_str());
break;
}
- instrument.finalize(_wavetable);
+ instrument.finalize(_wavetable, SIERRASTANDARD_SIZE);
_instruments.push_back(instrument);
}
@@ -789,8 +822,8 @@ bool SoundGen2GS::loadWaveFile(Common::String &wavePath, const IIgsExeInfo &exeI
Common::String md5str = Common::computeStreamMD5AsString(*uint8Wave, SIERRASTANDARD_SIZE);
if (md5str != exeInfo.instSet->waveFileMd5) {
warning("Unknown Apple IIGS wave file (md5: %s, game: %s).\n" \
- "Please report the information on the previous line to the ScummVM team.\n" \
- "Using the wave file as it is - music may sound weird", md5str.c_str(), exeInfo.exePrefix);
+ "Please report the information on the previous line to the ScummVM team.\n" \
+ "Using the wave file as it is - music may sound weird", md5str.c_str(), exeInfo.exePrefix);
}
// Convert the wave file to 8-bit signed and save the result
diff --git a/engines/agi/sound_2gs.h b/engines/agi/sound_2gs.h
index 8a1999c8eb..49a375cdbc 100644
--- a/engines/agi/sound_2gs.h
+++ b/engines/agi/sound_2gs.h
@@ -44,14 +44,14 @@ namespace Agi {
#define ENVELOPE_COEF 100 / _sampleRate
// MIDI player commands
-#define MIDI_NOTE_OFF 0x8
-#define MIDI_NOTE_ON 0x9
-#define MIDI_CONTROLLER 0xB
-#define MIDI_PROGRAM_CHANGE 0xC
-#define MIDI_PITCH_WHEEL 0xE
+#define MIDI_NOTE_OFF 0x8
+#define MIDI_NOTE_ON 0x9
+#define MIDI_CONTROLLER 0xB
+#define MIDI_PROGRAM_CHANGE 0xC
+#define MIDI_PITCH_WHEEL 0xE
-#define MIDI_STOP_SEQUENCE 0xFC
-#define MIDI_TIMER_SYNC 0xF8
+#define MIDI_STOP_SEQUENCE 0xFC
+#define MIDI_TIMER_SYNC 0xF8
// Size of the SIERRASTANDARD file (i.e. the wave file i.e. the sample data used by the instruments).
#define SIERRASTANDARD_SIZE 65536
@@ -70,26 +70,26 @@ namespace Agi {
struct IIgsInstrumentHeader {
struct {
- frac_t bp; ///< Envelope segment breakpoint
- frac_t inc; ///< Envelope segment velocity
+ frac_t bp; ///< Envelope segment breakpoint
+ frac_t inc; ///< Envelope segment velocity
} env[ENVELOPE_SEGMENT_COUNT];
- uint8 seg; ///< Envelope release segment
- uint8 bend; ///< Maximum range for pitch bend
- uint8 vibDepth; ///< Vibrato depth
- uint8 vibSpeed; ///< Vibrato speed
- uint8 waveCount[2]; ///< Wave count for both generators
+ uint8 seg; ///< Envelope release segment
+ uint8 bend; ///< Maximum range for pitch bend
+ uint8 vibDepth; ///< Vibrato depth
+ uint8 vibSpeed; ///< Vibrato speed
+ uint8 waveCount[2]; ///< Wave count for both generators
struct {
- uint8 key; ///< Highest MIDI key to use this wave
- int offset; ///< Offset of wave data, relative to base
- uint size; ///< Wave size
- bool halt; ///< Oscillator halted?
- bool loop; ///< Loop mode?
- bool swap; ///< Swap mode?
- bool chn; ///< Output channel (left / right)
- int16 tune; ///< Fine tune in semitones (8.8 fixed point)
+ uint8 key; ///< Highest MIDI key to use this wave
+ uint32 offset; ///< Offset of wave data, relative to base
+ uint32 size; ///< Wave size
+ bool halt; ///< Oscillator halted?
+ bool loop; ///< Loop mode?
+ bool swap; ///< Swap mode?
+ bool rightChannel; ///< Output channel (left / right)
+ int16 tune; ///< Fine tune in semitones (8.8 fixed point)
} wave[2][MAX_OSCILLATOR_WAVES];
- int8* base; ///< Base of wave data
+ int8 *wavetableBase; ///< Base of wave data
/**
* Read an Apple IIGS instrument header from the given stream.
@@ -98,7 +98,7 @@ struct IIgsInstrumentHeader {
* @return True if successful, false otherwise.
*/
bool read(Common::SeekableReadStream &stream, bool ignoreAddr = false);
- bool finalize(int8 *);
+ bool finalize(int8 *wavetable, uint32 wavetableSize);
};
struct IIgsSampleHeader {
@@ -107,8 +107,8 @@ struct IIgsSampleHeader {
uint8 unknownByte_Ofs3; // 0x7F in Gold Rush's sound resource 60, 0 in all others.
uint8 volume; ///< Current guess: Logarithmic in 6 dB steps
uint8 unknownByte_Ofs5; ///< 0 in all tested samples.
- uint16 instrumentSize; ///< Little endian. 44 in all tested samples. A guess.
- uint16 sampleSize; ///< Little endian. Accurate in all tested samples excluding Manhunter I's sound resource 16.
+ uint16 instrumentSize; ///< 44 in all tested samples. A guess.
+ uint16 sampleSize; ///< Accurate in all tested samples excluding Manhunter I's sound resource 16.
IIgsInstrumentHeader instrument;
/**
@@ -117,29 +117,34 @@ struct IIgsSampleHeader {
* @return True if successful, false otherwise.
*/
bool read(Common::SeekableReadStream &stream);
- bool finalize(int8 *sample);
+ bool finalize(int8 *sampleData);
};
class IIgsGenerator {
public:
- IIgsGenerator() : ins(NULL), key(-1), chn(-1) {}
+ IIgsGenerator() : curInstrument(nullptr), key(-1), channel(-1) {
+ memset(&osc, 0, sizeof(osc));
+ seg = 0;
+ a = 0;
+ velocity = 0;
+ }
- const IIgsInstrumentHeader *ins; ///< Currently used instrument
- int key; ///< MIDI key
- int vel; ///< MIDI velocity (& channel volume)
- int chn; ///< MIDI channel
+ const IIgsInstrumentHeader *curInstrument; ///< Currently used instrument
+ int key; ///< MIDI key
+ int velocity; ///< MIDI velocity (& channel volume)
+ int channel; ///< MIDI channel
struct {
- int8 *base; ///< Sample base pointer
- uint size; ///< Sample size
- frac_t p; ///< Sample pointer
- frac_t pd; ///< Sample pointer delta
- bool halt; ///< Is oscillator halted?
- bool loop; ///< Is looping enabled?
- bool swap; ///< Is swapping enabled?
- bool chn; ///< Output channel (left / right)
+ int8 *base; ///< Sample base pointer
+ uint size; ///< Sample size
+ frac_t p; ///< Sample pointer
+ frac_t pd; ///< Sample pointer delta
+ bool halt; ///< Is oscillator halted?
+ bool loop; ///< Is looping enabled?
+ bool swap; ///< Is swapping enabled?
+ bool rightChannel; ///< Output channel (left / right)
} osc[2];
- int seg; ///< Current envelope segment
- frac_t a; ///< Current envelope amplitude
+ int seg; ///< Current envelope segment
+ frac_t a; ///< Current envelope amplitude
};
class IIgsMidi : public AgiSound {
@@ -161,14 +166,13 @@ public:
class IIgsSample : public AgiSound {
public:
- IIgsSample(uint8 *data, uint32 len, int resnum);
+ IIgsSample(uint8 *data, uint32 len, int16 resourceNr);
~IIgsSample() { delete[] _sample; }
virtual uint16 type() { return _header.type; }
const IIgsSampleHeader &getHeader() const { return _header; }
- const int8 *getSample() const { return _sample; }
protected:
- IIgsSampleHeader _header; ///< Apple IIGS AGI sample header
- int8 *_sample; ///< Sample data (8-bit signed format)
+ IIgsSampleHeader _header; ///< Apple IIGS AGI sample header
+ int8 *_sample; ///< Sample data (8-bit signed format)
};
/** Apple IIGS MIDI program change to instrument number mapping. */
@@ -193,11 +197,11 @@ struct IIgsInstrumentSetInfo {
/** Apple IIGS AGI executable file information. */
struct IIgsExeInfo {
- enum AgiGameID gameid; ///< Game ID
- const char *exePrefix; ///< Prefix of the Apple IIGS AGI executable (e.g. "SQ", "PQ", "KQ4" etc)
- uint agiVer; ///< Apple IIGS AGI version number, not strictly needed
- uint exeSize; ///< Size of the Apple IIGS AGI executable file in bytes
- uint instSetStart; ///< Starting offset of the instrument set inside the executable file
+ enum AgiGameID gameid; ///< Game ID
+ const char *exePrefix; ///< Prefix of the Apple IIGS AGI executable (e.g. "SQ", "PQ", "KQ4" etc)
+ uint agiVer; ///< Apple IIGS AGI version number, not strictly needed
+ uint exeSize; ///< Size of the Apple IIGS AGI executable file in bytes
+ uint instSetStart; ///< Starting offset of the instrument set inside the executable file
const IIgsInstrumentSetInfo *instSet; ///< Information about the used instrument set
};
@@ -205,12 +209,12 @@ class IIgsMidiChannel {
public:
IIgsMidiChannel() : _instrument(NULL), _volume(127) {}
void setInstrument(const IIgsInstrumentHeader *instrument) { _instrument = instrument; }
- const IIgsInstrumentHeader* getInstrument() { return _instrument; }
+ const IIgsInstrumentHeader *getInstrument() { return _instrument; }
void setVolume(int volume) { _volume = volume; }
int getVolume() { return _volume; }
private:
- const IIgsInstrumentHeader *_instrument; ///< Instrument used on this MIDI channel
- int _volume; ///< MIDI controller number 7 (Volume)
+ const IIgsInstrumentHeader *_instrument; ///< Instrument used on this MIDI channel
+ int _volume; ///< MIDI controller number 7 (Volume)
};
class SoundGen2GS : public SoundGen, public Audio::AudioStream {
@@ -237,32 +241,32 @@ private:
void setProgramChangeMapping(const IIgsMidiProgramMapping *mapping);
// Player methods
- void advancePlayer(); ///< Advance the player
- void advanceMidiPlayer(); ///< Advance MIDI player
- uint generateOutput(); ///< Fill the output buffer
+ void advancePlayer(); ///< Advance the player
+ void advanceMidiPlayer(); ///< Advance MIDI player
+ uint generateOutput(); ///< Fill the output buffer
- void haltGenerators(); ///< Halt all generators
- uint activeGenerators(); ///< How many generators are active?
+ void haltGenerators(); ///< Halt all generators
+ uint activeGenerators(); ///< How many generators are active?
void midiNoteOff(int channel, int note, int velocity);
void midiNoteOn(int channel, int note, int velocity);
double midiKeyToFreq(int key, double finetune);
- IIgsInstrumentHeader* getInstrument(uint8 program) { return &_instruments[_progToInst->map(program)]; }
- IIgsGenerator* allocateGenerator() { IIgsGenerator* g = &_generators[_nextGen++]; _nextGen %= 16; return g; }
-
- bool _disableMidi; ///< Disable MIDI if loading instruments fail
- int _playingSound; ///< Resource number for the currently playing sound
- bool _playing; ///< True when the resource is still playing
-
- IIgsGenerator _generators[MAX_GENERATORS]; ///< IIGS sound generators that are used to play single notes
- uint _nextGen; ///< Next generator available for allocation
- IIgsMidiChannel _channels[16]; ///< MIDI channels
- Common::Array<IIgsInstrumentHeader> _instruments; ///< Instrument data
- const IIgsMidiProgramMapping *_progToInst; ///< MIDI program number to instrument mapping
- int8 *_wavetable; ///< Sample data used by the instruments
- uint _ticks; ///< MIDI ticks (60Hz)
- int16 *_out; ///< Output buffer
- uint _outSize; ///< Output buffer size
+ IIgsInstrumentHeader *getInstrument(uint8 program) { return &_instruments[_progToInst->map(program)]; }
+ IIgsGenerator *allocateGenerator() { IIgsGenerator *g = &_generators[_nextGen++]; _nextGen %= 16; return g; }
+
+ bool _disableMidi; ///< Disable MIDI if loading instruments fail
+ int _playingSound; ///< Resource number for the currently playing sound
+ bool _playing; ///< True when the resource is still playing
+
+ IIgsGenerator _generators[MAX_GENERATORS]; ///< IIGS sound generators that are used to play single notes
+ uint _nextGen; ///< Next generator available for allocation
+ IIgsMidiChannel _channels[16]; ///< MIDI channels
+ Common::Array<IIgsInstrumentHeader> _instruments; ///< Instrument data
+ const IIgsMidiProgramMapping *_progToInst; ///< MIDI program number to instrument mapping
+ int8 *_wavetable; ///< Sample data used by the instruments
+ uint _ticks; ///< MIDI ticks (60Hz)
+ int16 *_out; ///< Output buffer
+ uint _outSize; ///< Output buffer size
static const int kSfxMidiChannel = 15; ///< MIDI channel used for playing sample resources
};
diff --git a/engines/agi/sound_midi.cpp b/engines/agi/sound_midi.cpp
index 35dc896789..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"
@@ -153,9 +152,15 @@ unsigned char instr[] = {50, 51, 19};
static void writeDelta(Common::MemoryWriteStreamDynamic *st, int32 delta) {
int32 i;
- i = delta >> 21; if (i > 0) st->writeByte((i & 127) | 128);
- i = delta >> 14; if (i > 0) st->writeByte((i & 127) | 128);
- i = delta >> 7; if (i > 0) st->writeByte((i & 127) | 128);
+ i = delta >> 21;
+ if (i > 0)
+ st->writeByte((i & 127) | 128);
+ i = delta >> 14;
+ if (i > 0)
+ st->writeByte((i & 127) | 128);
+ i = delta >> 7;
+ if (i > 0)
+ st->writeByte((i & 127) | 128);
st->writeByte(delta & 127);
}
@@ -190,7 +195,7 @@ static uint32 convertSND2MIDI(byte *snddata, byte **data) {
for (pos = start; pos < end; pos += 5) {
uint16 freq, dur;
dur = (snddata[pos + 0] | (snddata[pos + 1] << 8)) * SPEED_FACTOR;
- freq = ((snddata[pos + 2] & 0x3F) << 4) + (snddata[pos + 3] & 0x0F);
+ freq = ((snddata[pos + 2] & 0x3F) << 4) + (snddata[pos + 3] & 0x0F);
if (snddata[pos + 2] > 0) {
double fr;
int note;
diff --git a/engines/agi/sound_pcjr.cpp b/engines/agi/sound_pcjr.cpp
index ea7a2789e0..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) {
@@ -150,7 +151,7 @@ void SoundGenPCJr::play(int resnum) {
_tchannel[i].noteCount = 0;
_tchannel[i].freqCount = 250;
_tchannel[i].freqCountPrev = -1;
- _tchannel[i].atten = 0xF; // silence
+ _tchannel[i].atten = 0xF; // silence
_tchannel[i].genType = kGenTone;
_tchannel[i].genTypePrev = -1;
}
@@ -186,10 +187,10 @@ int SoundGenPCJr::volumeCalc(SndGenChan *chan) {
assert(chan);
attenuation = chan->attenuation;
- if (attenuation != 0x0F) { // != silence
+ if (attenuation != 0x0F) { // != silence
if (chan->dissolveCount != 0xFFFF) {
dissolveValue = dissolveData[chan->dissolveCount];
- if (dissolveValue == -100) { // if at end of list
+ if (dissolveValue == -100) { // if at end of list
chan->dissolveCount = 0xFFFF;
chan->attenuation = chan->attenuationCopy;
attenuation = chan->attenuation;
@@ -215,8 +216,7 @@ int SoundGenPCJr::volumeCalc(SndGenChan *chan) {
return attenuation;
}
-int SoundGenPCJr::getNextNote(int ch)
-{
+int SoundGenPCJr::getNextNote(int ch) {
if (_vm->getVersion() > 0x2001)
return getNextNote_v2(ch);
else
@@ -236,7 +236,7 @@ int SoundGenPCJr::getNextNote_v2(int ch) {
assert(ch < CHAN_MAX);
- if (!_vm->getflag(fSoundOn))
+ if (!_vm->getFlag(VM_FLAG_SOUND_ON))
return -1;
tpcm = &_tchannel[ch];
@@ -248,7 +248,7 @@ int SoundGenPCJr::getNextNote_v2(int ch) {
data = chan->data;
// read the duration of the note
- chan->duration = READ_LE_UINT16(data); // duration
+ chan->duration = READ_LE_UINT16(data); // duration
// if it's 0 then it's not going to be played
// if it's 0xFFFF then the channel data has finished.
@@ -263,7 +263,7 @@ int SoundGenPCJr::getNextNote_v2(int ch) {
_tchannel[ch].freqCountPrev = -1;
// only tone channels dissolve
- if ((ch != 3) && (_dissolveMethod != 0)) // != noise??
+ if ((ch != 3) && (_dissolveMethod != 0)) // != noise??
chan->dissolveCount = 0;
// attenuation (volume)
@@ -280,8 +280,8 @@ int SoundGenPCJr::getNextNote_v2(int ch) {
if (chan->duration == 0xFFFF) {
// kill channel
chan->avail = 0;
- chan->attenuation = 0x0F; // silent
- chan->attenuationCopy = 0x0F; // dunno really
+ chan->attenuation = 0x0F; // silent
+ chan->attenuationCopy = 0x0F; // dunno really
return -1;
}
@@ -364,14 +364,14 @@ void SoundGenPCJr::writeData(uint8 val) {
// bit0 = output
// noise feedback for white noise mode
-#define FB_WNOISE 0x12000 // bit15.d(16bits) = bit0(out) ^ bit2
-//#define FB_WNOISE 0x14000 // bit15.d(16bits) = bit0(out) ^ bit1
-//#define FB_WNOISE 0x28000 // bit16.d(17bits) = bit0(out) ^ bit2 (same to AY-3-8910)
-//#define FB_WNOISE 0x50000 // bit17.d(18bits) = bit0(out) ^ bit2
+#define FB_WNOISE 0x12000 // bit15.d(16bits) = bit0(out) ^ bit2
+//#define FB_WNOISE 0x14000 // bit15.d(16bits) = bit0(out) ^ bit1
+//#define FB_WNOISE 0x28000 // bit16.d(17bits) = bit0(out) ^ bit2 (same to AY-3-8910)
+//#define FB_WNOISE 0x50000 // bit17.d(18bits) = bit0(out) ^ bit2
// noise feedback for periodic noise mode
// it is correct maybe (it was in the Megadrive sound manual)
-//#define FB_PNOISE 0x10000 // 16bit rorate
+//#define FB_PNOISE 0x10000 // 16bit rorate
#define FB_PNOISE 0x08000
// noise generator start preset (for periodic noise)
@@ -431,18 +431,18 @@ int SoundGenPCJr::chanGen(int chan, int16 *stream, int len) {
fillSize = (tpcm->noteCount <= len) ? tpcm->noteCount : len;
switch (tpcm->genType) {
- case kGenTone:
- fillSize = fillSquare(tpcm, stream, fillSize);
- break;
- case kGenPeriod:
- case kGenWhite:
- fillSize = fillNoise(tpcm, stream, fillSize);
- break;
- case kGenSilence:
- default:
- // fill with whitespace
- memset(stream, 0, fillSize * sizeof(int16));
- break;
+ case kGenTone:
+ fillSize = fillSquare(tpcm, stream, fillSize);
+ break;
+ case kGenPeriod:
+ case kGenWhite:
+ fillSize = fillNoise(tpcm, stream, fillSize);
+ break;
+ case kGenSilence:
+ default:
+ // fill with whitespace
+ memset(stream, 0, fillSize * sizeof(int16));
+ break;
}
tpcm->noteCount -= fillSize;
diff --git a/engines/agi/sound_pcjr.h b/engines/agi/sound_pcjr.h
index 7f84112345..24d081419a 100644
--- a/engines/agi/sound_pcjr.h
+++ b/engines/agi/sound_pcjr.h
@@ -41,7 +41,7 @@ enum GenType {
struct SndGenChan {
const byte *data;
uint16 duration;
- uint16 avail; // turned on (1) but when the channel's data runs out, it's set to (0)
+ uint16 avail; // turned on (1) but when the channel's data runs out, it's set to (0)
uint16 dissolveCount;
byte attenuation;
byte attenuationCopy;
@@ -67,8 +67,8 @@ struct ToneChan {
int count;
int scale;
int sign;
- unsigned int noiseState; /* noise generator */
- int feedback; /* noise feedback mask */
+ unsigned int noiseState; /* noise generator */
+ int feedback; /* noise feedback mask */
};
class SoundGenPCJr : public SoundGen, public Audio::AudioStream {
diff --git a/engines/agi/sound_sarien.cpp b/engines/agi/sound_sarien.cpp
index 98479f3edc..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"
@@ -40,7 +39,7 @@ static const int16 waveformRamp[WAVEFORM_SIZE] = {
0, -248, -240, -232, -224, -216, -208, -200,
-192, -184, -176, -168, -160, -152, -144, -136,
-128, -120, -112, -104, -96, -88, -80, -72,
- -64, -56, -48, -40, -32, -24, -16, -8 // Ramp up
+ -64, -56, -48, -40, -32, -24, -16, -8 // Ramp up
};
static const int16 waveformSquare[WAVEFORM_SIZE] = {
@@ -51,7 +50,7 @@ static const int16 waveformSquare[WAVEFORM_SIZE] = {
-255, -230, -220, -220, -220, -220, -220, -220,
-220, -220, -220, -220, -220, -220, -220, -220,
-220, -220, -220, -220, -220, -220, -220, -220,
- -220, -220, -220, -110, 0, 0, 0, 0 // Square
+ -220, -220, -220, -110, 0, 0, 0, 0 // Square
};
static const int16 waveformMac[WAVEFORM_SIZE] = {
@@ -72,9 +71,10 @@ SoundGenSarien::SoundGenSarien(AgiBase *vm, Audio::Mixer *pMixer) : SoundGen(vm,
_env = false;
_playingSound = -1;
_playing = false;
- _useChorus = true; // FIXME: Currently always true?
+ _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);
}
@@ -154,14 +154,14 @@ void SoundGenSarien::stopNote(int i) {
if (_useChorus) {
// Stop chorus ;)
if (_chn[i].type == AGI_SOUND_4CHN &&
- _vm->_soundemu == SOUND_EMU_NONE && i < 3) {
+ _vm->_soundemu == SOUND_EMU_NONE && i < 3) {
stopNote(i + 4);
}
}
}
void SoundGenSarien::playNote(int i, int freq, int vol) {
- if (!_vm->getflag(fSoundOn))
+ if (!_vm->getFlag(VM_FLAG_SOUND_ON))
vol = 0;
else if (vol && _vm->_soundemu == SOUND_EMU_PC)
vol = 160;
@@ -175,7 +175,7 @@ void SoundGenSarien::playNote(int i, int freq, int vol) {
if (_useChorus) {
// Add chorus ;)
if (_chn[i].type == AGI_SOUND_4CHN &&
- _vm->_soundemu == SOUND_EMU_NONE && i < 3) {
+ _vm->_soundemu == SOUND_EMU_NONE && i < 3) {
int newfreq = freq * 1007 / 1000;
@@ -265,7 +265,7 @@ uint32 SoundGenSarien::mixSound() {
#endif
_sndBuffer[i] += (b * m) >> 4;
- p += (uint32) 118600 *4 / _chn[c].freq;
+ p += (uint32) 118600 * 4 / _chn[c].freq;
// FIXME: Fingolfin asks: why is there a FIXME here? Please either clarify what
// needs fixing, or remove it!
diff --git a/engines/agi/sound_sarien.h b/engines/agi/sound_sarien.h
index 1c4dbb7bca..c380ec0702 100644
--- a/engines/agi/sound_sarien.h
+++ b/engines/agi/sound_sarien.h
@@ -27,24 +27,24 @@
namespace Agi {
-#define BUFFER_SIZE 410
+#define BUFFER_SIZE 410
-#define WAVEFORM_SIZE 64
-#define ENV_ATTACK 10000 /**< envelope attack rate */
-#define ENV_DECAY 1000 /**< envelope decay rate */
-#define ENV_SUSTAIN 100 /**< envelope sustain level */
-#define ENV_RELEASE 7500 /**< envelope release rate */
-#define NUM_CHANNELS 7 /**< number of sound channels */
+#define WAVEFORM_SIZE 64
+#define ENV_ATTACK 10000 /**< envelope attack rate */
+#define ENV_DECAY 1000 /**< envelope decay rate */
+#define ENV_SUSTAIN 100 /**< envelope sustain level */
+#define ENV_RELEASE 7500 /**< envelope release rate */
+#define NUM_CHANNELS 7 /**< number of sound channels */
enum AgiSoundFlags {
- AGI_SOUND_LOOP = 0x0001,
- AGI_SOUND_ENVELOPE = 0x0002
+ AGI_SOUND_LOOP = 0x0001,
+ AGI_SOUND_ENVELOPE = 0x0002
};
enum AgiSoundEnv {
- AGI_SOUND_ENV_ATTACK = 3,
- AGI_SOUND_ENV_DECAY = 2,
- AGI_SOUND_ENV_SUSTAIN = 1,
- AGI_SOUND_ENV_RELEASE = 0
+ AGI_SOUND_ENV_ATTACK = 3,
+ AGI_SOUND_ENV_DECAY = 2,
+ AGI_SOUND_ENV_SUSTAIN = 1,
+ AGI_SOUND_ENV_RELEASE = 0
};
@@ -57,7 +57,7 @@ struct ChannelInfo {
const int16 *ins;
int32 size;
uint32 phase;
- uint32 flags; // ORs values from AgiSoundFlags
+ uint32 flags; // ORs values from AgiSoundFlags
AgiSoundEnv adsr;
int32 timer;
uint32 end;
diff --git a/engines/agi/sprite.cpp b/engines/agi/sprite.cpp
index 92f88d8fcb..8263ea12ac 100644
--- a/engines/agi/sprite.cpp
+++ b/engines/agi/sprite.cpp
@@ -23,530 +23,415 @@
#include "agi/agi.h"
#include "agi/sprite.h"
#include "agi/graphics.h"
+#include "agi/text.h"
namespace Agi {
-/**
- * Sprite structure.
- * This structure holds information on visible and priority data of
- * a rectangular area of the AGI screen. Sprites are chained in two
- * circular lists, one for updating and other for non-updating sprites.
- */
-struct Sprite {
- VtEntry *v; /**< pointer to view table entry */
- int16 xPos; /**< x coordinate of the sprite */
- int16 yPos; /**< y coordinate of the sprite */
- int16 xSize; /**< width of the sprite */
- int16 ySize; /**< height of the sprite */
- uint8 *buffer; /**< buffer to store background data */
-};
-
-/*
- * Sprite pool replaces dynamic allocation
- */
-#undef ALLOC_DEBUG
-
-
-#define POOL_SIZE 68000 // Gold Rush mine room needs > 50000
- // Speeder bike challenge needs > 67000
-
-void *SpritesMgr::poolAlloc(int size) {
- uint8 *x;
-
- // Adjust size to sizeof(void *) boundary to prevent data misalignment
- // errors.
- const int alignPadding = sizeof(void *) - 1;
- size = (size + alignPadding) & ~alignPadding;
-
- x = _poolTop;
- _poolTop += size;
-
- if (_poolTop >= (uint8 *)_spritePool + POOL_SIZE) {
- debugC(1, kDebugLevelMain | kDebugLevelResources, "not enough memory");
- _poolTop = x;
- return NULL;
- }
-
- return x;
+SpritesMgr::SpritesMgr(AgiEngine *agi, GfxMgr *gfx) {
+ _vm = agi;
+ _gfx = gfx;
}
-// Note: it's critical that pool_release() is called in the exact
-// reverse order of pool_alloc()
-void SpritesMgr::poolRelease(void *s) {
- _poolTop = (uint8 *)s;
+SpritesMgr::~SpritesMgr() {
+ _spriteRegularList.clear();
+ _spriteStaticList.clear();
}
-/*
- * Blitter functions
- */
-
-// Blit one pixel considering the priorities
-void SpritesMgr::blitPixel(uint8 *p, uint8 *end, uint8 col, int spr, int width, int *hidden) {
- int epr = 0, pr = 0; // effective and real priorities
+static bool sortSpriteHelper(const Sprite &entry1, const Sprite &entry2) {
+ if (entry1.sortOrder == entry2.sortOrder) {
+ // If sort-order is the same, we sort according to given order
+ // which makes this sort stable.
+ return entry1.givenOrderNr < entry2.givenOrderNr;
+ }
+ return entry1.sortOrder < entry2.sortOrder;
+}
- // CM: priority 15 overrides control lines and is ignored when
- // tracking effective priority. This tweak is needed to fix
- // Sarien bug #451768, and should not affect Sierra games because
- // sprites shouldn't have priority 15 (like the AGI Mouse
- // demo "mouse pointer")
- //
- // Update: this solution breaks other games, and can't be used.
+void SpritesMgr::buildRegularSpriteList() {
+ ScreenObjEntry *screenObj = NULL;
+ uint16 givenOrderNr = 0;
- if (p >= end)
- return;
-
- // Check if we're on a control line
- if ((pr = *p & 0xf0) < 0x30) {
- uint8 *p1;
- // Yes, get effective priority going down
- for (p1 = p; p1 < end && (epr = *p1 & 0xf0) < 0x30; p1 += width)
- ;
- if (p1 >= end)
- epr = 0x40;
- } else {
- epr = pr;
+ freeList(_spriteRegularList);
+ for (screenObj = _vm->_game.screenObjTable; screenObj < &_vm->_game.screenObjTable[SCREENOBJECTS_MAX]; screenObj++) {
+ if ((screenObj->flags & (fAnimated | fUpdate | fDrawn)) == (fAnimated | fUpdate | fDrawn)) {
+ buildSpriteListAdd(givenOrderNr, screenObj, _spriteRegularList);
+ givenOrderNr++;
+ }
}
- if (spr >= epr) {
- // Keep control line information visible, but put our
- // priority over water (0x30) surface
- if (_vm->getFeatures() & (GF_AGI256 | GF_AGI256_2))
- *(p + FROM_SBUF16_TO_SBUF256_OFFSET) = col; // Write to 256 color buffer
- else
- *p = (pr < 0x30 ? pr : spr) | col; // Write to 16 color (+control line/priority info) buffer
-
- *hidden = false;
-
- // Except if our priority is 15, which should never happen
- // (fixes Sarien bug #451768)
- //
- // Update: breaks other games, can't be used
- //
- // if (spr == 0xf0)
- // *p = spr | col;
- }
+ // Now sort this list
+ Common::sort(_spriteRegularList.begin(), _spriteRegularList.end(), sortSpriteHelper);
+// warning("buildRegular: %d", _spriteRegularList.size());
}
+void SpritesMgr::buildStaticSpriteList() {
+ ScreenObjEntry *screenObj = NULL;
+ uint16 givenOrderNr = 0;
-int SpritesMgr::blitCel(int x, int y, int spr, ViewCel *c, bool agi256_2) {
- uint8 *p0, *p, *q = NULL, *end;
- int i, j, t, m, col;
- int hidden = true;
-
- // Fixes Sarien bug #477841 (crash in PQ1 map C4 when y == -2)
- if (y < 0)
- y = 0;
- if (x < 0)
- x = 0;
- if (y >= _HEIGHT)
- y = _HEIGHT - 1;
- if (x >= _WIDTH)
- x = _WIDTH - 1;
-
- q = c->data;
- t = c->transparency;
- m = c->mirror;
- spr <<= 4;
- p0 = &_vm->_game.sbuf16c[x + y * _WIDTH + m * (c->width - 1)];
-
- end = _vm->_game.sbuf16c + _WIDTH * _HEIGHT;
-
- for (i = 0; i < c->height; i++) {
- p = p0;
- while (*q) {
- col = agi256_2 ? *q : (*q & 0xf0) >> 4; // Uses whole byte for color info with AGI256-2
- for (j = agi256_2 ? 1 : *q & 0x0f; j; j--, p += 1 - 2 * m) { // No RLE with AGI256-2
- if (col != t) {
- blitPixel(p, end, col, spr, _WIDTH, &hidden);
- }
- }
- q++;
+ freeList(_spriteStaticList);
+ for (screenObj = _vm->_game.screenObjTable; screenObj < &_vm->_game.screenObjTable[SCREENOBJECTS_MAX]; screenObj++) {
+ if ((screenObj->flags & (fAnimated | fUpdate | fDrawn)) == (fAnimated | fDrawn)) { // DIFFERENCE IN HERE!
+ buildSpriteListAdd(givenOrderNr, screenObj, _spriteStaticList);
+ givenOrderNr++;
}
- p0 += _WIDTH;
- q++;
}
- return hidden;
+ // Now sort this list
+ Common::sort(_spriteStaticList.begin(), _spriteStaticList.end(), sortSpriteHelper);
}
-void SpritesMgr::objsSaveArea(Sprite *s) {
- int y;
- int16 xPos = s->xPos, yPos = s->yPos;
- int16 xSize = s->xSize, ySize = s->ySize;
- uint8 *p0, *q;
+void SpritesMgr::buildAllSpriteLists() {
+ buildStaticSpriteList();
+ buildRegularSpriteList();
+}
+
+void SpritesMgr::buildSpriteListAdd(uint16 givenOrderNr, ScreenObjEntry *screenObj, SpriteList &spriteList) {
+ Sprite spriteEntry;
- if (xPos + xSize > _WIDTH)
- xSize = _WIDTH - xPos;
+ // Check, if screen object points to currently loaded view, if not don't add it
+ if (!(_vm->_game.dirView[screenObj->currentViewNr].flags & RES_LOADED))
+ return;
- if (xPos < 0) {
- xSize += xPos;
- xPos = 0;
+ spriteEntry.givenOrderNr = givenOrderNr;
+// warning("sprite add objNr %d", screenObjPtr->objectNr);
+ if (screenObj->flags & fFixedPriority) {
+ spriteEntry.sortOrder = _gfx->priorityToY(screenObj->priority);
+// warning(" - priorityToY (fixed) %d -> %d", screenObj->priority, spriteEntry.sortOrder);
+ } else {
+ spriteEntry.sortOrder = screenObj->yPos;
+// warning(" - Ypos %d -> %d", screenObjPtr->yPos, spriteEntry.sortOrder);
}
- if (yPos + ySize > _HEIGHT)
- ySize = _HEIGHT - yPos;
+ spriteEntry.screenObjPtr = screenObj;
+ spriteEntry.xPos = screenObj->xPos;
+ spriteEntry.yPos = (screenObj->yPos) - (screenObj->ySize) + 1;
+ spriteEntry.xSize = screenObj->xSize;
+ spriteEntry.ySize = screenObj->ySize;
- if (yPos < 0) {
- ySize += yPos;
- yPos = 0;
+ // Checking, if xPos/yPos/right/bottom are valid and do not go outside of playscreen (visual screen)
+ // Original AGI did not do this (but it then resulted in memory corruption)
+ if (spriteEntry.xPos < 0) {
+ warning("buildSpriteListAdd(): ignoring screen obj %d, b/c xPos (%d) < 0", screenObj->objectNr, spriteEntry.xPos);
+ return;
}
-
- if (xSize <= 0 || ySize <= 0)
+ if (spriteEntry.yPos < 0) {
+ warning("buildSpriteListAdd(): ignoring screen obj %d, b/c yPos (%d) < 0", screenObj->objectNr, spriteEntry.yPos);
+ return;
+ }
+ int16 xRight = spriteEntry.xPos + spriteEntry.xSize;
+ if (xRight > SCRIPT_HEIGHT) {
+ warning("buildSpriteListAdd(): ignoring screen obj %d, b/c rightPos (%d) > %d", screenObj->objectNr, xRight, SCRIPT_WIDTH);
+ return;
+ }
+ int16 yBottom = spriteEntry.yPos + spriteEntry.ySize;
+ if (yBottom > SCRIPT_HEIGHT) {
+ warning("buildSpriteListAdd(): ignoring screen obj %d, b/c bottomPos (%d) > %d", screenObj->objectNr, yBottom, SCRIPT_HEIGHT);
return;
-
- p0 = &_vm->_game.sbuf[xPos + yPos * _WIDTH];
- q = s->buffer;
- for (y = 0; y < ySize; y++) {
- memcpy(q, p0, xSize);
- q += xSize;
- p0 += _WIDTH;
}
-}
-void SpritesMgr::objsRestoreArea(Sprite *s) {
- int y, offset;
- int16 xPos = s->xPos, yPos = s->yPos;
- int16 xSize = s->xSize, ySize = s->ySize;
- uint8 *q;
- uint32 pos0;
+// warning("list-add: %d, %d, original yPos: %d, ySize: %d", spriteEntry.xPos, spriteEntry.yPos, screenObj->yPos, screenObj->ySize);
+ spriteEntry.backgroundBuffer = (uint8 *)malloc(spriteEntry.xSize * spriteEntry.ySize * 2); // for visual + priority data
+ assert(spriteEntry.backgroundBuffer);
+ spriteList.push_back(spriteEntry);
+}
- if (xPos + xSize > _WIDTH)
- xSize = _WIDTH - xPos;
+void SpritesMgr::freeList(SpriteList &spriteList) {
+ SpriteList::iterator iter;
+ for (iter = spriteList.reverse_begin(); iter != spriteList.end(); iter--) {
+ Sprite &sprite = *iter;
- if (xPos < 0) {
- xSize += xPos;
- xPos = 0;
+ free(sprite.backgroundBuffer);
}
+ spriteList.clear();
+}
- if (yPos + ySize > _HEIGHT)
- ySize = _HEIGHT - yPos;
+void SpritesMgr::freeRegularSprites() {
+ freeList(_spriteRegularList);
+}
- if (yPos < 0) {
- ySize += yPos;
- yPos = 0;
- }
+void SpritesMgr::freeStaticSprites() {
+ freeList(_spriteStaticList);
+}
- if (xSize <= 0 || ySize <= 0)
- return;
+void SpritesMgr::freeAllSprites() {
+ freeList(_spriteRegularList);
+ freeList(_spriteStaticList);
+}
- pos0 = xPos + yPos * _WIDTH;
- q = s->buffer;
- offset = _vm->_game.lineMinPrint * CHAR_LINES;
- for (y = 0; y < ySize; y++) {
- memcpy(&_vm->_game.sbuf[pos0], q, xSize);
- _gfx->putPixelsA(xPos, yPos + y + offset, xSize, &_vm->_game.sbuf16c[pos0]);
- q += xSize;
- pos0 += _WIDTH;
+void SpritesMgr::eraseSprites(SpriteList &spriteList) {
+ SpriteList::iterator iter;
+// warning("eraseSprites - count %d", spriteList.size());
+ for (iter = spriteList.reverse_begin(); iter != spriteList.end(); iter--) {
+ Sprite &sprite = *iter;
+ _gfx->block_restore(sprite.xPos, sprite.yPos, sprite.xSize, sprite.ySize, sprite.backgroundBuffer);
}
- // WORKAROUND (see ScummVM bug #1945716)
- // When set.view command is called, current code cannot detect this situation while updating
- // Thus we force removal of the old sprite
- if (s->v && s->v->viewReplaced) {
- commitBlock(xPos, yPos, xPos + xSize, yPos + ySize);
- s->v->viewReplaced = false;
- }
+ freeList(spriteList);
}
-
/**
- * Condition to determine whether a sprite will be in the 'updating' list.
+ * Erase updating sprites.
+ * This function follows the list of all updating sprites and restores
+ * the visible and priority data of their background buffers back to
+ * the AGI screen.
+ *
+ * @see erase_nonupd_sprites()
+ * @see erase_both()
*/
-bool SpritesMgr::testUpdating(VtEntry *v, AgiEngine *agi) {
- // Sanity check (see Sarien bug #779302)
- if (~agi->_game.dirView[v->currentView].flags & RES_LOADED)
- return false;
-
- return (v->flags & (fAnimated | fUpdate | fDrawn)) == (fAnimated | fUpdate | fDrawn);
+void SpritesMgr::eraseRegularSprites() {
+ eraseSprites(_spriteRegularList);
}
-/**
- * Condition to determine whether a sprite will be in the 'non-updating' list.
- */
-bool SpritesMgr::testNotUpdating(VtEntry *v, AgiEngine *vm) {
- // Sanity check (see Sarien bug #779302)
- if (~vm->_game.dirView[v->currentView].flags & RES_LOADED)
- return false;
+void SpritesMgr::eraseStaticSprites() {
+ eraseSprites(_spriteStaticList);
+}
- return (v->flags & (fAnimated | fUpdate | fDrawn)) == (fAnimated | fDrawn);
+void SpritesMgr::eraseSprites() {
+ eraseSprites(_spriteRegularList);
+ eraseSprites(_spriteStaticList);
}
/**
- * Convert sprite priority to y value.
+ * Draw all sprites in the given list.
*/
-int SpritesMgr::prioToY(int p) {
- int i;
+void SpritesMgr::drawSprites(SpriteList &spriteList) {
+ SpriteList::iterator iter;
+// warning("drawSprites");
- if (p == 0)
- return -1;
+ for (iter = spriteList.begin(); iter != spriteList.end(); ++iter) {
+ Sprite &sprite = *iter;
+ ScreenObjEntry *screenObj = sprite.screenObjPtr;
- for (i = 167; i >= 0; i--) {
- if (_vm->_game.priTable[i] < p)
- return i;
+ _gfx->block_save(sprite.xPos, sprite.yPos, sprite.xSize, sprite.ySize, sprite.backgroundBuffer);
+ //debugC(8, kDebugLevelSprites, "drawSprites(): s->v->entry = %d (prio %d)", s->viewPtr->entry, s->viewPtr->priority);
+// warning("sprite %d (view %d), priority %d, sort %d, givenOrder %d", screenObj->objectNr, screenObj->currentView, screenObj->priority, sprite.sortOrder, sprite.givenOrderNr);
+ drawCel(screenObj);
}
-
- return -1; // (p - 5) * 12 + 48;
-}
-
-/**
- * Create and initialize a new sprite structure.
- */
-Sprite *SpritesMgr::newSprite(VtEntry *v) {
- Sprite *s;
- s = (Sprite *)poolAlloc(sizeof(Sprite));
- if (s == NULL)
- return NULL;
-
- s->v = v; // link sprite to associated view table entry
- s->xPos = v->xPos;
- s->yPos = v->yPos - v->ySize + 1;
- s->xSize = v->xSize;
- s->ySize = v->ySize;
- s->buffer = (uint8 *)poolAlloc(s->xSize * s->ySize);
- v->s = s; // link view table entry to this sprite
-
- return s;
}
/**
- * Insert sprite in the specified sprite list.
+ * Blit updating sprites.
+ * This function follows the list of all updating sprites and blits
+ * them on the AGI screen.
+ *
+ * @see blit_nonupd_sprites()
+ * @see blit_both()
*/
-void SpritesMgr::sprAddlist(SpriteList &l, VtEntry *v) {
- Sprite *s = newSprite(v);
- l.push_back(s);
-}
+void SpritesMgr::drawRegularSpriteList() {
+ debugC(7, kDebugLevelSprites, "drawRegularSpriteList()");
+ drawSprites(_spriteRegularList);
+}
+
+void SpritesMgr::drawStaticSpriteList() {
+ //debugC(7, kDebugLevelSprites, "drawRegularSpriteList()");
+ drawSprites(_spriteStaticList);
+}
+
+void SpritesMgr::drawAllSpriteLists() {
+ drawSprites(_spriteStaticList);
+ drawSprites(_spriteRegularList);
+}
+
+void SpritesMgr::drawCel(ScreenObjEntry *screenObj) {
+ int16 curX = screenObj->xPos;
+ int16 baseX = screenObj->xPos;
+ int16 curY = screenObj->yPos;
+ AgiViewCel *celPtr = screenObj->celData;
+ byte *celDataPtr = celPtr->rawBitmap;
+ uint8 remainingCelHeight = celPtr->height;
+ uint8 celWidth = celPtr->width;
+ byte celClearKey = celPtr->clearKey;
+ byte viewPriority = screenObj->priority;
+ byte screenPriority = 0;
+ byte curColor = 0;
+ byte isViewHidden = true;
+
+ // Adjust vertical position, given yPos is lower left, but we need upper left
+ curY = curY - celPtr->height + 1;
+
+ while (remainingCelHeight) {
+ for (int16 loopX = 0; loopX < celWidth; loopX++) {
+ curColor = *celDataPtr++;
+
+ if (curColor != celClearKey) {
+ screenPriority = _gfx->getPriority(curX, curY);
+ if (screenPriority <= 2) {
+ // control data found
+ if (_gfx->checkControlPixel(curX, curY, viewPriority)) {
+ _gfx->putPixel(curX, curY, GFX_SCREEN_MASK_VISUAL, curColor, 0);
+ isViewHidden = false;
+ }
+ } else if (screenPriority <= viewPriority) {
+ _gfx->putPixel(curX, curY, GFX_SCREEN_MASK_ALL, curColor, viewPriority);
+ isViewHidden = false;
+ }
-/**
- * Sort sprites from lower y values to build a sprite list.
- */
-void SpritesMgr::buildList(SpriteList &l, bool (*test)(VtEntry *, AgiEngine *)) {
- int i, j, k;
- VtEntry *v;
- VtEntry *entry[0x100];
- int yVal[0x100];
- int minY = 0xff, minIndex = 0;
-
- // fill the arrays with all sprites that satisfy the 'test'
- // condition and their y values
- i = 0;
- for (v = _vm->_game.viewTable; v < &_vm->_game.viewTable[MAX_VIEWTABLE]; v++) {
- if ((*test)(v, _vm)) {
- entry[i] = v;
- yVal[i] = v->flags & fFixedPriority ? prioToY(v->priority) : v->yPos;
- i++;
+ }
+ curX++;
}
+
+ // go to next vertical position
+ remainingCelHeight--;
+ curX = baseX;
+ curY++;
}
- debugC(5, kDebugLevelSprites, "buildList() --> entries %d", i);
+ if (screenObj->objectNr == 0) { // if ego, update if ego is visible at the moment
+ _vm->setFlag(VM_FLAG_EGO_INVISIBLE, isViewHidden);
+ }
+}
- // now look for the smallest y value in the array and put that
- // sprite in the list
- for (j = 0; j < i; j++) {
- minY = 0xff;
- for (k = 0; k < i; k++) {
- if (yVal[k] < minY) {
- minIndex = k;
- minY = yVal[k];
- }
- }
+void SpritesMgr::showSprite(ScreenObjEntry *screenObj) {
+ int16 x = 0;
+ int16 y = 0;
+ int16 width = 0;
+ int16 height = 0;
- yVal[minIndex] = 0xff;
- sprAddlist(l, entry[minIndex]);
- }
-}
+ int16 view_height_prev = 0;
+ int16 view_width_prev = 0;
-/**
- * Build list of updating sprites.
- */
-void SpritesMgr::buildUpdBlitlist() {
- buildList(_sprUpd, testUpdating);
-}
+ int16 y2 = 0;
+ int16 height1 = 0;
+ int16 height2 = 0;
-/**
- * Build list of non-updating sprites.
- */
-void SpritesMgr::buildNonupdBlitlist() {
- buildList(_sprNonupd, testNotUpdating);
-}
+ int16 x2 = 0;
+ int16 width1 = 0;
+ int16 width2 = 0;
-/**
- * Clear the given sprite list.
- */
-void SpritesMgr::freeList(SpriteList &l) {
- SpriteList::iterator iter;
- for (iter = l.reverse_begin(); iter != l.end(); ) {
- Sprite* s = *iter;
+ if (!_vm->_game.pictureShown)
+ return;
- poolRelease(s->buffer);
- poolRelease(s);
- iter = l.reverse_erase(iter);
- }
-}
+ view_height_prev = screenObj->ySize_prev;
+ view_width_prev = screenObj->xSize_prev;
-/**
- * Copy sprites from the pic buffer to the screen buffer, and check if
- * sprites of the given list have moved.
- */
-void SpritesMgr::commitSprites(SpriteList &l, bool immediate) {
- SpriteList::iterator iter;
- for (iter = l.begin(); iter != l.end(); ++iter) {
- Sprite *s = *iter;
- int x1, y1, x2, y2;
+ screenObj->ySize_prev = screenObj->ySize;
+ screenObj->xSize_prev = screenObj->xSize;
+
+ if (screenObj->yPos < screenObj->yPos_prev) {
+ y = screenObj->yPos_prev;
+ y2 = screenObj->yPos;
- x1 = MIN((int)MIN(s->v->xPos, s->v->xPos2), MIN(s->v->xPos + s->v->celData->width, s->v->xPos2 + s->v->celData2->width));
- x2 = MAX((int)MAX(s->v->xPos, s->v->xPos2), MAX(s->v->xPos + s->v->celData->width, s->v->xPos2 + s->v->celData2->width));
- y1 = MIN((int)MIN(s->v->yPos, s->v->yPos2), MIN(s->v->yPos - s->v->celData->height, s->v->yPos2 - s->v->celData2->height));
- y2 = MAX((int)MAX(s->v->yPos, s->v->yPos2), MAX(s->v->yPos - s->v->celData->height, s->v->yPos2 - s->v->celData2->height));
+ height1 = view_height_prev;
+ height2 = screenObj->ySize;
+ } else {
+ y = screenObj->yPos;
+ y2 = screenObj->yPos_prev;
- s->v->celData2 = s->v->celData;
+ height1 = screenObj->ySize;
+ height2 = view_height_prev;
+ }
- commitBlock(x1, y1, x2, y2, immediate);
+ if ((y2 - height2) > (y - height1)) {
+ height = height1;
+ } else {
+ height = y - y2 + height2;
+ }
- if (s->v->stepTimeCount != s->v->stepTime)
- continue;
+ if (screenObj->xPos > screenObj->xPos_prev) {
+ x = screenObj->xPos_prev;
+ x2 = screenObj->xPos;
+ width1 = view_width_prev;
+ width2 = screenObj->xSize;
+ } else {
+ x = screenObj->xPos;
+ x2 = screenObj->xPos_prev;
+ width1 = screenObj->xSize;
+ width2 = view_width_prev;
+ }
- if (s->v->xPos == s->v->xPos2 && s->v->yPos == s->v->yPos2) {
- s->v->flags |= fDidntMove;
- continue;
- }
+ if ((x2 + width2) < (x + width1)) {
+ width = width1;
+ } else {
+ width = width2 + x2 - x;
+ }
- s->v->xPos2 = s->v->xPos;
- s->v->yPos2 = s->v->yPos;
- s->v->flags &= ~fDidntMove;
+ if ((x + width) > 161) {
+ width = 161 - x;
}
-}
-/**
- * Erase all sprites in the given list.
- */
-void SpritesMgr::eraseSprites(SpriteList &l) {
- SpriteList::iterator iter;
- for (iter = l.reverse_begin(); iter != l.end(); --iter) {
- Sprite *s = *iter;
- objsRestoreArea(s);
+ if (1 < (height - y)) {
+ height = y + 1;
}
- freeList(l);
+ // render this block
+ int16 upperY = y - height + 1;
+ _gfx->render_Block(x, upperY, width, height);
}
-/**
- * Blit all sprites in the given list.
- */
-void SpritesMgr::blitSprites(SpriteList& l) {
- int hidden;
+void SpritesMgr::showSprites(SpriteList &spriteList) {
SpriteList::iterator iter;
+ ScreenObjEntry *screenObjPtr = NULL;
- for (iter = l.begin(); iter != l.end(); ++iter) {
- Sprite *s = *iter;
+ for (iter = spriteList.begin(); iter != spriteList.end(); ++iter) {
+ Sprite &sprite = *iter;
+ screenObjPtr = sprite.screenObjPtr;
- objsSaveArea(s);
- debugC(8, kDebugLevelSprites, "blitSprites(): s->v->entry = %d (prio %d)", s->v->entry, s->v->priority);
- hidden = blitCel(s->xPos, s->yPos, s->v->priority, s->v->celData, s->v->viewData->agi256_2);
+ showSprite(screenObjPtr);
- if (s->v->entry == 0) { // if ego, update f1
- _vm->setflag(fEgoInvisible, hidden);
+ if (screenObjPtr->stepTimeCount == screenObjPtr->stepTime) {
+ if ((screenObjPtr->xPos == screenObjPtr->xPos_prev) && (screenObjPtr->yPos == screenObjPtr->yPos_prev)) {
+ screenObjPtr->flags |= fDidntMove;
+ } else {
+ screenObjPtr->xPos_prev = screenObjPtr->xPos;
+ screenObjPtr->yPos_prev = screenObjPtr->yPos;
+ screenObjPtr->flags &= ~fDidntMove;
+ }
}
}
+ g_system->updateScreen();
+ //g_system->delayMillis(20);
}
-/*
- * Public functions
- */
-
-void SpritesMgr::commitUpdSprites() {
- commitSprites(_sprUpd);
+void SpritesMgr::showRegularSpriteList() {
+ debugC(7, kDebugLevelSprites, "showRegularSpriteList()");
+ showSprites(_spriteRegularList);
}
-void SpritesMgr::commitNonupdSprites() {
- commitSprites(_sprNonupd);
+void SpritesMgr::showStaticSpriteList() {
+ debugC(7, kDebugLevelSprites, "showStaticSpriteList()");
+ showSprites(_spriteStaticList);
}
-// check moves in both lists
-void SpritesMgr::commitBoth() {
- commitUpdSprites();
- commitNonupdSprites();
+void SpritesMgr::showAllSpriteLists() {
+ showSprites(_spriteStaticList);
+ showSprites(_spriteRegularList);
}
/**
- * Erase updating sprites.
- * This function follows the list of all updating sprites and restores
- * the visible and priority data of their background buffers back to
- * the AGI screen.
- *
- * @see erase_nonupd_sprites()
- * @see erase_both()
+ * Show object and description
+ * This function shows an object from the player's inventory, displaying
+ * a message box with the object description.
+ * @param n Number of the object to show
*/
-void SpritesMgr::eraseUpdSprites() {
- eraseSprites(_sprUpd);
-}
+void SpritesMgr::showObject(int16 viewNr) {
+ ScreenObjEntry screenObj;
+ uint8 *backgroundBuffer = NULL;
-/**
- * Erase non-updating sprites.
- * This function follows the list of all non-updating sprites and restores
- * the visible and priority data of their background buffers back to
- * the AGI screen.
- *
- * @see erase_upd_sprites()
- * @see erase_both()
- */
-void SpritesMgr::eraseNonupdSprites() {
- eraseSprites(_sprNonupd);
-}
+ _vm->agiLoadResource(RESOURCETYPE_VIEW, viewNr);
+ _vm->setView(&screenObj, viewNr);
-/**
- * Erase all sprites.
- * This function follows the lists of all updating and non-updating
- * sprites and restores the visible and priority data of their background
- * buffers back to the AGI screen.
- *
- * @see erase_upd_sprites()
- * @see erase_nonupd_sprites()
- */
-void SpritesMgr::eraseBoth() {
- eraseUpdSprites();
- eraseNonupdSprites();
-}
+ screenObj.ySize_prev = screenObj.celData->height;
+ screenObj.xSize_prev = screenObj.celData->width;
+ screenObj.xPos_prev = ((SCRIPT_WIDTH - 1) - screenObj.xSize) / 2;
+ screenObj.xPos = screenObj.xPos_prev;
+ screenObj.yPos_prev = SCRIPT_HEIGHT - 1;
+ screenObj.yPos = screenObj.yPos_prev;
+ screenObj.priority = 15;
+ screenObj.flags = fFixedPriority; // Original AGI did "| fFixedPriority" on uninitialized memory
+ screenObj.objectNr = 255; // ???
-/**
- * Blit updating sprites.
- * This function follows the list of all updating sprites and blits
- * them on the AGI screen.
- *
- * @see blit_nonupd_sprites()
- * @see blit_both()
- */
-void SpritesMgr::blitUpdSprites() {
- debugC(7, kDebugLevelSprites, "blitUpdSprites()");
- buildUpdBlitlist();
- blitSprites(_sprUpd);
-}
+ backgroundBuffer = (uint8 *)malloc(screenObj.xSize * screenObj.ySize * 2); // for visual + priority data
-/**
- * Blit non-updating sprites.
- * This function follows the list of all non-updating sprites and blits
- * them on the AGI screen.
- *
- * @see blit_upd_sprites()
- * @see blit_both()
- */
-void SpritesMgr::blitNonupdSprites() {
- debugC(7, kDebugLevelSprites, "blitNonupdSprites()");
- buildNonupdBlitlist();
- blitSprites(_sprNonupd);
-}
+ _gfx->block_save(screenObj.xPos, (screenObj.yPos - screenObj.ySize + 1), screenObj.xSize, screenObj.ySize, backgroundBuffer);
+ drawCel(&screenObj);
+ showSprite(&screenObj);
-/**
- * Blit all sprites.
- * This function follows the lists of all updating and non-updating
- * sprites and blits them on the AGI screen.
- *
- * @see blit_upd_sprites()
- * @see blit_nonupd_sprites()
- */
-void SpritesMgr::blitBoth() {
- blitNonupdSprites();
- blitUpdSprites();
+ _vm->_text->messageBox((char *)_vm->_game.views[viewNr].description);
+
+ _gfx->block_restore(screenObj.xPos, (screenObj.yPos - screenObj.ySize + 1), screenObj.xSize, screenObj.ySize, backgroundBuffer);
+ showSprite(&screenObj);
+
+ free(backgroundBuffer);
}
/**
@@ -562,188 +447,107 @@ void SpritesMgr::blitBoth() {
* @param pri priority to use
* @param mar if < 4, create a margin around the the base of the cel
*/
-void SpritesMgr::addToPic(int view, int loop, int cel, int x, int y, int pri, int mar) {
- ViewCel *c = NULL;
- int x1, y1, x2, y2, y3;
- uint8 *p1, *p2;
-
- debugC(3, kDebugLevelSprites, "addToPic(view=%d, loop=%d, cel=%d, x=%d, y=%d, pri=%d, mar=%d)", view, loop, cel, x, y, pri, mar);
-
- _vm->recordImageStackCall(ADD_VIEW, view, loop, cel, x, y, pri, mar);
-
- // Was hardcoded to 8, changed to pri_table[y] to fix Gold
- // Rush (see Sarien bug #587558)
- if (pri == 0)
- pri = _vm->_game.priTable[y];
-
- c = &_vm->_game.views[view].loop[loop].cel[cel];
-
- x1 = x;
- y1 = y - c->height + 1;
- x2 = x + c->width - 1;
- y2 = y;
-
- if (x1 < 0) {
- x2 -= x1;
- x1 = 0;
- }
- if (y1 < 0) {
- y2 -= y1;
- y1 = 0;
+void SpritesMgr::addToPic(int16 viewNr, int16 loopNr, int16 celNr, int16 xPos, int16 yPos, int16 priority, int16 border) {
+ debugC(3, kDebugLevelSprites, "addToPic(view=%d, loop=%d, cel=%d, x=%d, y=%d, pri=%d, border=%d)", viewNr, loopNr, celNr, xPos, yPos, priority, border);
+
+ _vm->recordImageStackCall(ADD_VIEW, viewNr, loopNr, celNr, xPos, yPos, priority, border);
+
+ ScreenObjEntry *screenObj = &_vm->_game.addToPicView;
+ screenObj->objectNr = -1; // addToPic-view
+
+ _vm->setView(screenObj, viewNr);
+ _vm->setLoop(screenObj, loopNr);
+ _vm->setCel(screenObj, celNr);
+
+ screenObj->xSize_prev = screenObj->xSize;
+ screenObj->ySize_prev = screenObj->ySize;
+ screenObj->xPos_prev = xPos;
+ screenObj->xPos = xPos;
+ screenObj->yPos_prev = yPos;
+ screenObj->yPos = yPos;
+ screenObj->flags = fIgnoreObjects | fIgnoreHorizon | fFixedPriority;
+ screenObj->priority = 15;
+ _vm->fixPosition(screenObj);
+ if (priority == 0) {
+ screenObj->flags = fIgnoreHorizon;
}
- if (x2 >= _WIDTH)
- x2 = _WIDTH - 1;
- if (y2 >= _HEIGHT)
- y2 = _HEIGHT - 1;
-
- eraseBoth();
-
- debugC(4, kDebugLevelSprites, "blitCel(%d, %d, %d, c)", x, y, pri);
- blitCel(x1, y1, pri, c, _vm->_game.views[view].agi256_2);
-
- // If margin is 0, 1, 2, or 3, the base of the cel is
- // surrounded with a rectangle of the corresponding priority.
- // If margin >= 4, this extra margin is not shown.
- //
- // -1 indicates ignore and is set for V1
- if (mar < 4 && mar != -1) {
- // add rectangle around object, don't clobber control
- // info in priority data. The box extends to the end of
- // its priority band!
- y3 = (y2 / 12) * 12;
-
- // SQ1 needs +1 (see Sarien bug #810331)
- if (_vm->getGameID() == GID_SQ1)
- y3++;
-
- // don't let box extend below y.
- if (y3 > y2) y3 = y2;
-
- p1 = &_vm->_game.sbuf16c[x1 + y3 * _WIDTH];
- p2 = &_vm->_game.sbuf16c[x2 + y3 * _WIDTH];
-
- for (y = y3; y <= y2; y++) {
- if ((*p1 >> 4) >= 4)
- *p1 = (mar << 4) | (*p1 & 0x0f);
-
- if ((*p2 >> 4) >= 4)
- *p2 = (mar << 4) | (*p2 & 0x0f);
-
- p1 += _WIDTH;
- p2 += _WIDTH;
- }
-
- debugC(4, kDebugLevelSprites, "pri box: %d %d %d %d (%d)", x1, y3, x2, y2, mar);
- p1 = &_vm->_game.sbuf16c[x1 + y3 * _WIDTH];
- p2 = &_vm->_game.sbuf16c[x1 + y2 * _WIDTH];
- for (x = x1; x <= x2; x++) {
- if ((*p1 >> 4) >= 4)
- *p1 = (mar << 4) | (*p1 & 0x0f);
+ screenObj->priority = priority;
- if ((*p2 >> 4) >= 4)
- *p2 = (mar << 4) | (*p2 & 0x0f);
+ eraseSprites();
- p1++;
- p2++;
- }
+ // bugs related to this code: required by Gold Rush (see Sarien bug #587558)
+ if (screenObj->priority == 0) {
+ screenObj->priority = _gfx->priorityFromY(screenObj->yPos);
}
+ drawCel(screenObj);
- blitBoth();
-
- commitBlock(x1, y1, x2, y2, true);
-}
-
-/**
- * Show object and description
- * This function shows an object from the player's inventory, displaying
- * a message box with the object description.
- * @param n Number of the object to show
- */
-void SpritesMgr::showObj(int n) {
- ViewCel *c;
- Sprite s;
- int x1, y1, x2, y2;
-
- _vm->agiLoadResource(rVIEW, n);
- if (!(c = &_vm->_game.views[n].loop[0].cel[0]))
- return;
-
- x1 = (_WIDTH - c->width) / 2;
- y1 = 112;
- x2 = x1 + c->width - 1;
- y2 = y1 + c->height - 1;
-
- s.xPos = x1;
- s.yPos = y1;
- s.xSize = c->width;
- s.ySize = c->height;
- s.buffer = (uint8 *)malloc(s.xSize * s.ySize);
- s.v = 0;
-
- objsSaveArea(&s);
- blitCel(x1, y1, 15, c, _vm->_game.views[n].agi256_2);
- commitBlock(x1, y1, x2, y2, true);
- _vm->messageBox(_vm->_game.views[n].descr);
- objsRestoreArea(&s);
- commitBlock(x1, y1, x2, y2, true);
-
- free(s.buffer);
-}
-
-void SpritesMgr::commitBlock(int x1, int y1, int x2, int y2, bool immediate) {
- int i, w, offset;
- uint8 *q;
-
- if (!_vm->_game.pictureShown)
- return;
+ if (border <= 3) {
+ // Create priority-box
+ addToPicDrawPriorityBox(screenObj, border);
+ }
+ buildAllSpriteLists();
+ drawAllSpriteLists();
+ showSprite(screenObj);
+}
+
+// bugs previously related to this:
+// Sarien bug #247)
+void SpritesMgr::addToPicDrawPriorityBox(ScreenObjEntry *screenObj, int16 border) {
+ int16 priorityFromY = _gfx->priorityFromY(screenObj->yPos);
+ int16 priorityHeight = 0;
+ int16 curY = 0;
+ int16 curX = 0;
+ int16 height = 0;
+ int16 width = 0;
+ int16 offsetX = 0;
+
+ // Figure out the height of the box
+ curY = screenObj->yPos;
+ do {
+ priorityHeight++;
+ if (curY <= 0)
+ break;
+ curY--;
+ } while (_gfx->priorityFromY(curY) == priorityFromY);
+
+ // box height may not be larger than the actual view
+ if (screenObj->ySize < priorityHeight)
+ priorityHeight = screenObj->ySize;
+
+ // now actually draw lower horizontal line
+ curY = screenObj->yPos;
+ curX = screenObj->xPos;
+
+ width = screenObj->xSize;
+ while (width) {
+ _gfx->putPixel(curX, curY, GFX_SCREEN_MASK_PRIORITY, 0, border);
+ curX++;
+ width--;
+ }
- x1 = CLIP(x1, 0, _WIDTH - 1);
- x2 = CLIP(x2, 0, _WIDTH - 1);
- y1 = CLIP(y1, 0, _HEIGHT - 1);
- y2 = CLIP(y2, 0, _HEIGHT - 1);
-
- // Check if a window is active, and clip the block commited to exclude the
- // window's contents. Fixes bug #3295652, and partially fixes bug #3080415.
- AgiBlock &window = _vm->_game.window;
- if (window.active) {
- if (y1 < window.y2 && y2 > window.y2 && (x1 < window.x2 || x2 > window.x1)) {
- // The top of the block covers the bottom of the window
- y1 = window.y2;
+ if (priorityHeight > 1) {
+ // Actual rectangle is needed
+ curY = screenObj->yPos;
+ curX = screenObj->xPos;
+ offsetX = screenObj->xSize - 1;
+
+ height = priorityHeight - 1;
+ while (height) {
+ curY--;
+ height--;
+ _gfx->putPixel(curX, curY, GFX_SCREEN_MASK_PRIORITY, 0, border); // left line
+ _gfx->putPixel(curX + offsetX, curY, GFX_SCREEN_MASK_PRIORITY, 0, border); // right line
}
- if (y1 < window.y1 && y2 > window.y1 && (x1 < window.x2 || x2 > window.x1)) {
- // The bottom of the block covers the top of the window
- y2 = window.y1;
+ // and finally the upper horizontal line
+ width = screenObj->xSize - 2;
+ curX++;
+ while (width > 0) {
+ _gfx->putPixel(curX, curY, GFX_SCREEN_MASK_PRIORITY, 0, border);
+ curX++;
+ width--;
}
}
-
- debugC(7, kDebugLevelSprites, "commitBlock(%d, %d, %d, %d)", x1, y1, x2, y2);
-
- w = x2 - x1 + 1;
- q = &_vm->_game.sbuf16c[x1 + _WIDTH * y1];
- offset = _vm->_game.lineMinPrint * CHAR_LINES;
-
- for (i = y1; i <= y2; i++) {
- _gfx->putPixelsA(x1, i + offset, w, q);
- q += _WIDTH;
- }
-
- _gfx->flushBlockA(x1, y1 + offset, x2, y2 + offset);
-
- if (immediate)
- _gfx->doUpdate();
-}
-
-SpritesMgr::SpritesMgr(AgiEngine *agi, GfxMgr *gfx) {
- _vm = agi;
- _gfx = gfx;
-
- _spritePool = (uint8 *)malloc(POOL_SIZE);
- _poolTop = _spritePool;
-}
-
-SpritesMgr::~SpritesMgr() {
- free(_spritePool);
}
} // End of namespace Agi
diff --git a/engines/agi/sprite.h b/engines/agi/sprite.h
index 549eb59832..b29ccc1796 100644
--- a/engines/agi/sprite.h
+++ b/engines/agi/sprite.h
@@ -25,9 +25,25 @@
namespace Agi {
+/**
+ * Sprite structure.
+ * This structure holds information on visible and priority data of
+ * a rectangular area of the AGI screen. Sprites are chained in two
+ * circular lists, one for updating and other for non-updating sprites.
+ */
+struct Sprite {
+ uint16 givenOrderNr;
+ uint16 sortOrder;
+ ScreenObjEntry *screenObjPtr; /**< pointer to view table entry */
+ int16 xPos; /**< x coordinate of the sprite */
+ int16 yPos; /**< y coordinate of the sprite */
+ int16 xSize; /**< width of the sprite */
+ int16 ySize; /**< height of the sprite */
+ byte *backgroundBuffer; /**< buffer to store background data */
+};
-struct Sprite;
-typedef Common::List<Sprite *> SpriteList;
+typedef Common::List<Sprite> SpriteList;
+typedef Common::List<Sprite *> SpritePtrList;
class AgiEngine;
class GfxMgr;
@@ -38,35 +54,42 @@ private:
GfxMgr *_gfx;
AgiEngine *_vm;
- uint8 *_spritePool;
- uint8 *_poolTop;
-
//
// Sprite management functions
//
- SpriteList _sprUpd;
- SpriteList _sprNonupd;
-
- void *poolAlloc(int size);
- void poolRelease(void *s);
- void blitPixel(uint8 *p, uint8 *end, uint8 col, int spr, int width, int *hidden);
- int blitCel(int x, int y, int spr, ViewCel *c, bool agi256_2);
- void objsSaveArea(Sprite *s);
- void objsRestoreArea(Sprite *s);
-
- int prioToY(int p);
- Sprite *newSprite(VtEntry *v);
- void sprAddlist(SpriteList &l, VtEntry *v);
- void buildList(SpriteList &l, bool (*test)(VtEntry *, AgiEngine *));
- void buildUpdBlitlist();
- void buildNonupdBlitlist();
- void freeList(SpriteList &l);
- void commitSprites(SpriteList &l, bool immediate = false);
- void eraseSprites(SpriteList &l);
- void blitSprites(SpriteList &l);
- static bool testUpdating(VtEntry *v, AgiEngine *);
- static bool testNotUpdating(VtEntry *v, AgiEngine *);
+ SpriteList _spriteRegularList;
+ SpriteList _spriteStaticList;
+
+public:
+ void buildRegularSpriteList();
+ void buildStaticSpriteList();
+ void buildAllSpriteLists();
+ void buildSpriteListAdd(uint16 givenOrderNr, ScreenObjEntry *screenObj, SpriteList &spriteList);
+ void freeList(SpriteList &spriteList);
+ void freeRegularSprites();
+ void freeStaticSprites();
+ void freeAllSprites();
+
+ void eraseSprites(SpriteList &spriteList);
+ void eraseRegularSprites();
+ void eraseStaticSprites();
+ void eraseSprites();
+
+ void drawSprites(SpriteList &spriteList);
+ void drawRegularSpriteList();
+ void drawStaticSpriteList();
+ void drawAllSpriteLists();
+
+ void drawCel(ScreenObjEntry *screenObj);
+
+ void showSprite(ScreenObjEntry *screenObj);
+ void showSprites(SpriteList &spriteList);
+ void showRegularSpriteList();
+ void showStaticSpriteList();
+ void showAllSpriteLists();
+
+ void showObject(int16 viewNr);
public:
SpritesMgr(AgiEngine *agi, GfxMgr *gfx);
@@ -74,18 +97,8 @@ public:
int initSprites();
void deinitSprites();
- void eraseUpdSprites();
- void eraseNonupdSprites();
- void eraseBoth();
- void blitUpdSprites();
- void blitNonupdSprites();
- void blitBoth();
- void commitUpdSprites();
- void commitNonupdSprites();
- void commitBoth();
- void addToPic(int, int, int, int, int, int, int);
- void showObj(int);
- void commitBlock(int x1, int y1, int x2, int y2, bool immediate = false);
+ void addToPic(int16 viewNr, int16 loopNr, int16 celNr, int16 xPos, int16 yPos, int16 priority, int16 border);
+ void addToPicDrawPriorityBox(ScreenObjEntry *screenObj, int16 border);
};
} // End of namespace Agi
diff --git a/engines/agi/systemui.cpp b/engines/agi/systemui.cpp
new file mode 100644
index 0000000000..1f26267ad6
--- /dev/null
+++ b/engines/agi/systemui.cpp
@@ -0,0 +1,1172 @@
+/* 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 "agi/agi.h"
+#include "agi/graphics.h"
+#include "agi/text.h"
+#include "agi/keyboard.h"
+#include "agi/systemui.h"
+
+namespace Agi {
+
+SystemUI::SystemUI(AgiEngine *vm, GfxMgr *gfx, TextMgr *text) {
+ _vm = vm;
+ _gfx = gfx;
+ _text = text;
+
+ _askForVerificationContinueOnMessageBoxClick = false;
+ _askForVerificationCancelled = false;
+ _askForVerificationMouseLockedButtonNr = -1;
+ _askForVerificationMouseActiveButtonNr = -1;
+
+ clearSavedGameSlots();
+
+ _textStatusScore = "Score:%v3 of %v7";
+ _textStatusSoundOn = "Sound:on";
+ _textStatusSoundOff = "Sound:off";
+
+ _textEnterCommand = "Enter input\n\n";
+
+ _textPause = " Game paused.\nPress Enter to continue.";
+ _textPauseButton = nullptr;
+
+ _textRestart = "Press ENTER to restart\nthe game.\n\nPress ESC to continue\nthis game.";
+ _textRestartButton1 = nullptr;
+ _textRestartButton2 = nullptr;
+
+ _textQuit = "Press ENTER to quit.\nPress ESC to keep playing.";
+ _textQuitButton1 = nullptr;
+ _textQuitButton2 = nullptr;
+
+ _textInventoryYouAreCarrying = "You are carrying:";
+ _textInventoryNothing = "nothing";
+ _textInventorySelectItems = "Press ENTER to select, ESC to cancel";
+ _textInventoryReturnToGame = "Press a key to return to the game";
+
+ _textSaveGameSelectSlot = "Use the arrow keys to select the slot in which you wish to save the game. Press ENTER to save in the slot, ESC to not save a game.";
+ _textSaveGameEnterDescription = "How would you like to describe this saved game?\n\n";
+ _textSaveGameVerify = "About to save the game\ndescribed as:\n\n%s\n\nin file:\n%s\n\nPress ENTER to continue.\nPress ESC to cancel.";
+ _textSaveGameVerifyButton1 = nullptr;
+ _textSaveGameVerifyButton2 = nullptr;
+
+ _textRestoreGameNoSlots = "There are no games to\nrestore in\n\n ScummVM saved game directory\n\nPress ENTER to continue.";
+ _textRestoreGameSelectSlot = "Use the arrow keys to select the game which you wish to restore. Press ENTER to restore the game, ESC to not restore a game.";
+ _textRestoreGameError = "Error in restoring game.\nPress ENTER to quit.";
+ _textRestoreGameVerify = "About to restore the game\ndescribed as:\n\n%s\n\nfrom file:\n%s\n\nPress ENTER to continue.\nPress ESC to cancel.";
+ _textRestoreGameVerifyButton1 = nullptr;
+ _textRestoreGameVerifyButton2 = nullptr;
+
+ // Replace with translated text, when needed
+ switch (_vm->getLanguage()) {
+ case Common::RU_RUS:
+ _textStatusScore = "\x91\xE7\xA5\xE2: %v3 \xA8\xA7 %v7";
+ _textStatusSoundOn = "\x87\xA2\xE3\xAA: \xA2\xAA\xAB";
+ _textStatusSoundOff = "\x87\xA2\xE3\xAA: \xA2\xEB\xAA\xAB";
+
+ _textPause = " \x88\xA3\xE0\xA0 \xAE\xE1\xE2\xA0\xAD\xAE\xA2\xAB\xA5\xAD\xA0\nENTER - \xAF\xE0\xAE\xA4\xAE\xAB\xA6\xA5\xAD\xA8\xA5.";
+ //_textPause = " \x88\xa3\xe0\xa0 \xae\xe1\xe2\xa0\xad\xae\xa2\xab\xa5\xad\xa0. \n\n\n"; <- mouse
+ // pause button text "\x8f\xe0\xae\xa4\xae\xab\xa6\xa8\xe2\xec"
+ _textRestart = "ENTER - \xAF\xA5\xE0\xA5\xA7\xA0\xAF\xE3\xE1\xE2\xA8\xE2\xEC \xA8\xA3\xE0\xE3.\n\nESC - \xAF\xE0\xAE\xA4\xAE\xAB\xA6\xA5\xAD\xA8\xA5 \xA8\xA3\xE0\xEB.";
+ _textQuit = "ENTER-\xA2\xEB\xE5\xAE\xA4 \xA8\xA7 \xA8\xA3\xE0\xEB.\nESC - \xA8\xA3\xE0\xA0\xE2\xEC \xA4\xA0\xAB\xEC\xE8\xA5.";
+
+ _textInventoryYouAreCarrying = " \x93 \xA2\xA0\xE1 \xA5\xE1\xE2\xEC\x3A ";
+ _textInventoryNothing = "\xAD\xA8\xE7\xA5\xA3\xAE";
+ _textInventorySelectItems = "ENTER - \xA2\xEB\xA1\xAE\xE0, ESC - \xAE\xE2\xAC\xA5\xAD\xA0.";
+ _textInventoryReturnToGame = "\x8B\xEE\xA1\xA0\xEF \xAA\xAB\xA0\xA2\xA8\xE8\xA0 - \xA2\xAE\xA7\xA2\xE0\xA0\xE2 \xA2 \xA8\xA3\xE0\xE3";
+
+ _textSaveGameSelectSlot = "\x91 \xAF\xAE\xAC\xAE\xE9\xEC\xEE \xAA\xAB\xA0\xA2\xA8\xE8 \xAA\xE3\xE0\xE1\xAE\xE0\xA0 \xA2\xEB\xA1\xA5\xE0\xA8\xE2\xA5 \xE1\xE2\xE0\xAE\xAA\xE3, \xA2 \xAA\xAE\xE2\xAE\xE0\xE3\xEE \xA2\xEB \xA6\xA5\xAB\xA0\xA5\xE2\xA5 \xA7\xA0\xAF\xA8\xE1\xA0\xE2\xEC \xA8\xA3\xE0\xE3. \x8D\xA0\xA6\xAC\xA8\xE2\xA5 ENTER \xA4\xAB\xEF \xA7\xA0\xAF\xA8\xE1\xA8 \xA8\xA3\xE0\xEB, ESC - \xAE\xE2\xAC\xA5\xAD\xA0 \xA7\xA0\xAF\xA8\xE1\xA8.";
+ _textSaveGameEnterDescription = "\x8A\xA0\xAA \xA2\xEB \xA6\xA5\xAB\xA0\xA5\xE2\xA5 \xAD\xA0\xA7\xA2\xA0\xE2\xEC \xED\xE2\xE3 \xA7\xA0\xAF\xA8\xE1\xEB\xA2\xA0\xA5\xAC\xE3\xEE \xA8\xA3\xE0\xE3?\n\n";
+ _textSaveGameVerify = "\x83\xAE\xE2\xAE\xA2 \xAA \xA7\xA0\xAF\xA8\xE1\xA8 \xA8\xA3\xE0\xEB, \n\xAE\xAF\xA8\xE1\xA0\xAD\xAD\xAE\xA9 \xAA\xA0\xAA:\n\n%s\n\n\xA2 \xE4\xA0\xA9\xAB:\n%s\n\n\x84\xAB\xEF \xAF\xE0\xAE\xA4\xAE\xAB\xA6\xA5\xAD\xA8\xEF \xAD\xA0\xA6\xAC\xA8\xE2\xA5 ENTER.\nESC - \xAE\xE2\xAC\xA5\xAD\xA0.";
+
+ _textRestoreGameNoSlots = "\x82 \xAA\xA0\xE2\xA0\xAB\xAE\xA3\xA5\n\n ScummVM saved game directory\n\n\xAD\xA5\xE2 \xA7\xA0\xAF\xA8\xE1\xA0\xAD\xAD\xEB\xE5 \xA8\xA3\xE0.\n\nENTER - \xAF\xE0\xAE\xA4\xAE\xAB\xA6\xA5\xAD\xA8\xA5.";
+ _textRestoreGameSelectSlot = "\x91 \xAF\xAE\xAC\xAE\xE9\xEC\xEE \xAA\xAB\xA0\xA2\xA8\xE8 \xAA\xE3\xE0\xE1\xAE\xE0\xA0 \xA2\xEB\xA1\xA5\xE0\xA8\xE2\xA5 \xA8\xA3\xE0\xE3, \xAA\xAE\xE2\xAE\xE0\xE3\xEE \xA2\xEB \xA6\xA5\xAB\xA0\xA5\xE2\xA5 \xE1\xE7\xA8\xE2\xA0\xE2\xEC. \x8D\xA0\xA6\xAC\xA8\xE2\xA5 ENTER \xA4\xAB\xEF \xE1\xE7\xA8\xE2\xEB\xA2\xA0\xAD\xA8\xEF \xA8\xA3\xE0\xEB, ESC - \xA4\xAB\xEF \xAE\xE2\xAC\xA5\xAD\xEB.";
+ _textRestoreGameError = "\x8E\xE8\xA8\xA1\xAA\xA0 \xA2 \xA7\xA0\xAF\xA8\xE1\xA0\xAD\xAD\xAE\xA9 \xA8\xA3\xE0\xA5.\nENTER - \xA2\xEB\xE5\xAE\xA4.";
+ _textRestoreGameVerify = "\x83\xAE\xE2\xAE\xA2 \xAA \xE1\xE7\xA8\xE2\xEB\xA2\xA0\xAD\xA8\xEE \xA8\xA3\xE0\xEB\x2C\n\xAE\xAF\xA8\xE1\xA0\xAD\xAD\xAE\xA9 \xAA\xA0\xAA.\n\n%s\n\n\xA8\xA7 \xE4\xA0\xA9\xAB\xA0:\n%s\n\n\x84\xAB\xEF \xAF\xE0\xAE\xA4\xAE\xAB\xA6\xA5\xAD\xA8\xEF \xAD\xA0\xA6\xAC\xA8\xE2\xA5 ENTER.\nESC - \xAE\xE2\xAC\xA5\xAD\xA0.";
+ break;
+ default:
+ break;
+ }
+
+ // Now replace some text again for some render modes
+ switch (_vm->_renderMode) {
+ case Common::kRenderAmiga:
+ _textPause = "Game paused.";
+ _textPauseButton = "Continue";
+
+ _textRestart = "Restart the game?";
+ _textRestartButton1 = "Restart";
+ _textRestartButton2 = "Cancel";
+
+ _textQuit = "Quit the game, or continue?";
+ _textQuitButton1 = "Quit";
+ _textQuitButton2 = "Continue";
+
+ _textSaveGameVerify = "About to save the game\ndescribed as:\n\n%s\n\nin file:\n%s";
+ _textSaveGameVerifyButton1 = "Save";
+ _textSaveGameVerifyButton2 = "Cancel";
+
+ _textRestoreGameVerify = "About to restore the game\ndescribed as:\n\n%s\n\nfrom file:\n%s";
+ _textRestoreGameVerifyButton1 = "Restore";
+ _textRestoreGameVerifyButton2 = "Cancel";
+ break;
+
+ case Common::kRenderApple2GS:
+ _textPause = "Game paused.";
+ _textPauseButton = "Continue";
+
+ _textRestart = "Restart the game? "; // additional spaces for buttons
+ _textRestartButton1 = "Restart";
+ _textRestartButton2 = "Cancel";
+
+ _textQuit = "Press ENTER to quit.\nPress ESC to keep playing.";
+ _textQuitButton1 = "Quit";
+ _textQuitButton2 = "Continue";
+
+ // Apple IIgs used OS dialogs for saving/restoring
+ _textSaveGameVerify = "About to save the game\ndescribed as:\n\n%s\n\nin file:\n%s";
+ _textSaveGameVerifyButton1 = "Save";
+ _textSaveGameVerifyButton2 = "Cancel";
+
+ _textRestoreGameVerify = "About to restore the game\ndescribed as:\n\n%s\n\nfrom file:\n%s";
+ _textRestoreGameVerifyButton1 = "Restore";
+ _textRestoreGameVerifyButton2 = "Cancel";
+ break;
+
+ case Common::kRenderAtariST:
+ _textPause = "Game paused. Press the left\nmouse button to continue.";
+ // Variation KQ3 _textPause = " Game paused.\nPress RETURN to continue.";
+
+ _textRestart = "About to restart the game.";
+ _textRestartButton1 = "OK";
+ _textRestartButton2 = "Cancel";
+
+ _textQuit = "About to leave the game.";
+ _textQuitButton1 = "OK";
+ _textQuitButton2 = "Cancel";
+
+ _textSaveGameVerify = "About to save the game\ndescribed as:\n\n%s\n\nin file:\n%s";
+ _textSaveGameVerifyButton1 = "OK";
+ _textSaveGameVerifyButton2 = "Cancel";
+
+ _textRestoreGameVerify = "About to restore the game\ndescribed as:\n\n%s\n\nfrom file:\n%s";
+ _textRestoreGameVerifyButton1 = "OK";
+ _textRestoreGameVerifyButton2 = "Cancel";
+ break;
+
+ default:
+ break;
+ }
+}
+
+SystemUI::~SystemUI() {
+ clearSavedGameSlots();
+}
+
+const char *SystemUI::getStatusTextScore() {
+ return _textStatusScore;
+}
+const char *SystemUI::getStatusTextSoundOn() {
+ return _textStatusSoundOn;
+}
+const char *SystemUI::getStatusTextSoundOff() {
+ return _textStatusSoundOff;
+}
+
+void SystemUI::pauseDialog() {
+ askForVerification(_textPause, _textPauseButton, nullptr, true);
+}
+
+bool SystemUI::restartDialog() {
+ return askForVerification(_textRestart, _textRestartButton1, _textRestartButton2, false);
+}
+
+bool SystemUI::quitDialog() {
+ return askForVerification(_textQuit, _textQuitButton1, _textQuitButton2, false);
+}
+
+const char *SystemUI::getInventoryTextNothing() {
+ return _textInventoryNothing;
+}
+const char *SystemUI::getInventoryTextYouAreCarrying() {
+ return _textInventoryYouAreCarrying;
+}
+const char *SystemUI::getInventoryTextSelectItems() {
+ return _textInventorySelectItems;
+}
+const char *SystemUI::getInventoryTextReturnToGame() {
+ return _textInventoryReturnToGame;
+}
+
+bool SystemUI::askForCommand(Common::String &commandText) {
+ // Let user enter the command (this was originally only available for Hercules rendering, we allow it everywhere)
+ bool previousEditState = _text->inputGetEditStatus();
+ byte previousEditCursor = _text->inputGetCursorChar();
+
+ _text->drawMessageBox(_textEnterCommand, 0, 36, true);
+
+ _text->inputEditOn();
+
+ _text->charPos_Push();
+ _text->charAttrib_Push();
+
+ _text->charPos_SetInsideWindow(2, 0);
+ _text->charAttrib_Set(15, 0);
+ _text->clearBlockInsideWindow(2, 0, 36, 0); // input line is supposed to be black
+ _text->inputSetCursorChar('_');
+
+ _text->stringSet(commandText.c_str()); // Set current command text (may be a command recall)
+
+ _vm->cycleInnerLoopActive(CYCLE_INNERLOOP_GETSTRING);
+ _text->stringEdit(35); // only allow up to 35 characters
+
+ _text->charAttrib_Pop();
+ _text->charPos_Pop();
+ _text->inputSetCursorChar(previousEditCursor);
+ if (!previousEditState) {
+ _text->inputEditOff();
+ }
+
+ _text->closeWindow();
+
+ if (!_text->stringWasEntered()) {
+ // User cancelled? exit now
+ return false;
+ }
+
+ commandText.clear();
+ commandText += (char *)_text->_inputString;
+ return true;
+}
+
+int16 SystemUI::figureOutAutomaticSaveGameSlot(const char *automaticSaveDescription) {
+ int16 matchedGameSlotId = -1;
+ int16 freshGameSlotId = -1;
+
+ // Fill saved game slot cache
+ readSavedGameSlots(false, false); // don't filter, but also don't include auto-save slot
+
+ // Walk through saved game slots
+ // check, if description matches and return the slot
+ // if no match can be found, return the first non-existant slot
+ // if all slots exist, return -1
+ figureOutAutomaticSavedGameSlot(automaticSaveDescription, matchedGameSlotId, freshGameSlotId);
+
+ if (matchedGameSlotId >= 0)
+ return matchedGameSlotId; // return matched slot
+
+ if (freshGameSlotId >= 0)
+ return freshGameSlotId; // return first non-existant slot
+
+ return -1; // no slots exist, not match found
+}
+
+int16 SystemUI::figureOutAutomaticRestoreGameSlot(const char *automaticSaveDescription) {
+ int16 matchedGameSlotId = -1;
+ int16 freshGameSlotId = -1;
+
+ // Fill saved game slot cache
+ readSavedGameSlots(true, false); // filter non-existant/invalid saves, also don't include auto-save slot
+
+ // Walk through saved game slots
+ // check, if description matches and return the slot. Otherwise return -1
+ figureOutAutomaticSavedGameSlot(automaticSaveDescription, matchedGameSlotId, freshGameSlotId);
+
+ if (matchedGameSlotId >= 0)
+ return matchedGameSlotId; // return matched slot
+ return -1; // no match found
+}
+
+int16 SystemUI::askForSaveGameSlot() {
+ int16 saveGameSlotNr = -1;
+
+ // Fill saved game slot cache
+ readSavedGameSlots(false, false); // don't filter, but also don't include auto-save slot
+
+ saveGameSlotNr = askForSavedGameSlot(_textSaveGameSelectSlot);
+
+ if (saveGameSlotNr < 0) {
+ // User cancelled? exit now
+ return -1;
+ }
+
+ // return actual slot number of the saved game
+ return _savedGameArray[saveGameSlotNr].slotId;
+}
+
+bool SystemUI::askForSaveGameDescription(int16 slotId, Common::String &newDescription) {
+ // Let user enter new description
+ bool previousEditState = _text->inputGetEditStatus();
+ byte previousEditCursor = _text->inputGetCursorChar();
+
+ _text->drawMessageBox(_textSaveGameEnterDescription, 0, 31, true);
+
+ _text->inputEditOn();
+
+ _text->charPos_Push();
+ _text->charAttrib_Push();
+
+ _text->charPos_SetInsideWindow(3, 0);
+ _text->charAttrib_Set(15, 0);
+ _text->clearBlockInsideWindow(3, 0, 31, 0); // input line is supposed to be black
+ _text->inputSetCursorChar('_');
+
+ // figure out the current description of the slot
+ _text->stringSet("");
+ for (uint16 slotNr = 0; slotNr < _savedGameArray.size(); slotNr++) {
+ if (_savedGameArray[slotNr].slotId == slotId) {
+ // found slotId
+ if (_savedGameArray[slotNr].isValid) {
+ // and also valid, so use its description
+ _text->stringSet(_savedGameArray[slotNr].description);
+ }
+ }
+ }
+
+ _vm->cycleInnerLoopActive(CYCLE_INNERLOOP_GETSTRING);
+ _text->stringEdit(30); // only allow up to 30 characters
+
+ _text->charAttrib_Pop();
+ _text->charPos_Pop();
+ _text->inputSetCursorChar(previousEditCursor);
+ if (!previousEditState) {
+ _text->inputEditOff();
+ }
+
+ _text->closeWindow();
+
+ if (!_text->stringWasEntered()) {
+ // User cancelled? exit now
+ return false;
+ }
+
+ // Now verify that the user really wants to do this
+ if (!askForSavedGameVerification(_textSaveGameVerify, _textSaveGameVerifyButton1, _textSaveGameVerifyButton2, (char *)_text->_inputString, slotId)) {
+ return false;
+ }
+
+ newDescription.clear();
+ newDescription += (char *)_text->_inputString;
+ return true;
+}
+
+int16 SystemUI::askForRestoreGameSlot() {
+ int16 restoreGameSlotNr = -1;
+
+ // Fill saved game slot cache
+ readSavedGameSlots(true, true); // filter empty/corrupt slots, but include auto-save slot
+
+ if (_savedGameArray.size() == 0) {
+ // no saved games
+ _vm->_text->messageBox(_textRestoreGameNoSlots);
+ return -1;
+ }
+
+ restoreGameSlotNr = askForSavedGameSlot(_textRestoreGameSelectSlot);
+
+ // User cancelled? exit now
+ if (restoreGameSlotNr < 0)
+ return -1;
+
+ SystemUISavedGameEntry *selectedSavedGameEntry = &_savedGameArray[restoreGameSlotNr];
+
+ // Check, if selected saved game was marked as valid
+ if (!selectedSavedGameEntry->isValid) {
+ _vm->_text->messageBox(_textRestoreGameError);
+ return -1;
+ }
+
+ // Now verify that the user really wants to do this
+ if (!askForSavedGameVerification(_textRestoreGameVerify, _textRestoreGameVerifyButton1, _textRestoreGameVerifyButton2, selectedSavedGameEntry->description, selectedSavedGameEntry->slotId)) {
+ return -1;
+ }
+
+ // return actual slot number of the saved game
+ return _savedGameArray[restoreGameSlotNr].slotId;
+}
+
+int16 SystemUI::askForSavedGameSlot(const char *slotListText) {
+ int16 messageBoxHeight = 0;
+ int16 slotsCount = _savedGameArray.size();
+
+ if (slotsCount > SYSTEMUI_SAVEDGAME_SLOTS_ON_SCREEN) {
+ messageBoxHeight = 5 + SYSTEMUI_SAVEDGAME_SLOTS_ON_SCREEN;
+ } else {
+ messageBoxHeight = 5 + slotsCount;
+ }
+ _text->drawMessageBox(slotListText, messageBoxHeight, 34, true);
+
+ drawSavedGameSlots();
+ drawSavedGameSlotSelector(true);
+
+ _vm->cycleInnerLoopActive(CYCLE_INNERLOOP_SYSTEMUI_SELECTSAVEDGAMESLOT);
+ do {
+ _vm->processAGIEvents();
+ } while (_vm->cycleInnerLoopIsActive() && !(_vm->shouldQuit() || _vm->_restartGame));
+
+ _text->closeWindow();
+
+ return _savedGameSelectedSlotNr;
+}
+
+void SystemUI::savedGameSlot_KeyPress(uint16 newKey) {
+ int16 slotCount = _savedGameArray.size();
+ int16 newUpmostSlotNr = _savedGameUpmostSlotNr;
+ int16 newSelectedSlotNr = _savedGameSelectedSlotNr;
+ bool slotsScrolled = false;
+
+ switch (newKey) {
+ case AGI_KEY_ENTER:
+ _vm->cycleInnerLoopInactive(); // exit savedGameSlot-loop
+ return;
+ break;
+
+ case AGI_KEY_ESCAPE:
+ _savedGameSelectedSlotNr = -1;
+ _vm->cycleInnerLoopInactive(); // exit savedGameSlot-loop
+ return;
+ break;
+ case AGI_KEY_UP: // previous slot
+ newSelectedSlotNr--;
+ break;
+ case AGI_KEY_DOWN: // next slot
+ newSelectedSlotNr++;
+ break;
+ // FEATURE: any scroll functionality was not available in original AGI
+ // Original AGI was in fact limited to a total of 12 save slots
+ case AGI_KEY_PAGE_UP: // scroll up
+ newUpmostSlotNr -= SYSTEMUI_SAVEDGAME_SLOTS_ON_SCREEN;
+ break;
+ case AGI_KEY_PAGE_DOWN: // scroll down
+ newUpmostSlotNr += SYSTEMUI_SAVEDGAME_SLOTS_ON_SCREEN;
+ break;
+ case AGI_KEY_HOME: // scroll all the way up
+ newUpmostSlotNr = 0;
+ break;
+ case AGI_KEY_END: // scroll all the way down
+ newUpmostSlotNr = (slotCount - 1) - (SYSTEMUI_SAVEDGAME_SLOTS_ON_SCREEN - 1);
+ break;
+
+ default:
+ break;
+ }
+
+ if (newUpmostSlotNr != _savedGameUpmostSlotNr) {
+ // Make sure, upmost slot number is valid
+ if (newUpmostSlotNr < 0) {
+ newUpmostSlotNr = 0;
+ }
+ if (newUpmostSlotNr + (SYSTEMUI_SAVEDGAME_SLOTS_ON_SCREEN - 1) >= slotCount) {
+ newUpmostSlotNr = (slotCount - 1) - (SYSTEMUI_SAVEDGAME_SLOTS_ON_SCREEN - 1);
+ if (newUpmostSlotNr < 0)
+ newUpmostSlotNr = 0;
+ }
+
+ if (newUpmostSlotNr != _savedGameUpmostSlotNr) {
+ // Still different? then actually force a slot number change in any case
+ slotsScrolled = true;
+
+ // also adjust selected slot number now
+ int16 slotDifference = _savedGameSelectedSlotNr - _savedGameUpmostSlotNr;
+ newSelectedSlotNr = newUpmostSlotNr + slotDifference;
+ }
+ }
+
+ if ((newSelectedSlotNr != _savedGameSelectedSlotNr) || slotsScrolled) {
+ // slot number was changed
+
+ // Make slot number valid and scroll in case it's needed
+ if (newSelectedSlotNr < 0) {
+ newSelectedSlotNr = slotCount - 1;
+ newUpmostSlotNr = newSelectedSlotNr - SYSTEMUI_SAVEDGAME_SLOTS_ON_SCREEN;
+ if (newUpmostSlotNr < 0)
+ newUpmostSlotNr = 0;
+ }
+ if (newSelectedSlotNr >= slotCount) {
+ newSelectedSlotNr = 0;
+ newUpmostSlotNr = 0;
+ }
+
+ if (newSelectedSlotNr < newUpmostSlotNr) {
+ // scroll up when needed
+ newUpmostSlotNr = newSelectedSlotNr;
+ }
+
+ if (newSelectedSlotNr >= newUpmostSlotNr + SYSTEMUI_SAVEDGAME_SLOTS_ON_SCREEN) {
+ // scroll down when needed
+ newUpmostSlotNr = newSelectedSlotNr - (SYSTEMUI_SAVEDGAME_SLOTS_ON_SCREEN - 1);
+ }
+
+ bool drawSlots = false;
+
+ // remove selector
+ drawSavedGameSlotSelector(false);
+
+ if (newUpmostSlotNr != _savedGameUpmostSlotNr) {
+ drawSlots = true;
+ }
+
+ _savedGameUpmostSlotNr = newUpmostSlotNr;
+ _savedGameSelectedSlotNr = newSelectedSlotNr;
+ if (drawSlots) {
+ drawSavedGameSlots();
+ }
+ drawSavedGameSlotSelector(true);
+ }
+}
+
+void SystemUI::clearSavedGameSlots() {
+ _savedGameArray.clear();
+ _savedGameUpmostSlotNr = 0;
+ _savedGameSelectedSlotNr = 0;
+}
+
+void SystemUI::createSavedGameDisplayText(char *destDisplayText, const char *actualDescription, int16 slotId, bool fillUpWithSpaces) {
+ char fillUpChar = fillUpWithSpaces ? ' ' : 0x00;
+ char slotIdChar[3];
+ int16 actualDescriptionLen = 0;
+
+ // clear with spaces
+ memset(destDisplayText, fillUpChar, SYSTEMUI_SAVEDGAME_DISPLAYTEXT_LEN);
+
+ // create fixed prefix (" 1:", "10:", etc.)
+ sprintf(slotIdChar, "%02d", slotId);
+ memcpy(destDisplayText, slotIdChar, 2);
+ destDisplayText[2] = ':';
+
+ actualDescriptionLen = strlen(actualDescription);
+ if (actualDescriptionLen > (SYSTEMUI_SAVEDGAME_DISPLAYTEXT_LEN - SYSTEMUI_SAVEDGAME_DISPLAYTEXT_PREFIX_LEN)) {
+ actualDescriptionLen = SYSTEMUI_SAVEDGAME_DISPLAYTEXT_LEN - SYSTEMUI_SAVEDGAME_DISPLAYTEXT_PREFIX_LEN;
+ }
+
+ if (actualDescriptionLen > 0) {
+ memcpy(destDisplayText + SYSTEMUI_SAVEDGAME_DISPLAYTEXT_PREFIX_LEN, actualDescription, actualDescriptionLen);
+ }
+ destDisplayText[SYSTEMUI_SAVEDGAME_DISPLAYTEXT_LEN] = 0; // terminator
+}
+
+void SystemUI::readSavedGameSlots(bool filterNonexistant, bool withAutoSaveSlot) {
+ SavedGameSlotIdArray slotIdArray;
+ int16 lastSlotId = -1;
+ int16 curSlotId = 0;
+ int16 loopSlotId = 0;
+ SystemUISavedGameEntry savedGameEntry;
+ Common::String saveDescription;
+ uint32 saveDate = 0;
+ uint32 saveTime = 0;
+ bool saveIsValid = false;
+
+ int16 mostRecentSlotNr = -1;
+ uint32 mostRecentSlotSaveDate = 0;
+ uint32 mostRecentSlotSaveTime = 0;
+
+ clearSavedGameSlots();
+
+ // we assume that the Slot-Ids are in order
+ slotIdArray = _vm->getSavegameSlotIds();
+ slotIdArray.push_back(SYSTEMUI_SAVEDGAME_MAXIMUM_SLOTS); // so that the loop will process all slots
+
+ SavedGameSlotIdArray::iterator it;
+ SavedGameSlotIdArray::iterator end = slotIdArray.end();
+
+ for (it = slotIdArray.begin(); it != end; it++) {
+ curSlotId = *it;
+
+ assert(curSlotId > lastSlotId); // safety check
+
+ if (curSlotId == 0) {
+ // Skip over auto-save slot, if not requested
+ if (!withAutoSaveSlot)
+ continue;
+ }
+
+ // only allow slot-ids 000 up to 099
+ if (curSlotId >= SYSTEMUI_SAVEDGAME_MAXIMUM_SLOTS)
+ curSlotId = SYSTEMUI_SAVEDGAME_MAXIMUM_SLOTS;
+
+ if (!filterNonexistant) {
+ // add slot-ids from last one up to current one (not including the current one)
+ lastSlotId++;
+ for (loopSlotId = lastSlotId; loopSlotId < curSlotId; loopSlotId++) {
+ if (loopSlotId == 0) {
+ // Skip over auto-save slot, if not requested
+ if (!withAutoSaveSlot)
+ continue;
+ }
+
+ savedGameEntry.slotId = loopSlotId;
+ savedGameEntry.exists = false;
+ savedGameEntry.isValid = false;
+ memset(savedGameEntry.description, 0, sizeof(savedGameEntry.description));
+ createSavedGameDisplayText(savedGameEntry.displayText, "", loopSlotId, true);
+
+ _savedGameArray.push_back(savedGameEntry);
+ }
+ }
+
+ if (curSlotId >= SYSTEMUI_SAVEDGAME_MAXIMUM_SLOTS)
+ break; // force an exit, limit reached
+
+ savedGameEntry.slotId = curSlotId;
+ if (_vm->getSavegameInformation(curSlotId, saveDescription, saveDate, saveTime, saveIsValid)) {
+ if (saveIsValid) {
+ // saved game is valid
+ // check, if this is the latest slot
+ if (saveDate > mostRecentSlotSaveDate) {
+ mostRecentSlotNr = _savedGameArray.size();
+ mostRecentSlotSaveDate = saveDate;
+ mostRecentSlotSaveTime = saveTime;
+ } else if ((saveDate == mostRecentSlotSaveDate) && (saveTime >= mostRecentSlotSaveTime)) {
+ // larger or equal is on purpose, so that we use the last slot in case there are multiple saves
+ // with the exact same date+time
+ mostRecentSlotNr = _savedGameArray.size();
+ mostRecentSlotSaveDate = saveDate;
+ mostRecentSlotSaveTime = saveTime;
+ }
+ }
+ } else {
+ // slot doesn't exist
+ if (filterNonexistant) {
+ continue;
+ }
+ }
+
+ savedGameEntry.exists = true;
+ savedGameEntry.isValid = saveIsValid;
+ memset(savedGameEntry.description, 0, sizeof(savedGameEntry.description));
+ strncpy(savedGameEntry.description, saveDescription.c_str(), SYSTEMUI_SAVEDGAME_DESCRIPTION_LEN);
+ createSavedGameDisplayText(savedGameEntry.displayText, saveDescription.c_str(), curSlotId, true);
+
+ _savedGameArray.push_back(savedGameEntry);
+
+ lastSlotId = curSlotId;
+ }
+
+ if (mostRecentSlotNr >= 0) {
+ // valid slot found, we use it as default
+ // Sierra AGI seems to have done the same
+ _savedGameSelectedSlotNr = mostRecentSlotNr;
+ if (mostRecentSlotNr < SYSTEMUI_SAVEDGAME_SLOTS_ON_SCREEN) {
+ // available without scrolling, so keep upmost slot 0
+ _savedGameUpmostSlotNr = 0;
+ } else {
+ // we need to scroll, try to have the slot in the middle
+ int16 slotCount = _savedGameArray.size();
+
+ _savedGameUpmostSlotNr = mostRecentSlotNr - (SYSTEMUI_SAVEDGAME_SLOTS_ON_SCREEN / 2);
+ if ((_savedGameUpmostSlotNr + (SYSTEMUI_SAVEDGAME_SLOTS_ON_SCREEN - 1)) >= slotCount) {
+ // current upmost would result in empty lines, because it's at the end, push it upwards
+ _savedGameUpmostSlotNr = (slotCount - 1) - (SYSTEMUI_SAVEDGAME_SLOTS_ON_SCREEN - 1);
+ }
+ }
+ }
+}
+
+void SystemUI::figureOutAutomaticSavedGameSlot(const char *automaticSaveDescription, int16 &matchedGameSlotId, int16 &freshGameSlotId) {
+ bool foundFresh = false;
+
+ matchedGameSlotId = -1;
+ freshGameSlotId = -1;
+
+ for (uint16 slotNr = 0; slotNr < _savedGameArray.size(); slotNr++) {
+ SystemUISavedGameEntry *savedGameEntry = &_savedGameArray[slotNr];
+
+ if (savedGameEntry->isValid) {
+ // valid saved game
+ if (strcmp(savedGameEntry->description, automaticSaveDescription) == 0) {
+ // we got a match
+ matchedGameSlotId = savedGameEntry->slotId;
+ return;
+ }
+ }
+ if (!foundFresh) {
+ // no new slot found yet
+ if (!savedGameEntry->exists) {
+ // and current slot doesn't exist
+ if (savedGameEntry->slotId) {
+ // and slot is not the auto-save slot -> remember this slot
+ freshGameSlotId = savedGameEntry->slotId;
+ foundFresh = true;
+ }
+ }
+ }
+ }
+ return;
+}
+
+void SystemUI::drawSavedGameSlots() {
+ int16 slotsToDrawCount = _savedGameArray.size() - _savedGameUpmostSlotNr;
+ int16 slotNr = 0;
+
+ if (slotsToDrawCount > SYSTEMUI_SAVEDGAME_SLOTS_ON_SCREEN) {
+ slotsToDrawCount = SYSTEMUI_SAVEDGAME_SLOTS_ON_SCREEN;
+ }
+ _text->charAttrib_Push();
+ _text->charAttrib_Set(0, 15);
+
+ for (slotNr = 0; slotNr < slotsToDrawCount; slotNr++) {
+ _text->displayTextInsideWindow("-", 5 + slotNr, 1);
+ _text->displayTextInsideWindow(_savedGameArray[_savedGameUpmostSlotNr + slotNr].displayText, 5 + slotNr, 3);
+ }
+ _text->charAttrib_Pop();
+}
+
+void SystemUI::drawSavedGameSlotSelector(bool active) {
+ int16 windowRow = 5 + (_savedGameSelectedSlotNr - _savedGameUpmostSlotNr);
+
+ _text->charAttrib_Push();
+ _text->charAttrib_Set(0, 15);
+ if (active) {
+ _text->displayTextInsideWindow("\x1a", windowRow, 0);
+ } else {
+ _text->displayTextInsideWindow(" ", windowRow, 0);
+ }
+ _text->charAttrib_Pop();
+}
+
+bool SystemUI::askForSavedGameVerification(const char *verifyText, const char *verifyButton1, const char *verifyButton2, const char *actualDescription, int16 slotId) {
+ char displayDescription[SYSTEMUI_SAVEDGAME_DISPLAYTEXT_LEN + 1];
+ Common::String userActionVerify;
+ Common::String savedGameFilename = _vm->getSavegameFilename(slotId);
+
+ createSavedGameDisplayText(displayDescription, actualDescription, slotId, false);
+ userActionVerify = Common::String::format(verifyText, displayDescription, savedGameFilename.c_str());
+
+ if (askForVerification(userActionVerify.c_str(), verifyButton1, verifyButton2, false)) {
+ return true;
+ }
+ return false;
+}
+
+bool SystemUI::askForVerification(const char *verifyText, const char *button1Text, const char *button2Text, bool continueOnMessageBoxClick) {
+ int16 forcedHeight = 0;
+ SystemUIButtonEntry buttonEntry;
+
+ _buttonArray.clear();
+
+ if (button1Text || button2Text) {
+ // Buttons are enabled, check how much space we need
+ const char *verifyTextSearch = verifyText;
+ char verifyTextSearchChar = 0;
+
+ forcedHeight = 1; // at least 1 line
+ do {
+ verifyTextSearchChar = *verifyTextSearch++;
+ if (verifyTextSearchChar == '\n')
+ forcedHeight++;
+ } while (verifyTextSearchChar);
+
+ switch (_vm->_renderMode) {
+ case Common::kRenderApple2GS:
+ case Common::kRenderAmiga:
+ forcedHeight += 3;
+ break;
+ case Common::kRenderAtariST:
+ forcedHeight += 2;
+ break;
+ default:
+ break;
+ }
+ }
+
+ // draw basic message box
+ _text->drawMessageBox(verifyText, forcedHeight, 35);
+
+ if (button1Text || button2Text) {
+ // Buttons enabled, calculate button coordinates
+ int16 msgBoxX = 0, msgBoxY = 0, msgBoxLowerY = 0;
+ int16 msgBoxWidth = 0, msgBoxHeight = 0;
+ int16 fontHeight = _gfx->getDisplayFontHeight();
+ int16 fontWidth = _gfx->getDisplayFontWidth();
+
+ _text->getMessageBoxInnerDisplayDimensions(msgBoxX, msgBoxY, msgBoxWidth, msgBoxHeight);
+ // Calculate lower Y
+ msgBoxLowerY = msgBoxY + (msgBoxHeight - 1);
+
+ buttonEntry.active = false;
+ if (button1Text) {
+ buttonEntry.text = button1Text;
+ buttonEntry.textWidth = strlen(button1Text) * _gfx->getDisplayFontWidth();
+ buttonEntry.isDefault = true;
+ _buttonArray.push_back(buttonEntry);
+ }
+ if (button2Text) {
+ buttonEntry.text = button2Text;
+ buttonEntry.textWidth = strlen(button2Text) * _gfx->getDisplayFontWidth();
+ buttonEntry.isDefault = false;
+ _buttonArray.push_back(buttonEntry);
+ }
+
+ // Render-Mode specific calculations
+ switch (_vm->_renderMode) {
+ case Common::kRenderApple2GS:
+ _buttonArray[0].rect = createRect(msgBoxX, +2, msgBoxLowerY - fontHeight, -(8 + 2), _buttonArray[0].textWidth, +14, fontHeight, +6);
+
+ if (_buttonArray.size() > 1) {
+ int16 adjustedX = msgBoxX + msgBoxWidth - _buttonArray[1].textWidth; // - 10;
+ _buttonArray[1].rect = createRect(adjustedX, -(14 + 10), _buttonArray[0].rect.top, 0, _buttonArray[1].textWidth, +14, fontHeight, +6);
+ }
+ break;
+
+ case Common::kRenderAmiga: {
+ _buttonArray[0].rect = createRect(msgBoxX, 0, msgBoxLowerY - fontHeight, -(2 + 2), _buttonArray[0].textWidth, +(4 + 4), fontHeight, +(2 + 2));
+
+ if (_buttonArray.size() > 1) {
+ int16 adjustedX = msgBoxX + msgBoxWidth - _buttonArray[1].textWidth;
+ _buttonArray[1].rect = createRect(adjustedX, -(4 + 4), _buttonArray[0].rect.top, 0, _buttonArray[1].textWidth, +(4 + 4), fontHeight, +(2 + 2));
+ }
+ break;
+ }
+
+ case Common::kRenderAtariST:
+ _buttonArray[0].rect = createRect(msgBoxX + (5 * fontWidth), 0, msgBoxLowerY - fontHeight, 0, _buttonArray[0].textWidth, 0, fontHeight, 0);
+
+ if (_buttonArray.size() > 1) {
+ int16 adjustedX = msgBoxX + msgBoxWidth - (5 * fontWidth + _buttonArray[1].textWidth);
+ _buttonArray[1].rect = createRect(adjustedX, 0, _buttonArray[0].rect.top, 0, _buttonArray[1].textWidth, 0, fontHeight, 0);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ drawButton(&_buttonArray[0]);
+ if (_buttonArray.size() > 1) {
+ drawButton(&_buttonArray[1]);
+ }
+ }
+
+ if ((continueOnMessageBoxClick) && (_buttonArray.size() == 0)) {
+ // continue on message box click allowed and no buttons? -> enable continue on message box
+ _askForVerificationContinueOnMessageBoxClick = true;
+ } else {
+ _askForVerificationContinueOnMessageBoxClick = false;
+ }
+
+ _vm->cycleInnerLoopActive(CYCLE_INNERLOOP_SYSTEMUI_VERIFICATION);
+ _askForVerificationCancelled = false;
+ _askForVerificationMouseLockedButtonNr = -1;
+ _askForVerificationMouseActiveButtonNr = -1;
+ do {
+ _vm->processAGIEvents();
+ } while (_vm->cycleInnerLoopIsActive() && !(_vm->shouldQuit() || _vm->_restartGame));
+
+ _text->closeWindow();
+
+ if (_askForVerificationCancelled)
+ return false;
+ return true;
+}
+
+void SystemUI::askForVerificationKeyPress(uint16 newKey) {
+ Common::Point mousePos = _vm->_mouse.pos;
+ bool searchButton = false; // searches for button at current mouse location, sets current button to inactive only
+ bool lockButton = false; // when new button is found, lock selection to it
+ bool executeButton = false; // actually triggers current button, exits inner loop
+
+ if (_vm->_renderMode == Common::kRenderAtariST) {
+ // Atari ST activates/deactivates buttons automatically on mouse over
+ searchButton = true;
+ }
+
+ switch (newKey) {
+ case AGI_KEY_ENTER:
+ _vm->cycleInnerLoopInactive();
+ break;
+ case AGI_KEY_ESCAPE:
+ _askForVerificationCancelled = true;
+ _vm->cycleInnerLoopInactive();
+ break;
+ case AGI_MOUSE_BUTTON_LEFT:
+ if (_askForVerificationContinueOnMessageBoxClick) {
+ // check, if cursor is within message box
+ if (_text->isMouseWithinMessageBox()) {
+ _vm->cycleInnerLoopInactive();
+ return;
+ }
+ }
+
+ // check, if any button is under the mouse cursor
+ searchButton = true;
+ lockButton = true;
+
+ if (_vm->_renderMode == Common::kRenderAtariST) {
+ // Atari ST reacts immediately on clicks
+ executeButton = true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (_askForVerificationMouseLockedButtonNr >= 0) {
+ // button is currently locked in, check if mouse is still over it
+ searchButton = true;
+
+ if (_vm->_mouse.button == kAgiMouseButtonUp) {
+ // mouse button released, execute button
+ executeButton = true;
+ }
+ }
+
+ if (searchButton) {
+ int16 mouseOverButtonNr = -1;
+
+ for (uint16 buttonNr = 0; buttonNr < _buttonArray.size(); buttonNr++) {
+ SystemUIButtonEntry *button = &_buttonArray[buttonNr];
+
+ if (button->rect.contains(mousePos))
+ mouseOverButtonNr = buttonNr;
+ }
+
+ if (_askForVerificationMouseLockedButtonNr >= 0) {
+ // Lock active, do not allow any other buttons atm
+ if (mouseOverButtonNr >= 0) {
+ // Mouse currently over a button
+ if (mouseOverButtonNr != _askForVerificationMouseLockedButtonNr) {
+ // And it's not the one that we are locked to
+ // Treat this as if mouse was over no button
+ mouseOverButtonNr = -1;
+ }
+ }
+ }
+
+ if (mouseOverButtonNr != _askForVerificationMouseActiveButtonNr) {
+ // Selection changed
+ if (_askForVerificationMouseActiveButtonNr >= 0) {
+ SystemUIButtonEntry *oldButton = &_buttonArray[_askForVerificationMouseActiveButtonNr];
+
+ oldButton->active = false;
+ drawButton(oldButton);
+ }
+ if (mouseOverButtonNr >= 0) {
+ SystemUIButtonEntry *newButton = &_buttonArray[mouseOverButtonNr];
+
+ newButton->active = true;
+ drawButton(newButton);
+
+ if (lockButton) {
+ _askForVerificationMouseLockedButtonNr = mouseOverButtonNr;
+ }
+ }
+ _askForVerificationMouseActiveButtonNr = mouseOverButtonNr;
+ }
+ }
+
+ if (executeButton) {
+ if (_askForVerificationMouseActiveButtonNr >= 0) {
+ SystemUIButtonEntry *button = &_buttonArray[_askForVerificationMouseActiveButtonNr];
+
+ if (button->active) {
+ if (!button->isDefault) {
+ // Not default button? -> that's cancel
+ _askForVerificationCancelled = true;
+ }
+ _vm->cycleInnerLoopInactive();
+ }
+ }
+ // Remove button lock in case it was locked
+ _askForVerificationMouseLockedButtonNr = -1;
+ }
+}
+
+Common::Rect SystemUI::createRect(int16 x, int16 adjX, int16 y, int16 adjY, int16 width, int16 adjWidth, int16 height, int16 adjHeight) {
+ switch (_gfx->getUpscaledHires()) {
+ case DISPLAY_UPSCALED_DISABLED:
+ break;
+ case DISPLAY_UPSCALED_640x400:
+ adjX *= 2; adjY *= 2;
+ adjWidth *= 2; adjHeight *= 2;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ x += adjX; y += adjY;
+ width += adjWidth; height += adjHeight;
+ Common::Rect newRect(width, height);
+ newRect.moveTo(x, y);
+ return newRect;
+}
+
+#define SYSTEMUI_BUTTONEDGE_APPLEIIGS_WIDTH 8
+#define SYSTEMUI_BUTTONEDGE_APPLEIIGS_HEIGHT 5
+
+static byte buttonEdgeAppleIIgsDefault[] = {
+ 0x07, 0x1C, 0x33, 0x6E, 0xDC
+};
+
+static byte buttonEdgeAppleIIgsDefaultActive[] = {
+ 0x07, 0x1C, 0x33, 0x6F, 0xDF
+};
+
+static byte buttonEdgeAppleIIgsNonDefault[] = {
+ 0x00, 0x00, 0x03, 0x0E, 0x1C
+};
+
+static byte buttonEdgeAppleIIgsNonDefaultActive[] = {
+ 0x00, 0x00, 0x03, 0x0F, 0x1F
+};
+
+void SystemUI::drawButton(SystemUIButtonEntry *button) {
+ switch (_vm->_renderMode) {
+ case Common::kRenderApple2GS:
+ drawButtonAppleIIgs(button);
+ break;
+ case Common::kRenderAmiga:
+ drawButtonAmiga(button);
+ break;
+ case Common::kRenderAtariST:
+ drawButtonAtariST(button);
+ break;
+ default:
+ break;
+ }
+}
+
+// Note: It seems that Apple IIgs AGI used a system font for the buttons (and the menu)
+// We use the regular 8x8 Sierra Apple IIgs font, that's why our buttons are not the exact same width
+void SystemUI::drawButtonAppleIIgs(SystemUIButtonEntry *button) {
+ byte foregroundColor = 0;
+ byte backgroundColor = 15;
+ byte *edgeBitmap = nullptr;
+
+ if (button->active) {
+ SWAP<byte>(foregroundColor, backgroundColor);
+ }
+
+ // draw base box for it
+ _gfx->drawDisplayRect(button->rect.left, button->rect.top, button->rect.width(), button->rect.height(), backgroundColor, false);
+
+ // draw inner lines
+ _gfx->drawDisplayRect(button->rect.left, +1, button->rect.top, -1, button->rect.width(), -2, 0, 1, 0, false); // lower horizontal
+ _gfx->drawDisplayRect(button->rect.left, -2, button->rect.top, +1, 0, 2, button->rect.height(), -2, 0, false); // left vertical
+ _gfx->drawDisplayRect(button->rect.right, 0, button->rect.top, +1, 0, 2, button->rect.height(), -2, 0, false); // right vertical
+ _gfx->drawDisplayRect(button->rect.left, +1, button->rect.bottom, 0, button->rect.width(), -2, 0, 1, 0, false); // upper horizontal
+
+ if (button->isDefault) {
+ // draw outer lines
+ _gfx->drawDisplayRect(button->rect.left, 0, button->rect.top, -3, button->rect.width(), 0, 0, 1, 0, false); // upper horizontal
+ _gfx->drawDisplayRect(button->rect.left, -5, button->rect.top, +2, 0, 2, button->rect.height(), -2, 0, false); // left vertical
+ _gfx->drawDisplayRect(button->rect.right, +3, button->rect.top, +2, 0, 2, button->rect.height(), -2, 0, false); // right vertical
+ _gfx->drawDisplayRect(button->rect.left, 0, button->rect.bottom, +2, button->rect.width(), 0, 0, 1, 0, false); // lower horizontal
+
+ if (button->active)
+ edgeBitmap = buttonEdgeAppleIIgsDefaultActive;
+ else
+ edgeBitmap = buttonEdgeAppleIIgsDefault;
+
+ } else {
+ if (button->active)
+ edgeBitmap = buttonEdgeAppleIIgsNonDefaultActive;
+ else
+ edgeBitmap = buttonEdgeAppleIIgsNonDefault;
+ }
+
+ // draw edge graphics
+ drawButtonAppleIIgsEdgePixels(button->rect.left, -5, button->rect.top, -3, edgeBitmap, false, false);
+ drawButtonAppleIIgsEdgePixels(button->rect.right, +4, button->rect.top, -3, edgeBitmap, true, false);
+ drawButtonAppleIIgsEdgePixels(button->rect.left, -5, button->rect.bottom, +2, edgeBitmap, false, true);
+ drawButtonAppleIIgsEdgePixels(button->rect.right, +4, button->rect.bottom, +2, edgeBitmap, true, true);
+
+ // Button text
+ _gfx->drawStringOnDisplay(button->rect.left, +7, button->rect.top, +3, button->text, foregroundColor, backgroundColor);
+
+ _gfx->copyDisplayRectToScreen(button->rect.left, -5, button->rect.top, -3, button->rect.width(), +10, button->rect.height(), +6);
+}
+
+void SystemUI::drawButtonAppleIIgsEdgePixels(int16 x, int16 adjX, int16 y, int16 adjY, byte *edgeBitmap, bool mirrored, bool upsideDown) {
+ int8 directionY = upsideDown ? -1 : +1;
+ int8 directionX = mirrored ? -1 : +1;
+ int8 curY = 0;
+ int8 curX;
+ int8 heightLeft = SYSTEMUI_BUTTONEDGE_APPLEIIGS_HEIGHT;
+ int8 widthLeft;
+ byte curBitmapByte;
+ byte curBitmapBit;
+
+ while (heightLeft) {
+ widthLeft = SYSTEMUI_BUTTONEDGE_APPLEIIGS_WIDTH;
+ curX = 0;
+ curBitmapByte = *edgeBitmap++;
+ curBitmapBit = 0x80;
+
+ while (widthLeft) {
+ if (curBitmapByte & curBitmapBit) {
+ _gfx->putPixelOnDisplay(x, adjX + curX, y, adjY + curY, 0);
+ } else {
+ _gfx->putPixelOnDisplay(x, adjX + curX, y, adjY + curY, 15);
+ }
+
+ curBitmapBit = curBitmapBit >> 1;
+ curX += directionX;
+ widthLeft--;
+ }
+
+ curY += directionY;
+ heightLeft--;
+ }
+}
+
+void SystemUI::drawButtonAmiga(SystemUIButtonEntry *button) {
+ byte foregroundColor;
+ byte backgroundColor;
+
+ if (!button->active)
+ foregroundColor = 15;
+ else
+ foregroundColor = 0;
+
+ if (button->isDefault) {
+ if (!button->active)
+ backgroundColor = 2; // green
+ else
+ backgroundColor = 13; // orange
+ } else {
+ if (!button->active)
+ backgroundColor = 4; // red
+ else
+ backgroundColor = 11; // cyan
+ }
+
+ // draw base box for it
+ _gfx->drawDisplayRect(button->rect.left, button->rect.top, button->rect.width(), button->rect.height(), backgroundColor, false);
+
+ // Button text
+ _gfx->drawStringOnDisplay(button->rect.left, +4, button->rect.top, +2, button->text, foregroundColor, backgroundColor);
+
+ _gfx->copyDisplayRectToScreen(button->rect.left, button->rect.top, button->rect.width(), button->rect.height());
+}
+
+void SystemUI::drawButtonAtariST(SystemUIButtonEntry *button) {
+ byte foregroundColor = 0;
+ byte backgroundColor = 15;
+
+ if (button->active) {
+ SWAP<byte>(foregroundColor, backgroundColor);
+ }
+
+ // Button text
+ _gfx->drawStringOnDisplay(button->rect.left, button->rect.top, button->text, foregroundColor, backgroundColor);
+}
+
+} // End of namespace Agi
diff --git a/engines/agi/systemui.h b/engines/agi/systemui.h
new file mode 100644
index 0000000000..283de8794c
--- /dev/null
+++ b/engines/agi/systemui.h
@@ -0,0 +1,167 @@
+/* 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 AGI_SYSTEMUI_H
+#define AGI_SYSTEMUI_H
+
+namespace Agi {
+
+#define SYSTEMUI_SAVEDGAME_MAXIMUM_SLOTS 100
+#define SYSTEMUI_SAVEDGAME_SLOTS_ON_SCREEN 12
+#define SYSTEMUI_SAVEDGAME_DESCRIPTION_LEN 30
+#define SYSTEMUI_SAVEDGAME_DISPLAYTEXT_LEN 31
+#define SYSTEMUI_SAVEDGAME_DISPLAYTEXT_PREFIX_LEN 3
+
+struct SystemUISavedGameEntry {
+ int16 slotId;
+ bool exists;
+ bool isValid;
+ char description[SYSTEMUI_SAVEDGAME_DESCRIPTION_LEN + 1]; // actual description
+ char displayText[SYSTEMUI_SAVEDGAME_DISPLAYTEXT_LEN + 1]; // modified description, meant for display purposes only
+};
+typedef Common::Array<SystemUISavedGameEntry> SystemUISavedGameArray;
+
+struct SystemUIButtonEntry {
+ Common::Rect rect;
+ const char *text;
+ int16 textWidth;
+ bool active;
+ bool isDefault;
+};
+typedef Common::Array<SystemUIButtonEntry> SystemUIButtonArray;
+
+class SystemUI {
+public:
+ SystemUI(AgiEngine *vm, GfxMgr *gfx, TextMgr *text);
+ ~SystemUI();
+
+private:
+ AgiEngine *_vm;
+ GfxMgr *_gfx;
+ TextMgr *_text;
+
+public:
+ const char *getStatusTextScore();
+ const char *getStatusTextSoundOn();
+ const char *getStatusTextSoundOff();
+
+ void pauseDialog();
+ bool restartDialog();
+ bool quitDialog();
+
+private:
+
+
+public:
+ const char *getInventoryTextNothing();
+ const char *getInventoryTextYouAreCarrying();
+ const char *getInventoryTextSelectItems();
+ const char *getInventoryTextReturnToGame();
+
+ bool askForCommand(Common::String &commandText);
+
+ int16 figureOutAutomaticSaveGameSlot(const char *automaticSaveDescription);
+ int16 figureOutAutomaticRestoreGameSlot(const char *automaticSaveDescription);
+
+ int16 askForSaveGameSlot();
+ int16 askForRestoreGameSlot();
+ bool askForSaveGameDescription(int16 slotId, Common::String &newDescription);
+
+ void savedGameSlot_KeyPress(uint16 newKey);
+
+private:
+ int16 askForSavedGameSlot(const char *slotListText);
+ bool askForSavedGameVerification(const char *verifyText, const char *verifyButton1, const char *verifyButton2, const char *actualDescription, int16 slotId);
+
+ bool askForVerification(const char *verifyText, const char *button1Text, const char *button2Text, bool continueOnMessageBoxClick);
+
+ void createSavedGameDisplayText(char *destDisplayText, const char *actualDescription, int16 slotId, bool fillUpWithSpaces);
+ void clearSavedGameSlots();
+ void readSavedGameSlots(bool filterNonexistant, bool withAutoSaveSlot);
+ void figureOutAutomaticSavedGameSlot(const char *automaticSaveDescription, int16 &matchedGameSlotId, int16 &freshGameSlotId);
+
+ void drawSavedGameSlots();
+ void drawSavedGameSlotSelector(bool active);
+
+ SystemUISavedGameArray _savedGameArray;
+ int16 _savedGameUpmostSlotNr;
+ int16 _savedGameSelectedSlotNr;
+
+private:
+ SystemUIButtonArray _buttonArray;
+
+ Common::Rect createRect(int16 x, int16 adjX, int16 y, int16 adjY, int16 width, int16 adjWidth, int16 height, int16 adjHeight);
+ //void moveRect(int16 x, int16 adjX, int16 y, int16 adjY);
+
+ void drawButton(SystemUIButtonEntry *button);
+ void drawButtonAppleIIgs(SystemUIButtonEntry *buttonEntry);
+ void drawButtonAppleIIgsEdgePixels(int16 x, int16 adjX, int16 y, int16 adjY, byte *edgeBitmap, bool mirrored, bool upsideDown);
+ void drawButtonAmiga(SystemUIButtonEntry *buttonEntry);
+ void drawButtonAtariST(SystemUIButtonEntry *buttonEntry);
+
+public:
+ void askForVerificationKeyPress(uint16 newKey);
+
+private:
+ bool _askForVerificationContinueOnMessageBoxClick;
+ bool _askForVerificationCancelled;
+ int16 _askForVerificationMouseLockedButtonNr;
+ int16 _askForVerificationMouseActiveButtonNr;
+
+private:
+ const char *_textStatusScore;
+ const char *_textStatusSoundOn;
+ const char *_textStatusSoundOff;
+
+ const char *_textEnterCommand;
+
+ const char *_textPause;
+ const char *_textPauseButton;
+ const char *_textRestart;
+ const char *_textRestartButton1;
+ const char *_textRestartButton2;
+ const char *_textQuit;
+ const char *_textQuitButton1;
+ const char *_textQuitButton2;
+
+ const char *_textInventoryNothing;
+ const char *_textInventoryYouAreCarrying;
+ const char *_textInventorySelectItems;
+ const char *_textInventoryReturnToGame;
+
+ const char *_textSaveGameSelectSlot;
+ const char *_textSaveGameEnterDescription;
+ const char *_textSaveGameVerify;
+ const char *_textSaveGameVerifyButton1;
+ const char *_textSaveGameVerifyButton2;
+
+ const char *_textRestoreGameNoSlots;
+ const char *_textRestoreGameSelectSlot;
+ const char *_textRestoreGameError;
+ const char *_textRestoreGameVerify;
+ const char *_textRestoreGameVerifyButton1;
+ const char *_textRestoreGameVerifyButton2;
+};
+
+} // End of namespace Agi
+
+#endif /* AGI_SYSTEMUI_H */
diff --git a/engines/agi/text.cpp b/engines/agi/text.cpp
index 16c8284ce0..4aa42ffec3 100644
--- a/engines/agi/text.cpp
+++ b/engines/agi/text.cpp
@@ -20,497 +20,1108 @@
*
*/
+#include "common/config-manager.h"
#include "agi/agi.h"
-#include "agi/sprite.h" // for commit_both()
+#include "agi/sprite.h" // for commit_both()
#include "agi/graphics.h"
#include "agi/keyboard.h"
+#include "agi/text.h"
+#include "agi/systemui.h"
+#include "agi/words.h"
+#ifdef __DS__
+#include "wordcompletion.h"
+#endif
namespace Agi {
-void AgiEngine::printText2(int l, const char *msg, int foff, int xoff, int yoff,
- int len, int fg, int bg, bool checkerboard) {
- int x1, y1;
- int maxx, minx, ofoff;
- int update;
- // Note: Must be unsigned to use AGDS cyrillic characters!
-#ifdef __DS__
- // On the DS, a compiler bug causes the text to render incorrectly, because
- // GCC tries to optimisie out writes to this pointer (tested on DevkitARM v19b and v20)
- // Making this pointer volatile fixes this.
- volatile const unsigned char *m;
-#else
- const unsigned char *m;
-#endif
+TextMgr::TextMgr(AgiEngine *vm, Words *words, GfxMgr *gfx) {
+ _vm = vm;
+ _words = words;
+ _gfx = gfx;
+
+ _systemUI = NULL;
+
+ memset(&_messageState, 0, sizeof(_messageState));
+ _textPos.row = 0;
+ _textPos.column = 0;
+ _reset_Column = 0;
+
+ charAttrib_Set(15, 0);
+
+ _messageState.wanted_TextPos.row = -1;
+ _messageState.wanted_TextPos.column = -1;
+ _messageState.wanted_Text_Width = -1;
+
+ _textPosArrayCount = 0;
+ memset(&_textPosArray, 0, sizeof(_textPosArray));
+ _textAttribArrayCount = 0;
+ memset(&_textAttribArray, 0, sizeof(_textAttribArray));
+
+ _inputEditEnabled = false;
+ _inputCursorChar = 0;
+
+ _statusEnabled = false;
+ _statusRow = 0;
+
+ _promptRow = 0;
+ promptDisable();
+ promptReset();
- // kludge!
- update = 1;
- if (l == 2) {
- update = l = 0;
+ _inputStringRow = 0;
+ _inputStringColumn = 0;
+ _inputStringEntered = false;
+ _inputStringMaxLen = 0;
+ _inputStringCursorPos = 0;
+ _inputString[0] = 0;
+
+ configureScreen(2);
+
+ _messageBoxCancelled = false;
+
+ _optionCommandPromptWindow = false;
+
+ if (ConfMan.getBool("commandpromptwindow")) {
+ _optionCommandPromptWindow = true;
}
+}
- // FR: strings with len == 1 were not printed
- if (len == 1) {
- _gfx->putTextCharacter(l, xoff + foff, yoff, *msg, fg, bg, checkerboard, _fontData);
- maxx = 1;
- minx = 0;
- ofoff = foff;
- y1 = 0; // Check this
- } else {
- maxx = 0;
- minx = GFX_WIDTH;
- ofoff = foff;
+TextMgr::~TextMgr() {
+}
+
+void TextMgr::init(SystemUI *systemUI) {
+ _systemUI = systemUI;
+}
+
+void TextMgr::configureScreen(uint16 row_Min) {
+ _window_Row_Min = row_Min;
+ _window_Row_Max = row_Min + 21;
+
+ // forward data to GfxMgr as well
+ _gfx->setRenderStartOffset(row_Min * FONT_VISUAL_HEIGHT);
+}
+uint16 TextMgr::getWindowRowMin() {
+ return _window_Row_Min;
+}
- for (m = (const unsigned char *)msg, x1 = y1 = 0; *m; m++) {
+void TextMgr::dialogueOpen() {
+ _messageState.dialogue_Open = true;
+}
- // Note: there were extra checks for *m being a cursor character
- // here (1, 2 or 3), which have been removed, as the cursor
- // character is no longer printed via this function.
- if (*m >= 0x20) {
- int ypos = (y1 * CHAR_LINES) + yoff;
+void TextMgr::dialogueClose() {
+ _messageState.dialogue_Open = false;
+}
- if ((x1 != (len - 1) || x1 == 39) && (ypos <= (GFX_HEIGHT - CHAR_LINES))) {
- int xpos = (x1 * CHAR_COLS) + xoff + foff;
+void TextMgr::charPos_Clip(int16 &row, int16 &column) {
+ row = CLIP<int16>(row, 0, FONT_ROW_CHARACTERS - 1);
+ column = CLIP<int16>(column, 0, FONT_COLUMN_CHARACTERS - 1);
+}
- if (xpos >= GFX_WIDTH)
- continue;
+void TextMgr::charPos_Set(int16 row, int16 column) {
+ _textPos.row = row;
+ _textPos.column = column;
+}
- _gfx->putTextCharacter(l, xpos, ypos, *m, fg, bg, checkerboard, _fontData);
+void TextMgr::charPos_Set(TextPos_Struct *posPtr) {
+ _textPos.row = posPtr->row;
+ _textPos.column = posPtr->column;
+}
- if (x1 > maxx)
- maxx = x1;
- if (x1 < minx)
- minx = x1;
- }
+void TextMgr::charPos_Get(int16 &row, int16 &column) {
+ row = _textPos.row;
+ column = _textPos.column;
+}
- x1++;
+void TextMgr::charPos_Get(TextPos_Struct *posPtr) {
+ posPtr->row = _textPos.row;
+ posPtr->column = _textPos.column;
+}
- // Change line if we've reached the end of this one, unless the next
- // character is a new line itself, or the end of the string
- if (x1 == len && m[1] != '\n' && m[1] != 0) {
- y1++;
- x1 = foff = 0;
- }
+void TextMgr::charPos_Push() {
+ if (_textPosArrayCount < TEXTPOSARRAY_MAX) {
+ charPos_Get(&_textPosArray[_textPosArrayCount]);
+ _textPosArrayCount++;
+ }
+}
+
+void TextMgr::charPos_Pop() {
+ if (_textPosArrayCount > 0) {
+ _textPosArrayCount--;
+ charPos_Set(&_textPosArray[_textPosArrayCount]);
+ }
+}
+
+void TextMgr::charPos_SetInsideWindow(int16 windowRow, int16 windowColumn) {
+ if (!_messageState.window_Active)
+ return;
+
+ _textPos.row = _messageState.textPos.row + windowRow;
+ _textPos.column = _messageState.textPos.column + windowColumn;
+}
+
+static byte charAttrib_CGA_Conversion[] = {
+ 0, 1, 1, 1, 2, 2, 2, 3, 3, 1, 1, 1, 2, 2, 2
+};
+
+void TextMgr::charAttrib_Set(byte foreground, byte background) {
+ _textAttrib.foreground = foreground;
+ _textAttrib.background = calculateTextBackground(background);
+
+ if (!_vm->_game.gfxMode) {
+ // Text-mode:
+ // just use the given colors directly
+ _textAttrib.combinedForeground = foreground;
+ _textAttrib.combinedBackground = background;
+ } else {
+ // Graphics-mode:
+ switch (_vm->_renderMode) {
+ case Common::kRenderCGA:
+ // CGA
+ if (background) {
+ _textAttrib.combinedForeground = 3;
+ _textAttrib.combinedBackground = 8; // enable invert of colors
} else {
- if (m[1] != 0) {
- y1++;
- x1 = foff = 0;
+ if (foreground > 14) {
+ _textAttrib.combinedForeground = 3;
+ } else {
+ _textAttrib.combinedForeground = charAttrib_CGA_Conversion[foreground & 0x0F];
}
+ _textAttrib.combinedBackground = 0;
}
+ break;
+ case Common::kRenderHercA:
+ case Common::kRenderHercG:
+ if (background) {
+ _textAttrib.combinedForeground = 0;
+ _textAttrib.combinedBackground = 1;
+ } else {
+ _textAttrib.combinedForeground = 1;
+ _textAttrib.combinedBackground = 0;
+ }
+ break;
+ default:
+ // EGA-handling:
+ if (background) {
+ _textAttrib.combinedForeground = 15;
+ _textAttrib.combinedBackground = 8; // enable invert of colors
+ } else {
+ _textAttrib.combinedForeground = foreground;
+ _textAttrib.combinedBackground = 0;
+ }
+ break;
}
}
+}
- if (l)
- return;
+byte TextMgr::charAttrib_GetForeground() {
+ return _textAttrib.foreground;
+}
+byte TextMgr::charAttrib_GetBackground() {
+ return _textAttrib.background;
+}
+
+void TextMgr::charAttrib_Push() {
+ if (_textAttribArrayCount < TEXTATTRIBARRAY_MAX) {
+ memcpy(&_textAttribArray[_textAttribArrayCount], &_textAttrib, sizeof(_textAttrib));
+ _textAttribArrayCount++;
+ }
+}
+
+void TextMgr::charAttrib_Pop() {
+ if (_textAttribArrayCount > 0) {
+ _textAttribArrayCount--;
+ memcpy(&_textAttrib, &_textAttribArray[_textAttribArrayCount], sizeof(_textAttrib));
+ }
+}
+
+byte TextMgr::calculateTextBackground(byte background) {
+ if ((_vm->_game.gfxMode) && (background)) {
+ return 15; // interpreter sets 0xFF, but drawClearCharacter() would use upper 4 bits by shift
+ }
+ return 0;
+}
+
+void TextMgr::display(int16 textNr, int16 textRow, int16 textColumn) {
+ const char *logicTextPtr = NULL;
+ char *processedTextPtr = NULL;
+
+ charPos_Push();
+ charPos_Set(textRow, textColumn);
- if (maxx < minx)
+ if (textNr >= 1 && textNr <= _vm->_game._curLogic->numTexts) {
+ logicTextPtr = _vm->_game._curLogic->texts[textNr - 1];
+ processedTextPtr = stringPrintf(logicTextPtr);
+ processedTextPtr = stringWordWrap(processedTextPtr, 40);
+ displayText(processedTextPtr);
+
+ // Signal, that non-blocking text is shown at the moment
+ if (textRow > 0) {
+ // only signal, when it's not the status line (kq3)
+ _vm->nonBlockingText_IsShown();
+ }
+ }
+ charPos_Pop();
+}
+
+void TextMgr::displayTextInsideWindow(const char *textPtr, int16 windowRow, int16 windowColumn) {
+ int16 textRow = 0;
+ int16 textColumn = 0;
+
+ if (!_messageState.window_Active)
return;
- maxx *= CHAR_COLS;
- minx *= CHAR_COLS;
+ charPos_Push();
+ textRow = _messageState.textPos.row + windowRow;
+ textColumn = _messageState.textPos.column + windowColumn;
+ charPos_Set(textRow, textColumn);
+ displayText(textPtr);
+ charPos_Pop();
+}
+
+void TextMgr::displayText(const char *textPtr, bool disabledLook) {
+ const char *curTextPtr = textPtr;
+ byte curCharacter = 0;
- if (update) {
- _gfx->scheduleUpdate(foff + xoff + minx, yoff, ofoff + xoff + maxx + CHAR_COLS - 1,
- yoff + y1 * CHAR_LINES + CHAR_LINES + 1);
+ while (1) {
+ curCharacter = *curTextPtr;
+ if (!curCharacter)
+ break;
- // Making synchronous text updates reduces CPU load
- // when updating status line and input area
- _gfx->doUpdate();
+ curTextPtr++;
+ displayCharacter(curCharacter, disabledLook);
}
}
-//
-// len is in characters, not pixels!!
-//
-void AgiEngine::blitTextbox(const char *p, int y, int x, int len) {
- // if x | y = -1, then center the box
- int xoff, yoff, lin, h, w;
- char *msg, *m;
+void TextMgr::displayCharacter(byte character, bool disabledLook) {
+ TextPos_Struct charCurPos;
- debugC(3, kDebugLevelText, "blitTextbox(): x=%d, y=%d, len=%d", x, y, len);
- if (_game.window.active)
- closeWindow();
+ charPos_Get(&charCurPos);
- if (x == 0 && y == 0 && len == 0)
- x = y = -1;
+ switch (character) {
+ case 0x08: // backspace
+ if (charCurPos.column) {
+ charCurPos.column--;
+ } else if (charCurPos.row > 21) {
+ charCurPos.column = (FONT_COLUMN_CHARACTERS - 1);
+ charCurPos.row--;
+ }
+ clearBlock(charCurPos.row, charCurPos.column, charCurPos.row, charCurPos.column, _textAttrib.background);
+ charPos_Set(&charCurPos);
+ break;
- if (len <= 0)
- len = 30;
+ case 0x0D:
+ case 0x0A: // CR/LF
+ if (charCurPos.row < (FONT_ROW_CHARACTERS - 1))
+ charCurPos.row++;
+ charCurPos.column = _reset_Column;
+ charPos_Set(&charCurPos);
+ break;
+ default:
+ // ch_attrib(state.text_comb, conversion);
+ _gfx->drawCharacter(charCurPos.row, charCurPos.column, character, _textAttrib.combinedForeground, _textAttrib.combinedBackground, disabledLook);
+
+ charCurPos.column++;
+ if (charCurPos.column <= (FONT_COLUMN_CHARACTERS - 1)) {
+ charPos_Set(&charCurPos);
+ } else {
+ displayCharacter(0x0D); // go to next line
+ }
+ }
+}
- xoff = x * CHAR_COLS;
- yoff = y * CHAR_LINES;
+void TextMgr::print(int16 textNr) {
+ const char *logicTextPtr = NULL;
+ if (textNr >= 1 && textNr <= _vm->_game._curLogic->numTexts) {
+ logicTextPtr = _vm->_game._curLogic->texts[textNr - 1];
+ messageBox(logicTextPtr);
+ }
+}
+
+void TextMgr::printAt(int16 textNr, int16 textPos_Row, int16 textPos_Column, int16 text_Width) {
+ // Sierra didn't do clipping, we do it for security
+ charPos_Clip(textPos_Row, textPos_Column);
- m = msg = wordWrapString(agiSprintf(p), &len);
+ _messageState.wanted_TextPos.row = textPos_Row;
+ _messageState.wanted_TextPos.column = textPos_Column;
+ _messageState.wanted_Text_Width = text_Width;
- for (lin = 1; *m; m++) {
- // Test \r for MacOS 8
- if (*m == '\n' || *m == '\r')
- lin++;
+ if (_messageState.wanted_Text_Width == 0) {
+ _messageState.wanted_Text_Width = 30;
}
+ print(textNr);
- if (lin * CHAR_LINES > GFX_HEIGHT)
- lin = (GFX_HEIGHT / CHAR_LINES);
+ _messageState.wanted_TextPos.row = -1;
+ _messageState.wanted_TextPos.column = -1;
+ _messageState.wanted_Text_Width = -1;
+}
- w = (len + 2) * CHAR_COLS;
- h = (lin + 2) * CHAR_LINES;
+bool TextMgr::messageBox(const char *textPtr) {
+ drawMessageBox(textPtr);
- if (xoff < 0)
- xoff = (GFX_WIDTH - w - CHAR_COLS) / 2;
- else
- xoff -= CHAR_COLS;
+ if (_vm->getFlag(VM_FLAG_OUTPUT_MODE)) {
+ // non-blocking window
+ _vm->setFlag(VM_FLAG_OUTPUT_MODE, false);
- if (yoff < 0)
- yoff = (GFX_HEIGHT - 3 * CHAR_LINES - h) / 2;
+ // Signal, that non-blocking text is shown at the moment
+ _vm->nonBlockingText_IsShown();
+ return true;
+ }
- drawWindow(xoff, yoff, xoff + w - 1, yoff + h - 1);
+ // blocking window
+ _vm->_noSaveLoadAllowed = true;
+ _vm->nonBlockingText_Forget();
- printText2(2, msg, 0, CHAR_COLS + xoff, CHAR_LINES + yoff,
- len + 1, MSG_BOX_TEXT, MSG_BOX_COLOR);
+ // timed window
+ uint32 windowTimer = _vm->getVar(VM_VAR_WINDOW_AUTO_CLOSE_TIMER);
+ debugC(3, kDebugLevelText, "blocking window v21=%d", windowTimer);
+
+ windowTimer = windowTimer * 10; // 1 = 0.5 seconds
+ _messageBoxCancelled = false;
+
+ _vm->inGameTimerResetPassedCycles();
+ _vm->cycleInnerLoopActive(CYCLE_INNERLOOP_MESSAGEBOX);
+ do {
+ _vm->processAGIEvents();
+ _vm->inGameTimerUpdate();
+
+ if (windowTimer > 0) {
+ if (_vm->inGameTimerGetPassedCycles() >= windowTimer) {
+ // Timer reached, close automatically
+ _vm->cycleInnerLoopInactive();
+ }
+ }
+ } while (_vm->cycleInnerLoopIsActive() && !(_vm->shouldQuit() || _vm->_restartGame));
+
+ _vm->inGameTimerResetPassedCycles();
+
+ _vm->setVar(VM_VAR_WINDOW_AUTO_CLOSE_TIMER, 0);
- free(msg);
+ closeWindow();
+ _vm->_noSaveLoadAllowed = false;
- _gfx->doUpdate();
+ if (_messageBoxCancelled)
+ return false;
+ return true;
}
-void AgiEngine::eraseTextbox() {
- if (!_game.window.active) {
- debugC(3, kDebugLevelText, "eraseTextbox(): no window active");
- return;
+void TextMgr::messageBox_KeyPress(uint16 newKey) {
+ switch (newKey) {
+ case AGI_KEY_ENTER:
+ _vm->cycleInnerLoopInactive(); // exit messagebox-loop
+ break;
+ case AGI_KEY_ESCAPE:
+ _messageBoxCancelled = true;
+ _vm->cycleInnerLoopInactive(); // exit messagebox-loop
+ break;
+ case AGI_MOUSE_BUTTON_LEFT: {
+ // Check, if mouse cursor is within message box
+ // If it is, take the click as ENTER.
+ // That's what AGI on Amiga + Apple IIgs did.
+ // On Atari ST at least via emulator it seems that the mouse cursor froze when messageboxes were diplayed.
+ if (isMouseWithinMessageBox()) {
+ _vm->cycleInnerLoopInactive(); // exit messagebox-loop
+ }
+ break;
+ }
+ default:
+ break;
}
+}
- debugC(4, kDebugLevelText, "eraseTextbox(): x1=%d, y1=%d, x2=%d, y2=%d", _game.window.x1,
- _game.window.y1, _game.window.x2, _game.window.y2);
+void TextMgr::drawMessageBox(const char *textPtr, int16 forcedHeight, int16 wantedWidth, bool forcedWidth) {
+ int16 maxWidth = wantedWidth;
+ int16 startingRow = 0;
+ char *processedTextPtr;
- _gfx->restoreBlock(_game.window.x1, _game.window.y1,
- _game.window.x2, _game.window.y2, _game.window.buffer);
+ if (_messageState.window_Active) {
+ closeWindow();
+ }
+ charAttrib_Push();
+ charPos_Push();
+ charAttrib_Set(0, 15);
+
+ if ((_messageState.wanted_Text_Width == -1) && (maxWidth == 0)) {
+ maxWidth = 30;
+ } else if (_messageState.wanted_Text_Width != -1) {
+ maxWidth = _messageState.wanted_Text_Width;
+ }
- free(_game.window.buffer);
- _game.window.active = false;
+ processedTextPtr = stringPrintf(textPtr);
- _gfx->doUpdate();
-}
+ int16 calculatedWidth = 0;
+ int16 calculatedHeight = 0;
-/*
- * Public functions
- */
+ processedTextPtr = stringWordWrap(processedTextPtr, maxWidth, &calculatedWidth, &calculatedHeight);
+ _messageState.textSize_Width = calculatedWidth;
+ _messageState.textSize_Height = calculatedHeight;
-/**
- * Print text in the AGI engine screen.
- */
-void AgiEngine::printText(const char *msg, int f, int x, int y, int len, int fg, int bg, bool checkerboard) {
- f *= CHAR_COLS;
- x *= CHAR_COLS;
- y *= CHAR_LINES;
+ _messageState.printed_Height = _messageState.textSize_Height;
- debugC(4, kDebugLevelText, "printText(): %s, %d, %d, %d, %d, %d, %d", msg, f, x, y, len, fg, bg);
- printText2(0, agiSprintf(msg), f, x, y, len, fg, bg, checkerboard);
-}
+ // Caller wants to force specified width/height? set it
+ if (forcedHeight)
+ _messageState.textSize_Height = forcedHeight;
-/**
- * Print text in the AGI engine console.
- */
-void AgiEngine::printTextConsole(const char *msg, int x, int y, int len, int fg, int bg) {
- x *= CHAR_COLS;
- y *= 10;
+ if (forcedWidth) {
+ if (wantedWidth)
+ _messageState.textSize_Width = wantedWidth;
+ }
- debugC(4, kDebugLevelText, "printTextConsole(): %s, %d, %d, %d, %d, %d", msg, x, y, len, fg, bg);
- printText2(1, msg, 0, x, y, len, fg, bg);
-}
+ if (_messageState.wanted_TextPos.row == -1) {
+ startingRow = ((HEIGHT_MAX - _messageState.textSize_Height - 1) / 2) + 1;
+ } else {
+ startingRow = _messageState.wanted_TextPos.row;
+ }
+ _messageState.textPos.row = startingRow + _window_Row_Min;
+ _messageState.textPos_Edge.row = _messageState.textSize_Height + _messageState.textPos.row - 1;
-/**
- * Wrap text line to the specified width.
- * @param str String to wrap.
- * @param len Length of line.
- *
- * Based on GBAGI implementation with permission from the author
- */
-char *AgiEngine::wordWrapString(const char *s, int *len) {
- char *outStr, *msgBuf;
- int maxWidth = *len;
- const char *pWord;
- int lnLen, wLen;
+ if (_messageState.wanted_TextPos.column == -1) {
+ _messageState.textPos.column = (FONT_COLUMN_CHARACTERS - _messageState.textSize_Width) / 2;
+ } else {
+ _messageState.textPos.column = _messageState.wanted_TextPos.column;
+ }
+ _messageState.textPos_Edge.column = _messageState.textPos.column + _messageState.textSize_Width;
- // Allocate some extra space for the final buffer, as
- // outStr may end up being longer than s
- // 26 = 200 (screen height) / 8 (font height) + 1
- msgBuf = outStr = (char *)malloc(strlen(s) + 26);
+ charPos_Set(_messageState.textPos.row, _messageState.textPos.column);
- int msgWidth = 0;
+ _messageState.backgroundSize_Width = (_messageState.textSize_Width * FONT_VISUAL_WIDTH) + 10;
+ _messageState.backgroundSize_Height = (_messageState.textSize_Height * FONT_VISUAL_HEIGHT) + 10;
+ _messageState.backgroundPos_x = (_messageState.textPos.column * FONT_VISUAL_WIDTH) - 5;
+ _messageState.backgroundPos_y = (startingRow * FONT_VISUAL_HEIGHT) - 5;
+ // original AGI used lowerY here, calculated using (_messageState.textPos_Edge.row - _window_Row_Min + 1) * FONT_VISUAL_HEIGHT + 4;
- lnLen = 0;
+ // Hardcoded colors: white background and red lines
+ _gfx->drawBox(_messageState.backgroundPos_x, _messageState.backgroundPos_y, _messageState.backgroundSize_Width, _messageState.backgroundSize_Height, 15, 4);
- while (*s) {
- pWord = s;
+ _messageState.window_Active = true;
- while (*s != '\0' && *s != ' ' && *s != '\n' && *s != '\r')
- s++;
+ _reset_Column = _messageState.textPos.column;
+ displayText(processedTextPtr);
+ _reset_Column = 0;
- wLen = (int)(s - pWord);
+ charPos_Pop();
+ charAttrib_Pop();
- if (wLen && *s == '\n' && s[-1] == ' ')
- wLen--;
+ _messageState.dialogue_Open = true;
+}
- if (wLen + lnLen >= maxWidth) {
- // Check if outStr isn't msgBuf. If this is the case, outStr hasn't advanced
- // yet, so no output has been written yet
- if (outStr != msgBuf) {
- if (outStr[-1] == ' ')
- outStr[-1] = '\n';
- else
- *outStr++ = '\n';
- }
+void TextMgr::getMessageBoxInnerDisplayDimensions(int16 &x, int16 &y, int16 &width, int16 &height) {
+ if (!_messageState.window_Active)
+ return;
- lnLen = 0;
+ y = _messageState.textPos.row;
+ x = _messageState.textPos.column;
+ width = _messageState.textSize_Width;
+ height = _messageState.textSize_Height;
+ _gfx->translateFontRectToDisplayScreen(x, y, width, height);
+}
- while (wLen >= maxWidth) {
- msgWidth = maxWidth;
+bool TextMgr::isMouseWithinMessageBox() {
+ // Find out, where current mouse cursor actually is
+ int16 mouseY = _vm->_mouse.pos.y;
+ int16 mouseX = _vm->_mouse.pos.x;
- memcpy(outStr, pWord, maxWidth);
+ if (_messageState.window_Active) {
+ _gfx->translateDisplayPosToGameScreen(mouseX, mouseY);
- wLen -= maxWidth;
- outStr += maxWidth;
- pWord += maxWidth;
- *outStr++ = '\n';
+ if ((mouseX >= _messageState.backgroundPos_x) && (mouseX < (_messageState.backgroundPos_x + _messageState.backgroundSize_Width))) {
+ if ((mouseY >= _messageState.backgroundPos_y) && (mouseY < (_messageState.backgroundPos_y + _messageState.backgroundSize_Height))) {
+ return true;
}
}
+ }
+ return false;
+}
- if (wLen) {
- memcpy(outStr, pWord, wLen);
- outStr += wLen;
- }
- lnLen += wLen+1;
+void TextMgr::closeWindow() {
+ if (_messageState.window_Active) {
+ _gfx->render_Block(_messageState.backgroundPos_x, _messageState.backgroundPos_y, _messageState.backgroundSize_Width, _messageState.backgroundSize_Height);
+ }
+ _messageState.dialogue_Open = false;
+ _messageState.window_Active = false;
+}
- if (lnLen > msgWidth) {
- msgWidth = lnLen;
+void TextMgr::statusRow_Set(int16 row) {
+ _statusRow = row;
+}
+int16 TextMgr::statusRow_Get() {
+ return _statusRow;
+}
+
+void TextMgr::statusEnable() {
+ _statusEnabled = true;
+}
+void TextMgr::statusDisable() {
+ _statusEnabled = false;
+}
+bool TextMgr::statusEnabled() {
+ return _statusEnabled;
+}
- if (*s == '\0' || *s == ' ' || *s == '\n' || *s == '\r')
- msgWidth--;
+void TextMgr::statusDraw() {
+ char *statusTextPtr = NULL;
+
+ charAttrib_Push();
+ charPos_Push();
+
+ if (_statusEnabled) {
+ clearLine(_statusRow, 15);
+
+ charAttrib_Set(0, 15);
+ charPos_Set(_statusRow, 1);
+ statusTextPtr = stringPrintf(_systemUI->getStatusTextScore());
+ displayText(statusTextPtr);
+
+ charPos_Set(_statusRow, 30);
+ if (_vm->getFlag(VM_FLAG_SOUND_ON)) {
+ statusTextPtr = stringPrintf(_systemUI->getStatusTextSoundOn());
+ } else {
+ statusTextPtr = stringPrintf(_systemUI->getStatusTextSoundOff());
}
+ displayText(statusTextPtr);
+ }
+
+ charPos_Pop();
+ charAttrib_Pop();
+}
+
+void TextMgr::statusClear() {
+ clearLine(_statusRow, 0);
+}
+
+void TextMgr::clearLine(int16 row, byte color) {
+ clearLines(row, row, color);
+}
+
+void TextMgr::clearLines(int16 row_Upper, int16 row_Lower, byte color) {
+ clearBlock(row_Upper, 0, row_Lower, FONT_COLUMN_CHARACTERS - 1, color);
+}
+
+void TextMgr::clearBlock(int16 row_Upper, int16 column_Upper, int16 row_Lower, int16 column_Lower, byte color) {
+ // Sierra didn't do clipping of the coordinates, we do it for security
+ // and b/c there actually are some games, that call commands with invalid coordinates
+ // see cmdClearLines() comments.
+ charPos_Clip(row_Upper, column_Upper);
+ charPos_Clip(row_Lower, column_Lower);
+
+ int16 x = column_Upper;
+ int16 y = row_Upper;
+ int16 width = (column_Lower + 1 - column_Upper);
+ int16 height = (row_Lower + 1 - row_Upper);
+ _gfx->translateFontRectToDisplayScreen(x, y, width, height);
- if (*s == '\n')
- lnLen = 0;
+ _gfx->drawDisplayRect(x, y, width, height, color);
+}
+
+void TextMgr::clearBlockInsideWindow(int16 windowRow, int16 windowColumn, int16 width, byte color) {
+ int16 row;
+ int16 column;
+ if (!_messageState.window_Active)
+ return;
- if (*s)
- *outStr++ = *s++;
+ row = _messageState.textPos.row + windowRow;
+ column = _messageState.textPos.column + windowColumn;
+ clearBlock(row, column, row, column + width - 1, color);
+}
+
+bool TextMgr::inputGetEditStatus() {
+ return _inputEditEnabled;
+}
+
+void TextMgr::inputEditOn() {
+ if (!_inputEditEnabled) {
+ _inputEditEnabled = true;
+ if (_inputCursorChar) {
+ displayCharacter(0x08); // backspace
+ }
}
- *outStr = '\0';
- *len = msgWidth;
+}
- return msgBuf;
+void TextMgr::inputEditOff() {
+ if (_inputEditEnabled) {
+ _inputEditEnabled = false;
+ if (_inputCursorChar) {
+ displayCharacter(_inputCursorChar);
+ }
+ }
}
-/**
- * Remove existing window, if any.
- */
-void AgiEngine::closeWindow() {
- debugC(4, kDebugLevelText, "closeWindow()");
+void TextMgr::inputSetCursorChar(int16 cursorChar) {
+ _inputCursorChar = cursorChar;
+}
- _sprites->eraseBoth();
- eraseTextbox(); // remove window, if any
- _sprites->blitBoth();
- _sprites->commitBoth(); // redraw sprites
- _game.hasWindow = false;
+byte TextMgr::inputGetCursorChar() {
+ return _inputCursorChar;
}
-/**
- * Display a message box.
- * This function displays the specified message in a text box
- * centered in the screen and waits until a key is pressed.
- * @param p The text to be displayed
- */
-int AgiEngine::messageBox(const char *s) {
- int k;
-
- _sprites->eraseBoth();
- blitTextbox(s, -1, -1, -1);
- _sprites->blitBoth();
- k = waitKey();
- debugC(4, kDebugLevelText, "messageBox(): wait_key returned %02x", k);
- closeWindow();
+void TextMgr::promptRow_Set(int16 row) {
+ _promptRow = row;
+}
- return k;
+int16 TextMgr::promptRow_Get() {
+ return _promptRow;
}
-/**
- * Display a message box with buttons.
- * This function displays the specified message in a text box
- * centered in the screen and waits until a button is pressed.
- * @param p The text to be displayed
- * @param b NULL-terminated list of button labels
- */
-int AgiEngine::selectionBox(const char *m, const char **b) {
- int numButtons = 0;
- int x, y, i, s;
- int bx[5], by[5];
+void TextMgr::promptReset() {
+ _promptCursorPos = 0;
+ memset(_prompt, 0, sizeof(_prompt));
+ memset(_promptPrevious, 0, sizeof(_promptPrevious));
+}
- _noSaveLoadAllowed = true;
+void TextMgr::promptEnable() {
+ _promptEnabled = true;
+}
+void TextMgr::promptDisable() {
+ _promptEnabled = false;
+}
+bool TextMgr::promptIsEnabled() {
+ return _promptEnabled;
+}
- _sprites->eraseBoth();
- blitTextbox(m, -1, -1, -1);
+void TextMgr::promptKeyPress(uint16 newKey) {
+ int16 maxChars = 0;
+ int16 scriptsInputLen = _vm->getVar(VM_VAR_MAX_INPUT_CHARACTERS);
- x = _game.window.x1 + 5 * CHAR_COLS / 2;
- y = _game.window.y2 - 5 * CHAR_LINES / 2;
- s = _game.window.x2 - _game.window.x1 + 1 - 5 * CHAR_COLS;
- debugC(3, kDebugLevelText, "selectionBox(): s = %d", s);
+ bool acceptableInput = false;
+
+ // FEATURE: Sierra didn't check for valid characters (filtered out umlauts etc.)
+ // In text-mode this sort of worked at least with the DOS interpreter
+ // but as soon as invalid characters were used in graphics mode they weren't properly shown
+ switch (_vm->getLanguage()) {
+ case Common::RU_RUS:
+ if (newKey >= 0x20)
+ acceptableInput = true;
+ break;
+ default:
+ if ((newKey >= 0x20) && (newKey <= 0x7f))
+ acceptableInput = true;
+ break;
+ }
- // Automatically position buttons
- for (i = 0; b[i]; i++) {
- numButtons++;
- s -= CHAR_COLS * strlen(b[i]);
+ if (_optionCommandPromptWindow) {
+ // Forward to command prompt window, using last command
+ if (acceptableInput) {
+ promptCommandWindow(false, newKey);
+ }
+ return;
}
- if (i > 1) {
- debugC(3, kDebugLevelText, "selectionBox(): s / %d = %d", i - 1, s / (i - 1));
- s /= (i - 1);
+ if (_messageState.dialogue_Open) {
+ maxChars = TEXT_STRING_MAX_SIZE - 4;
} else {
- x += s / 2;
+ maxChars = TEXT_STRING_MAX_SIZE - strlen(_vm->_game.strings[0]); // string 0 is the prompt string prefix
+ }
+
+ if (_promptCursorPos)
+ maxChars--;
+
+ if (scriptsInputLen < maxChars)
+ maxChars = scriptsInputLen;
+
+ inputEditOn();
+
+ switch (newKey) {
+ case AGI_KEY_BACKSPACE: {
+ if (_promptCursorPos) {
+ _promptCursorPos--;
+ _prompt[_promptCursorPos] = 0;
+ displayCharacter(newKey);
+
+ promptRememberForAutoComplete();
+ }
+ break;
+ }
+ case 0x0A: // LF
+ break;
+ case AGI_KEY_ENTER: {
+ if (_promptCursorPos) {
+ // something got entered? -> process it and pass it to the scripts
+ promptRememberForAutoComplete(true);
+
+ memcpy(&_promptPrevious, &_prompt, sizeof(_prompt));
+ // parse text
+ _vm->_words->parseUsingDictionary((char *)&_prompt);
+
+ _promptCursorPos = 0;
+ _prompt[0] = 0;
+ promptRedraw();
+ }
+ break;
}
+ default:
+ if (maxChars > _promptCursorPos) {
+ if (acceptableInput) {
+ _prompt[_promptCursorPos] = newKey;
+ _promptCursorPos++;
+ _prompt[_promptCursorPos] = 0;
+ displayCharacter(newKey);
+
+ promptRememberForAutoComplete();
+ }
+ }
+ break;
+ }
+
+ inputEditOff();
+}
- for (i = 0; b[i]; i++) {
- bx[i] = x;
- by[i] = y;
- x += CHAR_COLS * strlen(b[i]) + s;
+void TextMgr::promptCancelLine() {
+ if (_optionCommandPromptWindow) {
+ // Abort, in case command prompt window is active
+ return;
}
- _sprites->blitBoth();
+ while (_promptCursorPos) {
+ promptKeyPress(0x08); // Backspace until prompt is empty
+ }
+}
- clearKeyQueue();
+void TextMgr::promptEchoLine() {
+ int16 previousLen = strlen((char *)_promptPrevious);
- AllowSyntheticEvents on(this);
+ if (_optionCommandPromptWindow) {
+ // Forward to command prompt window, using last command
+ promptCommandWindow(true, 0);
+ return;
+ }
- debugC(4, kDebugLevelText, "selectionBox(): waiting...");
- int key, active = 0;
- int rc = -1;
- while (rc == -1 && !(shouldQuit() || _restartGame)) {
- for (i = 0; b[i]; i++)
- _gfx->drawCurrentStyleButton(bx[i], by[i], b[i], i == active, false, i == 0);
+ if (_promptCursorPos < previousLen) {
+ inputEditOn();
- pollTimer();
- key = doPollKeyboard();
- switch (key) {
- case KEY_ENTER:
- rc = active;
- debugC(4, kDebugLevelText, "selectionBox(): Button pressed: %d", rc);
- break;
- case KEY_RIGHT:
- active++;
- if (active >= numButtons)
- active = 0;
- break;
- case KEY_LEFT:
- active--;
- if (active < 0)
- active = numButtons - 1;
- break;
- case BUTTON_LEFT:
- for (i = 0; b[i]; i++) {
- if (_gfx->testButton(bx[i], by[i], b[i])) {
- rc = active = i;
- debugC(4, kDebugLevelText, "selectionBox(): Button pressed: %d", rc);
- break;
- }
- }
- break;
- case 0x09: // Tab
- debugC(3, kDebugLevelText, "selectionBox(): Focus change");
- active++;
- active %= i;
- break;
+ while (_promptPrevious[_promptCursorPos]) {
+ promptKeyPress(_promptPrevious[_promptCursorPos]);
}
- _gfx->doUpdate();
+ promptRememberForAutoComplete();
- if (key == KEY_ESCAPE)
- break;
+ inputEditOff();
}
+}
- closeWindow();
- debugC(2, kDebugLevelText, "selectionBox(): Result = %d", rc);
+void TextMgr::promptRedraw() {
+ char *textPtr = nullptr;
+
+ if (_promptEnabled) {
+ if (_optionCommandPromptWindow) {
+ // Abort, in case command prompt window is active
+ return;
+ }
- _noSaveLoadAllowed = false;
+ inputEditOn();
+ clearLine(_promptRow, _textAttrib.background);
+ charPos_Set(_promptRow, 0);
+ // agi_printf(str_wordwrap(msg, state.string[0], 40) );
- return rc;
+ textPtr = _vm->_game.strings[0];
+ textPtr = stringPrintf(textPtr);
+ textPtr = stringWordWrap(textPtr, 40);
+
+ displayText(textPtr);
+ displayText((char *)&_prompt);
+ inputEditOff();
+ }
}
-/**
- *
- */
-int AgiEngine::print(const char *p, int lin, int col, int len) {
- if (p == NULL)
- return 0;
+// for AGI1
+void TextMgr::promptClear() {
+ if (_optionCommandPromptWindow) {
+ // Abort, in case command prompt window is active
+ return;
+ }
+ clearLine(_promptRow, _textAttrib.background);
+}
- debugC(4, kDebugLevelText, "print(): lin = %d, col = %d, len = %d", lin, col, len);
+void TextMgr::promptRememberForAutoComplete(bool entered) {
+#ifdef __DS__
+ DS::findWordCompletions((char *)_prompt);
+#endif
+}
- blitTextbox(p, lin, col, len);
+void TextMgr::promptCommandWindow(bool recallLastCommand, uint16 newKey) {
+ Common::String commandText;
- if (getflag(fOutputMode)) {
- // non-blocking window
- setflag(fOutputMode, false);
- return 1;
+ if (recallLastCommand) {
+ commandText += Common::String((char *)_promptPrevious);
+ }
+ if (newKey) {
+ if (newKey != ' ') {
+ // Only add char, when it's not a space.
+ // Original AGI did not filter space, but it makes no sense to start with a space.
+ // Space would get filtered anyway during dictionary parsing.
+ commandText += newKey;
+ }
}
- // blocking
+ if (_systemUI->askForCommand(commandText)) {
+ if (commandText.size()) {
+ // Something actually was entered?
+ strncpy((char *)&_prompt, commandText.c_str(), sizeof(_prompt));
+ promptRememberForAutoComplete(true);
+ memcpy(&_promptPrevious, &_prompt, sizeof(_prompt));
+ // parse text
+ _vm->_words->parseUsingDictionary((char *)&_prompt);
- _noSaveLoadAllowed = true;
+ _prompt[0] = 0;
+ }
+ }
+}
- if (_game.vars[vWindowReset] == 0) {
- int k;
- setvar(vKey, 0);
- k = waitKey();
- closeWindow();
+bool TextMgr::stringWasEntered() {
+ return _inputStringEntered;
+}
+
+void TextMgr::stringSet(const char *text) {
+ strncpy((char *)_inputString, text, sizeof(_inputString));
+ _inputString[sizeof(_inputString) - 1] = 0; // terminator
+}
+
+void TextMgr::stringPos_Get(int16 &row, int16 &column) {
+ row = _inputStringRow;
+ column = _inputStringColumn;
+}
+int16 TextMgr::stringGetMaxLen() {
+ return _inputStringMaxLen;
+}
- _noSaveLoadAllowed = false;
+void TextMgr::stringEdit(int16 stringMaxLen) {
+ int16 inputStringLen = strlen((const char *)_inputString);
- return k;
+ // Remember current position for predictive dialog
+ _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--;
}
- // timed window
+ // Caller can set the input string
+ _inputStringCursorPos = 0;
+ while (_inputStringCursorPos < inputStringLen) {
+ displayCharacter(_inputString[_inputStringCursorPos]);
+ _inputStringCursorPos++;
+ }
- debugC(3, kDebugLevelText, "f15==0, v21==%d => timed", getvar(21));
- _game.msgBoxTicks = getvar(vWindowReset) * 10;
- setvar(vKey, 0);
+ // should never happen unless there is a coding glitch
+ assert(_inputStringCursorPos <= stringMaxLen);
- _menuSelected = false;
+ _inputStringMaxLen = stringMaxLen;
+ _inputStringEntered = false;
+
+ inputEditOff();
do {
- if (getflag(fRestoreJustRan))
- break;
+ _vm->processAGIEvents();
+ } while (_vm->cycleInnerLoopIsActive() && !(_vm->shouldQuit() || _vm->_restartGame));
- if (_menuSelected)
- break;
+ inputEditOn();
- mainCycle();
- if (_game.keypress == KEY_ENTER) {
- debugC(4, kDebugLevelText, "KEY_ENTER");
- setvar(vWindowReset, 0);
- _game.keypress = 0;
- break;
+ // Forget non-blocking text, user was asked to enter something
+ _vm->nonBlockingText_Forget();
+}
+
+void TextMgr::stringKeyPress(uint16 newKey) {
+ inputEditOn();
+
+ switch (newKey) {
+ case 0x3: // ctrl-c
+ case 0x18: { // ctrl-x
+ // clear string
+ while (_inputStringCursorPos) {
+ _inputStringCursorPos--;
+ _inputString[_inputStringCursorPos] = 0;
+ displayCharacter(0x08);
}
- } while (_game.msgBoxTicks > 0 && !(shouldQuit() || _restartGame));
+ break;
+ }
- setvar(vWindowReset, 0);
+ case AGI_KEY_BACKSPACE: {
+ if (_inputStringCursorPos) {
+ _inputStringCursorPos--;
+ _inputString[_inputStringCursorPos] = 0;
+ displayCharacter(newKey);
- closeWindow();
+ stringRememberForAutoComplete();
+ }
+ break;
+ }
- _noSaveLoadAllowed = false;
+ case AGI_KEY_ENTER: {
+ stringRememberForAutoComplete(true);
- return 0;
+ _inputStringEntered = true;
+
+ _vm->cycleInnerLoopInactive(); // exit GetString-loop
+ break;
+ }
+
+ case AGI_KEY_ESCAPE: {
+ _inputString[0] = 0;
+ _inputStringCursorPos = 0;
+ _inputStringEntered = false;
+
+ _vm->cycleInnerLoopInactive(); // exit GetString-loop
+ break;
+ }
+
+ default:
+ if (_inputStringMaxLen > _inputStringCursorPos) {
+ bool acceptableInput = false;
+
+ // FEATURE: Sierra didn't check for valid characters (filtered out umlauts etc.)
+ // In text-mode this sort of worked at least with the DOS interpreter
+ // but as soon as invalid characters were used in graphics mode they weren't properly shown
+ switch (_vm->getLanguage()) {
+ case Common::RU_RUS:
+ if (newKey >= 0x20)
+ acceptableInput = true;
+ break;
+ default:
+ if ((newKey >= 0x20) && (newKey <= 0x7f))
+ acceptableInput = true;
+ break;
+ }
+
+ if (acceptableInput) {
+ if ((_vm->_game.cycleInnerLoopType == CYCLE_INNERLOOP_GETSTRING) || ((newKey >= '0') && (newKey <= '9'))) {
+ // Additionally check for GETNUMBER-mode, if character is a number
+ // Sierra also did not do this
+ _inputString[_inputStringCursorPos] = newKey;
+ _inputStringCursorPos++;
+ _inputString[_inputStringCursorPos] = 0;
+ displayCharacter(newKey);
+
+ stringRememberForAutoComplete();
+ }
+ }
+ }
+ break;
+ }
+
+ inputEditOff();
+}
+
+void TextMgr::stringRememberForAutoComplete(bool entered) {
+#ifdef __DS__
+ DS::findWordCompletions((char *)_inputString);
+#endif
}
/**
- *
+ * Wraps text line to the specified width.
+ * @param originalText String to wrap.
+ * @param maxWidth Length of line.
*/
-void AgiEngine::printStatus(const char *message, ...) {
- va_list args;
+char *TextMgr::stringWordWrap(const char *originalText, int16 maxWidth, int16 *calculatedWidthPtr, int16 *calculatedHeightPtr) {
+ static char resultWrappedBuffer[2000];
+ int16 boxWidth = 0;
+ int16 boxHeight = 0;
+ int16 lineWidth = 0; // width of current line
- va_start(args, message);
+ int16 lineWidthLeft = maxWidth; // width left of current line
- Common::String x = Common::String::vformat(message, args);
+ int16 wordStartPos = 0;
+ int16 wordLen = 0;
+ int16 curReadPos = 0;
+ int16 curWritePos = 0;
+ byte wordEndChar = 0;
- va_end(args);
+ //memset(resultWrappedBuffer, 0, sizeof(resultWrappedBuffer)); for debugging
+
+ // Good testcases:
+ // King's Quest 1 intro: the scrolling text is filled up with spaces, so that old lines are erased
+ // Apple IIgs restart system UI: spaces used to make the window larger
+ // Gold Rush Stagecoach path room 60: " Lake Michigan!", with max length 9 -> should get split into " Lake" / "Michigan!"
+
+ while (originalText[curReadPos]) {
+ // Try to find out length of next word
+
+ // If first character is a space, skip it, so that we process at least this space
+ if (originalText[curReadPos] == ' ')
+ curReadPos++;
+
+ while (originalText[curReadPos]) {
+ if (originalText[curReadPos] == ' ')
+ break;
+ if (originalText[curReadPos] == 0x0A)
+ break;
+ curReadPos++;
+ }
+ wordEndChar = originalText[curReadPos];
+
+ // Calculate word length
+ wordLen = curReadPos - wordStartPos;
+
+ if (wordLen >= lineWidthLeft) {
+ // Not enough space left
+
+ // If first character right after the new line is a space, skip over it
+ if (wordLen) {
+ if (originalText[wordStartPos] == ' ') {
+ wordStartPos++;
+ wordLen--;
+ }
+ }
- debugC(4, kDebugLevelText, "fg=%d, bg=%d", STATUS_FG, STATUS_BG);
- printText(x.c_str(), 0, 0, _game.lineStatus, 40, STATUS_FG, STATUS_BG);
+ if (wordLen > maxWidth) {
+ // Word way too long, split it in half
+ curReadPos = curReadPos - (wordLen - maxWidth);
+ wordLen = maxWidth;
+ }
+
+ // Add new line
+ resultWrappedBuffer[curWritePos++] = 0x0A;
+ if (lineWidth > boxWidth)
+ boxWidth = lineWidth;
+ boxHeight++; lineWidth = 0;
+ lineWidthLeft = maxWidth;
+
+ // Reached absolute maximum? -> exit now
+ if (boxHeight >= HEIGHT_MAX)
+ break;
+ }
+
+ // Copy current word over
+ memcpy(&resultWrappedBuffer[curWritePos], &originalText[wordStartPos], wordLen);
+ lineWidth += wordLen;
+ lineWidthLeft -= wordLen;
+ curWritePos += wordLen;
+
+ if (wordEndChar == 0x0A) {
+ // original text had a new line, so force it
+ curReadPos++;
+
+ resultWrappedBuffer[curWritePos++] = 0x0A;
+ if (lineWidth > boxWidth)
+ boxWidth = lineWidth;
+ boxHeight++; lineWidth = 0;
+ lineWidthLeft = maxWidth;
+
+ // Reached absolute maximum? -> exit now
+ if (boxHeight >= HEIGHT_MAX)
+ break;
+ }
+
+ wordStartPos = curReadPos;
+ }
+
+ resultWrappedBuffer[curWritePos] = 0;
+
+ if (curReadPos > 0) {
+ if (lineWidth > boxWidth)
+ boxWidth = lineWidth;
+ boxHeight++;
+ }
+
+ if (calculatedWidthPtr) {
+ *calculatedWidthPtr = boxWidth;
+ }
+ if (calculatedHeightPtr) {
+ *calculatedHeightPtr = boxHeight;
+ }
+ return resultWrappedBuffer;
}
+// ===============================================================
+
static void safeStrcat(Common::String &p, const char *t) {
if (t != NULL)
p += t;
@@ -523,31 +1134,31 @@ static void safeStrcat(Common::String &p, const char *t) {
* @param s string containing the format specifier
* @param n logic number
*/
-char *AgiEngine::agiSprintf(const char *s) {
- static char agiSprintf_buf[768];
- Common::String p;
+char *TextMgr::stringPrintf(const char *originalText) {
+ static char resultPrintfBuffer[2000];
+ Common::String resultString;
char z[16];
- debugC(3, kDebugLevelText, "logic %d, '%s'", _game.lognum, s);
+ debugC(3, kDebugLevelText, "logic %d, '%s'", _vm->_game.curLogicNr, originalText);
- while (*s) {
- switch (*s) {
+ while (*originalText) {
+ switch (*originalText) {
case '%':
- s++;
- switch (*s++) {
+ originalText++;
+ switch (*originalText++) {
int i;
case 'v':
- i = strtoul(s, NULL, 10);
- while (*s >= '0' && *s <= '9')
- s++;
- sprintf(z, "%015i", getvar(i));
+ i = strtoul(originalText, NULL, 10);
+ while (*originalText >= '0' && *originalText <= '9')
+ originalText++;
+ sprintf(z, "%015i", _vm->getVar(i));
i = 99;
- if (*s == '|') {
- s++;
- i = strtoul(s, NULL, 10);
- while (*s >= '0' && *s <= '9')
- s++;
+ if (*originalText == '|') {
+ originalText++;
+ i = strtoul(originalText, NULL, 10);
+ while (*originalText >= '0' && *originalText <= '9')
+ originalText++;
}
if (i == 99) {
@@ -558,173 +1169,48 @@ char *AgiEngine::agiSprintf(const char *s) {
} else {
i = 15 - i;
}
- safeStrcat(p, z + i);
+ safeStrcat(resultString, z + i);
break;
case '0':
- i = strtoul(s, NULL, 10) - 1;
- safeStrcat(p, objectName(i));
+ i = strtoul(originalText, NULL, 10) - 1;
+ safeStrcat(resultString, _vm->objectName(i));
break;
case 'g':
- i = strtoul(s, NULL, 10) - 1;
- safeStrcat(p, _game.logics[0].texts[i]);
+ i = strtoul(originalText, NULL, 10) - 1;
+ safeStrcat(resultString, _vm->_game.logics[0].texts[i]);
break;
case 'w':
- i = strtoul(s, NULL, 10) - 1;
- safeStrcat(p, _game.egoWords[i].word);
+ i = strtoul(originalText, NULL, 10) - 1;
+ safeStrcat(resultString, _vm->_words->getEgoWord(i));
break;
case 's':
- i = strtoul(s, NULL, 10);
- safeStrcat(p, agiSprintf(_game.strings[i]));
+ i = strtoul(originalText, NULL, 10);
+ safeStrcat(resultString, stringPrintf(_vm->_game.strings[i]));
break;
case 'm':
- i = strtoul(s, NULL, 10) - 1;
- if (_game.logics[_game.lognum].numTexts > i)
- safeStrcat(p, agiSprintf(_game.logics[_game.lognum].texts[i]));
+ i = strtoul(originalText, NULL, 10) - 1;
+ if (_vm->_game.logics[_vm->_game.curLogicNr].numTexts > i)
+ safeStrcat(resultString, stringPrintf(_vm->_game.logics[_vm->_game.curLogicNr].texts[i]));
break;
}
- while (*s >= '0' && *s <= '9')
- s++;
+ while (*originalText >= '0' && *originalText <= '9')
+ originalText++;
break;
case '\\':
- s++;
+ originalText++;
// FALL THROUGH
default:
- p += *s++;
+ resultString += *originalText++;
break;
}
}
- assert(p.size() < sizeof(agiSprintf_buf));
- strcpy(agiSprintf_buf, p.c_str());
- return agiSprintf_buf;
-}
-
-/**
- * Write the status line.
- */
-void AgiEngine::writeStatus() {
- char x[64];
-
- if (_debug.statusline) {
- printStatus("%3d(%03d) %3d,%3d(%3d,%3d) ",
- getvar(0), getvar(1), _game.viewTable[0].xPos,
- _game.viewTable[0].yPos, WIN_TO_PIC_X(_mouse.x),
- WIN_TO_PIC_Y(_mouse.y));
- return;
- }
-
- if (!_game.statusLine) {
- clearLines(_game.lineStatus, _game.lineStatus, 0);
- flushLines(_game.lineStatus, _game.lineStatus);
-
-#if 0
- // FIXME: Breaks wrist watch prompt in SQ2
-
- // Clear the user input line as well when clearing the status line
- // Fixes bug #1893564 - AGI: Texts messed out in Naturette 1
- clearLines(_game.lineUserInput, _game.lineUserInput, 0);
- flushLines(_game.lineUserInput, _game.lineUserInput);
-#endif
- return;
- }
-
- switch (getLanguage()) {
- case Common::RU_RUS:
- sprintf(x, " \x91\xe7\xa5\xe2: %i \xa8\xa7 %-3i", _game.vars[vScore], _game.vars[vMaxScore]);
- printStatus("%-17s \x87\xa2\xe3\xaa:%s", x, getflag(fSoundOn) ? "\xa2\xaa\xab " : "\xa2\xeb\xaa\xab");
- break;
- default:
- sprintf(x, " Score:%i of %-3i", _game.vars[vScore], _game.vars[vMaxScore]);
- printStatus("%-17s Sound:%s ", x, getflag(fSoundOn) ? "on " : "off");
- break;
- }
-}
-
-/**
- * Print user input prompt.
- */
-void AgiEngine::writePrompt() {
- int l, fg, bg, pos;
- int promptLength = strlen(agiSprintf(_game.strings[0]));
-
- if (!_game.inputEnabled || _game.inputMode != INPUT_NORMAL)
- return;
-
- l = _game.lineUserInput;
- fg = _game.colorFg;
- bg = _game.colorBg;
- pos = _game.cursorPos;
-
- debugC(4, kDebugLevelText, "erase line %d", l);
- clearLines(l, l, _game.colorBg);
-
- debugC(4, kDebugLevelText, "prompt = '%s'", agiSprintf(_game.strings[0]));
- printText(_game.strings[0], 0, 0, l, promptLength + 1, fg, bg);
- printText((char *)_game.inputBuffer, 0, promptLength, l, pos + 1, fg, bg);
- _gfx->printCharacter(pos + promptLength, l, _game.cursorChar, fg, bg);
-
- flushLines(l, l);
- _gfx->doUpdate();
-}
-
-void AgiEngine::clearPrompt(bool useBlackBg) {
- int l;
-
- l = _game.lineUserInput;
- clearLines(l, l, useBlackBg ? 0 : _game.colorBg);
- flushLines(l, l);
-
- _gfx->doUpdate();
-}
-
-/**
- * Clear text lines in the screen.
- * @param l1 start line
- * @param l2 end line
- * @param c color
- */
-void AgiEngine::clearLines(int l1, int l2, int c) {
- // do we need to adjust for +8 on topline?
- // inc for endline so it matches the correct num
- // ie, from 22 to 24 is 3 lines, not 2 lines.
-
- debugC(4, kDebugLevelText, "clearLines(%d, %d, %d)", l1, l2, c);
-
- l1 *= CHAR_LINES;
- l2 *= CHAR_LINES;
- l2 += CHAR_LINES - 1;
-
- _gfx->drawRectangle(0, l1, GFX_WIDTH - 1, l2, c);
-}
-
-/**
- *
- */
-void AgiEngine::flushLines(int l1, int l2) {
- l1 *= CHAR_LINES;
- l2 *= CHAR_LINES;
- l2 += CHAR_LINES - 1;
-
- _gfx->flushBlock(0, l1, GFX_WIDTH - 1, l2);
-}
-
-/**
- *
- */
-void AgiEngine::drawWindow(int x1, int y1, int x2, int y2) {
- _game.window.active = true;
- _game.window.x1 = x1;
- _game.window.y1 = y1;
- _game.window.x2 = x2;
- _game.window.y2 = y2;
- _game.window.buffer = (uint8 *)malloc((x2 - x1 + 1) * (y2 - y1 + 1));
-
- debugC(4, kDebugLevelText, "x1=%d, y1=%d, x2=%d, y2=%d", x1, y1, x2, y2);
- _gfx->saveBlock(x1, y1, x2, y2, _game.window.buffer);
- _gfx->drawBox(x1, y1, x2, y2, MSG_BOX_COLOR, MSG_BOX_LINE, 2);
+ assert(resultString.size() < sizeof(resultPrintfBuffer));
+ Common::strlcpy(resultPrintfBuffer, resultString.c_str(), 2000);
+ return resultPrintfBuffer;
}
} // End of namespace Agi
diff --git a/engines/agi/text.h b/engines/agi/text.h
new file mode 100644
index 0000000000..f0aeab7762
--- /dev/null
+++ b/engines/agi/text.h
@@ -0,0 +1,217 @@
+/* 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 AGI_TEXT_H
+#define AGI_TEXT_H
+
+namespace Agi {
+
+struct TextPos_Struct {
+ int16 row;
+ int16 column;
+};
+
+#define TEXTPOSARRAY_MAX 5
+
+struct TextAttrib_Struct {
+ byte foreground;
+ byte background;
+ byte combinedForeground;
+ byte combinedBackground;
+};
+
+#define TEXTATTRIBARRAY_MAX 5
+
+struct MessageState_Struct {
+ uint8 type;
+ int16 wanted_Text_Width;
+ TextPos_Struct wanted_TextPos;
+ bool dialogue_Open;
+ uint8 newline_Char;
+ bool window_Active;
+ TextPos_Struct textPos;
+ TextPos_Struct textPos_Edge;
+ int16 textSize_Width;
+ int16 textSize_Height;
+ uint16 printed_Height;
+
+ int16 backgroundPos_x;
+ int16 backgroundPos_y; // original AGI used lowerY here, we use upperY so that upscaling is easier
+ int16 backgroundSize_Width;
+ int16 backgroundSize_Height;
+};
+
+// this defines here are for calculating character-size inside the visual-screen!
+#define FONT_VISUAL_WIDTH 4
+#define FONT_VISUAL_HEIGHT 8
+
+#define FONT_DISPLAY_WIDTH 8
+#define FONT_DISPLAY_HEIGHT 8
+#define FONT_ROW_CHARACTERS 25
+#define FONT_COLUMN_CHARACTERS 40
+#define FONT_BYTES_PER_CHARACTER 8
+
+#define HEIGHT_MAX 20
+
+#define TEXT_STRING_MAX_SIZE 40
+
+class TextMgr {
+private:
+ Words *_words;
+ GfxMgr *_gfx;
+ AgiEngine *_vm;
+ SystemUI *_systemUI;
+
+public:
+ TextMgr(AgiEngine *vm, Words *words, GfxMgr *gfx);
+ ~TextMgr();
+
+ void init(SystemUI *systemUI);
+
+ TextPos_Struct _textPos;
+ int16 _textPosArrayCount;
+ TextPos_Struct _textPosArray[TEXTPOSARRAY_MAX];
+
+ TextAttrib_Struct _textAttrib;
+ int16 _textAttribArrayCount;
+ TextAttrib_Struct _textAttribArray[TEXTATTRIBARRAY_MAX];
+
+ uint16 _window_Row_Min;
+ uint16 _window_Row_Max;
+ int16 _reset_Column;
+
+ void configureScreen(uint16 row_Min);
+ uint16 getWindowRowMin();
+
+ void dialogueOpen();
+ void dialogueClose();
+
+ void charPos_Clip(int16 &row, int16 &column);
+ void charPos_Set(int16 row, int16 column);
+ void charPos_Set(TextPos_Struct *posPtr);
+ void charPos_Get(int16 &row, int16 &column);
+ void charPos_Get(TextPos_Struct *posPtr);
+ void charPos_Push();
+ void charPos_Pop();
+ void charPos_SetInsideWindow(int16 windowRow, int16 windowColumn);
+ void charAttrib_Set(byte foreground, byte background);
+ byte charAttrib_GetForeground();
+ byte charAttrib_GetBackground();
+ void charAttrib_Push();
+ void charAttrib_Pop();
+ byte calculateTextBackground(byte background);
+
+ void display(int16 textNr, int16 textRow, int16 textColumn);
+ void displayText(const char *textPtr, bool disabledLook = false);
+ void displayCharacter(byte character, bool disabledLook = false);
+
+ void displayTextInsideWindow(const char *textPtr, int16 windowRow, int16 windowColumn);
+
+ MessageState_Struct _messageState;
+
+ void printAt(int16 textNr, int16 textPos_Row, int16 textPos_Column, int16 text_Width);
+ void print(int16 textNr);
+
+ bool messageBox(const char *textPtr);
+ void messageBox_KeyPress(uint16 newKey);
+
+ bool _messageBoxCancelled;
+
+ void drawMessageBox(const char *textPtr, int16 forcedHeight = 0, int16 wantedWidth = 0, bool forcedWidth = false);
+ void getMessageBoxInnerDisplayDimensions(int16 &x, int16 &y, int16 &width, int16 &height);
+ bool isMouseWithinMessageBox();
+ void closeWindow();
+
+ void statusRow_Set(int16 row);
+ int16 statusRow_Get();
+
+ void statusEnable();
+ void statusDisable();
+ bool statusEnabled();
+
+ void statusDraw();
+ void statusClear();
+
+ bool _statusEnabled;
+ int16 _statusRow;
+
+ void clearLine(int16 row, byte color);
+ void clearLines(int16 row_Upper, int16 row_Lower, byte color);
+ void clearBlock(int16 row_Upper, int16 column_Upper, int16 row_Lower, int16 column_Lower, byte color);
+
+ void clearBlockInsideWindow(int16 windowRow, int16 windowColumn, int16 width, byte color);
+
+ bool _inputEditEnabled;
+ byte _inputCursorChar;
+
+ bool _optionCommandPromptWindow;
+
+ bool _promptEnabled;
+ int16 _promptRow;
+ int16 _promptCursorPos;
+ byte _prompt[42];
+ byte _promptPrevious[42];
+
+ bool inputGetEditStatus();
+ void inputEditOn();
+ void inputEditOff();
+ void inputSetCursorChar(int16 cursorChar);
+ byte inputGetCursorChar();
+
+ void promptReset();
+ void promptEnable();
+ void promptDisable();
+ bool promptIsEnabled();
+
+ void promptRow_Set(int16 row);
+ int16 promptRow_Get();
+ void promptKeyPress(uint16 newKey);
+ void promptCancelLine();
+ void promptEchoLine();
+ void promptRedraw();
+ void promptClear(); // for AGI1
+ void promptRememberForAutoComplete(bool entered = false); // for auto-completion
+
+ void promptCommandWindow(bool recallLastCommand, uint16 newKey);
+
+ int16 _inputStringRow;
+ int16 _inputStringColumn;
+ bool _inputStringEntered;
+ int16 _inputStringMaxLen;
+ int16 _inputStringCursorPos;
+ byte _inputString[42];
+
+ bool stringWasEntered();
+ void stringPos_Get(int16 &row, int16 &column);
+ int16 stringGetMaxLen();
+ void stringSet(const char *text);
+ void stringEdit(int16 stringMaxLen);
+ void stringKeyPress(uint16 newKey);
+ void stringRememberForAutoComplete(bool entered = false); // for auto-completion
+
+ char *stringPrintf(const char *originalText);
+ char *stringWordWrap(const char *originalText, int16 maxWidth, int16 *calculatedWidthPtr = nullptr, int16 *calculatedHeightPtr = nullptr);
+};
+
+} // End of namespace Agi
+
+#endif /* AGI_TEXT_H */
diff --git a/engines/agi/view.cpp b/engines/agi/view.cpp
index 6a274a1b73..a13e40e60d 100644
--- a/engines/agi/view.cpp
+++ b/engines/agi/view.cpp
@@ -21,107 +21,60 @@
*/
#include "agi/agi.h"
+#include "agi/graphics.h"
#include "agi/sprite.h"
namespace Agi {
-void AgiEngine::lSetCel(VtEntry *v, int n) {
- ViewLoop *currentVl;
- ViewCel *currentVc;
+void AgiEngine::updateView(ScreenObjEntry *screenObj) {
+ int16 celNr, lastCelNr;
- v->currentCel = n;
-
- currentVl = &_game.views[v->currentView].loop[v->currentLoop];
-
- // Added by Amit Vainsencher <amitv@subdimension.com> to prevent
- // crash in KQ1 -- not in the Sierra interpreter
- if (currentVl->numCels == 0)
- return;
-
- // WORKAROUND: This is a very nasty hack to fix a bug in the KQ4 introduction
- // In its original form, it caused a lot of regressions, including KQ4 bugs and crashes
- // Refer to Sarien bug #588899 for the original issue
- // Modifying this workaround to only work for a specific view in the KQ4 intro fixes several
- // ScummVM bugs. Refer to bugs #1660486, #1660169, #1660192, #1660162 and #1660354
- // FIXME: Remove this workaround and investigate the reason for the erroneous actor behavior
- // in the KQ4 introduction
- // It seems there's either a bug with KQ4's logic script 120 (the intro script)
- // or flag 64 is not set correctly, which causes the erroneous behavior from the actors
- if (getGameID() == GID_KQ4 && !(v->flags & fUpdate) && (v->currentView == 172))
- return;
-
- currentVc = &currentVl->cel[n];
- v->celData = currentVc;
- v->xSize = currentVc->width;
- v->ySize = currentVc->height;
-}
-
-void AgiEngine::lSetLoop(VtEntry *v, int n) {
- ViewLoop *currentVl;
- debugC(7, kDebugLevelResources, "vt entry #%d, loop = %d", v->entry, n);
-
- // Added to avoid crash when leaving the arcade machine in MH1
- // -- not in AGI 2.917
- if (n >= v->numLoops)
- n = 0;
-
- v->currentLoop = n;
- currentVl = &_game.views[v->currentView].loop[v->currentLoop];
-
- v->numCels = currentVl->numCels;
- if (v->currentCel >= v->numCels)
- v->currentCel = 0;
-
- v->loopData = &_game.views[v->currentView].loop[n];
-}
-
-void AgiEngine::updateView(VtEntry *v) {
- int cel, lastCel;
-
- if (v->flags & fDontupdate) {
- v->flags &= ~fDontupdate;
+ if (screenObj->flags & fDontupdate) {
+ screenObj->flags &= ~fDontupdate;
return;
}
- cel = v->currentCel;
- lastCel = v->numCels - 1;
+ celNr = screenObj->currentCelNr;
+ lastCelNr = screenObj->celCount - 1;
- switch (v->cycle) {
+ switch (screenObj->cycle) {
case kCycleNormal:
- if (++cel > lastCel)
- cel = 0;
+ celNr++;
+ if (celNr > lastCelNr)
+ celNr = 0;
break;
case kCycleEndOfLoop:
- if (cel < lastCel) {
- debugC(5, kDebugLevelResources, "cel %d (last = %d)", cel + 1, lastCel);
- if (++cel != lastCel)
+ if (celNr < lastCelNr) {
+ debugC(5, kDebugLevelResources, "cel %d (last = %d)", celNr + 1, lastCelNr);
+ if (++celNr != lastCelNr)
break;
}
- setflag(v->parm1, true);
- v->flags &= ~fCycling;
- v->direction = 0;
- v->cycle = kCycleNormal;
+ setFlag(screenObj->loop_flag, true);
+ screenObj->flags &= ~fCycling;
+ screenObj->direction = 0;
+ screenObj->cycle = kCycleNormal;
break;
case kCycleRevLoop:
- if (cel) {
- if (--cel)
+ if (celNr) {
+ celNr--;
+ if (celNr)
break;
}
- setflag(v->parm1, true);
- v->flags &= ~fCycling;
- v->direction = 0;
- v->cycle = kCycleNormal;
+ setFlag(screenObj->loop_flag, true);
+ screenObj->flags &= ~fCycling;
+ screenObj->direction = 0;
+ screenObj->cycle = kCycleNormal;
break;
case kCycleReverse:
- if (cel == 0) {
- cel = lastCel;
+ if (celNr == 0) {
+ celNr = lastCelNr;
} else {
- cel--;
+ celNr--;
}
break;
}
- setCel(v, cel);
+ setCel(screenObj, celNr);
}
/*
@@ -134,191 +87,513 @@ void AgiEngine::updateView(VtEntry *v) {
* and fills the corresponding views array element.
* @param n number of view resource to decode
*/
-int AgiEngine::decodeView(int n) {
- int loop, cel;
- uint8 *v, *lptr;
- uint16 lofs, cofs;
- ViewLoop *vl;
- ViewCel *vc;
+int AgiEngine::decodeView(byte *resourceData, uint16 resourceSize, int16 viewNr) {
+ AgiView *viewData = &_game.views[viewNr];
+ uint16 headerId = 0;
+ byte headerStepSize = 0;
+ byte headerCycleTime = 0;
+ byte headerLoopCount = 0;
+ uint16 headerDescriptionOffset = 0;
+ bool isAGI256Data = false;
+
+ AgiViewLoop *loopData = nullptr;
+ uint16 loopOffset = 0;
+ byte loopHeaderCelCount = 0;
+
+ AgiViewCel *celData = nullptr;
+ uint16 celOffset = 0;
+ byte celHeaderWidth = 0;
+ byte celHeaderHeight = 0;
+ byte celHeaderTransparencyMirror = 0;
+ byte celHeaderClearKey = 0;
+ bool celHeaderMirrored = false;
+ byte celHeaderMirrorLoop = 0;
+
+ byte *celCompressedData = nullptr;
+ uint16 celCompressedSize = 0;
+
+ debugC(5, kDebugLevelResources, "decode_view(%d)", viewNr);
+
+ if (resourceSize < 5)
+ error("unexpected end of view data for view %d", viewNr);
+
+ headerId = READ_LE_UINT16(resourceData);
+ if (getVersion() < 0x2000) {
+ headerStepSize = resourceData[0];
+ headerCycleTime = resourceData[1];
+ }
+ headerLoopCount = resourceData[2];
+ headerDescriptionOffset = READ_LE_UINT16(resourceData + 3);
+
+ if (headerId == 0xF00F)
+ isAGI256Data = true; // AGI 256-2 view detected, 256 color view
+
+ viewData->headerStepSize = headerStepSize;
+ viewData->headerCycleTime = headerCycleTime;
+ viewData->loopCount = headerLoopCount;
+ viewData->description = nullptr;
+ viewData->loop = nullptr;
+
+ if (headerDescriptionOffset) {
+ // Figure out length of description
+ uint16 descriptionPos = headerDescriptionOffset;
+ uint16 descriptionLen = 0;
+ while (descriptionPos < resourceSize) {
+ if (resourceData[descriptionPos] == 0)
+ break;
+ descriptionPos++;
+ descriptionLen++;
+ }
+ // Allocate memory for description
+ viewData->description = new byte[descriptionLen + 1];
+ // Copy description over
+ memcpy(viewData->description, resourceData + headerDescriptionOffset, descriptionLen);
+ viewData->description[descriptionLen] = 0; // set terminator
+ }
- debugC(5, kDebugLevelResources, "decode_view(%d)", n);
- v = _game.views[n].rdata;
+ if (!viewData->loopCount) // no loops, exit now
+ return errOK;
+
+ // Check, if at least the loop-offsets are available
+ if (resourceSize < 5 + (headerLoopCount * 2))
+ error("unexpected end of view data for view %d", viewNr);
+
+ // Allocate space for loop-information
+ loopData = new AgiViewLoop[headerLoopCount];
+ viewData->loop = loopData;
+
+ for (int16 loopNr = 0; loopNr < headerLoopCount; loopNr++) {
+ loopOffset = READ_LE_UINT16(resourceData + 5 + (loopNr * 2));
+
+ // Check, if at least the loop-header is available
+ if (resourceSize < (loopOffset + 1))
+ error("unexpected end of view data for view %d", viewNr);
+
+ // loop-header:
+ // celCount:BYTE
+ // relativeCelOffset[0]:WORD
+ // relativeCelOffset[1]:WORD
+ // etc.
+ loopHeaderCelCount = resourceData[loopOffset];
+
+ loopData->celCount = loopHeaderCelCount;
+ loopData->cel = nullptr;
+
+ // Check, if at least the cel-offsets for current loop are available
+ if (resourceSize < (loopOffset + 1 + (loopHeaderCelCount * 2)))
+ error("unexpected end of view data for view %d", viewNr);
+
+ if (loopHeaderCelCount) {
+ // Allocate space for cel-information of current loop
+ celData = new AgiViewCel[loopHeaderCelCount];
+ loopData->cel = celData;
+
+ for (int16 celNr = 0; celNr < loopHeaderCelCount; celNr++) {
+ celOffset = READ_LE_UINT16(resourceData + loopOffset + 1 + (celNr * 2));
+ celOffset += loopOffset; // cel offset is relative to loop offset, so adjust accordingly
+
+ // Check, if at least the cel-header is available
+ if (resourceSize < (celOffset + 3))
+ error("unexpected end of view data for view %d", viewNr);
+
+ // cel-header:
+ // width:BYTE
+ // height:BYTE
+ // Transparency + Mirroring:BYTE
+ // celData follows
+ celHeaderWidth = resourceData[celOffset + 0];
+ celHeaderHeight = resourceData[celOffset + 1];
+ celHeaderTransparencyMirror = resourceData[celOffset + 2];
+
+ if (!isAGI256Data) {
+ // regular AGI view data
+ // Transparency + Mirroring byte is as follows:
+ // Bit 0-3 - clear key
+ // Bit 4-6 - original loop, that is not supposed to be mirrored in any case
+ // Bit 7 - apply mirroring
+ celHeaderClearKey = celHeaderTransparencyMirror & 0x0F; // bit 0-3 is the clear key
+ celHeaderMirrored = false;
+ if (celHeaderTransparencyMirror & 0x80) {
+ // mirror bit is set
+ celHeaderMirrorLoop = (celHeaderTransparencyMirror >> 4) & 0x07;
+ if (celHeaderMirrorLoop != loopNr) {
+ // only set to mirror'd in case we are not the original loop
+ celHeaderMirrored = true;
+ }
+ }
+ } else {
+ // AGI256-2 view data
+ celHeaderClearKey = celHeaderTransparencyMirror; // full 8 bits for clear key
+ celHeaderMirrored = false;
+ }
+
+ celData->width = celHeaderWidth;
+ celData->height = celHeaderHeight;
+ celData->clearKey = celHeaderClearKey;
+ celData->mirrored = celHeaderMirrored;
+
+ // Now decompress cel-data
+ if ((celHeaderWidth == 0) && (celHeaderHeight == 0))
+ error("view cel is 0x0");
+
+ celCompressedData = resourceData + celOffset + 3;
+ celCompressedSize = resourceSize - (celOffset + 3);
+
+ if (celCompressedSize == 0)
+ error("compressed size of loop within view %d is 0 bytes", viewNr);
+
+ if (!isAGI256Data) {
+ unpackViewCelData(celData, celCompressedData, celCompressedSize);
+ } else {
+ unpackViewCelDataAGI256(celData, celCompressedData, celCompressedSize);
+ }
+ celData++;
+ }
+ }
- assert(v != NULL);
+ loopData++;
+ }
- _game.views[n].agi256_2 = (READ_LE_UINT16(v) == 0xf00f); // Detect AGI256-2 views by their header bytes
- _game.views[n].descr = READ_LE_UINT16(v + 3) ? (char *)(v + READ_LE_UINT16(v + 3)) : (char *)(v + 3);
+ return errOK;
+}
- // if no loops exist, return!
- if ((_game.views[n].numLoops = *(v + 2)) == 0)
- return errNoLoopsInView;
+void AgiEngine::unpackViewCelData(AgiViewCel *celData, byte *compressedData, uint16 compressedSize) {
+ byte *rawBitmap = new byte[celData->width * celData->height];
+ int16 remainingHeight = celData->height;
+ int16 remainingWidth = celData->width;
+ bool isMirrored = celData->mirrored;
+ byte curByte;
+ byte curColor;
+ byte curChunkLen;
+ int16 adjustPreChangeSingle = 0;
+ int16 adjustAfterChangeSingle = +1;
+
+ celData->rawBitmap = rawBitmap;
+
+ if (isMirrored) {
+ adjustPreChangeSingle = -1;
+ adjustAfterChangeSingle = 0;
+ rawBitmap += celData->width;
+ }
- // allocate memory for all views
- _game.views[n].loop = (ViewLoop *)calloc(_game.views[n].numLoops, sizeof(ViewLoop));
+ while (remainingHeight) {
+ if (!compressedSize)
+ error("unexpected end of data, while unpacking AGI256 data");
- if (_game.views[n].loop == NULL)
- return errNotEnoughMemory;
+ curByte = *compressedData++;
+ compressedSize--;
- // decode all of the loops in this view
- lptr = v + 5; // first loop address
+ if (curByte == 0) {
+ curColor = celData->clearKey;
+ curChunkLen = remainingWidth;
+ } else {
+ curColor = curByte >> 4;
+ curChunkLen = curByte & 0x0F;
+ if (curChunkLen > remainingWidth)
+ error("invalid chunk in view data");
+ }
+
+ switch (curChunkLen) {
+ case 0:
+ break;
+ case 1:
+ rawBitmap += adjustPreChangeSingle;
+ *rawBitmap = curColor;
+ rawBitmap += adjustAfterChangeSingle;
+ break;
+ default:
+ if (isMirrored)
+ rawBitmap -= curChunkLen;
+ memset(rawBitmap, curColor, curChunkLen);
+ if (!isMirrored)
+ rawBitmap += curChunkLen;
+ break;
+ }
- for (loop = 0; loop < _game.views[n].numLoops; loop++, lptr += 2) {
- lofs = READ_LE_UINT16(lptr); // loop header offset
- vl = &_game.views[n].loop[loop]; // the loop struct
+ remainingWidth -= curChunkLen;
- vl->numCels = *(v + lofs);
- debugC(6, kDebugLevelResources, "view %d, num_cels = %d", n, vl->numCels);
- vl->cel = (ViewCel *)calloc(vl->numCels, sizeof(ViewCel));
+ if (curByte == 0) {
+ remainingWidth = celData->width;
+ remainingHeight--;
- if (vl->cel == NULL) {
- free(_game.views[n].loop);
- _game.views[n].numLoops = 0;
- return errNotEnoughMemory;
+ if (isMirrored)
+ rawBitmap += celData->width * 2;
}
+ }
- // decode the cells
- for (cel = 0; cel < vl->numCels; cel++) {
- cofs = lofs + READ_LE_UINT16(v + lofs + 1 + (cel * 2));
- vc = &vl->cel[cel];
-
- vc->width = *(v + cofs);
- vc->height = *(v + cofs + 1);
-
- if (!_game.views[n].agi256_2) {
- vc->transparency = *(v + cofs + 2) & 0xf;
- vc->mirrorLoop = (*(v + cofs + 2) >> 4) & 0x7;
- vc->mirror = (*(v + cofs + 2) >> 7) & 0x1;
- } else {
- // Mirroring is disabled for AGI256-2 views because
- // AGI256-2 uses whole 8 bits for the transparency variable.
- vc->transparency = *(v + cofs + 2);
- vc->mirrorLoop = 0;
- vc->mirror = 0;
- }
+ // for CGA rendering, apply dithering
+ switch (_renderMode) {
+ case Common::kRenderCGA: {
+ uint16 totalPixels = celData->width * celData->height;
+
+ // dither clear key
+ celData->clearKey = _gfx->getCGAMixtureColor(celData->clearKey);
+
+ rawBitmap = celData->rawBitmap;
+ for (uint16 pixelNr = 0; pixelNr < totalPixels; pixelNr++) {
+ curColor = *rawBitmap;
+ *rawBitmap = _gfx->getCGAMixtureColor(curColor);
+ rawBitmap++;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
- // skip over width/height/trans|mirror data
- cofs += 3;
+void AgiEngine::unpackViewCelDataAGI256(AgiViewCel *celData, byte *compressedData, uint16 compressedSize) {
+ byte *rawBitmap = new byte[celData->width * celData->height];
+ int16 remainingHeight = celData->height;
+ int16 remainingWidth = celData->width;
+ byte curByte;
- vc->data = v + cofs;
+ celData->rawBitmap = rawBitmap;
- // If mirror_loop is pointing to the current loop,
- // then this is the original.
- if (vc->mirrorLoop == loop)
- vc->mirror = 0;
- } // cel
- } // loop
+ while (remainingHeight) {
+ if (!compressedSize)
+ error("unexpected end of data, while unpacking AGI256 view");
- return errOK;
+ curByte = *compressedData++;
+ compressedSize--;
+
+ if (curByte == 0) {
+ // Go to next vertical position
+ if (remainingWidth) {
+ // fill remaining bytes with clear key
+ memset(rawBitmap, celData->clearKey, remainingWidth);
+ rawBitmap += remainingWidth;
+ remainingWidth = 0;
+ }
+ } else {
+ if (!remainingWidth) {
+ error("broken view data, while unpacking AGI256 view");
+ break;
+ }
+ *rawBitmap = curByte;
+ rawBitmap++;
+ remainingWidth--;
+ }
+
+ if (curByte == 0) {
+ remainingWidth = celData->width;
+ remainingHeight--;
+ }
+ }
}
/**
* Unloads all data in a view resource
* @param n number of view resource
*/
-void AgiEngine::unloadView(int n) {
- int x;
+void AgiEngine::unloadView(int16 viewNr) {
+ AgiView *viewData = &_game.views[viewNr];
- debugC(5, kDebugLevelResources, "discard view %d", n);
- if (~_game.dirView[n].flags & RES_LOADED)
+ debugC(5, kDebugLevelResources, "discard view %d", viewNr);
+ if (!(_game.dirView[viewNr].flags & RES_LOADED))
return;
// Rebuild sprite list, see Sarien bug #779302
- _sprites->eraseBoth();
- _sprites->blitBoth();
- _sprites->commitBoth();
+ _sprites->eraseSprites();
+
+ // free data
+ for (int16 loopNr = 0; loopNr < viewData->loopCount; loopNr++) {
+ AgiViewLoop *loopData = &viewData->loop[loopNr];
+ for (int16 celNr = 0; celNr < loopData->celCount; celNr++) {
+ AgiViewCel *celData = &loopData->cel[celNr];
+
+ delete[] celData->rawBitmap;
+ }
+ delete[] loopData->cel;
+ }
+ delete[] viewData->loop;
+
+ if (viewData->description)
+ delete[] viewData->description;
- // free all the loops
- for (x = 0; x < _game.views[n].numLoops; x++)
- free(_game.views[n].loop[x].cel);
+ viewData->headerCycleTime = 0;
+ viewData->headerStepSize = 0;
+ viewData->description = nullptr;
+ viewData->loop = nullptr;
+ viewData->loopCount = 0;
- free(_game.views[n].loop);
- free(_game.views[n].rdata);
+ // Mark this view as not loaded anymore
+ _game.dirView[viewNr].flags &= ~RES_LOADED;
- _game.dirView[n].flags &= ~RES_LOADED;
+ _sprites->buildAllSpriteLists();
+ _sprites->drawAllSpriteLists();
}
/**
- * Set a view table entry to use the specified cel of the current loop.
- * @param v pointer to view table entry
- * @param n number of cel
+ * Set a view table entry to use the specified view resource.
+ * @param screenObj pointer to screen object
+ * @param viewNr number of AGI view resource
*/
-void AgiEngine::setCel(VtEntry *v, int n) {
- assert(v->viewData != NULL);
- assert(v->numCels >= n);
+void AgiEngine::setView(ScreenObjEntry *screenObj, int16 viewNr) {
+ if (!(_game.dirView[viewNr].flags & RES_LOADED)) {
+ // View resource currently not loaded, this is probably a game bug
+ // Load the resource now to fix the issue, and give out a warning
+ // This happens in at least Larry 1 for Apple IIgs right after getting beaten up by taxi driver
+ // Original interpreter bombs out in this situation saying "view not loaded, Press ESC to quit"
+ warning("setView() called on screen object %d to use view %d, but view not loaded", screenObj->objectNr, viewNr);
+ warning("probably game script bug, trying to load view into memory");
+ if (agiLoadResource(RESOURCETYPE_VIEW, viewNr) != errOK) {
+ // loading failed, we better error() out now
+ error("setView() called to set view %d for screen object %d, which is not loaded atm and loading failed", viewNr, screenObj->objectNr);
+ return;
+ };
+ }
- lSetCel(v, n);
+ screenObj->viewResource = &_game.views[viewNr];
+ screenObj->currentViewNr = viewNr;
+ screenObj->loopCount = screenObj->viewResource->loopCount;
+ screenObj->viewReplaced = true;
- // If position isn't appropriate, update it accordingly
- clipViewCoordinates(v);
+ if (getVersion() < 0x2000) {
+ screenObj->stepSize = screenObj->viewResource->headerStepSize;
+ screenObj->cycleTime = screenObj->viewResource->headerCycleTime;
+ screenObj->cycleTimeCount = 0;
+ }
+ if (screenObj->currentLoopNr >= screenObj->loopCount) {
+ setLoop(screenObj, 0);
+ } else {
+ setLoop(screenObj, screenObj->currentLoopNr);
+ }
}
/**
- * Restrict view table entry's position so it stays wholly inside the screen.
- * Also take horizon into account when clipping if not set to ignore it.
- * @param v pointer to view table entry
+ * Set a view table entry to use the specified loop of the current view.
+ * @param screenObj pointer to screen object
+ * @param loopNr number of loop
*/
-void AgiEngine::clipViewCoordinates(VtEntry *v) {
- if (v->xPos + v->xSize > _WIDTH) {
- v->flags |= fUpdatePos;
- v->xPos = _WIDTH - v->xSize;
- }
- if (v->yPos - v->ySize + 1 < 0) {
- v->flags |= fUpdatePos;
- v->yPos = v->ySize - 1;
+void AgiEngine::setLoop(ScreenObjEntry *screenObj, int16 loopNr) {
+ if (!(_game.dirView[screenObj->currentViewNr].flags & RES_LOADED)) {
+ error("setLoop() called on screen object %d, which has no loaded view resource assigned to it", screenObj->objectNr);
+ return;
}
- if (v->yPos <= _game.horizon && (~v->flags & fIgnoreHorizon)) {
- v->flags |= fUpdatePos;
- v->yPos = _game.horizon + 1;
+ assert(screenObj->viewResource);
+
+ if (screenObj->loopCount == 0) {
+ warning("setLoop() called on screen object %d, which has no loops (view %d)", screenObj->objectNr, screenObj->currentViewNr);
+ return;
}
- if (getVersion() < 0x2000) {
- v->flags |= fDontupdate;
+ if (loopNr >= screenObj->loopCount) {
+ // requested loop not existant
+ // instead of error()ing out, we instead clip it
+ // At least required for possibly Manhunter 1 according to previous comment when leaving the arcade machine
+ // TODO: Check MH1
+ // TODO: This causes an issue in KQ1, when bowing to the king in room 53
+ // Ego will face away from the king, because the scripts set the loop first and then the view
+ // Loop is corrected by us, because at that time it's invalid. Was already present in 1.7.0
+ // We should probably script-patch it out.
+ int16 requestedLoopNr = loopNr;
+
+ loopNr = screenObj->loopCount - 1;
+
+ warning("Non-existant loop requested for screen object %d", screenObj->objectNr);
+ warning("view %d, requested loop %d -> clipped to loop %d", screenObj->currentViewNr, requestedLoopNr, loopNr);
}
+ AgiViewLoop *curViewLoop = &_game.views[screenObj->currentViewNr].loop[loopNr];
+
+ screenObj->currentLoopNr = loopNr;
+ screenObj->loopData = curViewLoop;
+ screenObj->celCount = curViewLoop->celCount;
+
+ if (screenObj->currentCelNr >= screenObj->celCount) {
+ setCel(screenObj, 0);
+ } else {
+ setCel(screenObj, screenObj->currentCelNr);
+ }
}
/**
- * Set a view table entry to use the specified loop of the current view.
- * @param v pointer to view table entry
- * @param n number of loop
+ * Set a view table entry to use the specified cel of the current loop.
+ * @param screenObj pointer to screen object
+ * @param celNr number of cel
*/
-void AgiEngine::setLoop(VtEntry *v, int n) {
- assert(v->viewData != NULL);
- assert(v->numLoops >= n);
- lSetLoop(v, n);
- setCel(v, v->currentCel);
+void AgiEngine::setCel(ScreenObjEntry *screenObj, int16 celNr) {
+ if (!(_game.dirView[screenObj->currentViewNr].flags & RES_LOADED)) {
+ error("setCel() called on screen object %d, which has no loaded view resource assigned to it", screenObj->objectNr);
+ return;
+ }
+ assert(screenObj->viewResource);
+
+ if (screenObj->loopCount == 0) {
+ warning("setLoop() called on screen object %d, which has no loops (view %d)", screenObj->objectNr, screenObj->currentViewNr);
+ return;
+ }
+
+ AgiViewLoop *curViewLoop = &_game.views[screenObj->currentViewNr].loop[screenObj->currentLoopNr];
+
+ // Added by Amit Vainsencher <amitv@subdimension.com> to prevent
+ // crash in KQ1 -- not in the Sierra interpreter
+ if (curViewLoop->celCount == 0) {
+ warning("setCel() called on screen object %d, which has no cels (view %d)", screenObj->objectNr, screenObj->currentViewNr);
+ return;
+ }
+
+ if (celNr >= screenObj->celCount) {
+ // requested cel not existant
+ // instead of error()ing out, we instead clip it
+ // At least required for King's Quest 3 on Apple IIgs - walking the planks death cutscene
+ // see bug #5832, which is a game bug!
+ int16 requestedCelNr = celNr;
+
+ celNr = screenObj->celCount - 1;
+
+ warning("Non-existant cel requested for screen object %d", screenObj->objectNr);
+ warning("view %d, loop %d, requested cel %d -> clipped to cel %d", screenObj->currentViewNr, screenObj->currentLoopNr, requestedCelNr, celNr);
+ }
+
+ screenObj->currentCelNr = celNr;
+
+ AgiViewCel *curViewCel;
+ curViewCel = &curViewLoop->cel[celNr];
+ screenObj->celData = curViewCel;
+ screenObj->xSize = curViewCel->width;
+ screenObj->ySize = curViewCel->height;
+
+ // If position isn't appropriate, update it accordingly
+ clipViewCoordinates(screenObj);
}
/**
- * Set a view table entry to use the specified view resource.
+ * Restrict view table entry's position so it stays wholly inside the screen.
+ * Also take horizon into account when clipping if not set to ignore it.
* @param v pointer to view table entry
- * @param n number of AGI view resource
*/
-void AgiEngine::setView(VtEntry *v, int n) {
- v->viewData = &_game.views[n];
- v->currentView = n;
- v->numLoops = v->viewData->numLoops;
- v->viewReplaced = true;
+void AgiEngine::clipViewCoordinates(ScreenObjEntry *screenObj) {
+ if (screenObj->xPos + screenObj->xSize > SCRIPT_WIDTH) {
+ screenObj->flags |= fUpdatePos;
+ screenObj->xPos = SCRIPT_WIDTH - screenObj->xSize;
+ }
+ if (screenObj->yPos - screenObj->ySize + 1 < 0) {
+ screenObj->flags |= fUpdatePos;
+ screenObj->yPos = screenObj->ySize - 1;
+ }
+ if (screenObj->yPos <= _game.horizon && (~screenObj->flags & fIgnoreHorizon)) {
+ screenObj->flags |= fUpdatePos;
+ screenObj->yPos = _game.horizon + 1;
+ }
if (getVersion() < 0x2000) {
- v->stepSize = v->viewData->rdata[0];
- v->cycleTime = v->viewData->rdata[1];
- v->cycleTimeCount = 0;
+ screenObj->flags |= fDontupdate;
}
- setLoop(v, v->currentLoop >= v->numLoops ? 0 : v->currentLoop);
+
}
/**
* Set the view table entry as updating.
* @param v pointer to view table entry
*/
-void AgiEngine::startUpdate(VtEntry *v) {
+void AgiEngine::startUpdate(ScreenObjEntry *v) {
if (~v->flags & fUpdate) {
- _sprites->eraseBoth();
-
+ _sprites->eraseSprites();
v->flags |= fUpdate;
- _sprites->blitBoth();
- _sprites->commitBoth();
+ _sprites->buildAllSpriteLists();
+ _sprites->drawAllSpriteLists();
}
}
@@ -326,13 +601,12 @@ void AgiEngine::startUpdate(VtEntry *v) {
* Set the view table entry as non-updating.
* @param v pointer to view table entry
*/
-void AgiEngine::stopUpdate(VtEntry *v) {
- if (v->flags & fUpdate) {
- _sprites->eraseBoth();
-
- v->flags &= ~fUpdate;
- _sprites->blitBoth();
- _sprites->commitBoth();
+void AgiEngine::stopUpdate(ScreenObjEntry *viewPtr) {
+ if (viewPtr->flags & fUpdate) {
+ _sprites->eraseSprites();
+ viewPtr->flags &= ~fUpdate;
+ _sprites->buildAllSpriteLists();
+ _sprites->drawAllSpriteLists();
}
}
@@ -351,67 +625,67 @@ static int loopTable4[] = {
* This function is called at the end of each interpreter cycle
* to update the view table entries and blit the sprites.
*/
-void AgiEngine::updateViewtable() {
- VtEntry *v;
- int i, loop;
+void AgiEngine::updateScreenObjTable() {
+ ScreenObjEntry *screenObj;
+ int16 changeCount, loopNr;
- i = 0;
- for (v = _game.viewTable; v < &_game.viewTable[MAX_VIEWTABLE]; v++) {
- if ((v->flags & (fAnimated | fUpdate | fDrawn)) != (fAnimated | fUpdate | fDrawn)) {
+ changeCount = 0;
+ for (screenObj = _game.screenObjTable; screenObj < &_game.screenObjTable[SCREENOBJECTS_MAX]; screenObj++) {
+ if ((screenObj->flags & (fAnimated | fUpdate | fDrawn)) != (fAnimated | fUpdate | fDrawn)) {
continue;
}
- i++;
+ changeCount++;
- loop = 4;
- if (~v->flags & fFixLoop) {
- switch (v->numLoops) {
+ loopNr = 4;
+ if (!(screenObj->flags & fFixLoop)) {
+ switch (screenObj->loopCount) {
case 2:
case 3:
- loop = loopTable2[v->direction];
+ loopNr = loopTable2[screenObj->direction];
break;
case 4:
- loop = loopTable4[v->direction];
+ loopNr = loopTable4[screenObj->direction];
break;
default:
// for KQ4
if (getVersion() == 0x3086 || getGameID() == GID_KQ4)
- loop = loopTable4[v->direction];
+ loopNr = loopTable4[screenObj->direction];
break;
}
}
// AGI 2.272 (ddp, xmas) doesn't test step_time_count!
- if (loop != 4 && loop != v->currentLoop) {
- if (getVersion() <= 0x2272 ||
- v->stepTimeCount == 1) {
- setLoop(v, loop);
+ if (loopNr != 4 && loopNr != screenObj->currentLoopNr) {
+ if (getVersion() <= 0x2272 || screenObj->stepTimeCount == 1) {
+ setLoop(screenObj, loopNr);
}
}
- if (~v->flags & fCycling)
- continue;
-
- if (v->cycleTimeCount == 0)
- continue;
-
- if (--v->cycleTimeCount == 0) {
- updateView(v);
- v->cycleTimeCount = v->cycleTime;
+ if (screenObj->flags & fCycling) {
+ if (screenObj->cycleTimeCount) {
+ screenObj->cycleTimeCount--;
+ if (screenObj->cycleTimeCount == 0) {
+ updateView(screenObj);
+ screenObj->cycleTimeCount = screenObj->cycleTime;
+ }
+ }
}
}
- if (i) {
- _sprites->eraseUpdSprites();
+ if (changeCount) {
+ _sprites->eraseRegularSprites();
updatePosition();
- _sprites->blitUpdSprites();
- _sprites->commitUpdSprites();
- _game.viewTable[0].flags &= ~(fOnWater | fOnLand);
+ _sprites->buildRegularSpriteList();
+ _sprites->drawRegularSpriteList();
+ _sprites->showRegularSpriteList();
+
+ _game.screenObjTable[SCREENOBJECTS_EGO_ENTRY].flags &= ~(fOnWater | fOnLand);
}
}
-bool AgiEngine::isEgoView(const VtEntry* v) {
- return v == _game.viewTable;
+bool AgiEngine::isEgoView(const ScreenObjEntry *screenObj) {
+ return screenObj == _game.screenObjTable;
}
} // End of namespace Agi
diff --git a/engines/agi/view.h b/engines/agi/view.h
index b82fbe04d7..adcf7dd1b3 100644
--- a/engines/agi/view.h
+++ b/engines/agi/view.h
@@ -25,36 +25,36 @@
namespace Agi {
-struct ViewCel {
+struct AgiViewCel {
uint8 height;
uint8 width;
- uint8 transparency;
- uint8 mirrorLoop;
- uint8 mirror;
- uint8 *data;
+ uint8 clearKey;
+ bool mirrored;
+ byte *rawBitmap;
};
-struct ViewLoop {
- int numCels;
- struct ViewCel *cel;
+struct AgiViewLoop {
+ int16 celCount;
+ AgiViewCel *cel;
};
/**
* AGI view resource structure.
*/
struct AgiView {
- int numLoops;
- struct ViewLoop *loop;
- bool agi256_2;
- char *descr;
- uint8 *rdata;
+ byte headerStepSize;
+ byte headerCycleTime;
+ byte *description;
+ int16 loopCount;
+ AgiViewLoop *loop;
};
enum MotionType {
kMotionNormal = 0,
kMotionWander = 1,
kMotionFollowEgo = 2,
- kMotionMoveObj = 3
+ kMotionMoveObj = 3,
+ kMotionEgo = 4 // used by us for mouse movement only?
};
enum CycleType {
@@ -62,63 +62,78 @@ enum CycleType {
kCycleEndOfLoop = 1,
kCycleRevLoop = 2,
kCycleReverse = 3
- };
+};
enum ViewFlags {
- fDrawn = (1 << 0),
- fIgnoreBlocks = (1 << 1),
- fFixedPriority = (1 << 2),
- fIgnoreHorizon = (1 << 3),
- fUpdate = (1 << 4),
- fCycling = (1 << 5),
- fAnimated = (1 << 6),
- fMotion = (1 << 7),
- fOnWater = (1 << 8),
- fIgnoreObjects = (1 << 9),
- fUpdatePos = (1 << 10),
- fOnLand = (1 << 11),
- fDontupdate = (1 << 12),
- fFixLoop = (1 << 13),
- fDidntMove = (1 << 14),
- fAdjEgoXY = (1 << 15)
+ fDrawn = (1 << 0), // 0x0001
+ fIgnoreBlocks = (1 << 1), // 0x0002
+ fFixedPriority = (1 << 2), // 0x0004
+ fIgnoreHorizon = (1 << 3), // 0x0008
+ fUpdate = (1 << 4), // 0x0010
+ fCycling = (1 << 5), // 0x0020
+ fAnimated = (1 << 6), // 0x0040
+ fMotion = (1 << 7), // 0x0080
+ fOnWater = (1 << 8), // 0x0100
+ fIgnoreObjects = (1 << 9), // 0x0200
+ fUpdatePos = (1 << 10), // 0x0400
+ fOnLand = (1 << 11), // 0x0800
+ fDontupdate = (1 << 12), // 0x1000
+ fFixLoop = (1 << 13), // 0x2000
+ fDidntMove = (1 << 14), // 0x4000
+ fAdjEgoXY = (1 << 15) // 0x8000
};
/**
- * AGI view table entry
+ * AGI screen object table entry
*/
-struct VtEntry {
+struct ScreenObjEntry {
+ int16 objectNr; // 0-255 -> regular screenObjTable, -1 -> addToPic-view
uint8 stepTime;
uint8 stepTimeCount;
- uint8 entry;
int16 xPos;
int16 yPos;
- uint8 currentView;
+ uint8 currentViewNr;
bool viewReplaced;
- struct AgiView *viewData;
- uint8 currentLoop;
- uint8 numLoops;
- struct ViewLoop *loopData;
- uint8 currentCel;
- uint8 numCels;
- struct ViewCel *celData;
- struct ViewCel *celData2;
- int16 xPos2;
- int16 yPos2;
- void *s;
+ struct AgiView *viewResource;
+ uint8 currentLoopNr;
+ uint8 loopCount;
+ struct AgiViewLoop *loopData;
+ uint8 currentCelNr;
+ uint8 celCount;
+ struct AgiViewCel *celData;
+ //int16 xPos2;
+ //int16 yPos2;
int16 xSize;
int16 ySize;
+
+ int16 xPos_prev;
+ int16 yPos_prev;
+ int16 xSize_prev;
+ int16 ySize_prev;
+
uint8 stepSize;
uint8 cycleTime;
uint8 cycleTimeCount;
uint8 direction;
- MotionType motion;
+ MotionType motionType;
CycleType cycle;
uint8 priority;
uint16 flags;
- uint8 parm1;
- uint8 parm2;
- uint8 parm3;
- uint8 parm4;
+ // kMotionMoveObj
+ int16 move_x;
+ int16 move_y;
+ uint8 move_stepSize;
+ uint8 move_flag;
+ // kMotionFollowEgo
+ uint8 follow_stepSize;
+ uint8 follow_flag;
+ uint8 follow_count;
+ // kMotionWander
+ 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/agi/wagparser.cpp b/engines/agi/wagparser.cpp
index 0b49866531..fa11654ad9 100644
--- a/engines/agi/wagparser.cpp
+++ b/engines/agi/wagparser.cpp
@@ -79,7 +79,7 @@ bool WagProperty::read(Common::SeekableReadStream &stream) {
uint32 readBytes = stream.read(_propData, _propSize); // Read the data in
_propData[_propSize] = 0; // Set the trailing zero for easy C-style string access
- _readOk = (_propData != NULL && readBytes == _propSize); // Check that we got the whole data
+ _readOk = (readBytes == _propSize); // Check that we got the whole data
return _readOk;
}
@@ -111,9 +111,9 @@ WagFileParser::~WagFileParser() {
bool WagFileParser::checkAgiVersionProperty(const WagProperty &version) const {
if (version.getCode() == WagProperty::PC_INTVERSION && // Must be AGI interpreter version property
- version.getSize() >= 3 && // Need at least three characters for a version number like "X.Y"
- Common::isDigit(version.getData()[0]) && // And the first character must be a digit
- (version.getData()[1] == ',' || version.getData()[1] == '.')) { // And the second a comma or a period
+ version.getSize() >= 3 && // Need at least three characters for a version number like "X.Y"
+ Common::isDigit(version.getData()[0]) && // And the first character must be a digit
+ (version.getData()[1] == ',' || version.getData()[1] == '.')) { // And the second a comma or a period
for (int i = 2; i < version.getSize(); i++) // And the rest must all be digits
if (!Common::isDigit(version.getData()[i]))
@@ -129,7 +129,7 @@ uint16 WagFileParser::convertToAgiVersionNumber(const WagProperty &version) {
if (checkAgiVersionProperty(version)) { // Check that the string is a valid AGI interpreter version string
// Convert first ascii digit to an integer and put it in the fourth nibble (Bits 12...15) of the version number
// and at the same time set all other nibbles to zero.
- uint16 agiVerNum = ((uint16) (version.getData()[0] - '0')) << (3 * 4);
+ uint16 agiVerNum = ((uint16)(version.getData()[0] - '0')) << (3 * 4);
// Convert at most three least significant digits of the version number's minor part
// (i.e. the part after the decimal point) and put them in order to the third, second
@@ -137,7 +137,7 @@ uint16 WagFileParser::convertToAgiVersionNumber(const WagProperty &version) {
// is the number of digits after the decimal point.
int32 digitCount = MIN<int32>(3, ((int32) version.getSize()) - 2); // How many digits left to convert
for (int i = 0; i < digitCount; i++)
- agiVerNum |= ((uint16) (version.getData()[version.getSize() - digitCount + i] - '0')) << ((2 - i) * 4);
+ agiVerNum |= ((uint16)(version.getData()[version.getSize() - digitCount + i] - '0')) << ((2 - i) * 4);
debug(3, "WagFileParser: Converted AGI version from string %s to number 0x%x", version.getData(), agiVerNum);
return agiVerNum;
@@ -148,7 +148,7 @@ uint16 WagFileParser::convertToAgiVersionNumber(const WagProperty &version) {
bool WagFileParser::checkWagVersion(Common::SeekableReadStream &stream) {
if (stream.size() >= WINAGI_VERSION_LENGTH) { // Stream has space to contain the WinAGI version string
// Read the last WINAGI_VERSION_LENGTH bytes of the stream and make a string out of it
- char str[WINAGI_VERSION_LENGTH+1]; // Allocate space for the trailing zero also
+ char str[WINAGI_VERSION_LENGTH + 1]; // Allocate space for the trailing zero also
uint32 oldStreamPos = stream.pos(); // Save the old stream position
stream.seek(stream.size() - WINAGI_VERSION_LENGTH);
uint32 readBytes = stream.read(str, WINAGI_VERSION_LENGTH);
@@ -164,7 +164,7 @@ bool WagFileParser::checkWagVersion(Common::SeekableReadStream &stream) {
// WinAGI 1.1.21 recognizes as acceptable in the end of a *.wag file.
// Note that they are all of length 16 and are padded with spaces to be that long.
return scumm_stricmp(str, "WINAGI v1.0 ") == 0 ||
- scumm_stricmp(str, "1.0 BETA ") == 0;
+ scumm_stricmp(str, "1.0 BETA ") == 0;
} else { // Stream is too small to contain the WinAGI version string
debug(3, "WagFileParser::checkWagVersion: Stream is too small to contain a valid WAG file");
return false;
@@ -188,7 +188,7 @@ bool WagFileParser::parse(const Common::FSNode &node) {
if (property.read(*stream)) { // Read the property and check it was read ok
_propList.push_back(property); // Add read property to properties list
debug(4, "WagFileParser::parse: Read property with code %d, type %d, number %d, size %d, data \"%s\"",
- property.getCode(), property.getType(), property.getNumber(), property.getSize(), property.getData());
+ property.getCode(), property.getType(), property.getNumber(), property.getSize(), property.getData());
} else // Reading failed, let's bail out
break;
} while (!endOfProperties(*stream)); // Loop until the end of properties
diff --git a/engines/agi/words.cpp b/engines/agi/words.cpp
index ff9049fdc5..7072f003c2 100644
--- a/engines/agi/words.cpp
+++ b/engines/agi/words.cpp
@@ -21,22 +21,23 @@
*/
#include "agi/agi.h"
+#include "agi/words.h"
#include "common/textconsole.h"
namespace Agi {
-//
-// Local implementation to avoid problems with strndup() used by
-// gcc 3.2 Cygwin (see #635984)
-//
-static char *myStrndup(const char *src, int n) {
- char *tmp = strncpy((char *)malloc(n + 1), src, n);
- tmp[n] = 0;
- return tmp;
+Words::Words(AgiEngine *vm) {
+ _vm = vm;
+
+ clearEgoWords();
+}
+
+Words::~Words() {
+ clearEgoWords();
}
-int AgiEngine::loadWords_v1(Common::File &f) {
+int Words::loadDictionary_v1(Common::File &f) {
char str[64];
int k;
@@ -55,18 +56,21 @@ int AgiEngine::loadWords_v1(Common::File &f) {
// And store it in our internal dictionary
if (k > 0) {
- AgiWord *w = new AgiWord;
- w->word = myStrndup(str, k + 1);
- w->id = f.readUint16LE();
- _game.words[str[0] - 'a'].push_back(w);
- debug(3, "'%s' (%d)", w->word, w->id);
+ WordEntry *newWord = new WordEntry;
+ byte firstCharNr = str[0] - 'a';
+
+ newWord->word = Common::String(str, k + 1); // myStrndup(str, k + 1);
+ newWord->id = f.readUint16LE();
+
+ _dictionaryWords[firstCharNr].push_back(newWord);
+ debug(3, "'%s' (%d)", newWord->word.c_str(), newWord->id);
}
- } while((uint8)str[0] != 0xFF);
+ } while ((uint8)str[0] != 0xFF);
return errOK;
}
-int AgiEngine::loadWords(const char *fname) {
+int Words::loadDictionary(const char *fname) {
Common::File fp;
if (!fp.open(fname)) {
@@ -99,10 +103,10 @@ int AgiEngine::loadWords(const char *fname) {
// See bug #3615061
if (str[0] == 'a' + i) {
// And store it in our internal dictionary
- AgiWord *w = new AgiWord;
- w->word = myStrndup(str, k);
- w->id = fp.readUint16BE();
- _game.words[i].push_back(w);
+ WordEntry *newWord = new WordEntry;
+ newWord->word = Common::String(str, k);
+ newWord->id = fp.readUint16BE();
+ _dictionaryWords[i].push_back(newWord);
}
k = fp.readByte();
@@ -119,113 +123,254 @@ int AgiEngine::loadWords(const char *fname) {
return errOK;
}
-void AgiEngine::unloadWords() {
- for (int i = 0; i < 26; i++)
- _game.words[i].clear();
-}
+void Words::unloadDictionary() {
+ for (int16 firstCharNr = 0; firstCharNr < 26; firstCharNr++) {
+ Common::Array<WordEntry *> &dictionary = _dictionaryWords[firstCharNr];
+ int16 dictionarySize = dictionary.size();
-/**
- * Find a word in the dictionary
- * Uses an algorithm hopefully like the one Sierra used. Returns the ID
- * of the word and the length in flen. Returns -1 if not found.
- */
-int AgiEngine::findWord(const char *word, int *flen) {
- int c;
- int result = -1;
-
- debugC(2, kDebugLevelScripts, "find_word(%s)", word);
-
- if (word[0] >= 'a' && word[0] <= 'z')
- c = word[0] - 'a';
- else
- return -1;
-
- *flen = 0;
- Common::Array<AgiWord *> &a = _game.words[c];
-
- for (int i = 0; i < (int)a.size(); i++) {
- int wlen = strlen(a[i]->word);
- // Keep looking till we find the word itself, or the whole phrase.
- // Try to find the best match (i.e. the longest matching phrase).
- if (!strncmp(a[i]->word, word, wlen) && (word[wlen] == 0 || word[wlen] == 0x20) && wlen >= *flen) {
- *flen = wlen;
- result = a[i]->id;
+ for (int16 dictionaryWordNr = 0; dictionaryWordNr < dictionarySize; dictionaryWordNr++) {
+ delete dictionary[dictionaryWordNr];
}
+
+ _dictionaryWords[firstCharNr].clear();
+ }
+}
+
+void Words::clearEgoWords() {
+ for (int16 wordNr = 0; wordNr < MAX_WORDS; wordNr++) {
+ _egoWords[wordNr].id = 0;
+ _egoWords[wordNr].word.clear();
}
+ _egoWordCount = 0;
+}
+
+
+static bool isCharSeparator(const char curChar) {
+ switch (curChar) {
+ case ' ':
+ case ',':
+ case '.':
+ case '?':
+ case '!':
+ case '(':
+ case ')':
+ case ';':
+ case ':':
+ case '[':
+ case ']':
+ case '{':
+ case '}':
+ return true;
+ break;
+ default:
+ break;
+ }
+ return false;
+}
- return result;
+static bool isCharInvalid(const char curChar) {
+ switch (curChar) {
+ case 0x27: // '
+ case 0x60: // `
+ case '-':
+ case '\\':
+ case '"':
+ return true;
+ break;
+ default:
+ break;
+ }
+ return false;
}
-void AgiEngine::dictionaryWords(char *msg) {
- char *p = NULL;
- char *q = NULL;
- int wid, wlen;
-
- debugC(2, kDebugLevelScripts, "msg = \"%s\"", msg);
-
- cleanInput();
-
- for (p = msg; p && *p && getvar(vWordNotFound) == 0;) {
- if (*p == 0x20)
- p++;
-
- if (*p == 0)
- break;
-
- wid = findWord(p, &wlen);
- debugC(2, kDebugLevelScripts, "find_word(p) == %d", wid);
-
- switch (wid) {
- case -1:
- debugC(2, kDebugLevelScripts, "unknown word");
- _game.egoWords[_game.numEgoWords].word = strdup(p);
-
- q = _game.egoWords[_game.numEgoWords].word;
-
- _game.egoWords[_game.numEgoWords].id = 19999;
- setvar(vWordNotFound, 1 + _game.numEgoWords);
-
- _game.numEgoWords++;
-
- p += strlen(p);
- break;
- case 0:
- // ignore this word
- debugC(2, kDebugLevelScripts, "ignore word");
- p += wlen;
- q = NULL;
- break;
- default:
- // an OK word
- debugC(3, kDebugLevelScripts, "ok word (%d)", wid);
- _game.egoWords[_game.numEgoWords].id = wid;
- _game.egoWords[_game.numEgoWords].word = myStrndup(p, wlen);
- _game.numEgoWords++;
- p += wlen;
- break;
+void Words::cleanUpInput(const char *rawUserInput, Common::String &cleanInput) {
+ byte curChar = 0;
+
+ cleanInput.clear();
+
+ curChar = *rawUserInput;
+ while (curChar) {
+ // skip separators / invalid characters
+ if (isCharSeparator(curChar) || isCharInvalid(curChar)) {
+ rawUserInput++;
+ curChar = *rawUserInput;
+ } else {
+ do {
+ if (!isCharInvalid(curChar)) {
+ // not invalid char, add it to the cleaned up input
+ cleanInput += curChar;
+ }
+
+ rawUserInput++;
+ curChar = *rawUserInput;
+
+ if (isCharSeparator(curChar)) {
+ cleanInput += ' ';
+ break;
+ }
+ } while (curChar);
}
+ }
+ if (cleanInput.hasSuffix(" ")) {
+ // ends with a space? remove it
+ cleanInput.deleteLastChar();
+ }
+}
- if (p != NULL && *p) {
- debugC(2, kDebugLevelScripts, "p = %s", p);
- *p = 0;
- p++;
+int16 Words::findWordInDictionary(const Common::String &userInputLowcased, uint16 userInputLen, uint16 userInputPos, uint16 &foundWordLen) {
+ uint16 userInputLeft = userInputLen - userInputPos;
+ uint16 wordStartPos = userInputPos;
+ int16 wordId = DICTIONARY_RESULT_UNKNOWN;
+ byte firstChar = userInputLowcased[userInputPos];
+ byte curUserInputChar = 0;
+
+ foundWordLen = 0;
+
+ if ((firstChar >= 'a') && (firstChar <= 'z')) {
+ // word has to start with a letter
+ if (((userInputPos + 1) < userInputLen) && (userInputLowcased[userInputPos + 1] == ' ')) {
+ // current word is 1 char only?
+ if ((firstChar == 'a') || (firstChar == 'i')) {
+ // and it's "a" or "i"? -> then set current type to ignore
+ wordId = DICTIONARY_RESULT_IGNORE;
+ }
}
- if (q != NULL) {
- for (; (*q != 0 && *q != 0x20); q++)
- ;
- if (*q) {
- *q = 0;
- q++;
+ Common::Array<WordEntry *> &dictionary = _dictionaryWords[firstChar - 'a'];
+ int16 dictionarySize = dictionary.size();
+
+ for (int16 dictionaryWordNr = 0; dictionaryWordNr < dictionarySize; dictionaryWordNr++) {
+ WordEntry *dictionaryEntry = dictionary[dictionaryWordNr];
+ uint16 dictionaryWordLen = dictionaryEntry->word.size();
+
+ if (dictionaryWordLen <= userInputLeft) {
+ // dictionary word is longer or same length as the remaining user input
+ uint16 curCompareLeft = dictionaryWordLen;
+ uint16 dictionaryWordPos = 0;
+ byte curDictionaryChar = 0;
+
+ userInputPos = wordStartPos;
+ while (curCompareLeft) {
+ curUserInputChar = userInputLowcased[userInputPos];
+ curDictionaryChar = dictionaryEntry->word[dictionaryWordPos];
+
+ if (curUserInputChar != curDictionaryChar)
+ break;
+
+ userInputPos++;
+ dictionaryWordPos++;
+ curCompareLeft--;
+ }
+
+ if (!curCompareLeft) {
+ // check, if there is also nothing more of user input left or if a space the follow-up char?
+ if ((userInputPos >= userInputLen) || (userInputLowcased[userInputPos] == ' ')) {
+ // so fully matched, remember match
+ wordId = dictionaryEntry->id;
+ foundWordLen = dictionaryWordLen;
+
+ // perfect match? -> exit loop
+ if (userInputLeft == foundWordLen) {
+ // perfect match -> break
+ break;
+ }
+ }
+ }
}
}
}
- debugC(4, kDebugLevelScripts, "num_ego_words = %d", _game.numEgoWords);
- if (_game.numEgoWords > 0) {
- setflag(fEnteredCli, true);
- setflag(fSaidAcceptedInput, false);
+ if (foundWordLen == 0) {
+ userInputPos = wordStartPos;
+ while (userInputPos < userInputLen) {
+ if (userInputLowcased[userInputPos] == ' ') {
+ break;
+ }
+ userInputPos++;
+ }
+ foundWordLen = userInputPos - wordStartPos;
}
+ return wordId;
+}
+
+void Words::parseUsingDictionary(const char *rawUserInput) {
+ Common::String userInput;
+ Common::String userInputLowcased;
+ const char *userInputPtr = nullptr;
+ uint16 userInputLen;
+ uint16 userInputPos = 0;
+ uint16 foundWordPos;
+ int16 foundWordId;
+ uint16 foundWordLen = 0;
+ uint16 wordCount = 0;
+
+ assert(rawUserInput);
+ debugC(2, kDebugLevelScripts, "parse: userinput = \"%s\"", rawUserInput);
+
+ // Reset result
+ clearEgoWords();
+
+ // clean up user input
+ cleanUpInput(rawUserInput, userInput);
+
+ // Sierra compared independent of upper case and lower case
+ userInputLowcased = userInput;
+ userInputLowcased.toLowercase();
+
+ userInputLen = userInput.size();
+ userInputPtr = userInput.c_str();
+
+ while (userInputPos < userInputLen) {
+ // Skip trailing space
+ if (userInput[userInputPos] == ' ')
+ userInputPos++;
+
+ foundWordPos = userInputPos;
+ foundWordId = findWordInDictionary(userInputLowcased, userInputLen, userInputPos, foundWordLen);
+
+ if (foundWordId != DICTIONARY_RESULT_IGNORE) {
+ // word not supposed to get ignored
+ // add it now
+ if (foundWordId != DICTIONARY_RESULT_UNKNOWN) {
+ // known word
+ _egoWords[wordCount].id = foundWordId;
+ }
+
+ _egoWords[wordCount].word = Common::String(userInputPtr + foundWordPos, foundWordLen);
+ debugC(2, kDebugLevelScripts, "found word %s (id %d)", _egoWords[wordCount].word.c_str(), _egoWords[wordCount].id);
+ wordCount++;
+
+ if (foundWordId == DICTIONARY_RESULT_UNKNOWN) {
+ // unknown word
+ _vm->setVar(VM_VAR_WORD_NOT_FOUND, wordCount);
+ break; // and exit now
+ }
+ }
+
+ userInputPos += foundWordLen;
+ }
+
+ _egoWordCount = wordCount;
+
+ debugC(4, kDebugLevelScripts, "ego word count = %d", _egoWordCount);
+ if (_egoWordCount > 0) {
+ _vm->setFlag(VM_FLAG_ENTERED_CLI, true);
+ } else {
+ _vm->setFlag(VM_FLAG_ENTERED_CLI, false);
+ }
+ _vm->setFlag(VM_FLAG_SAID_ACCEPTED_INPUT, false);
+}
+
+uint16 Words::getEgoWordCount() {
+ return _egoWordCount;
+}
+const char *Words::getEgoWord(int16 wordNr) {
+ assert(wordNr >= 0 && wordNr < MAX_WORDS);
+ return _egoWords[wordNr].word.c_str();
+}
+uint16 Words::getEgoWordId(int16 wordNr) {
+ assert(wordNr >= 0 && wordNr < MAX_WORDS);
+ return _egoWords[wordNr].id;
}
} // End of namespace Agi
diff --git a/engines/agi/words.h b/engines/agi/words.h
new file mode 100644
index 0000000000..96dafae275
--- /dev/null
+++ b/engines/agi/words.h
@@ -0,0 +1,69 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef AGI_WORDS_H
+#define AGI_WORDS_H
+
+namespace Agi {
+
+#define DICTIONARY_RESULT_UNKNOWN -1
+#define DICTIONARY_RESULT_IGNORE 0
+
+struct WordEntry {
+ uint16 id;
+ Common::String word;
+};
+
+class Words {
+public:
+ Words(AgiEngine *vm);
+ ~Words();
+
+private:
+ AgiEngine *_vm;
+
+ // Dictionary
+ Common::Array<WordEntry *> _dictionaryWords[26];
+
+ WordEntry _egoWords[MAX_WORDS];
+ uint16 _egoWordCount;
+
+public:
+ uint16 getEgoWordCount();
+ const char *getEgoWord(int16 wordNr);
+ uint16 getEgoWordId(int16 wordNr);
+
+ int loadDictionary_v1(Common::File &f);
+ int loadDictionary(const char *fname);
+ void unloadDictionary();
+
+ void clearEgoWords();
+ void parseUsingDictionary(const char *rawUserInput);
+
+private:
+ void cleanUpInput(const char *userInput, Common::String &cleanInput);
+ int16 findWordInDictionary(const Common::String &userInput, uint16 userInputLen, uint16 userInputPos, uint16 &foundWordLen);
+};
+
+} // End of namespace Agi
+
+#endif /* AGI_WORDS_H */
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 72a38a3645..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 {
@@ -183,10 +183,9 @@ SaveStateList AgosMetaEngine::listSaves(const char *target) const {
Common::StringArray filenames;
Common::String saveDesc;
Common::String pattern = target;
- pattern += ".???";
+ pattern += ".###";
filenames = saveFileMan->listSavefiles(pattern);
- sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
SaveStateList saveList;
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
@@ -203,6 +202,8 @@ SaveStateList AgosMetaEngine::listSaves(const char *target) const {
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
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/sound.cpp b/engines/agos/sound.cpp
index 762f60bd91..13b5bf761c 100644
--- a/engines/agos/sound.cpp
+++ b/engines/agos/sound.cpp
@@ -217,7 +217,7 @@ static void convertVolume(int &vol) {
}
static void convertPan(int &pan) {
- // DirectSound was orginally used, which specifies volume
+ // DirectSound was originally used, which specifies volume
// and panning differently than ScummVM does, using a logarithmic scale
// rather than a linear one.
//
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/POTFILES b/engines/avalanche/POTFILES
new file mode 100644
index 0000000000..5b0bb910ed
--- /dev/null
+++ b/engines/avalanche/POTFILES
@@ -0,0 +1 @@
+engines/avalanche/parser.cpp
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 028f167e70..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[] = {
@@ -107,10 +107,9 @@ SaveStateList AvalancheMetaEngine::listSaves(const char *target) const {
Common::StringArray filenames;
Common::String pattern = target;
pattern.toUppercase();
- pattern += ".???";
+ pattern += ".###";
filenames = saveFileMan->listSavefiles(pattern);
- sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
SaveStateList saveList;
for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) {
@@ -152,6 +151,8 @@ SaveStateList AvalancheMetaEngine::listSaves(const char *target) const {
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
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 79be16d3c3..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"};
@@ -524,7 +526,7 @@ void Nim::dogFood() {
// 1) Look for 2 equal lines, then take the odd one out.
// 2) Look for A.P.s, and capitalise on them.
// 3) Go any old where.
- const byte other[3][2] = { { 2, 3 }, { 1, 3 }, { 1, 2 } };
+ const byte other[3][2] = { { 1, 2 }, { 0, 2 }, { 0, 1 } };
for (int i = 0; i < 3; i++) { // Look for 2 equal lines.
if (_stones[other[i][0]] == _stones[other[i][1]]) {
diff --git a/engines/avalanche/parser.cpp b/engines/avalanche/parser.cpp
index 220186ca5e..112dce93ac 100644
--- a/engines/avalanche/parser.cpp
+++ b/engines/avalanche/parser.cpp
@@ -30,6 +30,8 @@
#include "avalanche/nim.h"
#include "gui/saveload.h"
+#include "common/system.h"
+#include "common/translation.h"
namespace Avalanche {
@@ -1883,7 +1885,7 @@ void Parser::doThat() {
break;
case kVerbCodeLoad: {
- GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Restore game:", "Restore", false);
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false);
int16 savegameId = dialog->runModalWithCurrentTarget();
delete dialog;
@@ -1895,7 +1897,7 @@ void Parser::doThat() {
}
break;
case kVerbCodeSave: {
- GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Save game:", "Save", true);
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
int16 savegameId = dialog->runModalWithCurrentTarget();
Common::String savegameDescription = dialog->getResultString();
delete dialog;
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 11e4b6cea7..e7b20512a2 100644
--- a/engines/bbvs/bbvs.cpp
+++ b/engines/bbvs/bbvs.cpp
@@ -34,11 +34,14 @@
#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"
#include "common/fs.h"
#include "common/timer.h"
+#include "common/translation.h"
+#include "engines/advancedDetector.h"
#include "engines/util.h"
#include "graphics/cursorman.h"
#include "graphics/font.h"
@@ -116,15 +119,40 @@ BbvsEngine::BbvsEngine(OSystem *syst, const ADGameDescription *gd) :
Engine::syncSoundSettings();
+#ifdef USE_TRANSLATION
+ _oldGUILanguage = TransMan.getCurrentLanguage();
+
+ if (gd->flags & GF_GUILANGSWITCH)
+ TransMan.setLanguage(getLanguageLocale(gd->language));
+#endif
}
BbvsEngine::~BbvsEngine() {
+#ifdef USE_TRANSLATION
+ if (TransMan.getCurrentLanguage() != _oldGUILanguage)
+ TransMan.setLanguage(_oldGUILanguage);
+#endif
delete _random;
}
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;
}
@@ -150,24 +178,10 @@ Common::Error BbvsEngine::run() {
_sound = new SoundMan();
allocSnapshot();
- memset(_easterEggInput, 0, sizeof(_easterEggInput));
- _gameTicks = 0;
- _playVideoNumber = 0;
- _bootSaveSlot = -1;
+ newGame();
- memset(_inventoryItemStatus, 0, sizeof(_inventoryItemStatus));
- memset(_gameVars, 0, sizeof(_gameVars));
- memset(_sceneVisited, 0, sizeof(_sceneVisited));
-
- _mouseX = 160;
- _mouseY = 120;
- _mouseButtons = 0;
-
- _currVerbNum = kVerbLook;
- _currInventoryItem = -1;
- _currTalkObjectIndex = -1;
- _currSceneNum = 0;
+ _bootSaveSlot = -1;
_newSceneNum = 31;
if (ConfMan.hasKey("save_slot"))
@@ -1376,7 +1390,7 @@ void BbvsEngine::checkEasterEgg(char key) {
};
if (_currSceneNum == kCredits) {
- memcpy(&_easterEggInput[1], &_easterEggInput[0], 6);
+ memmove(&_easterEggInput[1], &_easterEggInput[0], 6);
_easterEggInput[0] = key;
for (int i = 0; i < ARRAYSIZE(kEasterEggStrings); ++i) {
if (!scumm_strnicmp(kEasterEggStrings[i], _easterEggInput, kEasterEggLengths[i])) {
diff --git a/engines/bbvs/bbvs.h b/engines/bbvs/bbvs.h
index bbd8046a8b..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"
@@ -63,6 +62,10 @@ class SoundMan;
#define BBVS_SAVEGAME_VERSION 0
enum {
+ GF_GUILANGSWITCH = (1 << 0) // If GUI language switch is required for menus
+};
+
+enum {
kVerbLook = 0,
kVerbUse = 1,
kVerbTalk = 2,
@@ -226,9 +229,15 @@ public:
void continueGameFromQuickSave();
void setNewSceneNum(int newSceneNum);
const Common::String getTargetName() { return _targetName; }
-private:
const ADGameDescription *_gameDescription;
+
+private:
Graphics::PixelFormat _pixelFormat;
+
+#ifdef USE_TRANSLATION
+ Common::String _oldGUILanguage;
+#endif
+
public:
Common::RandomSource *_random;
diff --git a/engines/bbvs/configure.engine b/engines/bbvs/configure.engine
index c1dc1ef924..8be3e078d9 100644
--- a/engines/bbvs/configure.engine
+++ b/engines/bbvs/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 bbvs "Beavis and Butthead in Virtual Stupidity" no
+add_engine bbvs "Beavis and Butthead in Virtual Stupidity" yes
diff --git a/engines/bbvs/detection.cpp b/engines/bbvs/detection.cpp
index 3e247aad99..7c0045ee73 100644
--- a/engines/bbvs/detection.cpp
+++ b/engines/bbvs/detection.cpp
@@ -30,7 +30,7 @@
#include "graphics/thumbnail.h"
static const PlainGameDescriptor bbvsGames[] = {
- { "bbvs", "Beavis and Butthead in Virtual Stupidity" },
+ { "bbvs", "Beavis and Butt-head in Virtual Stupidity" },
{ 0, 0 }
};
@@ -40,12 +40,21 @@ static const ADGameDescription gameDescriptions[] = {
{
"bbvs",
0,
- AD_ENTRY1s("game0001.vnm", "637e5411751c7065bc385dd73d224561", 64004),
+ AD_ENTRY1s("vspr0001.vnm", "7ffe9b9e7ca322db1d48e86f5130578e", 1166628),
Common::EN_ANY,
Common::kPlatformWindows,
ADGF_NO_FLAGS,
GUIO0()
},
+ {
+ "bbvs",
+ 0,
+ AD_ENTRY1s("vspr0001.vnm", "91c76b1048f93208cd7b1a05ebccb408", 1176976),
+ Common::RU_RUS,
+ Common::kPlatformWindows,
+ GF_GUILANGSWITCH | ADGF_NO_FLAGS,
+ GUIO0()
+ },
AD_TABLE_END_MARKER
};
@@ -60,13 +69,13 @@ 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;
}
virtual const char *getName() const {
- return "MTV's Beavis and Butt-Head in Virtual Stupidity";
+ return "MTV's Beavis and Butt-head in Virtual Stupidity";
}
virtual const char *getOriginalCopyright() const {
@@ -104,10 +113,9 @@ SaveStateList BbvsMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Bbvs::BbvsEngine::SaveHeader header;
Common::String pattern = target;
- pattern += ".???";
+ pattern += ".###";
Common::StringArray filenames;
filenames = saveFileMan->listSavefiles(pattern.c_str());
- Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
SaveStateList saveList;
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
@@ -122,6 +130,8 @@ SaveStateList BbvsMetaEngine::listSaves(const char *target) const {
}
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
diff --git a/engines/bbvs/dialogs.cpp b/engines/bbvs/dialogs.cpp
index af95f06c1e..64fa86e1ee 100644
--- a/engines/bbvs/dialogs.cpp
+++ b/engines/bbvs/dialogs.cpp
@@ -22,8 +22,12 @@
#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 {
@@ -53,6 +57,27 @@ static const MenuButton kMenuButtons[] = {
{"Back ..", kCmdBack}
};
+static const MenuButton kMenuButtonsRu[] = {
+ // Main menu
+ {"\xBD\xDE\xD2\xD0\xEF \xD8\xD3\xE0\xD0", kCmdNewGame},
+ {"\xBF\xE0\xDE\xD4\xDE\xDB\xD6\xD8\xE2\xEC", kCmdContinue},
+ {"\xB5\xE9\xD5 ..", kCmdOptions},
+ {"\xBC\xD8\xDD\xD8 \xB8\xD3\xE0\xEB", kCmdMiniGames},
+ {"\xB2\xEB\xE5\xDE\xD4", kCmdQuit},
+ // Options
+ {"\xB4\xD5\xD8\xDD\xE1\xE2\xD0\xDB\xDB\xEF\xE6\xD8\xEF", kCmdUninstall},
+ {"\xB0\xD2\xE2\xDE\xE0\xEB", kCmdCredits},
+ {"\xBF\xE0\xDE\xDB\xDE\xD3", kCmdOpening},
+ {"\xC0\xD5\xDA\xDB\xD0\xDC\xD0", kCmdChicksNStuff},
+ {"\xBD\xD0\xD7\xD0\xD4 ..", kCmdBack},
+ // Minigames
+ {"\xC1\xDD\xD0\xD9\xDF\xD5\xE0", kCmdHockALoogie},
+ {"\xB6\xE3\xDA\xDE\xD6\xD0\xE0\xDA\xD0", kCmdBugJustice},
+ {"\xBF\xE2\xD5\xDD\xD8\xE1", kCmdCourtChaos},
+ {"\xB6\xD8\xD0\xDE\xD9 \xB7\xD2\xE3\xDA", kCmdAirGuitar},
+ {"\xBD\xD0\xD7\xD0\xD4 ..", kCmdBack}
+};
+
MainMenu::MainMenu(BbvsEngine *vm) : Dialog(0, 0, 1, 1), _vm(vm) {
init();
}
@@ -70,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;
@@ -80,7 +105,7 @@ void MainMenu::reflowLayout() {
_w = 2 * buttonWidth + buttonPadding;
_h = 3 * buttonHeight + 3 * buttonPadding;
_x = (screenW - _w) / 2;
- _y = screenH - _h;
+ _y = screenH - _h - 2;
int x = 0, y = 0;
@@ -160,7 +185,13 @@ void MainMenu::handleCommand(GUI::CommandSender *sender, uint32 command, uint32
void MainMenu::gotoMenuScreen(int screen) {
for (int i = 0; i < 5; ++i) {
- const MenuButton *btn = &kMenuButtons[screen * 5 + i];
+ const MenuButton *btn;
+
+ if (_vm->_gameDescription->language == Common::RU_RUS) {
+ btn = &kMenuButtonsRu[screen * 5 + i];
+ } else {
+ btn = &kMenuButtons[screen * 5 + i];
+ }
_buttons[i]->setLabel(btn->label);
_buttons[i]->setCmd(btn->cmd);
_buttons[i]->setEnabled(btn->cmd != 0);
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/graphics.cpp b/engines/bbvs/graphics.cpp
index 43840607c8..e60bf0b8eb 100644
--- a/engines/bbvs/graphics.cpp
+++ b/engines/bbvs/graphics.cpp
@@ -66,7 +66,7 @@ void Screen::clear() {
void Screen::drawDrawList(DrawList &drawList, SpriteModule *spriteModule) {
for (uint i = 0; i < drawList.size(); ++i) {
- debug(1, "index: %d; x: %d; y: %d; priority: %d", drawList[i].index, drawList[i].x, drawList[i].y, drawList[i].priority);
+ debug(4, "index: %d; x: %d; y: %d; priority: %d", drawList[i].index, drawList[i].x, drawList[i].y, drawList[i].priority);
Sprite sprite = spriteModule->getSprite(drawList[i].index);
drawSprite(sprite, drawList[i].x, drawList[i].y);
}
@@ -105,7 +105,7 @@ void Screen::drawSprite(Sprite &sprite, int x, int y) {
if (destX + width >= _surface->w)
width = _surface->w - destX;
- debug(0, "drawSprite() (%d, %d, %d, %d); skipX: %d; skipY: %d; %d", destX, destY, width, height, skipX, skipY, sprite.type);
+ debug(6, "drawSprite() (%d, %d, %d, %d); skipX: %d; skipY: %d; %d", destX, destY, width, height, skipX, skipY, sprite.type);
if (sprite.type == 1) {
for (int yc = 0; yc < height; ++yc) {
diff --git a/engines/bbvs/minigames/bbairguitar.cpp b/engines/bbvs/minigames/bbairguitar.cpp
index 26e27a966f..f826667134 100644
--- a/engines/bbvs/minigames/bbairguitar.cpp
+++ b/engines/bbvs/minigames/bbairguitar.cpp
@@ -25,8 +25,8 @@
#include "common/savefile.h"
#include "common/translation.h"
-#include "gui/dialog.h"
#include "gui/message.h"
+#include "gui/filebrowser-dialog.h"
namespace Bbvs {
@@ -1204,15 +1204,25 @@ void MinigameBbAirGuitar::stopNote(int noteNum) {
}
bool MinigameBbAirGuitar::getLoadFilename(Common::String &filename) {
- // TODO Run dialog and return actual filename
- filename = "test.air";
- return true;
+ GUI::FileBrowserDialog browser(0, "air", GUI::kFBModeLoad);
+
+ if (browser.runModal() > 0) {
+ filename = browser.getResult();
+ return true;
+ }
+
+ return false;
}
bool MinigameBbAirGuitar::getSaveFilename(Common::String &filename) {
- // TODO Run dialog and return actual filename
- filename = "test.air";
- return true;
+ GUI::FileBrowserDialog browser(0, "air", GUI::kFBModeSave);
+
+ if (browser.runModal() > 0) {
+ filename = browser.getResult();
+ return true;
+ }
+
+ return false;
}
bool MinigameBbAirGuitar::querySaveModifiedDialog() {
@@ -1240,7 +1250,7 @@ bool MinigameBbAirGuitar::loadTracks() {
if (!querySaveModifiedTracks())
return false;
-
+
Common::String filename;
if (!getLoadFilename(filename))
return false;
diff --git a/engines/bbvs/minigames/bbtennis.cpp b/engines/bbvs/minigames/bbtennis.cpp
index 7763548330..6c7d8cbf31 100644
--- a/engines/bbvs/minigames/bbtennis.cpp
+++ b/engines/bbvs/minigames/bbtennis.cpp
@@ -516,7 +516,7 @@ void MinigameBbTennis::updateObjs() {
}
obj->blinkCtr = _vm->getRandom(64) + 60;
_tennisPlayerDelay = _vm->getRandom(128) + 400 - _playerDecrease;
- if (_vm->getRandom(10) == 1 && !isAnySoundPlaying(kAllSounds, 0x11))
+ if (_vm->getRandom(10) == 1 && !isAnySoundPlaying(kAllSounds, 11))
playSound(kYuppieEnteringCourtSounds[_vm->getRandom(2)]);
}
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 9ea73ad10b..9bef02a3cc 100644
--- a/engines/bbvs/videoplayer.cpp
+++ b/engines/bbvs/videoplayer.cpp
@@ -43,6 +43,8 @@ void BbvsEngine::playVideo(int videoNum) {
return;
}
+ debug(0, "Screen format: %s", _system->getScreenFormat().toString().c_str());
+
Video::VideoDecoder *videoDecoder = new Video::AVIDecoder();
if (!videoDecoder->loadFile(videoFilename)) {
delete videoDecoder;
@@ -58,13 +60,20 @@ void BbvsEngine::playVideo(int videoNum) {
if (videoDecoder->needsUpdate()) {
const Graphics::Surface *frame = videoDecoder->decodeNextFrame();
if (frame) {
- _system->copyRectToScreen(frame->getPixels(), frame->pitch, 0, 0, frame->w, frame->h);
+ 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 (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/bbvs/walk.cpp b/engines/bbvs/walk.cpp
index 5ef14101a0..e97182ff5d 100644
--- a/engines/bbvs/walk.cpp
+++ b/engines/bbvs/walk.cpp
@@ -326,12 +326,10 @@ void BbvsEngine::canWalkToDest(WalkArea *walkArea, int infoCount) {
}
bool BbvsEngine::walkTestLineWalkable(const Common::Point &sourcePt, const Common::Point &destPt, WalkInfo *walkInfo) {
- const float ptDeltaX = destPt.x - sourcePt.x;
+ const float ptDeltaX = MAX<float>(destPt.x - sourcePt.x, 1.0f);
const float ptDeltaY = destPt.y - sourcePt.y;
const float wDeltaX = walkInfo->x - sourcePt.x;
const float wDeltaY = walkInfo->y - sourcePt.y;
- if (destPt.x == sourcePt.x)
- return true;
if (walkInfo->direction) {
const float nDeltaY = wDeltaX * ptDeltaY / ptDeltaX + (float)sourcePt.y - (float)walkInfo->y;
return (nDeltaY >= 0.0f) && (nDeltaY < (float)walkInfo->delta);
diff --git a/engines/cge/POTFILES b/engines/cge/POTFILES
index 55430683c3..f8aef4932d 100644
--- a/engines/cge/POTFILES
+++ b/engines/cge/POTFILES
@@ -1,2 +1,3 @@
engines/cge/detection.cpp
+engines/cge/events.cpp
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 da5eb2b1f2..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;
@@ -196,10 +196,9 @@ SaveStateList CGEMetaEngine::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..)
SaveStateList saveList;
for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) {
@@ -235,6 +234,8 @@ SaveStateList CGEMetaEngine::listSaves(const char *target) const {
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
diff --git a/engines/cge/events.cpp b/engines/cge/events.cpp
index 24b3a270cf..5d3d0a16a0 100644
--- a/engines/cge/events.cpp
+++ b/engines/cge/events.cpp
@@ -26,10 +26,9 @@
*/
#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"
#include "engines/advancedDetector.h"
#include "cge/events.h"
#include "cge/events.h"
@@ -70,7 +69,7 @@ bool Keyboard::getKey(Common::Event &event) {
return false;
case Common::KEYCODE_F5:
if (_vm->canSaveGameStateCurrently()) {
- GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Save game:", "Save", true);
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
int16 savegameId = dialog->runModalWithCurrentTarget();
Common::String savegameDescription = dialog->getResultString();
delete dialog;
@@ -81,7 +80,7 @@ bool Keyboard::getKey(Common::Event &event) {
return false;
case Common::KEYCODE_F7:
if (_vm->canLoadGameStateCurrently()) {
- GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Restore game:", "Restore", false);
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false);
int16 savegameId = dialog->runModalWithCurrentTarget();
delete dialog;
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/POTFILES b/engines/cge2/POTFILES
index 1e904763ec..3bff3258fd 100644
--- a/engines/cge2/POTFILES
+++ b/engines/cge2/POTFILES
@@ -1 +1,2 @@
engines/cge2/detection.cpp
+engines/cge2/events.cpp
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 4acdea3fde..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;
@@ -196,10 +196,9 @@ SaveStateList CGE2MetaEngine::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..)
SaveStateList saveList;
for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) {
@@ -235,6 +234,8 @@ SaveStateList CGE2MetaEngine::listSaves(const char *target) const {
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
diff --git a/engines/cge2/events.cpp b/engines/cge2/events.cpp
index 85743c8011..2dac04a0a5 100644
--- a/engines/cge2/events.cpp
+++ b/engines/cge2/events.cpp
@@ -26,10 +26,9 @@
*/
#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"
#include "engines/advancedDetector.h"
#include "cge2/events.h"
#include "cge2/text.h"
@@ -63,7 +62,7 @@ bool Keyboard::getKey(Common::Event &event) {
return false;
case Common::KEYCODE_F5:
if (_vm->canSaveGameStateCurrently()) {
- GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Save game:", "Save", true);
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
int16 savegameId = dialog->runModalWithCurrentTarget();
Common::String savegameDescription = dialog->getResultString();
delete dialog;
@@ -74,7 +73,7 @@ bool Keyboard::getKey(Common::Event &event) {
return false;
case Common::KEYCODE_F7:
if (_vm->canLoadGameStateCurrently()) {
- GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Restore game:", "Restore", false);
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false);
int16 savegameId = dialog->runModalWithCurrentTarget();
delete dialog;
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 6673b67b7a..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 {
@@ -68,7 +66,7 @@ class Sound {
public:
SmpInfo _smpinf;
- Sound(CGE2Engine *vm);
+ explicit Sound(CGE2Engine *vm);
~Sound();
void open();
void close();
@@ -116,7 +114,7 @@ private:
// Stop MIDI File
void sndMidiStop();
public:
- MusicPlayer(CGE2Engine *vm);
+ explicit MusicPlayer(CGE2Engine *vm);
~MusicPlayer();
void loadMidi(int ref);
diff --git a/engines/cge2/vga13h.cpp b/engines/cge2/vga13h.cpp
index f4064f3565..8b0d8b6c77 100644
--- a/engines/cge2/vga13h.cpp
+++ b/engines/cge2/vga13h.cpp
@@ -141,7 +141,7 @@ Sprite::Sprite(CGE2Engine *vm)
memset(_actionCtrl, 0, sizeof(_actionCtrl));
memset(_file, 0, sizeof(_file));
memset(&_flags, 0, sizeof(_flags));
- _flags._frnt = 1;
+ _flags._frnt = true;
}
Sprite::Sprite(CGE2Engine *vm, BitmapPtr shpP, int cnt)
@@ -152,7 +152,7 @@ Sprite::Sprite(CGE2Engine *vm, BitmapPtr shpP, int cnt)
memset(_actionCtrl, 0, sizeof(_actionCtrl));
memset(_file, 0, sizeof(_file));
memset(&_flags, 0, sizeof(_flags));
- _flags._frnt = 1;
+ _flags._frnt = true;
setShapeList(shpP, cnt);
}
@@ -629,11 +629,11 @@ void Sprite::gotoxyz(V2D pos) {
if (!_follow) {
FXP m = _vm->_eye->_z / (_pos3D._z - _vm->_eye->_z);
_pos3D._x = (_vm->_eye->_x + (_vm->_eye->_x - _pos2D.x) / m);
- _pos3D._x.round();
+ _pos3D._x = _pos3D._x.round();
if (!_constY) {
_pos3D._y = _vm->_eye->_y + (_vm->_eye->_y - _pos2D.y) / m;
- _pos3D._y.round();
+ _pos3D._y = _pos3D._y.round();
}
}
@@ -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/POTFILES b/engines/cine/POTFILES
new file mode 100644
index 0000000000..76f76832c3
--- /dev/null
+++ b/engines/cine/POTFILES
@@ -0,0 +1 @@
+engines/cine/detection.cpp
diff --git a/engines/cine/anim.cpp b/engines/cine/anim.cpp
index c6099447d8..6ecf07fe15 100644
--- a/engines/cine/anim.cpp
+++ b/engines/cine/anim.cpp
@@ -535,7 +535,7 @@ int loadSpl(const char *resourceName, int16 idx) {
entry = idx < 0 ? emptyAnimSpace() : idx;
assert(entry >= 0);
- g_cine->_animDataTable[entry].load(dataPtr + 0x16, ANIM_RAW, g_cine->_partBuffer[foundFileIdx].unpackedSize - 0x16, 1, foundFileIdx, 0, currentPartName);
+ g_cine->_animDataTable[entry].load(dataPtr, ANIM_RAW, g_cine->_partBuffer[foundFileIdx].unpackedSize, 1, foundFileIdx, 0, currentPartName);
free(dataPtr);
return entry + 1;
diff --git a/engines/cine/cine.cpp b/engines/cine/cine.cpp
index 5fed92051c..d2f088dcd8 100644
--- a/engines/cine/cine.cpp
+++ b/engines/cine/cine.cpp
@@ -22,10 +22,14 @@
#include "common/config-manager.h"
#include "common/debug-channels.h"
+#include "common/events.h"
#include "engines/util.h"
#include "graphics/cursorman.h"
+#include "graphics/palette.h"
+
+#include "image/iff.h"
#include "cine/cine.h"
#include "cine/bg_list.h"
@@ -89,6 +93,10 @@ void CineEngine::syncSoundSettings() {
}
Common::Error CineEngine::run() {
+ if (g_cine->getGameType() == GType_FW && (g_cine->getFeatures() & GF_CD)) {
+ showSplashScreen();
+ }
+
// Initialize backend
initGraphics(320, 200, false);
@@ -239,4 +247,45 @@ void CineEngine::initialize() {
}
}
+void CineEngine::showSplashScreen() {
+ Common::File file;
+ if (!file.open("sony.lbm"))
+ return;
+
+ Image::IFFDecoder decoder;
+ if (!decoder.loadStream(file))
+ return;
+
+ const Graphics::Surface *surface = decoder.getSurface();
+ if (surface->w == 640 && surface->h == 480) {
+ initGraphics(640, 480, true);
+
+ const byte *palette = decoder.getPalette();
+ int paletteColorCount = decoder.getPaletteColorCount();
+ g_system->getPaletteManager()->setPalette(palette, 0, paletteColorCount);
+
+ g_system->copyRectToScreen(surface->getPixels(), 640, 0, 0, 640, 480);
+ g_system->updateScreen();
+
+ Common::EventManager *eventMan = g_system->getEventManager();
+
+ bool done = false;
+ uint32 now = g_system->getMillis();
+
+ while (!done && g_system->getMillis() - now < 2000) {
+ Common::Event event;
+ while (eventMan->pollEvent(event)) {
+ if (event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) {
+ done = true;
+ break;
+ }
+ if (shouldQuit())
+ done = true;
+ }
+ }
+ }
+
+ decoder.destroy();
+}
+
} // End of namespace Cine
diff --git a/engines/cine/cine.h b/engines/cine/cine.h
index e620d2ffa5..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"
@@ -123,6 +123,7 @@ public:
bool loadSaveDirectory();
void makeSystemMenu();
+ int scummVMSaveLoadDialog(bool isSave);
int modifyGameSpeed(int speedChange);
int getTimerDelay() const;
Common::Error loadGameState(int slot);
@@ -145,13 +146,14 @@ public:
private:
void initialize();
+ void showSplashScreen();
void resetEngine();
bool loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFormat saveGameFormat);
bool loadTempSaveOS(Common::SeekableReadStream &in);
bool makeLoad(const Common::String &saveName);
void makeSaveFW(Common::OutSaveFile &out);
void makeSaveOS(Common::OutSaveFile &out);
- void makeSave(char *saveFileName);
+ void makeSave(const Common::String &saveFileName);
void mainLoop(int bootScriptIdx);
void readVolCnf();
diff --git a/engines/cine/detection.cpp b/engines/cine/detection.cpp
index 4202bdc942..ec01e8734d 100644
--- a/engines/cine/detection.cpp
+++ b/engines/cine/detection.cpp
@@ -24,8 +24,10 @@
#include "engines/advancedDetector.h"
#include "engines/obsolete.h"
+
#include "common/system.h"
#include "common/textconsole.h"
+#include "common/translation.h"
#include "cine/cine.h"
#include "cine/various.h"
@@ -61,15 +63,29 @@ static const Engines::ObsoleteGameID obsoleteGameIDsTable[] = {
#include "cine/detection_tables.h"
+static const ADExtraGuiOptionsMap optionsList[] = {
+ {
+ GAMEOPTION_ORIGINAL_SAVELOAD,
+ {
+ _s("Use original save/load screens"),
+ _s("Use the original save/load screens, instead of the ScummVM ones"),
+ "originalsaveload",
+ false
+ }
+ },
+
+ AD_EXTRA_GUI_OPTIONS_TERMINATOR
+};
+
class CineMetaEngine : public AdvancedMetaEngine {
public:
- CineMetaEngine() : AdvancedMetaEngine(Cine::gameDescriptions, sizeof(Cine::CINEGameDescription), cineGames) {
- _singleid = "cine";
- _guioptions = GUIO1(GUIO_NOSPEECH);
+ CineMetaEngine() : AdvancedMetaEngine(Cine::gameDescriptions, sizeof(Cine::CINEGameDescription), cineGames, optionsList) {
+ _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 {
@@ -119,9 +135,8 @@ SaveStateList CineMetaEngine::listSaves(const char *target) const {
SaveStateList saveList;
Common::String pattern = target;
- pattern += ".?";
+ pattern += ".#";
Common::StringArray filenames = saveFileMan->listSavefiles(pattern);
- sort(filenames.begin(), filenames.end());
Common::StringArray::const_iterator file;
Common::String filename = target;
@@ -140,10 +155,6 @@ SaveStateList CineMetaEngine::listSaves(const char *target) const {
CommandeType saveDesc;
for (file = filenames.begin(); file != filenames.end(); ++file) {
- // Jump over savegame files that don't end with a digit (e.g. "fw.3" is ok, "fw.a" is not).
- if (!Common::isDigit(file->lastChar()))
- continue;
-
// Obtain the last digit of the filename, since they correspond to the save slot
int slotNum = atoi(file->c_str() + file->size() - 1);
@@ -157,6 +168,8 @@ SaveStateList CineMetaEngine::listSaves(const char *target) const {
delete in;
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
diff --git a/engines/cine/detection_tables.h b/engines/cine/detection_tables.h
index 1188deb1a6..ca6a8a9168 100644
--- a/engines/cine/detection_tables.h
+++ b/engines/cine/detection_tables.h
@@ -22,6 +22,8 @@
namespace Cine {
+#define GAMEOPTION_ORIGINAL_SAVELOAD GUIO_GAMEOPTIONS1
+
static const CINEGameDescription gameDescriptions[] = {
{
{
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 907086a9a1..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);
}
@@ -969,7 +974,7 @@ void CineEngine::makeSaveOS(Common::OutSaveFile &out) {
saveBgIncrustList(out);
}
-void CineEngine::makeSave(char *saveFileName) {
+void CineEngine::makeSave(const Common::String &saveFileName) {
Common::SharedPtr<Common::OutSaveFile> fHandle(_saveFileMan->openForSaving(saveFileName));
setMouseCursor(MOUSE_CURSOR_DISK);
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/cine/various.cpp b/engines/cine/various.cpp
index 8687699a44..74dee1f541 100644
--- a/engines/cine/various.cpp
+++ b/engines/cine/various.cpp
@@ -21,12 +21,16 @@
*/
+#include "common/config-manager.h"
#include "common/endian.h"
#include "common/events.h"
#include "common/textconsole.h"
+#include "common/translation.h"
#include "graphics/cursorman.h"
+#include "gui/saveload.h"
+
#include "cine/cine.h"
#include "cine/main_loop.h"
#include "cine/object.h"
@@ -335,6 +339,55 @@ void CineEngine::resetEngine() {
}
}
+int CineEngine::scummVMSaveLoadDialog(bool isSave) {
+ GUI::SaveLoadChooser *dialog;
+ Common::String desc;
+ int slot;
+
+ if (isSave) {
+ dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
+
+ slot = dialog->runModalWithCurrentTarget();
+ desc = dialog->getResultString();
+
+ if (desc.empty()) {
+ // create our own description for the saved game, the user didnt enter it
+ desc = dialog->createDefaultSaveDescription(slot);
+ }
+ }
+ else {
+ dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false);
+ slot = dialog->runModalWithCurrentTarget();
+ }
+
+ delete dialog;
+
+ if (slot < 0)
+ return true;
+
+ Common::String saveFileName(Common::String::format("%s.%1d", _targetName.c_str(), slot));
+
+ if (isSave) {
+ Common::String tmp = Common::String::format("%s.dir", _targetName.c_str());
+
+ Common::OutSaveFile *fHandle = _saveFileMan->openForSaving(tmp);
+ if (!fHandle) {
+ warning("Unable to open file %s for saving", tmp.c_str());
+ return false;
+ }
+
+ Common::strlcpy(currentSaveName[slot], desc.c_str(), 20);
+
+ fHandle->write(currentSaveName, 200);
+ delete fHandle;
+
+ makeSave(saveFileName);
+ return true;
+ } else {
+ return makeLoad(saveFileName);
+ }
+}
+
void CineEngine::makeSystemMenu() {
int16 numEntry, systemCommand;
int16 mouseX, mouseY, mouseButton;
@@ -381,7 +434,11 @@ void CineEngine::makeSystemMenu() {
}
case 4: { // load game
if (loadSaveDirectory()) {
-// int16 selectedSave;
+ if (!ConfMan.getBool("originalsaveload")) {
+ scummVMSaveLoadDialog(false);
+ inMenu = false;
+ return;
+ }
getMouseData(mouseUpdateStatus, (uint16 *)&mouseButton, (uint16 *)&mouseX, (uint16 *)&mouseY);
selectedSave = makeMenuChoice(currentSaveName, 10, mouseX, mouseY + 8, 180);
@@ -417,6 +474,13 @@ void CineEngine::makeSystemMenu() {
}
case 5: { // Save game
loadSaveDirectory();
+
+ if (!ConfMan.getBool("originalsaveload")) {
+ scummVMSaveLoadDialog(true);
+ inMenu = false;
+ return;
+ }
+
selectedSave = makeMenuChoice(currentSaveName, 10, mouseX, mouseY + 8, 180);
if (selectedSave >= 0) {
@@ -1428,7 +1492,7 @@ uint16 addAni(uint16 param1, uint16 objIdx, const int8 *ptr, SeqListElement &ele
int16 di;
debug(5, "addAni: param1 = %d, objIdx = %d, ptr = %p, element.var8 = %d, element.var14 = %d param3 = %d",
- param1, objIdx, ptr, element.var8, element.var14, param3);
+ param1, objIdx, (const void *)ptr, element.var8, element.var14, param3);
// In the original an error string is set and 0 is returned if the following doesn't hold
assert(ptr);
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 036c1e88d8..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 {
@@ -81,12 +81,12 @@ static const ComposerGameDescription gameDescriptions[] = {
GType_ComposerV1
},
- // Magic Tales: Baba Yaga and the Magic Geese Mac - from bug #3466402
+ // Magic Tales: Baba Yaga and the Magic Geese Mac - from bug #3466402, #7025
{
{
"babayaga",
"",
- AD_ENTRY1("Baba Yaga", "ae3a4445f42fe10253da7ee4ea0d37"),
+ AD_ENTRY1s("Baba Yaga", "ae3a4445f42fe10253da7ee4ea0d37d6", 44321),
Common::EN_ANY,
Common::kPlatformMacintosh,
ADGF_NO_FLAGS,
@@ -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 4ca88a08d6..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 {
@@ -228,10 +228,9 @@ bool CruiseMetaEngine::hasFeature(MetaEngineFeature f) const {
SaveStateList CruiseMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Common::StringArray filenames;
- Common::String pattern("cruise.s??");
+ Common::String pattern("cruise.s##");
filenames = saveFileMan->listSavefiles(pattern);
- sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
SaveStateList saveList;
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
@@ -250,6 +249,8 @@ SaveStateList CruiseMetaEngine::listSaves(const char *target) const {
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
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 c7cfe227df..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 {
@@ -117,10 +117,9 @@ bool DraciMetaEngine::hasFeature(MetaEngineFeature f) const {
SaveStateList DraciMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Common::StringArray filenames;
- Common::String pattern("draci.s??");
+ Common::String pattern("draci.s##");
filenames = saveFileMan->listSavefiles(pattern);
- sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
SaveStateList saveList;
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
@@ -143,6 +142,8 @@ SaveStateList DraciMetaEngine::listSaves(const char *target) const {
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
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 a84bd11cb1..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 {
@@ -352,10 +352,9 @@ SaveStateList DrasculaMetaEngine::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..)
SaveStateList saveList;
int slotNum = 0;
@@ -378,6 +377,8 @@ SaveStateList DrasculaMetaEngine::listSaves(const char *target) const {
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
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 01cfc7e506..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 {
@@ -127,8 +128,7 @@ bool DreamWebMetaEngine::createInstance(OSystem *syst, Engine **engine, const AD
SaveStateList DreamWebMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
- Common::StringArray files = saveFileMan->listSavefiles("DREAMWEB.D??");
- Common::sort(files.begin(), files.end());
+ Common::StringArray files = saveFileMan->listSavefiles("DREAMWEB.D##");
SaveStateList saveList;
for (uint i = 0; i < files.size(); ++i) {
@@ -146,6 +146,8 @@ SaveStateList DreamWebMetaEngine::listSaves(const char *target) const {
saveList.push_back(sd);
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
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.cpp b/engines/dreamweb/dreamweb.cpp
index 94a2e60ef1..0514c6e889 100644
--- a/engines/dreamweb/dreamweb.cpp
+++ b/engines/dreamweb/dreamweb.cpp
@@ -407,8 +407,6 @@ Common::Error DreamWebEngine::run() {
_console = new DreamWebConsole(this);
_sound = new DreamWebSound(this);
- ConfMan.registerDefault("originalsaveload", "false");
- ConfMan.registerDefault("bright_palette", true);
_hasSpeech = Common::File::exists(_speechDirName + "/r01c0000.raw") && !ConfMan.getBool("speech_mute");
_brightPalette = ConfMan.getBool("bright_palette");
_copyProtection = ConfMan.getBool("copy_protection");
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 24008dd073..8fff99f3fc 100644
--- a/engines/engine.cpp
+++ b/engines/engine.cpp
@@ -40,7 +40,7 @@
#include "common/str.h"
#include "common/error.h"
#include "common/list.h"
-#include "common/list_intern.h"
+#include "common/memstream.h"
#include "common/scummsys.h"
#include "common/taskbar.h"
#include "common/textconsole.h"
@@ -48,7 +48,9 @@
#include "common/singleton.h"
#include "backends/keymapper/keymapper.h"
+#include "base/version.h"
+#include "gui/gui-manager.h"
#include "gui/debugger.h"
#include "gui/dialog.h"
#include "gui/message.h"
@@ -56,7 +58,9 @@
#include "audio/mixer.h"
#include "graphics/cursorman.h"
+#include "graphics/fontman.h"
#include "graphics/pixelformat.h"
+#include "image/bmp.h"
#ifdef _WIN32_WCE
extern bool isSmartphone();
@@ -240,6 +244,65 @@ void initCommonGFX(bool defaultTo1XScaler) {
g_system->setFeatureState(OSystem::kFeatureFullscreenMode, ConfMan.getBool("fullscreen"));
}
+// Please leave the splash screen in working order for your releases, even if they're commercial.
+// This is a proper and good way to show your appreciation for our hard work over these years.
+bool splash = false;
+
+#include "logo_data.h"
+
+void splashScreen() {
+ Common::MemoryReadStream stream(logo_data, ARRAYSIZE(logo_data));
+
+ Image::BitmapDecoder bitmap;
+
+ if (!bitmap.loadStream(stream)) {
+ warning("Error loading logo file");
+ return;
+ }
+
+ g_system->showOverlay();
+
+ // Fill with orange
+ Graphics::Surface screen;
+ screen.create(g_system->getOverlayWidth(), g_system->getOverlayHeight(), g_system->getOverlayFormat());
+ screen.fillRect(Common::Rect(screen.w, screen.h), screen.format.ARGBToColor(0xff, 0xd4, 0x75, 0x0b));
+
+ // Load logo
+ Graphics::Surface *logo = bitmap.getSurface()->convertTo(g_system->getOverlayFormat(), bitmap.getPalette());
+ 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);
+ int w = font->getStringWidth(gScummVMVersionDate);
+ int x = g_system->getOverlayWidth() - w - 5; // lx + logo->w - w + 5;
+ int y = g_system->getOverlayHeight() - font->getFontHeight() - 5; //ly + logo->h + 5;
+ font->drawString(&screen, gScummVMVersionDate, x, y, w, screen.format.ARGBToColor(0xff, 0, 0, 0));
+
+ g_system->copyRectToOverlay(screen.getPixels(), screen.pitch, 0, 0, screen.w, screen.h);
+ screen.free();
+
+ // Draw logo
+ 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;
+
+ // Delay 0.6 secs
+ uint time0 = g_system->getMillis();
+ Common::Event event;
+ while (time0 + 600 > g_system->getMillis()) {
+ g_system->updateScreen();
+ (void)g_system->getEventManager()->pollEvent(event);
+ g_system->delayMillis(10);
+ }
+ g_system->hideOverlay();
+
+ splash = true;
+}
+
void initGraphics(int width, int height, bool defaultTo1xScaler, const Graphics::PixelFormat *format) {
g_system->beginGFXTransaction();
@@ -258,6 +321,9 @@ void initGraphics(int width, int height, bool defaultTo1xScaler, const Graphics:
OSystem::TransactionError gfxError = g_system->endGFXTransaction();
+ if (!splash && !GUI::GuiManager::instance()._launched)
+ splashScreen();
+
if (gfxError == OSystem::kTransactionSuccess)
return;
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 de0ed04d25..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 {
@@ -108,10 +108,9 @@ bool FullpipeMetaEngine::hasFeature(MetaEngineFeature f) const {
SaveStateList FullpipeMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Common::StringArray filenames;
- Common::String pattern("fullpipe.s??");
+ Common::String pattern("fullpipe.s##");
filenames = saveFileMan->listSavefiles(pattern);
- sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
SaveStateList saveList;
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
@@ -130,6 +129,8 @@ SaveStateList FullpipeMetaEngine::listSaves(const char *target) const {
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
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 7815475d37..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;
@@ -419,7 +421,7 @@ bool GameLoader::unloadScene(int sceneId) {
if (_sc2array[sceneTag]._isLoaded)
saveScenePicAniInfos(sceneId);
- _sc2array[sceneTag]._motionController->freeItems();
+ _sc2array[sceneTag]._motionController->detachAllObjects();
delete tag->_scene;
tag->_scene = 0;
diff --git a/engines/fullpipe/interaction.cpp b/engines/fullpipe/interaction.cpp
index 84e9688e30..4aac3485f4 100644
--- a/engines/fullpipe/interaction.cpp
+++ b/engines/fullpipe/interaction.cpp
@@ -311,7 +311,7 @@ LABEL_38:
if (abs(xpos - subj->_ox) > 1 || abs(ypos - subj->_oy) > 1
|| (inter->_staticsId2 != 0 && (subj->_statics == 0 || subj->_statics->_staticsId != inter->_staticsId2))) {
- mq = getSc2MctlCompoundBySceneId(g_fp->_currentScene->_sceneId)->method34(subj, xpos, ypos, 1, inter->_staticsId2);
+ mq = getSc2MctlCompoundBySceneId(g_fp->_currentScene->_sceneId)->startMove(subj, xpos, ypos, 1, inter->_staticsId2);
if (!mq)
return false;
diff --git a/engines/fullpipe/lift.cpp b/engines/fullpipe/lift.cpp
index 9a3d91540a..d066c89d4a 100644
--- a/engines/fullpipe/lift.cpp
+++ b/engines/fullpipe/lift.cpp
@@ -324,7 +324,7 @@ void FullpipeEngine::lift_walkAndGo() {
ExCommand *ex;
if (abs(_liftX - _aniMan->_ox) > 1 || abs(_liftY - _aniMan->_oy) > 1 || _aniMan->_movement || _aniMan->_statics->_staticsId != ST_MAN_UP) {
- mq = getCurrSceneSc2MotionController()->method34(_aniMan, _liftX, _liftY, 1, ST_MAN_UP);
+ mq = getCurrSceneSc2MotionController()->startMove(_aniMan, _liftX, _liftY, 1, ST_MAN_UP);
if (mq) {
ex = new ExCommand(0, 17, MSG_LIFT_CLICKBUTTON, 0, 0, 0, 1, 0, 0, 0);
diff --git a/engines/fullpipe/messagehandlers.cpp b/engines/fullpipe/messagehandlers.cpp
index d4f79d1dd8..b9c79963f2 100644
--- a/engines/fullpipe/messagehandlers.cpp
+++ b/engines/fullpipe/messagehandlers.cpp
@@ -425,6 +425,7 @@ int global_messageHandler3(ExCommand *cmd) {
if (g_fp->_msgX != cmd->_sceneClickX || g_fp->_msgY != cmd->_sceneClickY) {
ani = g_fp->_currentScene->getStaticANIObject1ById(g_fp->_gameLoader->_field_FA, -1);
if (!ani || (ani->isIdle() && !(ani->_flags & 0x80) && !(ani->_flags & 0x100))) {
+ warning("WWW 1");
result = startWalkTo(g_fp->_gameLoader->_field_FA, -1, cmd->_sceneClickX, cmd->_sceneClickY, 0);
if (result) {
ExCommand *ex = new ExCommand(g_fp->_gameLoader->_field_FA, 17, 64, 0, 0, 0, 1, 0, 0, 0);
@@ -765,7 +766,7 @@ int MovGraph_messageHandler(ExCommand *cmd) {
point.x = ani->_ox;
point.y = ani->_oy;
- double dst = gr->calcDistance(&point, (MovGraphLink *)(*i), 0);
+ double dst = gr->putToLink(&point, (MovGraphLink *)(*i), 0);
if (dst >= 0.0 && dst < mindistance) {
mindistance = dst;
link = (MovGraphLink *)(*i);
@@ -775,13 +776,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->_distance);
+ 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/mgm.cpp b/engines/fullpipe/mgm.cpp
index 1c8ca2a7b1..ca2ec060e2 100644
--- a/engines/fullpipe/mgm.cpp
+++ b/engines/fullpipe/mgm.cpp
@@ -155,10 +155,12 @@ void MGM::rebuildTables(int objId) {
if (!obj)
return;
+ warning("WWW rebuild. idx: %d, size: %d", idx, obj->_staticsList.size() * obj->_staticsList.size());
for (uint i = 0; i < obj->_staticsList.size(); i++) {
_items[idx]->statics.push_back((Statics *)obj->_staticsList[i]);
- _items[idx]->subItems.push_back(new MGMSubItem);
+ for (uint j = 0; j < obj->_staticsList.size(); j++) // Yes, square
+ _items[idx]->subItems.push_back(new MGMSubItem);
}
for (uint i = 0; i < obj->_movements.size(); i++)
@@ -389,9 +391,9 @@ int MGM::countPhases(int idx, int subIdx, int endIdx, int flag) {
if (subIdx < 0)
break;
- res += _items[idx]->subItems[subIdx + endIdx * _items[idx]->statics.size()]->movement->countPhasesWithFlag(-1, flag);
+ res += _items[idx]->subItems[subIdx + endIdx * _items[idx]->statics.size()]->movement->countPhasesWithFlag(0xffffffff, flag);
- subIdx = _items[idx]->subItems[subIdx + 6 * endIdx * _items[idx]->statics.size()]->staticsIndex;
+ subIdx = _items[idx]->subItems[subIdx + endIdx * _items[idx]->statics.size()]->staticsIndex;
}
return res;
@@ -474,7 +476,7 @@ int MGM::getStaticsIndexById(int idx, int16 id) {
return i;
}
- return 0;
+ return -1;
}
int MGM::getStaticsIndex(int idx, Statics *st) {
@@ -486,7 +488,7 @@ int MGM::getStaticsIndex(int idx, Statics *st) {
return i;
}
- return 0;
+ return -1;
}
void MGM::clearMovements2(int idx) {
@@ -502,7 +504,7 @@ int MGM::recalcOffsets(int idx, int st1idx, int st2idx, bool flip, bool flop) {
return 0;
}
- if (item->subItems[subIdx])
+ if (item->subItems[subIdx]->movement)
return item->subItems[subIdx]->field_8;
Common::Point point;
@@ -511,54 +513,59 @@ int MGM::recalcOffsets(int idx, int st1idx, int st2idx, bool flip, bool flop) {
Movement *mov = item->movements1[i];
if (mov->_staticsObj1 == item->statics[st1idx]) {
- if (!item->movements2[i] && (!flop || mov->_field_50)) {
- item->movements2[i] = 1;
+ if (item->movements2[i] || (flop && !mov->_field_50))
+ continue;
- int stidx = getStaticsIndex(idx, item->movements1[i]->_staticsObj2);
- int recalc = recalcOffsets(idx, stidx, st2idx, flip, flop);
- int sz = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size();
- int newsz = sz + item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->field_C;
+ item->movements2[i] = 1;
- if (recalc >= 0) {
- if (!item->subItems[subIdx]->movement || item->subItems[subIdx]->field_8 > recalc + 1 ||
- (item->subItems[subIdx]->field_8 == recalc + 1 && item->subItems[subIdx]->field_C > newsz)) {
- item->subItems[subIdx]->movement = mov;
- item->subItems[subIdx]->staticsIndex = stidx;
- item->subItems[subIdx]->field_8 = recalc + 1;
- item->subItems[subIdx]->field_C = newsz;
+ int stidx = getStaticsIndex(idx, mov->_staticsObj2);
+ int recalc = recalcOffsets(idx, stidx, st2idx, flip, flop);
+ int sz = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size();
+ int newsz = sz + item->subItems[stidx + st2idx * _items[idx]->statics.size()]->field_C;
- mov->calcSomeXY(point, 0, -1);
+ if (recalc < 0)
+ continue;
- item->subItems[subIdx]->x = item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->x + point.x;
- item->subItems[subIdx]->y = item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->y + point.y;
- }
- }
+ if (!item->subItems[subIdx]->movement || item->subItems[subIdx]->field_8 > recalc + 1 ||
+ (item->subItems[subIdx]->field_8 == recalc + 1 && item->subItems[subIdx]->field_C > newsz)) {
+ item->subItems[subIdx]->movement = mov;
+ item->subItems[subIdx]->staticsIndex = stidx;
+ item->subItems[subIdx]->field_8 = recalc + 1;
+ item->subItems[subIdx]->field_C = newsz;
+
+ mov->calcSomeXY(point, 0, -1);
+
+ item->subItems[subIdx]->x = item->subItems[stidx + st2idx * _items[idx]->statics.size()]->x + point.x;
+ item->subItems[subIdx]->y = item->subItems[stidx + st2idx * _items[idx]->statics.size()]->y + point.y;
}
} else if (flip) {
- if (mov->_staticsObj2 == item->statics[st1idx]) {
- if (!item->movements2[i] && (!flop || mov->_field_50)) {
- item->movements2[i] = 1;
+ if (mov->_staticsObj2 != item->statics[st1idx])
+ continue;
- int stidx = getStaticsIndex(idx, mov->_staticsObj1);
- int recalc = recalcOffsets(idx, stidx, st2idx, flip, flop);
+ if (item->movements2[i] || (flop && !mov->_field_50))
+ continue;
- if (recalc >= 0) {
- if (!item->subItems[subIdx]->movement || item->subItems[subIdx]->field_8 > recalc + 1) {
- item->subItems[subIdx]->movement = mov;
- item->subItems[subIdx]->staticsIndex = stidx;
- item->subItems[subIdx]->field_8 = recalc + 1;
+ item->movements2[i] = 1;
- int sz = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size();
+ int stidx = getStaticsIndex(idx, mov->_staticsObj1);
+ int recalc = recalcOffsets(idx, stidx, st2idx, flip, flop);
- item->subItems[subIdx]->field_C = sz + item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->field_C;
+ if (recalc < 0)
+ continue;
- mov->calcSomeXY(point, 0, -1);
+ if (!item->subItems[subIdx]->movement || item->subItems[subIdx]->field_8 > recalc + 1) {
+ item->subItems[subIdx]->movement = mov;
+ item->subItems[subIdx]->staticsIndex = stidx;
+ item->subItems[subIdx]->field_8 = recalc + 1;
- item->subItems[subIdx]->x = item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->x - point.x;
- item->subItems[subIdx]->y = item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->y - point.y;
- }
- }
- }
+ int sz = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size();
+
+ item->subItems[subIdx]->field_C = sz + item->subItems[stidx + st2idx * _items[idx]->statics.size()]->field_C;
+
+ mov->calcSomeXY(point, 0, -1);
+
+ item->subItems[subIdx]->x = item->subItems[stidx + st2idx * _items[idx]->statics.size()]->x - point.x;
+ item->subItems[subIdx]->y = item->subItems[stidx + st2idx * _items[idx]->statics.size()]->y - point.y;
}
}
}
@@ -576,6 +583,7 @@ int MGM::refreshOffsets(int objectId, int idx1, int idx2) {
int from = getStaticsIndexById(idx, idx1);
int to = getStaticsIndexById(idx, idx2);
+ warning("WWW 6, want idx: %d, off: %d", idx, from + to * _items[idx]->statics.size());
MGMSubItem *sub = _items[idx]->subItems[from + to * _items[idx]->statics.size()];
if (sub->movement) {
diff --git a/engines/fullpipe/motion.cpp b/engines/fullpipe/motion.cpp
index 5845ad1501..81424db93a 100644
--- a/engines/fullpipe/motion.cpp
+++ b/engines/fullpipe/motion.cpp
@@ -88,7 +88,7 @@ bool MctlCompound::load(MfcArchive &file) {
for (int i = 0; i < count; i++) {
debug(6, "CompoundArray[%d]", i);
- MctlCompoundArrayItem *obj = new MctlCompoundArrayItem();
+ MctlItem *obj = new MctlItem();
obj->_motionControllerObj = (MotionController *)file.readClass();
@@ -114,14 +114,14 @@ bool MctlCompound::load(MfcArchive &file) {
return true;
}
-void MctlCompound::addObject(StaticANIObject *obj) {
+void MctlCompound::attachObject(StaticANIObject *obj) {
for (uint i = 0; i < _motionControllers.size(); i++)
- _motionControllers[i]->_motionControllerObj->addObject(obj);
+ _motionControllers[i]->_motionControllerObj->attachObject(obj);
}
-int MctlCompound::removeObject(StaticANIObject *obj) {
+int MctlCompound::detachObject(StaticANIObject *obj) {
for (uint i = 0; i < _motionControllers.size(); i++)
- _motionControllers[i]->_motionControllerObj->removeObject(obj);
+ _motionControllers[i]->_motionControllerObj->detachObject(obj);
return 1;
}
@@ -150,12 +150,12 @@ void MctlCompound::initMovGraph2() {
}
}
-void MctlCompound::freeItems() {
+void MctlCompound::detachAllObjects() {
for (uint i = 0; i < _motionControllers.size(); i++)
- _motionControllers[i]->_motionControllerObj->freeItems();
+ _motionControllers[i]->_motionControllerObj->detachAllObjects();
}
-MessageQueue *MctlCompound::method34(StaticANIObject *ani, int sourceX, int sourceY, int fuzzyMatch, int staticsId) {
+MessageQueue *MctlCompound::startMove(StaticANIObject *ani, int sourceX, int sourceY, int fuzzyMatch, int staticsId) {
int idx = -1;
int sourceIdx = -1;
@@ -186,8 +186,9 @@ MessageQueue *MctlCompound::method34(StaticANIObject *ani, int sourceX, int sour
if (sourceIdx == -1)
return 0;
+ warning("WWW 2");
if (idx == sourceIdx)
- return _motionControllers[idx]->_motionControllerObj->method34(ani, sourceX, sourceY, fuzzyMatch, staticsId);
+ return _motionControllers[idx]->_motionControllerObj->startMove(ani, sourceX, sourceY, fuzzyMatch, staticsId);
double dist;
MctlConnectionPoint *cp = findClosestConnectionPoint(ani->_ox, ani->_oy, idx, sourceX, sourceY, sourceIdx, &dist);
@@ -195,7 +196,7 @@ MessageQueue *MctlCompound::method34(StaticANIObject *ani, int sourceX, int sour
if (!cp)
return 0;
- MessageQueue *mq = _motionControllers[idx]->_motionControllerObj->doWalkTo(ani, cp->_connectionX, cp->_connectionY, 1, cp->_field_14);
+ MessageQueue *mq = _motionControllers[idx]->_motionControllerObj->doWalkTo(ani, cp->_connectionX, cp->_connectionY, 1, cp->_mctlmirror);
if (!mq)
return 0;
@@ -264,7 +265,7 @@ MessageQueue *MctlCompound::doWalkTo(StaticANIObject *subj, int xpos, int ypos,
if (!closestP)
return 0;
- MessageQueue *mq = _motionControllers[match1]->_motionControllerObj->doWalkTo(subj, closestP->_connectionX, closestP->_connectionY, 1, closestP->_field_14);
+ MessageQueue *mq = _motionControllers[match1]->_motionControllerObj->doWalkTo(subj, closestP->_connectionX, closestP->_connectionY, 1, closestP->_mctlmirror);
ExCommand *ex;
@@ -287,7 +288,7 @@ MessageQueue *MctlCompound::doWalkTo(StaticANIObject *subj, int xpos, int ypos,
return mq;
}
-MctlCompoundArrayItem::~MctlCompoundArrayItem() {
+MctlItem::~MctlItem() {
delete _movGraphReactObj;
delete _motionControllerObj;
}
@@ -304,7 +305,7 @@ MctlLadder::MctlLadder() {
}
MctlLadder::~MctlLadder() {
- freeItems();
+ detachAllObjects();
}
int MctlLadder::collisionDetection(StaticANIObject *man) {
@@ -326,7 +327,7 @@ int MctlLadder::collisionDetection(StaticANIObject *man) {
return res;
}
-void MctlLadder::addObject(StaticANIObject *obj) {
+void MctlLadder::attachObject(StaticANIObject *obj) {
if (findObjectPos(obj) < 0) {
MctlLadderMovement *movement = new MctlLadderMovement;
@@ -391,7 +392,7 @@ bool MctlLadder::initMovement(StaticANIObject *ani, MctlLadderMovement *movement
return true;
}
-void MctlLadder::freeItems() {
+void MctlLadder::detachAllObjects() {
_mgm.clear();
for (uint i = 0; i < _ladmovements.size(); i++) {
@@ -402,7 +403,7 @@ void MctlLadder::freeItems() {
_ladmovements.clear();
}
-MessageQueue *MctlLadder::method34(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId) {
+MessageQueue *MctlLadder::startMove(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId) {
MessageQueue *mq = doWalkTo(subj, xpos, ypos, fuzzyMatch, staticsId);
if (mq) {
@@ -661,7 +662,7 @@ void MctlCompound::replaceNodeX(int from, int to) {
node->_x = to;
}
- gr->calcNodeDistancesAndAngles();
+ gr->recalcLinkParams();
}
}
}
@@ -669,10 +670,9 @@ void MctlCompound::replaceNodeX(int from, int to) {
MctlConnectionPoint::MctlConnectionPoint() {
_connectionX = 0;
_connectionY = 0;
- _field_C = 0;
- _field_10 = 0;
- _field_14 = 0;
- _field_16 = 0;
+ _mctlflags = 0;
+ _mctlstatic = 0;
+ _mctlmirror = 0;
_messageQueueObj = 0;
_motionControllerObj = 0;
}
@@ -779,7 +779,7 @@ bool MovGraph::load(MfcArchive &file) {
return true;
}
-void MovGraph::addObject(StaticANIObject *obj) {
+void MovGraph::attachObject(StaticANIObject *obj) {
_mgm.clear();
_mgm.addItem(obj->_id);
@@ -796,13 +796,13 @@ void MovGraph::addObject(StaticANIObject *obj) {
_mgm.addItem(obj->_id); // FIXME: Is it really needed?
}
-int MovGraph::removeObject(StaticANIObject *obj) {
- warning("STUB: MovGraph::removeObject()");
+int MovGraph::detachObject(StaticANIObject *obj) {
+ warning("STUB: MovGraph::detachObject()");
return 0;
}
-void MovGraph::freeItems() {
+void MovGraph::detachAllObjects() {
for (uint i = 0; i < _items.size(); i++) {
_items[i]->free();
@@ -812,7 +812,7 @@ void MovGraph::freeItems() {
_items.clear();
}
-Common::Array<MovItem *> *MovGraph::method28(StaticANIObject *ani, int x, int y, int flag1, int *rescount) {
+Common::Array<MovItem *> *MovGraph::getPaths(StaticANIObject *ani, int x, int y, int flag1, int *rescount) {
*rescount = 0;
if (_items.size() <= 0)
@@ -828,7 +828,7 @@ Common::Array<MovItem *> *MovGraph::method28(StaticANIObject *ani, int x, int y,
}
_items[idx]->free();
- calcNodeDistancesAndAngles();
+ recalcLinkParams();
_items[idx]->movarr._movSteps.clear();
@@ -837,8 +837,8 @@ Common::Array<MovItem *> *MovGraph::method28(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))
- findClosestLink(idx, &point, &_items[idx]->movarr);
+ if (!getHitPoint(idx, ani->_ox, ani->_oy, &_items[idx]->movarr, 0))
+ getNearestPoint(idx, &point, &_items[idx]->movarr);
_items[idx]->count = 0;
@@ -846,19 +846,19 @@ Common::Array<MovItem *> *MovGraph::method28(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;
@@ -873,12 +873,12 @@ Common::Array<MovItem *> *MovGraph::method28(StaticANIObject *ani, int x, int y,
return 0;
}
-bool MovGraph::method2C(StaticANIObject *obj, int x, int y) {
+bool MovGraph::setPosImmediate(StaticANIObject *obj, int x, int y) {
obj->setOXY(x, y);
- return method3C(obj, 1);
+ return resetPosition(obj, 1);
}
-MessageQueue *MovGraph::method34(StaticANIObject *ani, int xpos, int ypos, int fuzzyMatch, int staticsId) {
+MessageQueue *MovGraph::startMove(StaticANIObject *ani, int xpos, int ypos, int fuzzyMatch, int staticsId) {
if (!ani) {
if (!_items.size())
return 0;
@@ -896,7 +896,7 @@ MessageQueue *MovGraph::method34(StaticANIObject *ani, int xpos, int ypos, int f
return 0;
int count;
- Common::Array<MovItem *> *movitems = method28(ani, xpos, ypos, fuzzyMatch, &count);
+ Common::Array<MovItem *> *movitems = getPaths(ani, xpos, ypos, fuzzyMatch, &count);
if (!movitems)
return 0;
@@ -941,9 +941,9 @@ MessageQueue *MovGraph::method34(StaticANIObject *ani, int xpos, int ypos, int f
int count2;
ani->setSomeDynamicPhaseIndex(ex->_field_14);
- method28(ani, xpos, ypos, fuzzyMatch, &count2);
+ getPaths(ani, xpos, ypos, fuzzyMatch, &count2);
- int idx = getItemIndexByStaticAni(ani);
+ int idx = getObjectIndex(ani);
count = _items[idx]->count;
movitems = _items[idx]->movitems;
}
@@ -951,12 +951,12 @@ MessageQueue *MovGraph::method34(StaticANIObject *ani, int xpos, int ypos, int f
return method50(ani, _callback1(ani, movitems, count), staticsId);
}
-void MovGraph::changeCallback(MovArr *(*callback1)(StaticANIObject *ani, Common::Array<MovItem *> *items, signed int counter)) {
+void MovGraph::setSelFunc(MovArr *(*callback1)(StaticANIObject *ani, Common::Array<MovItem *> *items, signed int counter)) {
_callback1 = callback1;
}
-bool MovGraph::method3C(StaticANIObject *ani, int flag) {
- int idx = getItemIndexByStaticAni(ani);
+bool MovGraph::resetPosition(StaticANIObject *ani, int flag) {
+ int idx = getObjectIndex(ani);
if (idx == -1)
return false;
@@ -967,7 +967,7 @@ bool MovGraph::method3C(StaticANIObject *ani, int flag) {
point.x = ani->_ox;
point.y = ani->_oy;
- findClosestLink(idx, &point, &movarr);
+ getNearestPoint(idx, &point, &movarr);
ani->setOXY(point.x, point.y);
if (flag) {
@@ -990,15 +990,15 @@ bool MovGraph::method3C(StaticANIObject *ani, int flag) {
return true;
}
-bool MovGraph::method44(StaticANIObject *ani, int x, int y) {
- int idx = getItemIndexByStaticAni(ani);
+bool MovGraph::canDropInventory(StaticANIObject *ani, int x, int y) {
+ int idx = getObjectIndex(ani);
MovArr m;
if (idx != -1) {
if (x != -1 || y != -1) {
int counter;
- Common::Array<MovItem *> *movitem = method28(ani, x, y, 0, &counter);
+ Common::Array<MovItem *> *movitem = getPaths(ani, x, y, 0, &counter);
if (movitem) {
MovArr *movarr = _callback1(ani, movitem, counter);
@@ -1009,7 +1009,7 @@ bool MovGraph::method44(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;
}
}
@@ -1021,13 +1021,13 @@ MessageQueue *MovGraph::doWalkTo(StaticANIObject *subj, int xpos, int ypos, int
PicAniInfo picAniInfo;
int ss;
- Common::Array<MovItem *> *movitem = method28(subj, xpos, ypos, fuzzyMatch, &ss);
+ Common::Array<MovItem *> *movitem = getPaths(subj, xpos, ypos, fuzzyMatch, &ss);
subj->getPicAniInfo(&picAniInfo);
if (movitem) {
MovArr *goal = _callback1(subj, movitem, ss);
- int idx = getItemIndexByStaticAni(subj);
+ int idx = getObjectIndex(subj);
for (int i = 0; i < _items[idx]->count; i++) {
if ((*_items[idx]->movitems)[i]->movarr == goal) {
@@ -1052,10 +1052,10 @@ MessageQueue *MovGraph::doWalkTo(StaticANIObject *subj, int xpos, int ypos, int
}
}
- movitem = method28(subj, xpos, ypos, fuzzyMatch, &ss);
+ movitem = getPaths(subj, xpos, ypos, fuzzyMatch, &ss);
if (movitem) {
MovArr *goal = _callback1(subj, movitem, ss);
- int idx = getItemIndexByStaticAni(subj);
+ int idx = getObjectIndex(subj);
if (_items[idx]->count > 0) {
int arridx = 0;
@@ -1075,7 +1075,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;
@@ -1106,7 +1106,7 @@ MessageQueue *MovGraph::sub1(StaticANIObject *ani, int x, int y, int stid, int x
int rescount;
- Common::Array<MovItem *> *movitems = method28(ani, x1, y1, flag1, &rescount);
+ Common::Array<MovItem *> *movitems = getPaths(ani, x1, y1, flag1, &rescount);
if (!movitems) {
ani->setPicAniInfo(&picinfo);
@@ -1117,7 +1117,7 @@ MessageQueue *MovGraph::sub1(StaticANIObject *ani, int x, int y, int stid, int x
MessageQueue *res = 0;
MovArr *goal = _callback1(ani, movitems, rescount);
- int idx = getItemIndexByStaticAni(ani);
+ int idx = getObjectIndex(ani);
MovGraphItem *movgitem = _items[idx];
int cnt = movgitem->count;
@@ -1130,7 +1130,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;
}
@@ -1141,7 +1141,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;
@@ -1177,16 +1177,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->_distance;
+ nd = st->link->_graphSrc->_z;
} else {
if (st->sfield_0) {
- nx = st->link->_movGraphNode1->_x;
- ny = st->link->_movGraphNode1->_y;
- nd = st->link->_movGraphNode1->_distance;
+ 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->_distance;
+ nx = st->link->_graphDst->_x;
+ ny = st->link->_graphDst->_y;
+ nd = st->link->_graphDst->_z;
}
}
@@ -1262,7 +1262,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,24 +1284,24 @@ MessageQueue *MovGraph::method50(StaticANIObject *ani, MovArr *movarr, int stati
return mq;
}
-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;
+double MovGraph::putToLink(Common::Point *point, MovGraphLink *link, int fuzzyMatch) {
+ 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 dist1y = (double)(point->y - n1y);
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->_distance / dist1;
+ double dist1 = sqrt(dist1x * dist1x + dist1y * dist1y);
+ double dist2 = (dist2y * dist1y + dist2x * dist1x) / link->_length / dist1;
double distm = dist2 * dist1;
double res = sqrt(1.0 - dist2 * dist2) * dist1;
- if (dist2 <= 0.0 || distm >= link->_distance) {
+ if (dist2 <= 0.0 || distm >= link->_length) {
if (fuzzyMatch) {
if (dist2 > 0.0) {
- if (distm >= link->_distance) {
+ if (distm >= link->_length) {
point->x = n2x;
point->y = n2y;
}
@@ -1313,14 +1313,14 @@ double MovGraph::calcDistance(Common::Point *point, MovGraphLink *link, int fuzz
return -1.0;
}
} else {
- point->x = (int)(n1x + (dist2x * distm / link->_distance));
- point->y = (int)(n1y + (dist2y * distm / link->_distance));
+ point->x = (int)(n1x + (dist2x * distm / link->_length));
+ point->y = (int)(n1y + (dist2y * distm / link->_length));
}
return res;
}
-void MovGraph::calcNodeDistancesAndAngles() {
+void MovGraph::recalcLinkParams() {
for (ObList::iterator i = _links.begin(); i != _links.end(); ++i) {
assert(((CObject *)*i)->_objtype == kObjTypeMovGraphLink);
@@ -1328,11 +1328,11 @@ void MovGraph::calcNodeDistancesAndAngles() {
lnk->_flags &= 0x7FFFFFFF;
- lnk->calcNodeDistanceAndAngle();
+ lnk->recalcLength();
}
}
-bool MovGraph::findClosestLink(int unusedArg, Common::Point *p, MovArr *movarr) {
+bool MovGraph::getNearestPoint(int unusedArg, Common::Point *p, MovArr *movarr) {
MovGraphLink *link = 0;
double mindist = 1.0e20;
int resx = 0, resy = 0;
@@ -1341,14 +1341,14 @@ bool MovGraph::findClosestLink(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->_distance / sq1;
+ double sdist = (dy3 * dy1 + dx3 * dx1) / lnk->_length / sq1;
double ldist = sdist * sq1;
double dist = sqrt(1.0 - sdist * sdist) * sq1;
@@ -1357,14 +1357,14 @@ bool MovGraph::findClosestLink(int unusedArg, Common::Point *p, MovArr *movarr)
dist = sqrt(dx1 * dx1 + dy1 * dy1);
}
- if (ldist > lnk->_distance) {
- ldist = lnk->_distance;
+ if (ldist > lnk->_length) {
+ ldist = lnk->_length;
dist = sqrt(dx2 * dx2 + dy2 * dy2);
}
- if (ldist >= 0.0 && ldist <= lnk->_distance && dist < mindist) {
- resx = lnk->_movGraphNode1->_x + (int)(dx3 * ldist / lnk->_distance);
- resy = lnk->_movGraphNode1->_y + (int)(dy3 * ldist / lnk->_distance);
+ 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;
@@ -1387,7 +1387,7 @@ bool MovGraph::findClosestLink(int unusedArg, Common::Point *p, MovArr *movarr)
return false;
}
-int MovGraph::getItemIndexByStaticAni(StaticANIObject *ani) {
+int MovGraph::getObjectIndex(StaticANIObject *ani) {
for (uint i = 0; i < _items.size(); i++)
if (_items[i]->ani == ani)
return i;
@@ -1395,7 +1395,7 @@ int MovGraph::getItemIndexByStaticAni(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;
@@ -1410,15 +1410,15 @@ Common::Array<MovArr *> *MovGraph::genMovArr(int x, int y, int *arrSize, int fla
if (flag1) {
Common::Point point(x, y);
- double dist = calcDistance(&point, lnk, 0);
+ double dist = putToLink(&point, lnk, 0);
if (dist >= 0.0 && dist < 2.0) {
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->_distance / lnk->_distance;
+ 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);
@@ -1431,27 +1431,27 @@ 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->_distance / lnk->_distance;
+ 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;
- calcDistance(&movarr->_point, lnk, 0);
+ putToLink(&movarr->_point, lnk, 0);
arr->push_back(movarr);
}
@@ -1479,9 +1479,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;
}
}
@@ -1495,7 +1495,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;
@@ -1531,7 +1531,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) {
@@ -1545,10 +1545,10 @@ 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 findClosestLink(idx, 0, arr);
+ return getNearestPoint(idx, 0, arr);
bool res = false;
@@ -1582,20 +1582,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;
@@ -1634,6 +1634,7 @@ int MovGraph2::getItemSubIndexByMGM(int index, StaticANIObject *ani) {
int min = 0;
for (int i = 0; i < 4; i++) {
+ warning("WWW 5");
int tmp = _mgm.refreshOffsets(ani->_id, ani->_statics->_staticsId, _items2[index]->_subItems[i]._staticsId1);
if (tmp >= 0 && (minidx == -1 || tmp < min)) {
@@ -1777,8 +1778,8 @@ bool MovGraph2::initDirections(StaticANIObject *obj, MovGraph2Item *item) {
return true;
}
-void MovGraph2::addObject(StaticANIObject *obj) {
- MovGraph::addObject(obj);
+void MovGraph2::attachObject(StaticANIObject *obj) {
+ MovGraph::attachObject(obj);
int id = getItemIndexByGameObjectId(obj->_id);
@@ -2031,26 +2032,27 @@ MessageQueue *MovGraph2::buildMovInfo1MessageQueue(MovInfo1 *movInfo) {
return mq;
}
-int MovGraph2::removeObject(StaticANIObject *obj) {
- warning("STUB: MovGraph2::removeObject()");
+int MovGraph2::detachObject(StaticANIObject *obj) {
+ warning("STUB: MovGraph2::detachObject()");
return 0;
}
-void MovGraph2::freeItems() {
+void MovGraph2::detachAllObjects() {
for (uint i = 0; i < _items2.size(); i++)
delete _items2[i];
_items2.clear();
}
-MessageQueue *MovGraph2::method34(StaticANIObject *ani, int xpos, int ypos, int fuzzyMatch, int staticsId) {
+MessageQueue *MovGraph2::startMove(StaticANIObject *ani, int xpos, int ypos, int fuzzyMatch, int staticsId) {
if (!ani->isIdle())
return 0;
if (ani->_flags & 0x100)
return 0;
+ warning("WWW 3");
MessageQueue *mq = doWalkTo(ani, xpos, ypos, fuzzyMatch, staticsId);
if (!mq)
@@ -2119,6 +2121,7 @@ MessageQueue *MovGraph2::doWalkTo(StaticANIObject *obj, int xpos, int ypos, int
bool subMgm = false;
if (idxsub == -1) {
+ warning("WWW 4");
idxsub = getItemSubIndexByMGM(idx, obj);
subMgm = true;
@@ -2240,9 +2243,9 @@ MessageQueue *MovGraph2::doWalkTo(StaticANIObject *obj, int xpos, int ypos, int
int dx2, dy2;
if (linkInfoSource.node)
- movInfo1.distance1 = linkInfoSource.node->_distance;
+ movInfo1.distance1 = linkInfoSource.node->_z;
else
- movInfo1.distance1 = linkInfoSource.link->_movGraphNode1->_distance;
+ movInfo1.distance1 = linkInfoSource.link->_graphSrc->_z;
if (linkInfoDest.node) {
dx2 = linkInfoDest.node->_x;
@@ -2251,18 +2254,18 @@ MessageQueue *MovGraph2::doWalkTo(StaticANIObject *obj, int xpos, int ypos, int
movInfo1.pt2.x = linkInfoDest.node->_x;
movInfo1.pt2.y = linkInfoDest.node->_y;
- movInfo1.distance2 = linkInfoDest.node->_distance;
+ movInfo1.distance2 = linkInfoDest.node->_z;
} else {
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->_distance - nod->_distance;
+ int dst = linkInfoDest.link->_graphDst->_z - nod->_z;
- movInfo1.distance2 = (int)(nod->_distance + (dst1 * (double)dst / linkInfoDest.link->_distance));
+ movInfo1.distance2 = (int)(nod->_z + (dst1 * (double)dst / linkInfoDest.link->_length));
- calcDistance(&movInfo1.pt2, linkInfoDest.link, 1);
+ putToLink(&movInfo1.pt2, linkInfoDest.link, 1);
dx1 = movInfo1.pt1.x;
dy1 = movInfo1.pt1.y;
@@ -2350,7 +2353,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);
@@ -2361,16 +2364,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;
}
@@ -2381,10 +2384,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;
}
}
@@ -2397,8 +2400,8 @@ int MovGraph2::findLink(Common::Array<MovGraphLink *> *linkList, int idx, Common
rect->bottom = node2->_y;
}
if (point) {
- point->x = node3->_distance;
- point->y = node2->_distance;
+ point->x = node3->_z;
+ point->y = node2->_z;
}
if (abs(node3->_x - node2->_x) <= abs(node3->_y - node2->_y))
@@ -2620,13 +2623,13 @@ MovGraphLink *MovGraph2::findLink1(int x, int y, int idx, int fuzzyMatch) {
if (fuzzyMatch) {
point.x = x;
point.y = y;
- double dst = calcDistance(&point, lnk, 0);
+ double dst = putToLink(&point, lnk, 0);
if (dst >= 0.0 && dst < 2.0)
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;
@@ -2652,14 +2655,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->_distance / dst1;
+ double coeff1 = ((n1y - n2y) * n1dy + (n2x - n1x) * n1dx) / lnk->_length / dst1;
double dst3 = coeff1 * dst1;
double dst2 = sqrt(1.0 - coeff1 * coeff1) * dst1;
@@ -2667,11 +2670,11 @@ MovGraphLink *MovGraph2::findLink2(int x, int y) {
dst3 = 0.0;
dst2 = sqrt(n1dy * n1dy + n1dx * n1dx);
}
- if (dst3 > lnk->_distance) {
- dst3 = lnk->_distance;
+ if (dst3 > lnk->_length) {
+ dst3 = lnk->_length;
dst2 = sqrt((n2x - x) * (n2x - x) + (n2y - y) * (n2y - y));
}
- if (dst3 >= 0.0 && dst3 <= lnk->_distance && dst2 < mindist) {
+ if (dst3 >= 0.0 && dst3 <= lnk->_length && dst2 < mindist) {
mindist = dst2;
res = lnk;
}
@@ -2694,7 +2697,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;
@@ -2704,18 +2707,18 @@ double MovGraph2::findMinPath(LinkInfo *linkInfoSource, LinkInfo *linkInfoDest,
double newDistance = findMinPath(&linkInfoWorkSource, linkInfoDest, &tmpList);
- if (newDistance >= 0.0 && (minDistance < 0.0 || newDistance + lnk->_distance < minDistance)) {
+ if (newDistance >= 0.0 && (minDistance < 0.0 || newDistance + lnk->_length < minDistance)) {
listObj->clear();
listObj->push_back(tmpList);
- minDistance = newDistance + lnk->_distance;
+ 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;
@@ -2732,7 +2735,7 @@ double MovGraph2::findMinPath(LinkInfo *linkInfoSource, LinkInfo *linkInfoDest,
}
linkInfoWorkSource.link = 0;
- linkInfoWorkSource.node = linkInfoSource->link->_movGraphNode2;
+ linkInfoWorkSource.node = linkInfoSource->link->_graphDst;
tmpList.clear();
@@ -2775,11 +2778,11 @@ MovGraphNode *MovGraph::calcOffset(int ox, int oy) {
}
MovGraphLink::MovGraphLink() {
- _distance = 0;
+ _length = 0;
_angle = 0;
_flags = 0x10000000;
- _movGraphNode2 = 0;
- _movGraphNode1 = 0;
+ _graphDst = 0;
+ _graphSrc = 0;
_field_3C = 0;
_field_38 = 0;
_movGraphReact = 0;
@@ -2805,14 +2808,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();
- _distance = file.readDouble();
+ _length = file.readDouble();
_angle = file.readDouble();
- debug(8, "distance: %g, angle: %g", _distance, _angle);
+ debug(8, "length: %g, angle: %g", _length, _angle);
_movGraphReact = (MovGraphReact *)file.readClass();
_name = file.readPascalString();
@@ -2820,12 +2823,12 @@ bool MovGraphLink::load(MfcArchive &file) {
return true;
}
-void MovGraphLink::calcNodeDistanceAndAngle() {
- if (_movGraphNode1) {
- double dx = _movGraphNode2->_x - _movGraphNode1->_x;
- double dy = _movGraphNode2->_y - _movGraphNode1->_y;
+void MovGraphLink::recalcLength() {
+ if (_graphSrc) {
+ double dx = _graphDst->_x - _graphSrc->_x;
+ double dy = _graphDst->_y - _graphSrc->_y;
- _distance = sqrt(dy * dy + dx * dx);
+ _length = sqrt(dy * dy + dx * dx);
_angle = atan2(dx, dy);
}
}
@@ -2836,7 +2839,7 @@ bool MovGraphNode::load(MfcArchive &file) {
_field_14 = file.readUint32LE();
_x = file.readUint32LE();
_y = file.readUint32LE();
- _distance = file.readUint32LE();
+ _z = file.readUint32LE();
return true;
}
@@ -3032,7 +3035,7 @@ int startWalkTo(int objId, int objKey, int x, int y, int fuzzyMatch) {
MctlCompound *mc = getCurrSceneSc2MotionController();
if (mc)
- return (mc->method34(g_fp->_currentScene->getStaticANIObject1ById(objId, objKey), x, y, fuzzyMatch, 0) != 0);
+ return (mc->startMove(g_fp->_currentScene->getStaticANIObject1ById(objId, objKey), x, y, fuzzyMatch, 0) != 0);
return 0;
}
@@ -3042,7 +3045,7 @@ bool doSomeAnimation(int objId, int objKey, int a3) {
MctlCompound *cmp = getCurrSceneSc2MotionController();
if (ani && cmp)
- return cmp->method3C(ani, a3);
+ return cmp->resetPosition(ani, a3);
return false;
}
diff --git a/engines/fullpipe/motion.h b/engines/fullpipe/motion.h
index c488039e22..41860e32d0 100644
--- a/engines/fullpipe/motion.h
+++ b/engines/fullpipe/motion.h
@@ -48,19 +48,19 @@ public:
virtual bool load(MfcArchive &file);
virtual void methodC() {}
virtual void method10() {}
- virtual void clearEnabled() { _isEnabled = false; }
- virtual void setEnabled() { _isEnabled = true; }
- virtual void addObject(StaticANIObject *obj) {}
- virtual int removeObject(StaticANIObject *obj) { return 0; }
- virtual void freeItems() {}
- virtual Common::Array<MovItem *> *method28(StaticANIObject *ani, int x, int y, int flag1, int *rescount) { return 0; }
- virtual bool method2C(StaticANIObject *obj, int x, int y) { return false; }
+ virtual void deactivate() { _isEnabled = false; }
+ virtual void activate() { _isEnabled = true; }
+ virtual void attachObject(StaticANIObject *obj) {}
+ virtual int detachObject(StaticANIObject *obj) { return 0; }
+ virtual void detachAllObjects() {}
+ virtual Common::Array<MovItem *> *getPaths(StaticANIObject *ani, int x, int y, int flag1, int *rescount) { return 0; }
+ virtual bool setPosImmediate(StaticANIObject *obj, int x, int y) { return false; }
virtual int method30() { return 0; }
- virtual MessageQueue *method34(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId) { return 0; }
- virtual void changeCallback(MovArr *(*_callback1)(StaticANIObject *ani, Common::Array<MovItem *> *items, signed int counter)) {}
- virtual bool method3C(StaticANIObject *ani, int flag) { return 0; }
+ virtual MessageQueue *startMove(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId) { return 0; }
+ virtual void setSelFunc(MovArr *(*_callback1)(StaticANIObject *ani, Common::Array<MovItem *> *items, signed int counter)) {}
+ virtual bool resetPosition(StaticANIObject *ani, int flag) { return 0; }
virtual int method40() { return 0; }
- virtual bool method44(StaticANIObject *ani, int x, int y) { return false; }
+ virtual bool canDropInventory(StaticANIObject *ani, int x, int y) { return false; }
virtual int method48() { return -1; }
virtual MessageQueue *doWalkTo(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId) { return 0; }
@@ -82,7 +82,7 @@ public:
virtual bool pointInRegion(int x, int y);
};
-class MctlCompoundArrayItem : public CObject {
+class MctlItem : public CObject {
public:
MotionController *_motionControllerObj;
MovGraphReact *_movGraphReactObj;
@@ -92,11 +92,11 @@ public:
int _field_28;
public:
- MctlCompoundArrayItem() : _movGraphReactObj(0), _motionControllerObj(0), _field_20(0), _field_24(0), _field_28(0) {}
- ~MctlCompoundArrayItem();
+ MctlItem() : _movGraphReactObj(0), _motionControllerObj(0), _field_20(0), _field_24(0), _field_28(0) {}
+ ~MctlItem();
};
-class MctlCompoundArray : public Common::Array<MctlCompoundArrayItem *>, public CObject {
+class MctlCompoundArray : public Common::Array<MctlItem *>, public CObject {
public:
virtual bool load(MfcArchive &file);
};
@@ -109,10 +109,10 @@ public:
virtual bool load(MfcArchive &file);
- virtual void addObject(StaticANIObject *obj);
- virtual int removeObject(StaticANIObject *obj);
- virtual void freeItems();
- virtual MessageQueue *method34(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId);
+ virtual void attachObject(StaticANIObject *obj);
+ virtual int detachObject(StaticANIObject *obj);
+ virtual void detachAllObjects();
+ virtual MessageQueue *startMove(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId);
virtual MessageQueue *doWalkTo(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId);
void initMovGraph2();
@@ -156,10 +156,10 @@ public:
virtual ~MctlLadder();
int collisionDetection(StaticANIObject *man);
- virtual void addObject(StaticANIObject *obj);
- virtual int removeObject(StaticANIObject *obj) { return 1; }
- virtual void freeItems();
- virtual MessageQueue *method34(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId);
+ virtual void attachObject(StaticANIObject *obj);
+ virtual int detachObject(StaticANIObject *obj) { return 1; }
+ virtual void detachAllObjects();
+ virtual MessageQueue *startMove(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId);
virtual MessageQueue *doWalkTo(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId);
MessageQueue *controllerWalkTo(StaticANIObject *ani, int off);
@@ -173,12 +173,12 @@ class MovGraphNode : public CObject {
public:
int _x;
int _y;
- int _distance;
+ int _z;
int16 _field_10;
int _field_14;
public:
- MovGraphNode() : _x(0), _y(0), _distance(0), _field_10(0), _field_14(0) { _objtype = kObjTypeMovGraphNode; }
+ MovGraphNode() : _x(0), _y(0), _z(0), _field_10(0), _field_14(0) { _objtype = kObjTypeMovGraphNode; }
virtual bool load(MfcArchive &file);
};
@@ -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 _distance;
+ double _length;
double _angle;
MovGraphReact *_movGraphReact;
char *_name;
@@ -236,7 +236,7 @@ class MovGraphLink : public CObject {
virtual bool load(MfcArchive &file);
- void calcNodeDistanceAndAngle();
+ void recalcLength();
};
struct MovStep {
@@ -290,30 +290,30 @@ public:
virtual bool load(MfcArchive &file);
- virtual void addObject(StaticANIObject *obj);
- virtual int removeObject(StaticANIObject *obj);
- virtual void freeItems();
- virtual Common::Array<MovItem *> *method28(StaticANIObject *ani, int x, int y, int flag1, int *rescount);
- virtual bool method2C(StaticANIObject *obj, int x, int y);
- virtual MessageQueue *method34(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId);
- virtual void changeCallback(MovArr *(*_callback1)(StaticANIObject *ani, Common::Array<MovItem *> *items, signed int counter));
- virtual bool method3C(StaticANIObject *ani, int flag);
- virtual bool method44(StaticANIObject *ani, int x, int y);
+ virtual void attachObject(StaticANIObject *obj);
+ virtual int detachObject(StaticANIObject *obj);
+ virtual void detachAllObjects();
+ virtual Common::Array<MovItem *> *getPaths(StaticANIObject *ani, int x, int y, int flag1, int *rescount);
+ virtual bool setPosImmediate(StaticANIObject *obj, int x, int y);
+ virtual MessageQueue *startMove(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId);
+ virtual void setSelFunc(MovArr *(*_callback1)(StaticANIObject *ani, Common::Array<MovItem *> *items, signed int counter));
+ virtual bool resetPosition(StaticANIObject *ani, int flag);
+ virtual bool canDropInventory(StaticANIObject *ani, int x, int y);
virtual MessageQueue *doWalkTo(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId);
virtual MessageQueue *method50(StaticANIObject *ani, MovArr *movarr, int staticsId);
- double calcDistance(Common::Point *point, MovGraphLink *link, int fuzzyMatch);
- void calcNodeDistancesAndAngles();
- bool findClosestLink(int unusedArg, Common::Point *p, MovArr *movarr);
+ double putToLink(Common::Point *point, MovGraphLink *link, int fuzzyMatch);
+ void recalcLinkParams();
+ bool getNearestPoint(int unusedArg, Common::Point *p, MovArr *movarr);
MovGraphNode *calcOffset(int ox, int oy);
- int getItemIndexByStaticAni(StaticANIObject *ani);
- Common::Array<MovArr *> *genMovArr(int x, int y, int *arrSize, int flag1, int flag2);
+ int getObjectIndex(StaticANIObject *ani);
+ 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);
};
@@ -374,10 +374,10 @@ public:
Common::Array<MovGraph2Item *> _items2;
public:
- virtual void addObject(StaticANIObject *obj);
- virtual int removeObject(StaticANIObject *obj);
- virtual void freeItems();
- virtual MessageQueue *method34(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId);
+ virtual void attachObject(StaticANIObject *obj);
+ virtual int detachObject(StaticANIObject *obj);
+ virtual void detachAllObjects();
+ virtual MessageQueue *startMove(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId);
virtual MessageQueue *doWalkTo(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId);
int getItemIndexByGameObjectId(int objectId);
@@ -404,10 +404,9 @@ class MctlConnectionPoint : public CObject {
public:
int _connectionX;
int _connectionY;
- int _field_C;
- int _field_10;
- int16 _field_14;
- int16 _field_16;
+ int _mctlflags;
+ int _mctlstatic;
+ int16 _mctlmirror;
MessageQueue *_messageQueueObj;
int _motionControllerObj;
diff --git a/engines/fullpipe/scenes.cpp b/engines/fullpipe/scenes.cpp
index 13c653ad09..32aa955a61 100644
--- a/engines/fullpipe/scenes.cpp
+++ b/engines/fullpipe/scenes.cpp
@@ -583,8 +583,8 @@ bool FullpipeEngine::sceneSwitcher(EntranceInfo *entrance) {
_aniMan2 = _aniMan;
MctlCompound *cmp = getSc2MctlCompoundBySceneId(entrance->_sceneId);
cmp->initMovGraph2();
- cmp->addObject(_aniMan);
- cmp->setEnabled();
+ cmp->attachObject(_aniMan);
+ cmp->activate();
getGameLoaderInteractionController()->enableFlag24();
setInputDisabled(0);
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/scene04.cpp b/engines/fullpipe/scenes/scene04.cpp
index 4a87ae5b87..6c361d6f1a 100644
--- a/engines/fullpipe/scenes/scene04.cpp
+++ b/engines/fullpipe/scenes/scene04.cpp
@@ -238,7 +238,7 @@ int scene04_updateCursor() {
}
}
- if (g_fp->_objectIdAtCursor == PIC_CSR_ITN && g_fp->_objectIdAtCursor == PIC_SC4_DOWNTRUBA)
+ if (g_fp->_cursorId == PIC_CSR_ITN && g_fp->_objectIdAtCursor == PIC_SC4_DOWNTRUBA)
g_fp->_cursorId = PIC_CSR_GOD;
return g_fp->_cursorId;
@@ -275,7 +275,7 @@ void sceneHandler04_clickButton() {
}
void sceneHandler04_downLadder(int x, int y) {
- g_vars->scene04_ladder->method34(g_fp->_aniMan, x + g_vars->scene04_ladder->_ladder_field_20, y + g_vars->scene04_ladder->_ladder_field_24, 0, 0);
+ g_vars->scene04_ladder->startMove(g_fp->_aniMan, x + g_vars->scene04_ladder->_ladder_field_20, y + g_vars->scene04_ladder->_ladder_field_24, 0, 0);
}
void sceneHandler04_walkClimbLadder(ExCommand *ex) {
@@ -321,7 +321,7 @@ void sceneHandler04_walkClimbLadder(ExCommand *ex) {
g_vars->scene04_ladder->_ladder_field_20 = 0;
g_vars->scene04_ladder->_ladder_field_24 = -60;
- g_vars->scene04_ladder->addObject(g_fp->_aniMan);
+ g_vars->scene04_ladder->attachObject(g_fp->_aniMan);
if (g_vars->scene04_soundPlaying) {
g_vars->scene04_ladder->_ladmovements.front()->movVars->varUpStart = MV_MAN_STARTLADDER2;
@@ -337,7 +337,7 @@ void sceneHandler04_walkClimbLadder(ExCommand *ex) {
g_fp->_aniMan->_priority = 12;
- getSc2MctlCompoundBySceneId(g_fp->_currentScene->_sceneId)->clearEnabled();
+ getSc2MctlCompoundBySceneId(g_fp->_currentScene->_sceneId)->deactivate();
getGameLoaderInteractionController()->disableFlag24();
}
@@ -368,7 +368,7 @@ void sceneHandler04_clickLadder() {
} else {
if (g_fp->_aniMan->isIdle() && !(g_fp->_aniMan->_flags & 0x100)) {
if (abs(1095 - g_vars->scene04_dudePosX) > 1 || abs(434 - g_vars->scene04_dudePosY) > 1) {
- MessageQueue *mq = getSc2MctlCompoundBySceneId(g_fp->_currentScene->_sceneId)->method34(g_fp->_aniMan, 1095, 434, 1, ST_MAN_UP);
+ MessageQueue *mq = getSc2MctlCompoundBySceneId(g_fp->_currentScene->_sceneId)->startMove(g_fp->_aniMan, 1095, 434, 1, ST_MAN_UP);
if (mq) {
ExCommand *ex = new ExCommand(0, 17, MSG_SC4_CLICKLADDER, 0, 0, 0, 1, 0, 0, 0);
@@ -533,7 +533,7 @@ void sceneHandler04_manFromBottle() {
g_vars->scene04_ladder = 0;
- getSc2MctlCompoundBySceneId(g_fp->_currentScene->_sceneId)->setEnabled();
+ getSc2MctlCompoundBySceneId(g_fp->_currentScene->_sceneId)->activate();
getGameLoaderInteractionController()->enableFlag24();
}
@@ -1120,7 +1120,7 @@ void sceneHandler04_leaveLadder(ExCommand *ex) {
ex->_messageKind = 0;
- mc->setEnabled();
+ mc->activate();
getGameLoaderInteractionController()->enableFlag24();
} else {
delete mq;
@@ -1275,7 +1275,7 @@ void sceneHandler04_winArcade() {
g_vars->scene04_objectIsTaken = false;
g_vars->scene04_soundPlaying = false;
- getSc2MctlCompoundBySceneId(g_fp->_currentScene->_sceneId)->setEnabled();
+ getSc2MctlCompoundBySceneId(g_fp->_currentScene->_sceneId)->activate();
getGameLoaderInteractionController()->enableFlag24();
diff --git a/engines/fullpipe/scenes/scene06.cpp b/engines/fullpipe/scenes/scene06.cpp
index 06ec20dcb5..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;
}
@@ -118,7 +118,7 @@ void sceneHandler06_winArcade() {
sceneHandler06_setExits(g_fp->_currentScene);
- getCurrSceneSc2MotionController()->setEnabled();
+ getCurrSceneSc2MotionController()->activate();
getGameLoaderInteractionController()->enableFlag24();
}
@@ -300,7 +300,7 @@ void sceneHandler06_startAiming() {
if (getCurrSceneSc2MotionController()->_isEnabled)
g_fp->_updateScreenCallback = sceneHandler06_updateScreenCallback;
- getCurrSceneSc2MotionController()->clearEnabled();
+ getCurrSceneSc2MotionController()->deactivate();
getGameLoaderInteractionController()->disableFlag24();
g_vars->scene06_ballDrop->queueMessageQueue(0);
@@ -313,7 +313,7 @@ void sceneHandler06_takeBall() {
|| abs(452 - g_fp->_aniMan->_oy) > 1
|| g_fp->_aniMan->_movement
|| g_fp->_aniMan->_statics->_staticsId != (0x4000 | ST_MAN_RIGHT)) {
- MessageQueue *mq = getCurrSceneSc2MotionController()->method34(g_fp->_aniMan, 1158, 452, 1, (0x4000 | ST_MAN_RIGHT));
+ MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, 1158, 452, 1, (0x4000 | ST_MAN_RIGHT));
if (mq) {
ExCommand *ex = new ExCommand(0, 17, MSG_SC6_TAKEBALL, 0, 0, 0, 1, 0, 0, 0);
@@ -562,7 +562,7 @@ int sceneHandler06(ExCommand *ex) {
case MSG_SC6_RESTORESCROLL:
g_fp->_aniMan2 = g_fp->_aniMan;
- getCurrSceneSc2MotionController()->setEnabled();
+ getCurrSceneSc2MotionController()->activate();
getGameLoaderInteractionController()->enableFlag24();
sceneHandler06_setExits(g_fp->_currentScene);
break;
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/scene08.cpp b/engines/fullpipe/scenes/scene08.cpp
index a5f5a8b389..d64df8688e 100644
--- a/engines/fullpipe/scenes/scene08.cpp
+++ b/engines/fullpipe/scenes/scene08.cpp
@@ -224,7 +224,7 @@ void sceneHandler08_startArcade() {
g_vars->scene08_onBelly = false;
getGameLoaderInteractionController()->disableFlag24();
- getCurrSceneSc2MotionController()->clearEnabled();
+ getCurrSceneSc2MotionController()->deactivate();
g_vars->scene08_batuta->stopAnim_maybe();
@@ -276,7 +276,7 @@ void sceneHandler08_finishArcade() {
g_vars->scene08_inArcade = false;
getGameLoaderInteractionController()->enableFlag24();
- getCurrSceneSc2MotionController()->setEnabled();
+ getCurrSceneSc2MotionController()->activate();
}
void sceneHandler08_jumpOff(ExCommand *cmd) {
diff --git a/engines/fullpipe/scenes/scene09.cpp b/engines/fullpipe/scenes/scene09.cpp
index 99cf0b20fd..ffe8a1b2de 100644
--- a/engines/fullpipe/scenes/scene09.cpp
+++ b/engines/fullpipe/scenes/scene09.cpp
@@ -271,7 +271,7 @@ void sceneHandler09_spitterClick() {
g_vars->scene09_spitter->setPicAniInfo(&info);
if (ABS(x - g_fp->_aniMan->_ox) > 1 || ABS(y - g_fp->_aniMan->_oy) > 1) {
- MessageQueue *mq = getCurrSceneSc2MotionController()->method34(g_fp->_aniMan, x, y, 1, ST_MAN_UP);
+ MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, x, y, 1, ST_MAN_UP);
if (mq) {
ExCommand *ex = new ExCommand(0, 17, MSG_SC9_PLVCLICK, 0, 0, 0, 1, 0, 0, 0);
@@ -602,14 +602,14 @@ int sceneHandler09(ExCommand *cmd) {
break;
case MSG_SC9_FROMLADDER:
- getCurrSceneSc2MotionController()->setEnabled();
+ getCurrSceneSc2MotionController()->activate();
getGameLoaderInteractionController()->enableFlag24();
g_vars->scene09_dudeIsOnLadder = false;
break;
case MSG_SC9_TOLADDER:
- getCurrSceneSc2MotionController()->clearEnabled();
+ getCurrSceneSc2MotionController()->deactivate();
getGameLoaderInteractionController()->disableFlag24();
g_vars->scene09_dudeIsOnLadder = true;
diff --git a/engines/fullpipe/scenes/scene10.cpp b/engines/fullpipe/scenes/scene10.cpp
index 8c9e0b67d0..3e2a918b64 100644
--- a/engines/fullpipe/scenes/scene10.cpp
+++ b/engines/fullpipe/scenes/scene10.cpp
@@ -82,7 +82,7 @@ void sceneHandler10_clickGum() {
int y = g_vars->scene10_gum->_oy - 48;
if (abs(x - g_fp->_aniMan->_ox) > 1 || abs(y - g_fp->_aniMan->_oy) > 1) {
- MessageQueue *mq = getCurrSceneSc2MotionController()->method34(g_fp->_aniMan, x, y, 1, ST_MAN_RIGHT);
+ MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, x, y, 1, ST_MAN_RIGHT);
if (mq) {
ExCommand *ex = new ExCommand(0, 17, MSG_SC10_CLICKGUM, 0, 0, 0, 1, 0, 0, 0);
ex->_excFlags = 2;
diff --git a/engines/fullpipe/scenes/scene11.cpp b/engines/fullpipe/scenes/scene11.cpp
index 0ce82f5d5f..1fa5cabc15 100644
--- a/engines/fullpipe/scenes/scene11.cpp
+++ b/engines/fullpipe/scenes/scene11.cpp
@@ -191,7 +191,7 @@ void sceneHandler11_restartMan() {
chainObjQueue(0, QU_SC11_RESTARTMAN, 1);
getGameLoaderInteractionController()->enableFlag24();
- getCurrSceneSc2MotionController()->setEnabled();
+ getCurrSceneSc2MotionController()->activate();
g_vars->scene11_scrollIsEnabled = false;
}
@@ -234,7 +234,7 @@ int sceneHandler11_updateScreenCallback() {
void sceneHandler11_manToSwing() {
g_vars->scene11_arcadeIsOn = true;
- getCurrSceneSc2MotionController()->clearEnabled();
+ getCurrSceneSc2MotionController()->deactivate();
getGameLoaderInteractionController()->disableFlag24();
g_fp->_aniMan2->hide();
@@ -271,7 +271,7 @@ void sceneHandler11_putABoot() {
void sceneHandler11_putBoot() {
if (abs(353 - g_fp->_aniMan->_ox) > 1 || abs(498 - g_fp->_aniMan->_oy) > 1
|| g_fp->_aniMan->_movement || g_fp->_aniMan->_statics->_staticsId != ST_MAN_RIGHT) {
- MessageQueue *mq = getCurrSceneSc2MotionController()->method34(g_fp->_aniMan, 353, 498, 1, ST_MAN_RIGHT);
+ MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, 353, 498, 1, ST_MAN_RIGHT);
if (mq) {
ExCommand *ex = new ExCommand(0, 17, MSG_SC11_PUTBOOT, 0, 0, 0, 1, 0, 0, 0);
@@ -299,7 +299,7 @@ void sceneHandler11_jumpFromSwing() {
g_vars->scene11_hint->_flags &= 0xFFFB;
g_vars->scene11_scrollIsEnabled = false;
- getCurrSceneSc2MotionController()->setEnabled();
+ getCurrSceneSc2MotionController()->activate();
getGameLoaderInteractionController()->enableFlag24();
g_vars->scene11_swingOldAngle = 0.0;
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 446f477133..d3ba3c345e 100644
--- a/engines/fullpipe/scenes/scene14.cpp
+++ b/engines/fullpipe/scenes/scene14.cpp
@@ -174,7 +174,7 @@ void sceneHandler14_exitScene() {
chainQueue(QU_SC14_ENDARCADE, 0);
getGameLoaderInteractionController()->disableFlag24();
- getCurrSceneSc2MotionController()->clearEnabled();
+ getCurrSceneSc2MotionController()->deactivate();
}
void sceneHandler14_showBallMan() {
@@ -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) {
@@ -284,13 +284,13 @@ void sceneHandler14_endArcade() {
setInputDisabled(0);
getGameLoaderInteractionController()->enableFlag24();
- getCurrSceneSc2MotionController()->setEnabled();
+ 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;
@@ -365,7 +365,7 @@ void sceneHandler14_startArcade() {
g_fp->_aniMan->_priority = 25;
}
- getCurrSceneSc2MotionController()->clearEnabled();
+ getCurrSceneSc2MotionController()->deactivate();
getGameLoaderInteractionController()->disableFlag24();
g_fp->_aniMan2 = 0;
@@ -458,7 +458,7 @@ bool sceneHandler14_arcadeProcessClick(ExCommand *cmd) {
if (cmd->_sceneClickX > 1237)
return false;
- MessageQueue *mq = getCurrSceneSc2MotionController()->method34(g_fp->_aniMan, 1237, 451, 1, 0);
+ MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, 1237, 451, 1, 0);
if (!mq)
return false;
@@ -473,7 +473,7 @@ bool sceneHandler14_arcadeProcessClick(ExCommand *cmd) {
cmd->_messageKind = 0;
- getCurrSceneSc2MotionController()->clearEnabled();
+ getCurrSceneSc2MotionController()->deactivate();
getGameLoaderInteractionController()->disableFlag24();
return true;
}
diff --git a/engines/fullpipe/scenes/scene16.cpp b/engines/fullpipe/scenes/scene16.cpp
index df005950d2..5079863b4e 100644
--- a/engines/fullpipe/scenes/scene16.cpp
+++ b/engines/fullpipe/scenes/scene16.cpp
@@ -298,7 +298,7 @@ void sceneHandler16_drink() {
void sceneHandler16_mugClick() {
if (abs(310 - g_fp->_aniMan->_ox) >= 1 || abs(449 - g_fp->_aniMan->_oy) >= 1
|| g_fp->_aniMan->_movement || g_fp->_aniMan->_statics->_staticsId != ST_MAN_RIGHT) {
- MessageQueue *mq = getCurrSceneSc2MotionController()->method34(g_fp->_aniMan, 310, 449, 1, ST_MAN_RIGHT);
+ MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, 310, 449, 1, ST_MAN_RIGHT);
if (mq) {
ExCommand *ex = new ExCommand(0, 17, MSG_SC16_MUGCLICK, 0, 0, 0, 1, 0, 0, 0);
diff --git a/engines/fullpipe/scenes/scene18and19.cpp b/engines/fullpipe/scenes/scene18and19.cpp
index 4f6677876b..5af7ef9043 100644
--- a/engines/fullpipe/scenes/scene18and19.cpp
+++ b/engines/fullpipe/scenes/scene18and19.cpp
@@ -379,7 +379,7 @@ int scene19_updateCursor() {
void sceneHandler18_clickBoard() {
if (ABS(967 - g_fp->_aniMan->_ox) > 1 || ABS(379 - g_fp->_aniMan->_oy) > 1 || g_fp->_aniMan->_statics->_staticsId != ST_MAN_RIGHT) {
- MessageQueue *mq = getCurrSceneSc2MotionController()->method34(g_fp->_aniMan, 967, 379, 1, ST_MAN_RIGHT);
+ MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, 967, 379, 1, ST_MAN_RIGHT);
ExCommand *ex = new ExCommand(0, 17, MSG_SC18_MANREADY, 0, 0, 0, 1, 0, 0, 0);
ex->_excFlags = 2;
diff --git a/engines/fullpipe/scenes/scene22.cpp b/engines/fullpipe/scenes/scene22.cpp
index 542834b51a..f51469da69 100644
--- a/engines/fullpipe/scenes/scene22.cpp
+++ b/engines/fullpipe/scenes/scene22.cpp
@@ -191,7 +191,7 @@ void sceneHandler22_stoolLogic(ExCommand *cmd) {
xpos = 841;
manId = ST_MAN_RIGHT;
LABEL_31:
- mq = getCurrSceneSc2MotionController()->method34(g_fp->_aniMan, xpos, 449, 1, manId);
+ mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, xpos, 449, 1, manId);
if (!mq)
return;
@@ -278,7 +278,7 @@ void sceneHandler22_stoolLogic(ExCommand *cmd) {
}
}
- mq = getCurrSceneSc2MotionController()->method34(g_fp->_aniMan, 1010, 443, 1, ST_MAN_UP);
+ mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, 1010, 443, 1, ST_MAN_UP);
if (mq) {
mq->addExCommandToEnd(cmd->createClone());
@@ -318,13 +318,13 @@ int sceneHandler22(ExCommand *cmd) {
g_vars->scene22_dudeIsOnStool = false;
g_vars->scene22_interactionIsDisabled = false;
- getCurrSceneSc2MotionController()->setEnabled();
+ getCurrSceneSc2MotionController()->activate();
g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 1);
break;
case MSG_SC22_ONSTOOL:
g_vars->scene22_dudeIsOnStool = true;
- getCurrSceneSc2MotionController()->clearEnabled();
+ getCurrSceneSc2MotionController()->deactivate();
g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 0);
break;
diff --git a/engines/fullpipe/scenes/scene23.cpp b/engines/fullpipe/scenes/scene23.cpp
index ded467e438..d6075c271b 100644
--- a/engines/fullpipe/scenes/scene23.cpp
+++ b/engines/fullpipe/scenes/scene23.cpp
@@ -296,7 +296,7 @@ void sceneHandler23_pushButton(ExCommand *cmd) {
if (g_fp->_msgX == 276 && g_fp->_msgY == 438 )
return;
- MessageQueue *mq = getCurrSceneSc2MotionController()->method34(g_fp->_aniMan, 276, 438, 1, ST_MAN_RIGHT);
+ MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, 276, 438, 1, ST_MAN_RIGHT);
if (mq) {
mq->addExCommandToEnd(cmd->createClone());
@@ -424,7 +424,7 @@ int sceneHandler23(ExCommand *cmd) {
case MSG_SC23_FROMSTOOL:
g_vars->scene23_isOnStool = false;
- getCurrSceneSc2MotionController()->setEnabled();
+ getCurrSceneSc2MotionController()->activate();
getGameLoaderInteractionController()->enableFlag24();
g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 1);
@@ -438,7 +438,7 @@ int sceneHandler23(ExCommand *cmd) {
case MSG_SC23_ONSTOOL:
g_vars->scene23_isOnStool = true;
- getCurrSceneSc2MotionController()->clearEnabled();
+ getCurrSceneSc2MotionController()->deactivate();
getGameLoaderInteractionController()->disableFlag24();
g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 0);
diff --git a/engines/fullpipe/scenes/scene25.cpp b/engines/fullpipe/scenes/scene25.cpp
index a07330f057..07eda73cf2 100644
--- a/engines/fullpipe/scenes/scene25.cpp
+++ b/engines/fullpipe/scenes/scene25.cpp
@@ -153,7 +153,7 @@ void sceneHandler25_enterMan() {
if (g_vars->scene25_waterIsPresent) {
chainQueue(QU_SC25_ENTERUP_WATER, 1);
- getCurrSceneSc2MotionController()->clearEnabled();
+ getCurrSceneSc2MotionController()->deactivate();
} else {
chainQueue(QU_SC25_ENTERUP_FLOOR, 1);
}
diff --git a/engines/fullpipe/scenes/scene26.cpp b/engines/fullpipe/scenes/scene26.cpp
index b9d9161e7d..baed928d00 100644
--- a/engines/fullpipe/scenes/scene26.cpp
+++ b/engines/fullpipe/scenes/scene26.cpp
@@ -257,7 +257,7 @@ void sceneHandler26_clickVent(StaticANIObject *ani, ExCommand *cmd) {
int y = ani->_oy + 61;
if (abs(x - g_fp->_aniMan->_ox) > 1 || abs(y - g_fp->_aniMan->_oy) > 1 || g_fp->_aniMan->_movement || g_fp->_aniMan->_statics->_staticsId != ST_MAN_UP) {
- MessageQueue *mq = getCurrSceneSc2MotionController()->method34(g_fp->_aniMan, x, y, 1, ST_MAN_UP);
+ MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, x, y, 1, ST_MAN_UP);
if (mq) {
ExCommand *ex = new ExCommand(0, 17, MSG_SC26_CLICKVENT, 0, 0, 0, 1, 0, 0, 0);
diff --git a/engines/fullpipe/scenes/scene27.cpp b/engines/fullpipe/scenes/scene27.cpp
index 8ec05caaff..9570d30913 100644
--- a/engines/fullpipe/scenes/scene27.cpp
+++ b/engines/fullpipe/scenes/scene27.cpp
@@ -159,7 +159,7 @@ void sceneHandler27_driverGiveVent() {
g_vars->scene27_driverHasVent = false;
- getCurrSceneSc2MotionController()->setEnabled();
+ getCurrSceneSc2MotionController()->activate();
getGameLoaderInteractionController()->enableFlag24();
g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 1);
@@ -226,7 +226,7 @@ void sceneHandler27_throwBat() {
g_fp->_aniMan->startAnim(MV_MAN27_THROWBET, 0, -1);
- getCurrSceneSc2MotionController()->clearEnabled();
+ getCurrSceneSc2MotionController()->deactivate();
getGameLoaderInteractionController()->disableFlag24();
g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 0);
@@ -247,7 +247,7 @@ void sceneHandler27_clickBat(ExCommand *cmd) {
if (ABS(bx - g_fp->_aniMan->_ox) > 1 || ABS(by - g_fp->_aniMan->_oy) > 1
|| g_fp->_aniMan->_movement || g_fp->_aniMan->_statics->_staticsId != ST_MAN_RIGHT) {
- MessageQueue *mq = getCurrSceneSc2MotionController()->method34(g_fp->_aniMan, bx, by, 1, ST_MAN_RIGHT);
+ MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, bx, by, 1, ST_MAN_RIGHT);
if (mq) {
mq->addExCommandToEnd(cmd->createClone());
@@ -501,7 +501,7 @@ void sceneHandler27_batLogic() {
default:
chainQueue(QU_SC27_RESTARTBETS, 1);
- getCurrSceneSc2MotionController()->setEnabled();
+ getCurrSceneSc2MotionController()->activate();
getGameLoaderInteractionController()->enableFlag24();
g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 1);
diff --git a/engines/fullpipe/scenes/scene28.cpp b/engines/fullpipe/scenes/scene28.cpp
index de5a96e70d..75ba2567b2 100644
--- a/engines/fullpipe/scenes/scene28.cpp
+++ b/engines/fullpipe/scenes/scene28.cpp
@@ -258,7 +258,7 @@ void sceneHandler28_clickLift(int keycode) {
if (abs(x - g_fp->_aniMan->_ox) > 1 || abs(472 - g_fp->_aniMan->_oy) > 1
|| g_fp->_aniMan->_movement
|| g_fp->_aniMan->_statics->_staticsId != ST_MAN_UP) {
- MessageQueue *mq = getCurrSceneSc2MotionController()->method34(g_fp->_aniMan, x, 472, 1, ST_MAN_UP);
+ MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, x, 472, 1, ST_MAN_UP);
if (mq) {
ExCommand *ex = new ExCommand(0, 17, MSG_SC28_CLICKLIFT, 0, 0, 0, 1, 0, 0, 0);
ex->_excFlags |= 3;
diff --git a/engines/fullpipe/scenes/scene29.cpp b/engines/fullpipe/scenes/scene29.cpp
index 222a541554..a03671a4d0 100644
--- a/engines/fullpipe/scenes/scene29.cpp
+++ b/engines/fullpipe/scenes/scene29.cpp
@@ -687,7 +687,7 @@ void sceneHandler29_ballHitCheck() {
void sceneHandler29_manFromL() {
if (g_vars->scene29_manX < 497 && !g_vars->scene29_scrollingDisabled) {
- getCurrSceneSc2MotionController()->setEnabled();
+ getCurrSceneSc2MotionController()->activate();
getGameLoaderInteractionController()->enableFlag24();
g_fp->_aniMan->changeStatics2(ST_MAN_RIGHT | 0x4000);
@@ -700,7 +700,7 @@ void sceneHandler29_manFromL() {
}
void sceneHandler29_manFromR() {
- getCurrSceneSc2MotionController()->setEnabled();
+ getCurrSceneSc2MotionController()->activate();
getGameLoaderInteractionController()->enableFlag24();
chainQueue(QU_SC29_MANFROM_R, 1);
@@ -721,7 +721,7 @@ int sceneHandler29_updateScreenCallback() {
}
void sceneHandler29_manToL() {
- getCurrSceneSc2MotionController()->clearEnabled();
+ getCurrSceneSc2MotionController()->deactivate();
getGameLoaderInteractionController()->disableFlag24();
chainQueue(QU_SC29_MANTO_L, 1);
@@ -737,7 +737,7 @@ void sceneHandler29_manToL() {
}
void sceneHandler29_manToR() {
- getCurrSceneSc2MotionController()->clearEnabled();
+ getCurrSceneSc2MotionController()->deactivate();
getGameLoaderInteractionController()->disableFlag24();
chainQueue(QU_SC29_MANTO_R, 1);
@@ -763,7 +763,7 @@ void sceneHandler29_clickPorter(ExCommand *cmd) {
if (ABS(351 - g_vars->scene29_manX) > 1 || ABS(443 - g_vars->scene29_manY) > 1
|| g_fp->_aniMan->_movement || g_fp->_aniMan->_statics->_staticsId != ST_MAN_RIGHT) {
if (g_fp->_msgX != 351 || g_fp->_msgY != 443) {
- MessageQueue *mq = getCurrSceneSc2MotionController()->method34(g_fp->_aniMan, 351, 443, 1, ST_MAN_RIGHT);
+ MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, 351, 443, 1, ST_MAN_RIGHT);
if (mq) {
mq->addExCommandToEnd(cmd->createClone());
@@ -781,7 +781,7 @@ void sceneHandler29_clickPorter(ExCommand *cmd) {
if (ABS(1582 - g_vars->scene29_manX) > 1 || ABS(445 - g_fp->_aniMan->_oy) > 1
|| g_fp->_aniMan->_movement || g_fp->_aniMan->_statics->_staticsId != (0x4000 | ST_MAN_RIGHT)) {
if (g_fp->_msgX != 1582 || g_fp->_msgY != 445) {
- MessageQueue *mq = getCurrSceneSc2MotionController()->method34(g_fp->_aniMan, 1582, 445, 1, (0x4000 | ST_MAN_RIGHT));
+ MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, 1582, 445, 1, (0x4000 | ST_MAN_RIGHT));
if (mq) {
mq->addExCommandToEnd(cmd->createClone());
@@ -1001,7 +1001,7 @@ int sceneHandler29(ExCommand *cmd) {
g_vars->scene29_reachedFarRight = false;
g_vars->scene29_rideBackEnabled = false;
- getCurrSceneSc2MotionController()->setEnabled();
+ getCurrSceneSc2MotionController()->activate();
getGameLoaderInteractionController()->enableFlag24();
break;
diff --git a/engines/fullpipe/scenes/scene32.cpp b/engines/fullpipe/scenes/scene32.cpp
index 9279db7513..05b78efb3d 100644
--- a/engines/fullpipe/scenes/scene32.cpp
+++ b/engines/fullpipe/scenes/scene32.cpp
@@ -189,7 +189,7 @@ void sceneHandler32_trySit(ExCommand *cmd) {
g_vars->scene32_dudeIsSitting = true;
- getCurrSceneSc2MotionController()->clearEnabled();
+ getCurrSceneSc2MotionController()->deactivate();
getGameLoaderInteractionController()->disableFlag24();
}
}
@@ -236,7 +236,7 @@ void sceneHandler32_ladderLogic(ExCommand *cmd) {
g_vars->scene32_dudeOnLadder = false;
- getCurrSceneSc2MotionController()->setEnabled();
+ getCurrSceneSc2MotionController()->activate();
getGameLoaderInteractionController()->enableFlag24();
}
@@ -258,7 +258,7 @@ void sceneHandler32_potLogic(ExCommand *cmd) {
mq->setFlags(mq->getFlags() | 1);
mq->chain(0);
- getCurrSceneSc2MotionController()->setEnabled();
+ getCurrSceneSc2MotionController()->activate();
getGameLoaderInteractionController()->enableFlag24();
g_vars->scene32_dudeIsSitting = false;
@@ -330,7 +330,7 @@ int sceneHandler32(ExCommand *cmd) {
case MSG_SC32_ONLADDER:
g_vars->scene32_dudeOnLadder = true;
- getCurrSceneSc2MotionController()->clearEnabled();
+ getCurrSceneSc2MotionController()->deactivate();
getGameLoaderInteractionController()->disableFlag24();
break;
diff --git a/engines/fullpipe/scenes/scene34.cpp b/engines/fullpipe/scenes/scene34.cpp
index 1c8c8b4855..32fb192756 100644
--- a/engines/fullpipe/scenes/scene34.cpp
+++ b/engines/fullpipe/scenes/scene34.cpp
@@ -115,7 +115,7 @@ int scene34_updateCursor() {
}
void sceneHandler34_leaveBoard() {
- getCurrSceneSc2MotionController()->setEnabled();
+ getCurrSceneSc2MotionController()->activate();
getGameLoaderInteractionController()->enableFlag24();
g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 1);
@@ -124,7 +124,7 @@ void sceneHandler34_leaveBoard() {
}
void sceneHandler34_onBoard() {
- getCurrSceneSc2MotionController()->clearEnabled();
+ getCurrSceneSc2MotionController()->deactivate();
getGameLoaderInteractionController()->disableFlag24();
g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 0);
@@ -149,7 +149,7 @@ void sceneHandler34_hideStool() {
}
void sceneHandler34_climb() {
- getCurrSceneSc2MotionController()->clearEnabled();
+ getCurrSceneSc2MotionController()->deactivate();
getGameLoaderInteractionController()->disableFlag24();
g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 0);
@@ -287,7 +287,7 @@ void sceneHandler34_showStool() {
}
void sceneHandler34_unclimb() {
- getCurrSceneSc2MotionController()->setEnabled();
+ getCurrSceneSc2MotionController()->activate();
getGameLoaderInteractionController()->enableFlag24();
g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 1);
@@ -323,7 +323,7 @@ int sceneHandler34(ExCommand *cmd) {
case MSG_SC34_FROMCACTUS:
g_vars->scene34_dudeOnCactus = false;
- getCurrSceneSc2MotionController()->setEnabled();
+ getCurrSceneSc2MotionController()->activate();
getGameLoaderInteractionController()->enableFlag24();
g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 1);
@@ -381,7 +381,7 @@ int sceneHandler34(ExCommand *cmd) {
case MSG_SC34_ONCACTUS:
g_vars->scene34_dudeOnCactus = true;
- getCurrSceneSc2MotionController()->clearEnabled();
+ getCurrSceneSc2MotionController()->deactivate();
getGameLoaderInteractionController()->disableFlag24();
g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 0);
diff --git a/engines/fullpipe/scenes/sceneFinal.cpp b/engines/fullpipe/scenes/sceneFinal.cpp
index d0040463ef..8b3ecb1025 100644
--- a/engines/fullpipe/scenes/sceneFinal.cpp
+++ b/engines/fullpipe/scenes/sceneFinal.cpp
@@ -97,7 +97,7 @@ void sceneHandlerFinal_goto2() {
void sceneHandlerFinal_startFinal() {
g_vars->sceneFinal_var01 = 1;
- getCurrSceneSc2MotionController()->clearEnabled();
+ getCurrSceneSc2MotionController()->deactivate();
getGameLoaderInteractionController()->disableFlag24();
g_fp->_aniMan2 = 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 de3e1ea728..059fd82e79 100644
--- a/engines/fullpipe/statics.cpp
+++ b/engines/fullpipe/statics.cpp
@@ -106,9 +106,14 @@ bool StepArray::gotoNextPoint() {
}
void StepArray::insertPoints(Common::Point **points, int pointsCount) {
- if (_currPointIndex + pointsCount >= _pointsCount)
+ if (_currPointIndex + pointsCount >= _pointsCount) {
_points = (Common::Point **)realloc(_points, sizeof(Common::Point *) * (_currPointIndex + pointsCount));
+ if (!_points) {
+ error("Out of memory at StepArray::insertPoints()");
+ }
+ }
+
_maxPointIndex = _currPointIndex + pointsCount;
for (int i = 0; i < pointsCount; i++) {
@@ -1571,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;
@@ -1758,8 +1766,8 @@ Common::Point *Movement::calcSomeXY(Common::Point &p, int idx, int dynidx) {
Common::Point point;
_staticsObj1->getSomeXY(point);
- int y1 = _my - point.y;
int x1 = _mx - point.x;
+ int y1 = _my - point.y;
setDynamicPhaseIndex(0);
diff --git a/engines/fullpipe/utils.cpp b/engines/fullpipe/utils.cpp
index 0cc8bd83f4..a7dee2e59c 100644
--- a/engines/fullpipe/utils.cpp
+++ b/engines/fullpipe/utils.cpp
@@ -262,15 +262,11 @@ double MfcArchive::readDouble() {
// http://randomascii.wordpress.com/2012/01/11/tricks-with-the-floating-point-format/
union {
- struct {
- int32 a;
- int32 b;
- } i;
+ byte b[8];
double d;
} tmp;
- tmp.i.a = readUint32LE();
- tmp.i.b = readUint32LE();
+ read(&tmp.b, 8);
return tmp.d;
}
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/gob.h b/engines/gob/gob.h
index aefc63c707..730d393906 100644
--- a/engines/gob/gob.h
+++ b/engines/gob/gob.h
@@ -25,7 +25,6 @@
#include "common/random.h"
#include "common/system.h"
-#include "common/savefile.h"
#include "graphics/pixelformat.h"
@@ -33,10 +32,6 @@
#include "gob/console.h"
-namespace GUI {
-class StaticTextWidget;
-}
-
/**
* This is the namespace of the Gob engine.
*
@@ -75,7 +70,6 @@ class PalAnim;
class Scenery;
class Util;
class SaveLoad;
-class GobConsole;
class PreGob;
#define WRITE_VAR_UINT32(var, val) _vm->_inter->_variables->writeVar32(var, val)
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/script.cpp b/engines/gob/script.cpp
index d6e9841e0a..9298f159a4 100644
--- a/engines/gob/script.cpp
+++ b/engines/gob/script.cpp
@@ -215,7 +215,7 @@ char *Script::readString(int32 length) {
}
byte Script::peekByte(int32 offset) {
- byte v;
+ byte v = 0;
peek(&v, 1, offset);
diff --git a/engines/gob/sound/adlib.cpp b/engines/gob/sound/adlib.cpp
index 1e024d5a50..2a9a716058 100644
--- a/engines/gob/sound/adlib.cpp
+++ b/engines/gob/sound/adlib.cpp
@@ -283,7 +283,12 @@ void AdLib::initOPL() {
_voiceOn [i] = 0;
}
- _opl->reset();
+ /* NOTE: We used to completely reset the OPL here, via _opl->reset(). However,
+ * with the OPL timer change in 73e8ac2a, reset() must not be called while
+ * the callback is still active. With the Gob AdLib rewrite in 03ef6689,
+ * this reset shouldn't be necessary anymore either, since this function
+ * here cleans everything properly anyway. If suddenly a certain piece of
+ * music in a Gob game sounds weird, we need to re-examine that. */
initOperatorVolumes();
resetFreqs();
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 b42cf09245..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"
@@ -69,7 +66,7 @@ GroovieEngine::GroovieEngine(OSystem *syst, const GroovieGameDescription *gd) :
// Initialize the custom debug levels
DebugMan.addDebugChannel(kDebugVideo, "Video", "Debug video and audio playback");
- DebugMan.addDebugChannel(kDebugResource, "Resource", "Debug resouce management");
+ DebugMan.addDebugChannel(kDebugResource, "Resource", "Debug resource management");
DebugMan.addDebugChannel(kDebugScript, "Script", "Debug the scripts");
DebugMan.addDebugChannel(kDebugUnknown, "Unknown", "Report values of unknown data in files");
DebugMan.addDebugChannel(kDebugHotspots, "Hotspots", "Show the hotspots");
@@ -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 a25b19e496..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;
@@ -150,10 +150,9 @@ SaveStateList HopkinsMetaEngine::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);
+ Common::String pattern = Common::String::format("%s.0##", target);
filenames = saveFileMan->listSavefiles(pattern);
- sort(filenames.begin(), filenames.end()); // Sort to get the files in numerical order
Hopkins::hopkinsSavegameHeader header;
@@ -178,6 +177,8 @@ SaveStateList HopkinsMetaEngine::listSaves(const char *target) const {
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
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/POTFILES b/engines/hugo/POTFILES
new file mode 100644
index 0000000000..ff61e12ca5
--- /dev/null
+++ b/engines/hugo/POTFILES
@@ -0,0 +1 @@
+engines/hugo/file.cpp
diff --git a/engines/hugo/detection.cpp b/engines/hugo/detection.cpp
index 3907215746..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;
}
@@ -177,10 +177,9 @@ SaveStateList HugoMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Common::StringArray filenames;
Common::String pattern = target;
- pattern += "-??.SAV";
+ pattern += "-##.SAV";
filenames = saveFileMan->listSavefiles(pattern);
- sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
SaveStateList saveList;
char slot[3];
@@ -217,6 +216,8 @@ SaveStateList HugoMetaEngine::listSaves(const char *target) const {
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
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.cpp b/engines/hugo/file.cpp
index e2633977a8..7a3538ea63 100644
--- a/engines/hugo/file.cpp
+++ b/engines/hugo/file.cpp
@@ -32,6 +32,7 @@
#include "common/savefile.h"
#include "common/textconsole.h"
#include "common/config-manager.h"
+#include "common/translation.h"
#include "graphics/surface.h"
#include "graphics/thumbnail.h"
@@ -294,7 +295,7 @@ bool FileManager::saveGame(const int16 slot, const Common::String &descrip) {
Common::String savegameDescription;
if (slot == -1) {
- GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Save game:", "Save", true);
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
savegameId = dialog->runModalWithCurrentTarget();
savegameDescription = dialog->getResultString();
delete dialog;
@@ -396,7 +397,7 @@ bool FileManager::restoreGame(const int16 slot) {
int16 savegameId;
if (slot == -1) {
- GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Restore game:", "Restore", false);
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false);
savegameId = dialog->runModalWithCurrentTarget();
delete dialog;
} else {
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 4a90722a35..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)
@@ -542,7 +540,7 @@ bool Debugger_EoB::cmdSaveOriginal(int argc, const char **argv) {
debugPrintf("Failure.\n");
}
} else {
- debugPrintf("Syntax: save_original\n (Saves game in original file format to a file which can be used with the orginal game executable.)\n\n");
+ debugPrintf("Syntax: save_original\n (Saves game in original file format to a file which can be used with the original game executable.)\n\n");
}
return true;
@@ -562,7 +560,7 @@ bool Debugger_EoB::cmdSaveOriginal(int argc, const char **argv) {
return true;
}
- debugPrintf("Syntax: save_original <slot>\n (Saves game in original file format to a file which can be used with the orginal game executable.\n A save slot between 0 and 5 must be specified.)\n\n");
+ debugPrintf("Syntax: save_original <slot>\n (Saves game in original file format to a file which can be used with the original game executable.\n A save slot between 0 and 5 must be specified.)\n\n");
return true;
}
diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp
index 95c4accd29..989a45b420 100644
--- a/engines/kyra/detection.cpp
+++ b/engines/kyra/detection.cpp
@@ -242,18 +242,13 @@ SaveStateList KyraMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Kyra::KyraEngine_v1::SaveHeader header;
Common::String pattern = target;
- pattern += ".???";
+ pattern += ".###";
Common::StringArray filenames;
filenames = saveFileMan->listSavefiles(pattern);
- Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
SaveStateList saveList;
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
- // Skip automatic final saves made by EOB for the purpose of party transfer
- if (!scumm_stricmp(file->c_str() + file->size() - 3, "fin"))
- continue;
-
// Obtain the last 3 digits of the filename, since they correspond to the save slot
int slotNum = atoi(file->c_str() + file->size() - 3);
@@ -273,6 +268,8 @@ SaveStateList KyraMetaEngine::listSaves(const char *target) const {
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
diff --git a/engines/kyra/detection_tables.h b/engines/kyra/detection_tables.h
index 2ee0262ef2..773d491423 100644
--- a/engines/kyra/detection_tables.h
+++ b/engines/kyra/detection_tables.h
@@ -1546,7 +1546,7 @@ const KYRAGameDescription adGameDescs[] = {
},
Common::EN_ANY,
Common::kPlatformDOS,
- ADGF_TESTING,
+ ADGF_NO_FLAGS,
GUIO7(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GUIO_RENDEREGA, GUIO_RENDERCGA, GAMEOPTION_EOB_HPGRAPHS)
},
EOB_FLAGS
@@ -1562,7 +1562,7 @@ const KYRAGameDescription adGameDescs[] = {
},
Common::DE_DEU,
Common::kPlatformDOS,
- ADGF_TESTING,
+ ADGF_NO_FLAGS,
GUIO7(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GUIO_RENDEREGA, GUIO_RENDERCGA, GAMEOPTION_EOB_HPGRAPHS)
},
EOB_FLAGS
@@ -1576,10 +1576,10 @@ const KYRAGameDescription adGameDescs[] = {
{ "EOBDATA3.PAK", 0, "3ed915ab5b94d60dbfe1b55379889c51", -1 },
{ 0, 0, 0, 0 }
},
- Common::IT_ITA,
- Common::kPlatformDOS,
- ADGF_TESTING,
- GUIO7(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GUIO_RENDEREGA, GUIO_RENDERCGA, GAMEOPTION_EOB_HPGRAPHS)
+ Common::IT_ITA,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO7(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GUIO_RENDEREGA, GUIO_RENDERCGA, GAMEOPTION_EOB_HPGRAPHS)
},
EOB_FLAGS
},
@@ -1594,7 +1594,7 @@ const KYRAGameDescription adGameDescs[] = {
},
Common::EN_ANY,
Common::kPlatformDOS,
- ADGF_TESTING,
+ ADGF_NO_FLAGS,
GUIO6(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GUIO_RENDEREGA, GAMEOPTION_EOB_HPGRAPHS)
},
EOB2_FLAGS
@@ -1610,7 +1610,7 @@ const KYRAGameDescription adGameDescs[] = {
},
Common::DE_DEU,
Common::kPlatformDOS,
- ADGF_TESTING,
+ ADGF_NO_FLAGS,
GUIO6(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GUIO_RENDEREGA, GAMEOPTION_EOB_HPGRAPHS)
},
EOB2_FLAGS
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/gui.cpp b/engines/kyra/gui.cpp
index e95d78c54d..d9c2f9183d 100644
--- a/engines/kyra/gui.cpp
+++ b/engines/kyra/gui.cpp
@@ -47,23 +47,16 @@ GUI::~GUI() {
}
void GUI::updateSaveFileList(Common::String targetName, bool excludeQuickSaves) {
- Common::String pattern = targetName + ".???";
+ Common::String pattern = targetName + ".###";
Common::StringArray saveFileList = _vm->_saveFileMan->listSavefiles(pattern);
_saveSlots.clear();
for (Common::StringArray::const_iterator i = saveFileList.begin(); i != saveFileList.end(); ++i) {
- char s1 = 0, s2 = 0, s3 = 0;
- s1 = (*i)[i->size() - 3];
- s2 = (*i)[i->size() - 2];
- s3 = (*i)[i->size() - 1];
- if (!Common::isDigit(s1) || !Common::isDigit(s2) || !Common::isDigit(s3))
+ // The last 3 digits of the filename correspond to the save slot.
+ const int slotNum = atoi(i->c_str() + i->size() - 3);
+ if (excludeQuickSaves && slotNum >= 990)
continue;
- s1 -= '0';
- s2 -= '0';
- s3 -= '0';
- if (excludeQuickSaves && s1 == 9 && s2 == 9)
- continue;
- _saveSlots.push_back(s1 * 100 + s2 * 10 + s3);
+ _saveSlots.push_back(slotNum);
}
if (_saveSlots.begin() == _saveSlots.end())
diff --git a/engines/kyra/gui_lol.cpp b/engines/kyra/gui_lol.cpp
index cfdf762bba..5ff0b6a109 100644
--- a/engines/kyra/gui_lol.cpp
+++ b/engines/kyra/gui_lol.cpp
@@ -2219,7 +2219,7 @@ int GUI_LoL::runMenu(Menu &menu) {
int fW = (d->w << 3) - wW;
int fC = 0;
- // LoL doesnt't have default higlighted items. No item should be
+ // LoL doesn't have default higlighted items. No item should be
// highlighted when entering a new menu.
// Instead, the respevtive struct entry is used to determine whether
// a menu has scroll buttons or slider bars.
diff --git a/engines/kyra/gui_v1.cpp b/engines/kyra/gui_v1.cpp
index a75c14b071..92891f71b2 100644
--- a/engines/kyra/gui_v1.cpp
+++ b/engines/kyra/gui_v1.cpp
@@ -200,7 +200,7 @@ void GUI_v1::processHighlights(Menu &menu) {
int mouseY = p.y;
if (_vm->game() == GI_LOL && menu.highlightedItem != 255) {
- // LoL doesnt't have default highlighted items.
+ // LoL doesn't have default highlighted items.
// We use a highlightedItem value of 255 for this.
// With LoL no highlighting should take place unless the
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.cpp b/engines/kyra/sound.cpp
index 3c3aff6ea9..6c0d529f96 100644
--- a/engines/kyra/sound.cpp
+++ b/engines/kyra/sound.cpp
@@ -37,7 +37,7 @@ namespace Kyra {
Sound::Sound(KyraEngine_v1 *vm, Audio::Mixer *mixer)
: _vm(vm), _mixer(mixer), _soundChannels(), _musicEnabled(1),
- _sfxEnabled(true) {
+ _sfxEnabled(true) {
}
Sound::~Sound() {
@@ -165,7 +165,7 @@ bool Sound::allVoiceChannelsPlaying() const {
#pragma mark -
MixedSoundDriver::MixedSoundDriver(KyraEngine_v1 *vm, Audio::Mixer *mixer, Sound *music, Sound *sfx)
- : Sound(vm, mixer), _music(music), _sfx(sfx) {
+ : Sound(vm, mixer), _music(music), _sfx(sfx) {
}
MixedSoundDriver::~MixedSoundDriver() {
@@ -289,16 +289,16 @@ void KyraEngine_v1::snd_playWanderScoreViaMap(int command, int restart) {
//}
if (_flags.platform == Common::kPlatformDOS || _flags.platform == Common::kPlatformMacintosh) {
- assert(command*2+1 < _trackMapSize);
- if (_curMusicTheme != _trackMap[command*2]) {
- if (_trackMap[command*2] != -1 && _trackMap[command*2] != -2)
- snd_playTheme(_trackMap[command*2], -1);
+ assert(command * 2 + 1 < _trackMapSize);
+ if (_curMusicTheme != _trackMap[command * 2]) {
+ if (_trackMap[command * 2] != -1 && _trackMap[command * 2] != -2)
+ snd_playTheme(_trackMap[command * 2], -1);
}
if (command != 1) {
if (_lastMusicCommand != command) {
_sound->haltTrack();
- _sound->playTrack(_trackMap[command*2+1]);
+ _sound->playTrack(_trackMap[command * 2 + 1]);
}
} else {
_sound->beginFadeOut();
@@ -307,8 +307,8 @@ void KyraEngine_v1::snd_playWanderScoreViaMap(int command, int restart) {
if (command == -1) {
_sound->haltTrack();
} else {
- assert(command*2+1 < _trackMapSize);
- if (_trackMap[command*2] != -2 && command != _lastMusicCommand) {
+ assert(command * 2 + 1 < _trackMapSize);
+ if (_trackMap[command * 2] != -2 && command != _lastMusicCommand) {
_sound->haltTrack();
_sound->playTrack(command);
}
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_intern.h b/engines/kyra/sound_intern.h
index 007ca3d3f5..4b77bf1351 100644
--- a/engines/kyra/sound_intern.h
+++ b/engines/kyra/sound_intern.h
@@ -151,7 +151,7 @@ private:
uint8 *_sfxFileData;
uint8 _sfxChannel;
- TownsEuphonyDriver *_driver;
+ EuphonyPlayer *_player;
bool _cdaPlaying;
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 725dedae3f..646f908b94 100644
--- a/engines/kyra/sound_towns.cpp
+++ b/engines/kyra/sound_towns.cpp
@@ -37,13 +37,13 @@ SoundTowns::SoundTowns(KyraEngine_v1 *vm, Audio::Mixer *mixer)
: Sound(vm, mixer), _lastTrack(-1), _musicTrackData(0), _sfxFileData(0), _cdaPlaying(0),
_sfxFileIndex((uint)-1), _musicFadeTable(0), _sfxWDTable(0), _sfxBTTable(0), _sfxChannel(0x46), _currentResourceSet(0) {
memset(&_resInfo, 0, sizeof(_resInfo));
- _driver = new TownsEuphonyDriver(_mixer);
+ _player = new EuphonyPlayer(_mixer);
}
SoundTowns::~SoundTowns() {
g_system->getAudioCDManager()->stop();
haltTrack();
- delete _driver;
+ delete _player;
delete[] _musicTrackData;
delete[] _sfxFileData;
for (int i = 0; i < 3; i++)
@@ -58,21 +58,24 @@ bool SoundTowns::init() {
_sfxBTTable = _vm->staticres()->loadRawData(k1TownsSFXbtTable, unused);
_musicTrackData = new uint8[50570];
- if (!_driver->init())
+ if (!_player->init())
return false;
if (!loadInstruments())
return false;
- _driver->intf()->callback(68);
- _driver->intf()->callback(70, 0x33);
- _driver->setOutputVolume(1, 118, 118);
+ /*_player->driver()->intf()->callback(68);
+ _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) {
@@ -93,9 +96,9 @@ void SoundTowns::playTrack(uint8 track) {
beginFadeOut();
if (_musicEnabled == 2 && trackNum != -1) {
- _driver->setOutputVolume(1, 118, 118);
+ _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,16 +111,16 @@ 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++)
- _driver->chanVolume(i, 0);
+ _player->driver()->channelVolume(i, 0);
for (int i = 0x40; i < 0x46; i++)
- _driver->chanVolume(i, 0);
+ _player->driver()->channelVolume(i, 0);
for (int i = 0; i < 32; i++)
- _driver->configChan_enable(i, 0);
- _driver->stopParser();
+ _player->configPart_enable(i, 0);
+ _player->stop();
}
void SoundTowns::initAudioResourceInfo(int set, void *info) {
@@ -179,11 +182,11 @@ void SoundTowns::playSoundEffect(uint8 track, uint8) {
if (offset == -1)
return;
- if (!_driver->soundEffectIsPlaying(_sfxChannel ^ 1)) {
+ if (!_player->driver()->soundEffectIsPlaying(_sfxChannel ^ 1)) {
_sfxChannel ^= 1;
- } else if (_driver->soundEffectIsPlaying(_sfxChannel)) {
+ } else if (_player->driver()->soundEffectIsPlaying(_sfxChannel)) {
_sfxChannel ^= 1;
- _driver->stopSoundEffect(_sfxChannel);
+ _player->driver()->stopSoundEffect(_sfxChannel);
}
uint32 *sfxHeader = (uint32 *)(fileBody + offset);
@@ -221,57 +224,57 @@ void SoundTowns::playSoundEffect(uint8 track, uint8) {
}
}
- _driver->chanVolume(_sfxChannel, 127);
- _driver->chanPanPos(_sfxChannel, 0x40);
- _driver->chanPitch(_sfxChannel, 0);
- _driver->playSoundEffect(_sfxChannel, note, 127, sfxPlaybackBuffer);
+ _player->driver()->channelVolume(_sfxChannel, 127);
+ _player->driver()->channelPan(_sfxChannel, 0x40);
+ _player->driver()->channelPitch(_sfxChannel, 0);
+ _player->driver()->playSoundEffect(_sfxChannel, note, 127, sfxPlaybackBuffer);
delete[] sfxPlaybackBuffer;
}
void SoundTowns::updateVolumeSettings() {
- if (!_driver)
+ if (!_player)
return;
bool mute = false;
- _driver->setSoundEffectVolume(ConfMan.getInt("sfx_volume"));
+ _player->driver()->setSoundEffectVolume(ConfMan.getInt("sfx_volume"));
if (ConfMan.hasKey("mute"))
mute = ConfMan.getBool("mute");
- _driver->setMusicVolume((mute ? 0 : ConfMan.getInt("music_volume")));
- _driver->setSoundEffectVolume((mute ? 0 : ConfMan.getInt("sfx_volume")));
+ _player->driver()->setMusicVolume((mute ? 0 : ConfMan.getInt("music_volume")));
+ _player->driver()->setSoundEffectVolume((mute ? 0 : ConfMan.getInt("sfx_volume")));
}
void SoundTowns::stopAllSoundEffects() {
- _driver->chanVolume(0x46, 0);
- _driver->chanVolume(0x47, 0);
- _driver->stopSoundEffect(0x46);
- _driver->stopSoundEffect(0x47);
+ _player->driver()->channelVolume(0x46, 0);
+ _player->driver()->channelVolume(0x47, 0);
+ _player->driver()->stopSoundEffect(0x46);
+ _player->driver()->stopSoundEffect(0x47);
_sfxChannel = 0x46;
}
void SoundTowns::beginFadeOut() {
if (_cdaPlaying) {
for (int i = 118; i > 103; i--) {
- _driver->setOutputVolume(1, i, i);
+ _player->driver()->setOutputVolume(1, i, i);
_vm->delay(2 * _vm->tickLength());
}
for (int i = 103; i > 83; i -= 2) {
- _driver->setOutputVolume(1, i, i);
+ _player->driver()->setOutputVolume(1, i, i);
_vm->delay(2 * _vm->tickLength());
}
for (int i = 83; i > 58; i -= 2) {
- _driver->setOutputVolume(1, i, i);
+ _player->driver()->setOutputVolume(1, i, i);
_vm->delay(_vm->tickLength());
}
for (int i = 58; i > 0; i--) {
- _driver->setOutputVolume(1, i, i);
+ _player->driver()->setOutputVolume(1, i, i);
_vm->delay(1);
}
- _driver->setOutputVolume(1, 0, 0);
+ _player->driver()->setOutputVolume(1, 0, 0);
} else {
if (_lastTrack == -1)
@@ -292,9 +295,9 @@ void SoundTowns::beginFadeOut() {
for (int i = 0; i < 12; i++) {
for (int ii = 0; ii < 6; ii++)
- _driver->chanVolume(ii, fadeVolCur[ii]);
+ _player->driver()->channelVolume(ii, fadeVolCur[ii]);
for (int ii = 0x40; ii < 0x46; ii++)
- _driver->chanVolume(ii, fadeVolCur[ii - 0x3A]);
+ _player->driver()->channelVolume(ii, fadeVolCur[ii - 0x3A]);
for (int ii = 0; ii < 6; ii++) {
fadeVolCur[ii] -= fadeVolStep[ii];
@@ -323,20 +326,20 @@ bool SoundTowns::loadInstruments() {
Screen::decodeFrame4(twm, _musicTrackData, 50570);
for (int i = 0; i < 128; i++)
- _driver->loadInstrument(0, i, &_musicTrackData[i * 48 + 8]);
+ _player->driver()->loadInstrument(0, i, &_musicTrackData[i * 48 + 8]);
Screen::decodeFrame4(twm + 3232, _musicTrackData, 50570);
for (int i = 0; i < 32; i++)
- _driver->loadInstrument(0x40, i, &_musicTrackData[i * 128 + 8]);
+ _player->driver()->loadInstrument(0x40, i, &_musicTrackData[i * 128 + 8]);
- _driver->unloadWaveTable(-1);
+ _player->driver()->unloadWaveTable(-1);
uint8 *src = &_musicTrackData[32 * 128 + 8];
for (int i = 0; i < 10; i++) {
- _driver->loadWaveTable(src);
+ _player->driver()->loadWaveTable(src);
src = src + READ_LE_UINT16(&src[12]) + 32;
}
- _driver->reserveSoundEffectChannels(2);
+ _player->driver()->reserveSoundEffectChannels(2);
delete[] twm;
@@ -350,26 +353,26 @@ void SoundTowns::playEuphonyTrack(uint32 offset, int loop) {
const uint8 *src = _musicTrackData + 852;
for (int i = 0; i < 32; i++)
- _driver->configChan_enable(i, *src++);
+ _player->configPart_enable(i, *src++);
for (int i = 0; i < 32; i++)
- _driver->configChan_setMode(i, *src++);
+ _player->configPart_setType(i, *src++);
for (int i = 0; i < 32; i++)
- _driver->configChan_remap(i, *src++);
+ _player->configPart_remap(i, *src++);
for (int i = 0; i < 32; i++)
- _driver->configChan_adjustVolume(i, *src++);
+ _player->configPart_adjustVolume(i, *src++);
for (int i = 0; i < 32; i++)
- _driver->configChan_setTranspose(i, *src++);
+ _player->configPart_setTranspose(i, *src++);
src = _musicTrackData + 1748;
for (int i = 0; i < 6; i++)
- _driver->assignChannel(i, *src++);
+ _player->driver()->assignPartToChannel(i, *src++);
for (int i = 0x40; i < 0x46; i++)
- _driver->assignChannel(i, *src++);
+ _player->driver()->assignPartToChannel(i, *src++);
uint32 trackSize = READ_LE_UINT32(_musicTrackData + 2048);
uint8 startTick = _musicTrackData[2052];
- _driver->setMusicTempo(_musicTrackData[2053]);
+ _player->setTempo(_musicTrackData[2053]);
src = _musicTrackData + 2054;
uint32 l = READ_LE_UINT32(src + trackSize);
@@ -377,14 +380,14 @@ void SoundTowns::playEuphonyTrack(uint32 offset, int loop) {
l = READ_LE_UINT32(src + trackSize);
trackSize += (l + 4);
- _driver->setMusicLoop(loop);
- _driver->startMusicTrack(src, trackSize, startTick);
+ _player->setLoopStatus(loop);
+ _player->startTrack(src, trackSize, startTick);
}
void SoundTowns::fadeOutSoundEffects() {
for (int i = 127; i > 0; i-= 12) {
- _driver->chanVolume(0x46, i);
- _driver->chanVolume(0x47, i);
+ _player->driver()->channelVolume(0x46, i);
+ _player->driver()->channelVolume(0x47, i);
_vm->delay(_vm->tickLength());
}
stopAllSoundEffects();
@@ -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 731f2f4ce5..e99321ddcb 100644
--- a/engines/kyra/staticres.cpp
+++ b/engines/kyra/staticres.cpp
@@ -39,7 +39,7 @@
namespace Kyra {
-#define RESFILE_VERSION 86
+#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
new file mode 100644
index 0000000000..2dc580735e
--- /dev/null
+++ b/engines/lab/anim.cpp
@@ -0,0 +1,355 @@
+/* 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 Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#include "common/file.h"
+
+#include "lab/lab.h"
+
+#include "lab/anim.h"
+#include "lab/dispman.h"
+#include "lab/eventman.h"
+#include "lab/music.h"
+#include "lab/utils.h"
+
+namespace Lab {
+
+Anim::Anim(LabEngine *vm) : _vm(vm) {
+ _lastBlockHeader = 0;
+ _numChunks = 1;
+ _headerdata._width = 0;
+ _headerdata._height = 0;
+ _headerdata._fps = 0;
+ _headerdata._flags = 0;
+ _delayMicros = 0;
+ _continuous = false;
+ _isPlaying = false;
+ _isAnim = false;
+ _isPal = false;
+ _noPalChange = false;
+ _donePal = false;
+ _frameNum = 0;
+ _playOnce = false;
+ _diffFile = nullptr;
+ _diffFileStart = 0;
+ _size = 0;
+ _scrollScreenBuffer = nullptr;
+ _waitForEffect = false;
+ _stopPlayingEnd = false;
+ _sampleSpeed = 0;
+ _doBlack = false;
+
+ for (int i = 0; i < 3 * 256; i++)
+ _diffPalette[i] = 0;
+
+ _outputBuffer = nullptr; // output to screen
+}
+
+Anim::~Anim() {
+ delete[] _vm->_anim->_scrollScreenBuffer;
+ _vm->_anim->_scrollScreenBuffer = nullptr;
+}
+
+void Anim::setOutputBuffer(byte *memoryBuffer) {
+ _outputBuffer = memoryBuffer;
+}
+
+uint16 Anim::getDIFFHeight() {
+ return _headerdata._height;
+}
+
+void Anim::diffNextFrame(bool onlyDiffData) {
+ if (_lastBlockHeader == 65535)
+ // Already done.
+ return;
+
+ bool drawOnScreen = false;
+ byte *startOfBuf = _outputBuffer;
+ int bufPitch = _vm->_graphics->_screenWidth;
+
+ if (!startOfBuf) {
+ startOfBuf = _vm->_graphics->getCurrentDrawingBuffer();
+ drawOnScreen = true;
+ }
+ byte *endOfBuf = startOfBuf + (int)_headerdata._width * _headerdata._height;
+
+ int curBit = 0;
+
+ while (1) {
+ byte *buf = startOfBuf + 0x10000 * curBit;
+
+ if (buf >= endOfBuf) {
+ if (!onlyDiffData) {
+ if (_headerdata._fps) {
+ uint32 targetMillis = _vm->_system->getMillis() + _delayMicros;
+ while (_vm->_system->getMillis() < targetMillis)
+ _vm->_system->delayMillis(10);
+ }
+
+ if (_isPal && !_noPalChange) {
+ _vm->_graphics->setPalette(_diffPalette, 256);
+ _isPal = false;
+ }
+
+ _donePal = true;
+ }
+
+ if (_isPal && !_noPalChange && !onlyDiffData && !_donePal) {
+ _vm->_graphics->setPalette(_diffPalette, 256);
+ _isPal = false;
+ }
+
+ _donePal = false;
+
+ _frameNum++;
+
+ if ((_frameNum == 1) && (_continuous || !_playOnce))
+ _diffFileStart = _diffFile->pos();
+
+ _isAnim = (_frameNum >= 3) && (!_playOnce);
+
+ if (drawOnScreen)
+ _vm->_graphics->screenUpdate();
+
+ // done with the next frame.
+ return;
+ }
+
+ _vm->updateEvents();
+ _lastBlockHeader = _diffFile->readUint32LE();
+ _size = _diffFile->readUint32LE();
+
+ uint32 curPos = 0;
+
+ switch (_lastBlockHeader) {
+ case 8:
+ _diffFile->read(_diffPalette, _size);
+ _isPal = true;
+ break;
+
+ case 10:
+ if (onlyDiffData) {
+ if (curBit > 0)
+ error("diffNextFrame: attempt to read screen to non-zero plane (%d)", curBit);
+ delete[] _scrollScreenBuffer;
+ _scrollScreenBuffer = new byte[_headerdata._width * _headerdata._height];
+ _diffFile->read(_scrollScreenBuffer, _size);
+ } else {
+ _diffFile->read(buf, _size);
+ }
+ curBit++;
+ break;
+
+ case 11:
+ curPos = _diffFile->pos();
+ _diffFile->skip(4);
+ _vm->_utils->runLengthDecode(buf, _diffFile);
+ curBit++;
+ _diffFile->seek(curPos + _size, SEEK_SET);
+ break;
+
+ case 12:
+ curPos = _diffFile->pos();
+ _diffFile->skip(4);
+ _vm->_utils->verticalRunLengthDecode(buf, _diffFile, bufPitch);
+ curBit++;
+ _diffFile->seek(curPos + _size, SEEK_SET);
+ break;
+
+ case 20:
+ curPos = _diffFile->pos();
+ _vm->_utils->unDiff(buf, buf, _diffFile, bufPitch, false);
+ curBit++;
+ _diffFile->seek(curPos + _size, SEEK_SET);
+ break;
+
+ case 21:
+ curPos = _diffFile->pos();
+ _vm->_utils->unDiff(buf, buf, _diffFile, bufPitch, true);
+ curBit++;
+ _diffFile->seek(curPos + _size, SEEK_SET);
+ break;
+
+ case 25:
+ case 26:
+ curBit++;
+ break;
+
+ case 30:
+ case 31:
+ if (_waitForEffect) {
+ while (_vm->_music->isSoundEffectActive()) {
+ _vm->updateEvents();
+ _vm->waitTOF();
+ }
+
+ _waitForEffect = false;
+ }
+
+ _size -= 8;
+
+ _diffFile->skip(4);
+ _sampleSpeed = _diffFile->readUint16LE();
+ _diffFile->skip(2);
+
+ // Sound effects embedded in animations are started here. These are
+ // 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;
+
+ case 65535:
+ if ((_frameNum == 1) || _playOnce || _stopPlayingEnd) {
+ bool didTOF = false;
+
+ if (_waitForEffect) {
+ while (_vm->_music->isSoundEffectActive()) {
+ _vm->updateEvents();
+ _vm->waitTOF();
+
+ if (drawOnScreen)
+ didTOF = true;
+ }
+
+ _waitForEffect = false;
+ }
+
+ _isPlaying = false;
+
+ if (!didTOF)
+ _vm->_graphics->screenUpdate();
+
+ return;
+ }
+
+ // Random frame number so it never gets back to 2
+ _frameNum = 4;
+ _diffFile->seek(_diffFileStart, SEEK_SET);
+ break;
+
+ default:
+ _diffFile->skip(_size);
+ break;
+ }
+ }
+}
+
+void Anim::stopDiff() {
+ if (_isPlaying && _isAnim)
+ _vm->_graphics->blackScreen();
+}
+
+void Anim::stopDiffEnd() {
+ if (!_isPlaying)
+ return;
+
+ _stopPlayingEnd = true;
+ while (_isPlaying) {
+ _vm->updateEvents();
+ diffNextFrame();
+ }
+}
+
+void Anim::readDiff(Common::File *diffFile, bool playOnce, bool onlyDiffData) {
+ _playOnce = playOnce;
+ _delayMicros = 0;
+ _frameNum = 0;
+ _numChunks = 1;
+ _donePal = false;
+ _stopPlayingEnd = false;
+ _isPlaying = true;
+
+ if (_doBlack) {
+ _doBlack = false;
+ _vm->_graphics->blackScreen();
+ }
+
+ _diffFile = diffFile;
+
+ _continuous = false;
+
+ if (!_diffFile)
+ return;
+
+ uint32 magicBytes = _diffFile->readUint32LE();
+ if (magicBytes != 1219009121) {
+ _isPlaying = false;
+ return;
+ }
+
+ uint32 signature3 = _diffFile->readUint32LE();
+ _size = _diffFile->readUint32LE();
+
+ if (signature3 != 0)
+ return;
+
+ // sizeof(headerdata) != 18, but the padding might be at the end
+ // 2 bytes, version, unused.
+ _diffFile->skip(2);
+ _headerdata._width = _diffFile->readUint16LE();
+ _headerdata._height = _diffFile->readUint16LE();
+ // 1 byte, depth, unused
+ _diffFile->skip(1);
+ _headerdata._fps = _diffFile->readByte();
+
+ // HACK: The original game defines a 1 second delay when changing screens, which is
+ // very annoying. We first removed the delay, but it looked wrong when changing screens
+ // as it was possible to see that something was displayed, without being able to tell
+ // what it was. A shorter delay (150ms) makes it acceptable during gameplay and
+ // readable. The big question is: do we need that message?
+ _vm->_system->delayMillis(150);
+
+ if (_headerdata._fps == 1)
+ _headerdata._fps = 0;
+
+ // 4 + 2 bytes, buffer size and machine, unused
+ _diffFile->skip(6);
+ _headerdata._flags = _diffFile->readUint32LE();
+
+ _diffFile->skip(_size - 18);
+
+ _continuous = CONTINUOUS & _headerdata._flags;
+ _vm->_utils->setBytesPerRow(_headerdata._width);
+
+ delete[] _scrollScreenBuffer;
+ _scrollScreenBuffer = nullptr;
+
+ if (_headerdata._fps)
+ _delayMicros = 1000 / _headerdata._fps;
+
+ _lastBlockHeader = signature3;
+ if (_playOnce) {
+ while (_lastBlockHeader != 65535)
+ diffNextFrame(onlyDiffData);
+ } else
+ diffNextFrame(onlyDiffData);
+}
+
+} // End of namespace Lab
diff --git a/engines/lab/anim.h b/engines/lab/anim.h
new file mode 100644
index 0000000000..7006787c61
--- /dev/null
+++ b/engines/lab/anim.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.
+ *
+ */
+
+/*
+ * This code is based on Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#ifndef LAB_ANIM_H
+#define LAB_ANIM_H
+
+namespace Lab {
+
+class LabEngine;
+#define CONTINUOUS 0xFFFF
+
+struct DIFFHeader {
+ uint16 _width;
+ uint16 _height;
+ char _fps;
+ uint32 _flags;
+};
+
+class Anim {
+private:
+ LabEngine *_vm;
+
+ uint32 _lastBlockHeader;
+ uint16 _numChunks;
+ uint32 _delayMicros;
+ bool _continuous;
+ bool _isPlaying;
+ bool _isAnim;
+ bool _isPal;
+ bool _donePal;
+ uint16 _frameNum;
+ bool _playOnce;
+ Common::File *_diffFile;
+ uint32 _diffFileStart;
+ uint32 _size;
+ bool _stopPlayingEnd;
+ uint16 _sampleSpeed;
+
+ byte *_outputBuffer;
+ DIFFHeader _headerdata;
+
+public:
+ Anim(LabEngine *vm);
+ ~Anim();
+
+ char _diffPalette[256 * 3];
+ bool _waitForEffect; // Wait for each sound effect to finish before continuing.
+ bool _doBlack; // Black the screen before new picture
+ bool _noPalChange; // Don't change the palette.
+ byte *_scrollScreenBuffer;
+
+ /**
+ * Reads in a DIFF file.
+ */
+ void setOutputBuffer(byte *memoryBuffer); // nullptr for output to screen
+ void readDiff(Common::File *diffFile, bool playOnce, bool onlyDiffData);
+ void diffNextFrame(bool onlyDiffData = false);
+
+ /**
+ * Stops an animation from running.
+ */
+ void stopDiff();
+
+ /**
+ * Stops an animation from running.
+ */
+ void stopDiffEnd();
+
+ uint16 getDIFFHeight();
+
+ bool isPlaying() const { return _isPlaying; }
+};
+
+} // End of namespace Lab
+
+#endif // LAB_ANIM_H
diff --git a/engines/lab/configure.engine b/engines/lab/configure.engine
new file mode 100644
index 0000000000..3be9545aa6
--- /dev/null
+++ b/engines/lab/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 lab "Labyrinth of Time" yes
diff --git a/engines/lab/console.cpp b/engines/lab/console.cpp
new file mode 100644
index 0000000000..20b1f5645b
--- /dev/null
+++ b/engines/lab/console.cpp
@@ -0,0 +1,138 @@
+/* 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 "gui/debugger.h"
+
+#include "lab/lab.h"
+#include "lab/console.h"
+#include "lab/dispman.h"
+#include "lab/eventman.h"
+#include "lab/music.h"
+#include "lab/processroom.h"
+#include "lab/resource.h"
+
+namespace Lab {
+
+Console::Console(LabEngine *vm) : GUI::Debugger(), _vm(vm) {
+ registerCmd("scene", WRAP_METHOD(Console, Cmd_Scene));
+ registerCmd("scene_resources", WRAP_METHOD(Console, Cmd_DumpSceneResources));
+ registerCmd("find_action", WRAP_METHOD(Console, Cmd_FindAction));
+}
+
+Console::~Console() {
+}
+
+bool Console::Cmd_Scene(int argc, const char **argv) {
+ if (argc != 2) {
+ const char *directions[] = { "North", "South", "East", "West" };
+ debugPrintf("Current scene is %d, direction: %s\n", _vm->_roomNum, directions[_vm->getDirection()]);
+ debugPrintf("Use %s <scene number> to change the current scene\n", argv[0]);
+ return true;
+ }
+
+ _vm->_roomNum = atoi(argv[1]);
+ _vm->_music->checkRoomMusic(1, _vm->_roomNum);
+ _vm->_curFileName = " ";
+ _vm->_closeDataPtr = nullptr;
+ _vm->_mainDisplay = true;
+ _vm->_followingCrumbs = false;
+ _vm->_event->simulateEvent();
+ _vm->_graphics->_longWinInFront = false;
+
+ return false;
+}
+
+bool Console::Cmd_DumpSceneResources(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("Usage: %s <scene number> to dump the resources for a scene\n", argv[0]);
+ return true;
+ }
+
+ int scene = atoi(argv[1]);
+ _vm->_resource->readViews(scene);
+ RoomData *roomData = &_vm->_rooms[scene];
+ RuleList &rules = roomData->_rules;
+ const char *transitions[] = { "None", "Wipe", "ScrollWipe", "ScrollBlack", "ScrollBounce", "Transporter", "ReadFirstFrame", "ReadNextFrame" };
+ const char *ruleTypes[] = { "None", "Action", "Operate", "Go forward", "Conditions", "Turn", "Go main view", "Turn from to" };
+ const char *directions[] = { "", "North", "South", "East", "West" };
+ const char *actionTypes[] = {
+ "", "PlaySound", "PlaySoundLooping", "ShowDiff", "ShowDiffLooping", "LoadDiff", "LoadBitmap", "ShowBitmap", "Transition", "NoUpdate", "ForceUpdate",
+ "ShowCurPict", "SetElement", "UnsetElement", "ShowMessage", "ShowMessages", "ChangeRoom", "SetCloseup", "MainView", "SubInv", "AddInv", "ShowDir",
+ "WaitSecs", "StopMusic", "StartMusic", "ChangeMusic", "ResetMusic", "FillMusic", "WaitSound", "ClearSound", "WinMusic", "WinGame", "LostGame",
+ "ResetBuffer", "SpecialCmd", "CShowMessage", "PlaySoundNoWait"
+ };
+
+ debugPrintf("Room mesage: %s\n", roomData->_roomMsg.c_str());
+ debugPrintf("Transition: %s (%d)\n", transitions[roomData->_transitionType], roomData->_transitionType);
+
+ debugPrintf("Script:\n");
+
+ for (RuleList::iterator rule = rules.begin(); rule != rules.end(); ++rule) {
+ debugPrintf("Rule type: %s", ruleTypes[rule->_ruleType]);
+ if (rule->_ruleType == kRuleTypeAction || rule->_ruleType == kRuleTypeOperate)
+ debugPrintf(" (item %d, closeup %d)", rule->_param1, rule->_param2);
+ else if (rule->_ruleType == kRuleTypeGoForward)
+ debugPrintf(" (%s)", directions[rule->_param1]);
+ else if (rule->_ruleType == kRuleTypeTurnFromTo)
+ debugPrintf(" (from %s to %s)", directions[rule->_param1], directions[rule->_param2]);
+ debugPrintf("\n");
+
+ ActionList::iterator action;
+ for (action = rule->_actionList.begin(); action != rule->_actionList.end(); ++action) {
+ debugPrintf(" - %s ('%s', %d, %d, %d)\n", actionTypes[action->_actionType], action->_messages[0].c_str(), action->_param1, action->_param2, action->_param3);
+ }
+ }
+
+ return true;
+}
+
+bool Console::Cmd_FindAction(int argc, const char **argv) {
+ if (argc < 2) {
+ debugPrintf("Usage: %s <action id> [param 1] [param 2] [param 3]\n", argv[0]);
+ return true;
+ }
+
+ int actionId = atoi(argv[1]);
+ int param1 = (argc > 2) ? atoi(argv[2]) : -1;
+ int param2 = (argc > 3) ? atoi(argv[3]) : -1;
+ int param3 = (argc > 4) ? atoi(argv[4]) : -1;
+
+ for (int i = 1; i <= _vm->_manyRooms; i++) {
+ _vm->_resource->readViews(i);
+
+ for (RuleList::iterator rule = _vm->_rooms[i]._rules.begin(); rule != _vm->_rooms[i]._rules.end(); ++rule) {
+ ActionList::iterator action;
+ for (action = rule->_actionList.begin(); action != rule->_actionList.end(); ++action) {
+ if (action->_actionType == actionId &&
+ (action->_param1 == param1 || param1 == -1) &&
+ (action->_param2 == param2 || param2 == -1) &&
+ (action->_param3 == param3 || param3 == -1)) {
+ debugPrintf("Found at script %d\n", i);
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+} // End of namespace Neverhood
diff --git a/engines/lab/console.h b/engines/lab/console.h
new file mode 100644
index 0000000000..af41b6034b
--- /dev/null
+++ b/engines/lab/console.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 LAB_CONSOLE_H
+#define LAB_CONSOLE_H
+
+#include "gui/debugger.h"
+
+namespace Lab {
+
+class LabEngine;
+
+class Console : public GUI::Debugger {
+public:
+ Console(LabEngine *vm);
+ virtual ~Console(void);
+
+private:
+ LabEngine *_vm;
+
+ bool Cmd_Scene(int argc, const char **argv);
+ bool Cmd_DumpSceneResources(int argc, const char **argv);
+ bool Cmd_FindAction(int argc, const char **argv);
+};
+
+} // End of namespace Lab
+#endif
diff --git a/engines/lab/detection.cpp b/engines/lab/detection.cpp
new file mode 100644
index 0000000000..30890b5acf
--- /dev/null
+++ b/engines/lab/detection.cpp
@@ -0,0 +1,231 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+ /*
+ * This code is based on Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#include "engines/advancedDetector.h"
+
+#include "lab/lab.h"
+
+static const PlainGameDescriptor lab_setting[] = {
+ { "lab", "Labyrinth of Time" },
+ { 0, 0 }
+};
+
+static const ADGameDescription labDescriptions[] = {
+ {
+ "lab",
+ "",
+ {
+ { "doors", 0, "d77536010e7e5ae17ee066323ceb9585", 2537 }, // game/doors
+ { "noteold.fon", 0, "6c1d90ad55149556e79d3f7bfddb4bd7", 9252 }, // game/spict/noteold.fon
+ { NULL, 0, NULL, 0 }
+ },
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO0()
+ },
+ {
+ "lab",
+ "Lowres",
+ {
+ { "doors", 0, "d77536010e7e5ae17ee066323ceb9585", 2537 }, // game/doors
+ { "64b", 0, "3a84d41bcc6a782f22e8e954bce09721", 39916 }, // game/pict/h2/64b
+ { NULL, 0, NULL, 0 }
+ },
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ Lab::GF_LOWRES | ADGF_NO_FLAGS,
+ GUIO0()
+ },
+ {
+ "lab",
+ "Rerelease",
+ {
+ { "doors", 0, "d77536010e7e5ae17ee066323ceb9585", 2537 }, // game/doors
+ { "noteold.fon", 0, "6c1d90ad55149556e79d3f7bfddb4bd7", 9252 }, // game/spict/noteold.fon
+ { "wyrmkeep",0, "97c7064c54c28b952d37c4ebff6efa50", 52286 }, // game/spict/intro
+ { NULL, 0, NULL, 0 }
+ },
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO0()
+ },
+ {
+ "lab",
+ "",
+ AD_ENTRY1s("doors", "7bf458df6ec30cc8ef4665e4d7c77f59", 2537), // game/doors
+ Common::EN_ANY,
+ Common::kPlatformAmiga,
+ Lab::GF_LOWRES | ADGF_UNSTABLE,
+ GUIO0()
+ },
+ AD_TABLE_END_MARKER
+};
+
+static const char *const directoryGlobs[] = {
+ "game",
+ "pict",
+ "spict",
+ "rooms",
+ "h2",
+ "intro",
+ 0
+};
+
+namespace Lab {
+
+Common::Platform LabEngine::getPlatform() const {
+ return _gameDescription->platform;
+}
+
+uint32 LabEngine::getFeatures() const {
+ return _gameDescription->flags | _extraGameFeatures;
+}
+
+} // End of namespace Lab
+
+class LabMetaEngine : public AdvancedMetaEngine {
+public:
+ LabMetaEngine() : AdvancedMetaEngine(labDescriptions, sizeof(ADGameDescription), lab_setting) {
+ _singleId = "lab";
+
+ _maxScanDepth = 4;
+ _directoryGlobs = directoryGlobs;
+ _flags = kADFlagUseExtraAsHint;
+ }
+
+ virtual const char *getName() const {
+ return "Lab";
+ }
+
+ virtual const char *getOriginalCopyright() const {
+ 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 {
+ // Instantiate Engine even if the game data is not found.
+ *engine = new Lab::LabEngine(syst, desc);
+ return true;
+ }
+
+ virtual bool hasFeature(MetaEngineFeature f) const;
+ SaveStateList listSaves(const char *target) const;
+ virtual int getMaximumSaveSlot() const;
+ void removeSaveState(const char *target, int slot) const;
+ SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
+};
+
+bool LabMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsListSaves) ||
+ (f == kSupportsLoadingDuringStartup) ||
+ (f == kSupportsDeleteSave) ||
+ (f == kSavesSupportMetaInfo) ||
+ (f == kSavesSupportThumbnail) ||
+ (f == kSavesSupportCreationDate) ||
+ (f == kSavesSupportPlayTime);
+}
+
+bool Lab::LabEngine::hasFeature(EngineFeature f) const {
+ return
+ (f == kSupportsRTL) ||
+ (f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsSavingDuringRuntime);
+}
+
+SaveStateList LabMetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Lab::SaveGameHeader header;
+ Common::String pattern = target;
+ pattern += ".###";
+
+ Common::StringArray filenames;
+ filenames = saveFileMan->listSavefiles(pattern.c_str());
+
+ SaveStateList saveList;
+
+ 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);
+
+ if ((slotNum >= 0) && (slotNum <= 999)) {
+ Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
+ if (in) {
+ if (Lab::readSaveGameHeader(in, header))
+ saveList.push_back(SaveStateDescriptor(slotNum, header._descr.getDescription()));
+ delete in;
+ }
+ }
+ }
+
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
+ return saveList;
+}
+
+int LabMetaEngine::getMaximumSaveSlot() const {
+ return 999;
+}
+
+void LabMetaEngine::removeSaveState(const char *target, int slot) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ saveFileMan->removeSavefile(Common::String::format("%s.%03u", target, slot));
+}
+
+SaveStateDescriptor LabMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
+ Common::String filename = Common::String::format("%s.%03u", target, slot);
+ Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(filename.c_str());
+
+ if (in) {
+ Lab::SaveGameHeader header;
+
+ bool successfulRead = Lab::readSaveGameHeader(in, header);
+ delete in;
+
+ if (successfulRead) {
+ SaveStateDescriptor desc(slot, header._descr.getDescription());
+ // Do not allow save slot 0 (used for auto-saving) to be deleted or
+ // overwritten.
+ //desc.setDeletableFlag(slot != 0);
+ //desc.setWriteProtectedFlag(slot == 0);
+
+ return header._descr;
+ }
+ }
+
+ return SaveStateDescriptor();
+}
+
+#if PLUGIN_ENABLED_DYNAMIC(LAB)
+ REGISTER_PLUGIN_DYNAMIC(LAB, PLUGIN_TYPE_ENGINE, LabMetaEngine);
+#else
+ REGISTER_PLUGIN_STATIC(LAB, PLUGIN_TYPE_ENGINE, LabMetaEngine);
+#endif
diff --git a/engines/lab/dispman.cpp b/engines/lab/dispman.cpp
new file mode 100644
index 0000000000..d642f2fed5
--- /dev/null
+++ b/engines/lab/dispman.cpp
@@ -0,0 +1,961 @@
+/* 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 Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#include "common/file.h"
+#include "graphics/palette.h"
+
+#include "lab/lab.h"
+
+#include "lab/anim.h"
+#include "lab/dispman.h"
+#include "lab/eventman.h"
+#include "lab/music.h"
+#include "lab/image.h"
+#include "lab/interface.h"
+#include "lab/resource.h"
+#include "lab/utils.h"
+
+namespace Lab {
+
+DisplayMan::DisplayMan(LabEngine *vm) : _vm(vm) {
+ _longWinInFront = false;
+ _lastMessageLong = false;
+ _actionMessageShown = false;
+
+ _screenBytesPerPage = 0;
+ _curBitmap = nullptr;
+ _displayBuffer = nullptr;
+ _currentDisplayBuffer = nullptr;
+ _fadePalette = nullptr;
+
+ _screenWidth = 0;
+ _screenHeight = 0;
+
+ for (int i = 0; i < 256 * 3; i++)
+ _curVgaPal[i] = 0;
+}
+
+DisplayMan::~DisplayMan() {
+ freePict();
+ delete[] _displayBuffer;
+}
+
+void DisplayMan::loadPict(const Common::String filename) {
+ freePict();
+ _curBitmap = _vm->_resource->openDataFile(filename, MKTAG('D', 'I', 'F', 'F'));
+}
+
+void DisplayMan::loadBackPict(const Common::String fileName, uint16 *highPal) {
+ _fadePalette = highPal;
+ _vm->_anim->_noPalChange = true;
+ readPict(fileName);
+
+ for (int i = 0; i < 16; i++) {
+ highPal[i] = ((_vm->_anim->_diffPalette[i * 3] >> 2) << 8) +
+ ((_vm->_anim->_diffPalette[i * 3 + 1] >> 2) << 4) +
+ ((_vm->_anim->_diffPalette[i * 3 + 2] >> 2));
+ }
+
+ _vm->_anim->_noPalChange = false;
+}
+
+void DisplayMan::readPict(const Common::String filename, bool playOnce, bool onlyDiffData, byte *memoryBuffer) {
+ _vm->_anim->stopDiff();
+ loadPict(filename);
+ _vm->_anim->setOutputBuffer(memoryBuffer);
+ _vm->_anim->readDiff(_curBitmap, playOnce, onlyDiffData);
+}
+
+void DisplayMan::freePict() {
+ delete _curBitmap;
+ _curBitmap = nullptr;
+}
+
+Common::String DisplayMan::getWord(const char *mainBuffer) {
+ Common::String result;
+
+ for (int i = 0; mainBuffer[i] && (mainBuffer[i] != ' ') && (mainBuffer[i] != '\n'); i++)
+ result += mainBuffer[i];
+
+ return result;
+}
+
+Common::String DisplayMan::getLine(TextFont *tf, const char **mainBuffer, uint16 lineWidth) {
+ uint16 curWidth = 0;
+ Common::String result;
+
+ while ((*mainBuffer)[0]) {
+ Common::String wordBuffer = getWord(*mainBuffer);
+
+ if ((curWidth + textLength(tf, wordBuffer)) <= lineWidth) {
+ result += wordBuffer;
+ (*mainBuffer) += wordBuffer.size();
+
+ // end of line
+ if ((*mainBuffer)[0] == '\n') {
+ (*mainBuffer)++;
+ break;
+ }
+
+ // append any space after the word
+ if ((*mainBuffer)[0]) {
+ result += (*mainBuffer)[0];
+ (*mainBuffer)++;
+ }
+
+ curWidth = textLength(tf, result);
+ } else
+ break;
+ }
+
+ return result;
+}
+
+int DisplayMan::flowText(TextFont *font, int16 spacing, byte penColor, byte backPen,
+ bool fillBack, bool centerh, bool centerv, bool output, Common::Rect textRect, const char *str, Image *targetImage) {
+
+ byte *saveDisplayBuffer = _currentDisplayBuffer;
+
+ if (targetImage) {
+ _currentDisplayBuffer = targetImage->_imageData;
+ assert(_screenBytesPerPage == (uint32)(targetImage->_width * targetImage->_height));
+ }
+
+ if (fillBack)
+ rectFill(textRect, backPen);
+
+ if (!str)
+ return 0;
+
+ const char *orig = str;
+
+ TextFont *msgFont = font;
+ uint16 fontHeight = textHeight(msgFont) + spacing;
+ uint16 numLines = (textRect.height() + 1) / fontHeight;
+ uint16 width = textRect.width() + 1;
+ uint16 y = textRect.top;
+
+ if (centerv && output) {
+ const char *temp = str;
+ uint16 actlines = 0;
+
+ while (temp[0]) {
+ getLine(msgFont, &temp, width);
+ actlines++;
+ }
+
+ if (actlines <= numLines)
+ y += ((textRect.height() + 1) - (actlines * fontHeight)) / 2;
+ }
+
+ while (numLines && str[0]) {
+ Common::String lineBuffer;
+ lineBuffer = getLine(msgFont, &str, width);
+
+ uint16 x = textRect.left;
+
+ if (centerh)
+ x += (width - textLength(msgFont, lineBuffer)) / 2;
+
+ if (output)
+ drawText(msgFont, x, y, penColor, lineBuffer);
+
+ numLines--;
+ y += fontHeight;
+ }
+
+ _currentDisplayBuffer = saveDisplayBuffer;
+
+ return (str - orig);
+}
+
+void DisplayMan::createBox(uint16 y2) {
+ // Message box area
+ rectFillScaled(4, 154, 315, y2 - 2, 7);
+
+ // Box around message area
+ drawHLine(_vm->_utils->vgaScaleX(2), _vm->_utils->vgaScaleY(152), _vm->_utils->vgaScaleX(317), 0);
+ drawVLine(_vm->_utils->vgaScaleX(317), _vm->_utils->vgaScaleY(152), _vm->_utils->vgaScaleY(y2), 0);
+ drawHLine(_vm->_utils->vgaScaleX(2), _vm->_utils->vgaScaleY(y2), _vm->_utils->vgaScaleX(317), 0);
+ drawVLine(_vm->_utils->vgaScaleX(2), _vm->_utils->vgaScaleY(152), _vm->_utils->vgaScaleY(y2), 0);
+}
+
+int DisplayMan::longDrawMessage(Common::String str, bool isActionMessage) {
+ if (isActionMessage) {
+ _actionMessageShown = true;
+ } else if (_actionMessageShown) {
+ _actionMessageShown = false;
+ return 0;
+ }
+
+ if (str.empty())
+ return 0;
+
+ _vm->_interface->attachButtonList(nullptr);
+
+ if (!_longWinInFront) {
+ _longWinInFront = true;
+ // Clear Area
+ rectFill(0, _vm->_utils->vgaScaleY(149) + _vm->_utils->svgaCord(2), _vm->_utils->vgaScaleX(319), _vm->_utils->vgaScaleY(199), 3);
+ }
+
+ createBox(198);
+
+ return flowText(_vm->_msgFont, 0, 1, 7, false, true, true, true, _vm->_utils->vgaRectScale(6, 155, 313, 195), str.c_str());
+}
+
+void DisplayMan::drawMessage(Common::String str, bool isActionMessage) {
+ if (isActionMessage) {
+ _actionMessageShown = true;
+ } else if (_actionMessageShown) {
+ _actionMessageShown = false;
+ return;
+ }
+
+ if (str.empty())
+ return;
+
+ if ((textLength(_vm->_msgFont, str) > _vm->_utils->vgaScaleX(306))) {
+ longDrawMessage(str, isActionMessage);
+ _lastMessageLong = true;
+ } else {
+ if (_longWinInFront) {
+ _longWinInFront = false;
+ drawPanel();
+ }
+
+ createBox(168);
+ drawText(_vm->_msgFont, _vm->_utils->vgaScaleX(7), _vm->_utils->vgaScaleY(155) + _vm->_utils->svgaCord(2), 1, str);
+ _lastMessageLong = false;
+ }
+}
+
+void DisplayMan::drawPanel() {
+ // Clear Area
+ rectFill(0, _vm->_utils->vgaScaleY(149) + _vm->_utils->svgaCord(2), _vm->_utils->vgaScaleX(319), _vm->_utils->vgaScaleY(199), 3);
+
+ // First Line
+ drawHLine(0, _vm->_utils->vgaScaleY(149) + _vm->_utils->svgaCord(2), _vm->_utils->vgaScaleX(319), 0);
+ // Second Line
+ drawHLine(0, _vm->_utils->vgaScaleY(149) + 1 + _vm->_utils->svgaCord(2), _vm->_utils->vgaScaleX(319), 5);
+ // Button Separators
+ drawHLine(0, _vm->_utils->vgaScaleY(170), _vm->_utils->vgaScaleX(319), 0);
+
+ if (!_vm->_alternate) {
+ // The horizontal lines under the black one
+ drawHLine(0, _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleX(319), 4);
+ _vm->_interface->drawButtonList(&_vm->_moveButtonList);
+ } else {
+ if (_vm->getPlatform() != Common::kPlatformWindows) {
+ // Vertical Black lines
+ drawVLine(_vm->_utils->vgaScaleX(124), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleY(199), 0);
+ drawVLine(_vm->_utils->vgaScaleX(194), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleY(199), 0);
+ } else {
+ // Vertical Black lines
+ drawVLine(_vm->_utils->vgaScaleX(90), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleY(199), 0);
+ drawVLine(_vm->_utils->vgaScaleX(160), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleY(199), 0);
+ drawVLine(_vm->_utils->vgaScaleX(230), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleY(199), 0);
+ }
+
+ // The horizontal lines under the black one
+ drawHLine(0, _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleX(122), 4);
+ drawHLine(_vm->_utils->vgaScaleX(126), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleX(192), 4);
+ drawHLine(_vm->_utils->vgaScaleX(196), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleX(319), 4);
+ // The vertical high light lines
+ drawVLine(_vm->_utils->vgaScaleX(1), _vm->_utils->vgaScaleY(170) + 2, _vm->_utils->vgaScaleY(198), 4);
+
+ if (_vm->getPlatform() != Common::kPlatformWindows) {
+ drawVLine(_vm->_utils->vgaScaleX(126), _vm->_utils->vgaScaleY(170) + 2, _vm->_utils->vgaScaleY(198), 4);
+ drawVLine(_vm->_utils->vgaScaleX(196), _vm->_utils->vgaScaleY(170) + 2, _vm->_utils->vgaScaleY(198), 4);
+ } else {
+ drawVLine(_vm->_utils->vgaScaleX(92), _vm->_utils->vgaScaleY(170) + 2, _vm->_utils->vgaScaleY(198), 4);
+ drawVLine(_vm->_utils->vgaScaleX(162), _vm->_utils->vgaScaleY(170) + 2, _vm->_utils->vgaScaleY(198), 4);
+ drawVLine(_vm->_utils->vgaScaleX(232), _vm->_utils->vgaScaleY(170) + 2, _vm->_utils->vgaScaleY(198), 4);
+ }
+
+ _vm->_interface->drawButtonList(&_vm->_invButtonList);
+ }
+}
+
+void DisplayMan::setUpScreens() {
+ Interface *i = _vm->_interface;
+ ButtonList *moveButtonList = &_vm->_moveButtonList;
+ ButtonList *invButtonList = &_vm->_invButtonList;
+ Image **moveImages = _vm->_moveImages;
+ Image **invImages = _vm->_invImages;
+
+ createScreen(_vm->_isHiRes);
+
+ // TODO: The CONTROL file is not present in the Amiga version
+ Common::File *controlFile = _vm->_resource->openDataFile("P:Control");
+ for (int j = 0; j < 20; j++)
+ _vm->_moveImages[j] = new Image(controlFile, _vm);
+ delete controlFile;
+
+ // Creates the buttons for the movement control panel
+ // The key mapping was only set for the Windows version.
+ // It's very convenient to have those shortcut, so I added them
+ // for all versions. (Strangerke)
+ uint16 y = _vm->_utils->vgaScaleY(173) - _vm->_utils->svgaCord(2);
+ moveButtonList->push_back(i->createButton( 1, y, 0, Common::KEYCODE_t, moveImages[0], moveImages[1]));
+ moveButtonList->push_back(i->createButton( 33, y, 1, Common::KEYCODE_m, moveImages[2], moveImages[3]));
+ moveButtonList->push_back(i->createButton( 65, y, 2, Common::KEYCODE_o, moveImages[4], moveImages[5]));
+ moveButtonList->push_back(i->createButton( 97, y, 3, Common::KEYCODE_c, moveImages[6], moveImages[7]));
+ moveButtonList->push_back(i->createButton(129, y, 4, Common::KEYCODE_l, moveImages[8], moveImages[9]));
+ moveButtonList->push_back(i->createButton(161, y, 5, Common::KEYCODE_i, moveImages[12], moveImages[13]));
+ moveButtonList->push_back(i->createButton(193, y, 6, Common::KEYCODE_LEFT, moveImages[14], moveImages[15]));
+ moveButtonList->push_back(i->createButton(225, y, 7, Common::KEYCODE_UP, moveImages[16], moveImages[17]));
+ moveButtonList->push_back(i->createButton(257, y, 8, Common::KEYCODE_RIGHT, moveImages[18], moveImages[19]));
+ moveButtonList->push_back(i->createButton(289, y, 9, Common::KEYCODE_p, moveImages[10], moveImages[11]));
+
+ // TODO: The INV file is not present in the Amiga version
+ Common::File *invFile = _vm->_resource->openDataFile("P:Inv");
+ if (_vm->getPlatform() == Common::kPlatformWindows) {
+ for (int imgIdx = 0; imgIdx < 10; imgIdx++)
+ _vm->_invImages[imgIdx] = new Image(invFile, _vm);
+ } else {
+ for (int imgIdx = 0; imgIdx < 6; imgIdx++)
+ _vm->_invImages[imgIdx] = new Image(invFile, _vm);
+ }
+
+ if (_vm->getPlatform() == Common::kPlatformWindows) {
+ invButtonList->push_back(i->createButton( 24, y, 0, Common::KEYCODE_ESCAPE, invImages[0], invImages[1]));
+ invButtonList->push_back(i->createButton( 56, y, 1, Common::KEYCODE_g, invImages[2], invImages[3]));
+ invButtonList->push_back(i->createButton( 94, y, 2, Common::KEYCODE_u, invImages[4], invImages[5]));
+ invButtonList->push_back(i->createButton(126, y, 3, Common::KEYCODE_l, moveImages[8], moveImages[9]));
+ invButtonList->push_back(i->createButton(164, y, 4, Common::KEYCODE_LEFT, moveImages[14], moveImages[15]));
+ invButtonList->push_back(i->createButton(196, y, 5, Common::KEYCODE_RIGHT, moveImages[18], moveImages[19]));
+ // The windows version has 2 extra buttons for breadcrumb trail
+ // CHECKME: the game is really hard to play without those, maybe we could add something to enable that.
+ invButtonList->push_back(i->createButton(234, y, 6, Common::KEYCODE_b, invImages[6], invImages[7]));
+ invButtonList->push_back(i->createButton(266, y, 7, Common::KEYCODE_f, invImages[8], invImages[9]));
+ } else {
+ invButtonList->push_back(i->createButton( 58, y, 0, Common::KEYCODE_ESCAPE, invImages[0], invImages[1]));
+ invButtonList->push_back(i->createButton( 90, y, 1, Common::KEYCODE_g, invImages[2], invImages[3]));
+ invButtonList->push_back(i->createButton(128, y, 2, Common::KEYCODE_u, invImages[4], invImages[5]));
+ invButtonList->push_back(i->createButton(160, y, 3, Common::KEYCODE_l, moveImages[8], moveImages[9]));
+ invButtonList->push_back(i->createButton(198, y, 4, Common::KEYCODE_LEFT, moveImages[14], moveImages[15]));
+ invButtonList->push_back(i->createButton(230, y, 5, Common::KEYCODE_RIGHT, moveImages[18], moveImages[19]));
+ }
+
+ delete invFile;
+}
+
+void DisplayMan::rectFill(Common::Rect fillRect, byte color) {
+ int width = fillRect.width() + 1;
+ int height = fillRect.height() + 1;
+
+ if (fillRect.left + width > _screenWidth)
+ width = _screenWidth - fillRect.left;
+
+ if (fillRect.top + height > _screenHeight)
+ height = _screenHeight - fillRect.top;
+
+ if ((width > 0) && (height > 0)) {
+ byte *d = getCurrentDrawingBuffer() + fillRect.top * _screenWidth + fillRect.left;
+
+ while (height-- > 0) {
+ byte *dd = d;
+ int ww = width;
+
+ while (ww-- > 0) {
+ *dd++ = color;
+ }
+
+ d += _screenWidth;
+ }
+ }
+}
+
+void DisplayMan::rectFill(uint16 x1, uint16 y1, uint16 x2, uint16 y2, byte color) {
+ rectFill(Common::Rect(x1, y1, x2, y2), color);
+}
+
+void DisplayMan::rectFillScaled(uint16 x1, uint16 y1, uint16 x2, uint16 y2, byte color) {
+ rectFill(_vm->_utils->vgaRectScale(x1, y1, x2, y2), color);
+}
+
+void DisplayMan::drawVLine(uint16 x, uint16 y1, uint16 y2, byte color) {
+ rectFill(x, y1, x, y2, color);
+}
+
+void DisplayMan::drawHLine(uint16 x1, uint16 y, uint16 x2, byte color) {
+ rectFill(x1, y, x2, y, color);
+}
+
+void DisplayMan::screenUpdate() {
+ _vm->_event->processInput();
+
+ _vm->_system->copyRectToScreen(_displayBuffer, _screenWidth, 0, 0, _screenWidth, _screenHeight);
+ _vm->_console->onFrame();
+ _vm->_system->updateScreen();
+}
+
+void DisplayMan::createScreen(bool hiRes) {
+ if (hiRes) {
+ _screenWidth = 640;
+ _screenHeight = 480;
+ } else {
+ _screenWidth = 320;
+ _screenHeight = 200;
+ }
+ _screenBytesPerPage = _screenWidth * _screenHeight;
+
+ if (_displayBuffer)
+ delete[] _displayBuffer;
+ _displayBuffer = new byte[_screenBytesPerPage];
+ memset(_displayBuffer, 0, _screenBytesPerPage);
+}
+
+void DisplayMan::setAmigaPal(uint16 *pal) {
+ byte vgaPal[16 * 3];
+ uint16 vgaIdx = 0;
+
+ for (int i = 0; i < 16; i++) {
+ vgaPal[vgaIdx++] = (byte)(((pal[i] & 0xf00) >> 8) << 2);
+ vgaPal[vgaIdx++] = (byte)(((pal[i] & 0x0f0) >> 4) << 2);
+ vgaPal[vgaIdx++] = (byte)(((pal[i] & 0x00f)) << 2);
+ }
+
+ writeColorRegs(vgaPal, 0, 16);
+}
+
+void DisplayMan::writeColorRegs(byte *buf, uint16 first, uint16 numReg) {
+ assert(first + numReg <= 256);
+ byte tmp[256 * 3];
+
+ for (int i = 0; i < numReg * 3; i++)
+ tmp[i] = (buf[i] << 2) | (buf[i] >> 4); // better results than buf[i] * 4
+
+ _vm->_system->getPaletteManager()->setPalette(tmp, first, numReg);
+ memcpy(&(_curVgaPal[first * 3]), buf, numReg * 3);
+}
+
+void DisplayMan::setPalette(void *newPal, uint16 numColors) {
+ if (memcmp(newPal, _curVgaPal, numColors * 3) != 0)
+ writeColorRegs((byte *)newPal, 0, numColors);
+}
+
+byte *DisplayMan::getCurrentDrawingBuffer() {
+ if (_currentDisplayBuffer)
+ return _currentDisplayBuffer;
+
+ return _displayBuffer;
+}
+
+void DisplayMan::checkerBoardEffect(uint16 penColor, uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
+ int w = x2 - x1 + 1;
+ int h = y2 - y1 + 1;
+
+ if (x1 + w > _screenWidth)
+ w = _screenWidth - x1;
+
+ if (y1 + h > _screenHeight)
+ h = _screenHeight - y1;
+
+ if ((w > 0) && (h > 0)) {
+ byte *d = getCurrentDrawingBuffer() + y1 * _screenWidth + x1;
+
+ while (h-- > 0) {
+ byte *dd = d;
+ int ww = w;
+
+ if (y1 & 1) {
+ dd++;
+ ww--;
+ }
+
+ while (ww > 0) {
+ *dd = penColor;
+ dd += 2;
+ ww -= 2;
+ }
+
+ d += _screenWidth;
+ y1++;
+ }
+ }
+}
+
+void DisplayMan::freeFont(TextFont **font) {
+ if (*font) {
+ if ((*font)->_data)
+ delete[] (*font)->_data;
+
+ delete *font;
+ *font = nullptr;
+ }
+}
+
+uint16 DisplayMan::textLength(TextFont *font, const Common::String text) {
+ uint16 length = 0;
+
+ if (font) {
+ int numChars = text.size();
+ for (int i = 0; i < numChars; i++) {
+ length += font->_widths[(byte)text[i]];
+ }
+ }
+
+ return length;
+}
+
+uint16 DisplayMan::textHeight(TextFont *tf) {
+ return (tf) ? tf->_height : 0;
+}
+
+void DisplayMan::drawText(TextFont *tf, uint16 x, uint16 y, uint16 color, const Common::String text) {
+ byte *vgaTop = getCurrentDrawingBuffer();
+ int numChars = text.size();
+
+ for (int i = 0; i < numChars; i++) {
+ uint32 realOffset = (_screenWidth * y) + x;
+ uint16 curPage = realOffset / _screenBytesPerPage;
+ uint32 segmentOffset = realOffset - (curPage * _screenBytesPerPage);
+ int32 leftInSegment = _screenBytesPerPage - segmentOffset;
+ byte *vgaCur = vgaTop + segmentOffset;
+
+ if (tf->_widths[(byte)text[i]]) {
+ byte *cdata = tf->_data + tf->_offsets[(byte)text[i]];
+ uint16 bwidth = *cdata++;
+ byte *vgaTemp = vgaCur;
+ byte *vgaTempLine = vgaCur;
+
+ for (int rows = 0; rows < tf->_height; rows++) {
+ int32 templeft = leftInSegment;
+
+ vgaTemp = vgaTempLine;
+
+ for (int cols = 0; cols < bwidth; cols++) {
+ uint16 data = *cdata++;
+
+ if (data && (templeft >= 8)) {
+ for (int j = 7; j >= 0; j--) {
+ if ((1 << j) & data)
+ *vgaTemp = color;
+ vgaTemp++;
+ }
+
+ templeft -= 8;
+ } else if (data) {
+ uint16 mask = 0x80;
+ templeft = leftInSegment;
+
+ for (int counterb = 0; counterb < 8; counterb++) {
+ if (templeft <= 0) {
+ curPage++;
+ vgaTemp = vgaTop - templeft;
+ // Set up VGATempLine for next line
+ vgaTempLine -= _screenBytesPerPage;
+ // Set up LeftInSegment for next line
+ leftInSegment += _screenBytesPerPage + templeft;
+ templeft += _screenBytesPerPage;
+ }
+
+ if (mask & data)
+ *vgaTemp = color;
+
+ vgaTemp++;
+
+ mask = mask >> 1;
+ templeft--;
+ }
+ } else {
+ templeft -= 8;
+ vgaTemp += 8;
+ }
+ }
+
+ vgaTempLine += _screenWidth;
+ leftInSegment -= _screenWidth;
+
+ if (leftInSegment <= 0) {
+ curPage++;
+ vgaTempLine -= _screenBytesPerPage;
+ leftInSegment += _screenBytesPerPage;
+ }
+ }
+ }
+
+ x += tf->_widths[(byte)text[i]];
+ }
+}
+
+void DisplayMan::doScrollBlack() {
+ uint16 width = _vm->_utils->vgaScaleX(320);
+ uint16 height = _vm->_utils->vgaScaleY(149) + _vm->_utils->svgaCord(2);
+
+ _vm->_event->mouseHide();
+
+ byte *mem = new byte[width * height];
+ int16 by = _vm->_utils->vgaScaleX(4);
+ int16 verticalScroll = height;
+
+ while (verticalScroll > 0) {
+ scrollDisplayY(-by, 0, 0, width - 1, height - 1, mem);
+ verticalScroll -= by;
+
+ _vm->updateEvents();
+ _vm->waitTOF();
+ }
+
+ delete[] mem;
+
+ _vm->_event->mouseShow();
+}
+
+void DisplayMan::copyPage(uint16 width, uint16 height, uint16 nheight, uint16 startLine, byte *mem) {
+ byte *baseAddr = getCurrentDrawingBuffer();
+
+ uint32 size = (int32)(height - nheight) * (int32)width;
+ mem += startLine * width;
+ uint16 curPage = ((int32)nheight * (int32)width) / _screenBytesPerPage;
+ uint32 offSet = ((int32)nheight * (int32)width) - (curPage * _screenBytesPerPage);
+
+ while (size) {
+ uint32 copySize;
+ if (size > (_screenBytesPerPage - offSet))
+ copySize = _screenBytesPerPage - offSet;
+ else
+ copySize = size;
+
+ size -= copySize;
+
+ memcpy(baseAddr + (offSet >> 2), mem, copySize);
+ mem += copySize;
+ curPage++;
+ offSet = 0;
+ }
+}
+
+void DisplayMan::doScrollWipe(const Common::String filename) {
+ _vm->_event->mouseHide();
+ uint16 width = _vm->_utils->vgaScaleX(320);
+ uint16 height = _vm->_utils->vgaScaleY(149) + _vm->_utils->svgaCord(2);
+
+ while (_vm->_music->isSoundEffectActive()) {
+ _vm->updateEvents();
+ _vm->waitTOF();
+ }
+
+ readPict(filename, true, true);
+ setPalette(_vm->_anim->_diffPalette, 256);
+ byte *mem = _vm->_anim->_scrollScreenBuffer;
+
+ _vm->updateEvents();
+ uint16 by = _vm->_utils->vgaScaleX(3);
+ uint16 nheight = height;
+ uint16 startLine = 0, onRow = 0;
+
+ while (onRow < _vm->_anim->getDIFFHeight()) {
+ _vm->updateEvents();
+
+ if ((by > nheight) && nheight)
+ by = nheight;
+
+ if ((startLine + by) > (_vm->_anim->getDIFFHeight() - height - 1))
+ break;
+
+ if (nheight)
+ nheight -= by;
+
+ copyPage(width, height, nheight, startLine, mem);
+ screenUpdate();
+
+ if (!nheight)
+ startLine += by;
+
+ onRow += by;
+
+ if (nheight <= (height / 4))
+ by = _vm->_utils->vgaScaleX(5);
+ else if (nheight <= (height / 3))
+ by = _vm->_utils->vgaScaleX(4);
+ else if (nheight <= (height / 2))
+ by = _vm->_utils->vgaScaleX(3);
+ }
+
+ _vm->_event->mouseShow();
+}
+
+void DisplayMan::doScrollBounce() {
+ const uint16 offsets[8] = { 3, 3, 2, 2, 2, 1, 1, 1 };
+ const int multiplier = (_vm->_isHiRes) ? 2 : 1;
+
+ _vm->_event->mouseHide();
+ int width = _vm->_utils->vgaScaleX(320);
+ int height = _vm->_utils->vgaScaleY(149) + _vm->_utils->svgaCord(2);
+ byte *mem = _vm->_anim->_scrollScreenBuffer;
+
+ _vm->updateEvents();
+ int startLine = _vm->_anim->getDIFFHeight() - height - 1;
+
+ for (int i = 0; i < 5; i++) {
+ _vm->updateEvents();
+ startLine -= (5 - i) * multiplier;
+ copyPage(width, height, 0, startLine, mem);
+ _vm->waitTOF();
+ }
+
+ for (int i = 8; i > 0; i--) {
+ _vm->updateEvents();
+ startLine += offsets[i - 1] * multiplier;
+ copyPage(width, height, 0, startLine, mem);
+ _vm->waitTOF();
+ }
+
+ _vm->_event->mouseShow();
+}
+
+void DisplayMan::doTransWipe(const Common::String filename) {
+ uint16 lastY, linesLast;
+
+ if (_vm->_isHiRes) {
+ linesLast = 3;
+ lastY = 358;
+ } else {
+ linesLast = 1;
+ lastY = 148;
+ }
+
+ uint16 linesDone = 0;
+
+ for (int j = 0; j < 2; j++) {
+ for (int i = 0; i < 2; i++) {
+ uint16 curY = i * 2;
+
+ while (curY < lastY) {
+ if (linesDone >= linesLast) {
+ _vm->updateEvents();
+ _vm->waitTOF();
+ linesDone = 0;
+ }
+
+ if (j == 0)
+ checkerBoardEffect(0, 0, curY, _screenWidth - 1, curY + 1);
+ else
+ rectFill(0, curY, _screenWidth - 1, curY + 1, 0);
+ curY += 4;
+ linesDone++;
+ } // while
+ } // for i
+ } // for j
+
+ if (filename.empty())
+ _vm->_curFileName = _vm->getPictName(true);
+ else if (filename[0] > ' ')
+ _vm->_curFileName = filename;
+ else
+ _vm->_curFileName = _vm->getPictName(true);
+
+ byte *bitMapBuffer = new byte[_screenWidth * (lastY + 5)];
+ readPict(_vm->_curFileName, true, false, bitMapBuffer);
+
+ setPalette(_vm->_anim->_diffPalette, 256);
+
+ Image imgSource(_vm);
+ imgSource._width = _screenWidth;
+ imgSource._height = lastY;
+ imgSource.setData(bitMapBuffer, true);
+
+ Image imgDest(_vm);
+ imgDest._width = _screenWidth;
+ imgDest._height = _screenHeight;
+ imgDest.setData(getCurrentDrawingBuffer(), false);
+
+ for (int j = 0; j < 2; j++) {
+ for (int i = 0; i < 2; i++) {
+ uint16 curY = i * 2;
+
+ while (curY < lastY) {
+ if (linesDone >= linesLast) {
+ _vm->updateEvents();
+ _vm->waitTOF();
+ linesDone = 0;
+ }
+
+ imgDest.setData(getCurrentDrawingBuffer(), false);
+
+ if (j == 0) {
+ imgSource.blitBitmap(0, curY, &imgDest, 0, curY, _screenWidth, 2, false);
+ checkerBoardEffect(0, 0, curY, _screenWidth - 1, curY + 1);
+ } else {
+ uint16 bitmapHeight = (curY == lastY) ? 1 : 2;
+ imgSource.blitBitmap(0, curY, &imgDest, 0, curY, _screenWidth, bitmapHeight, false);
+ }
+ curY += 4;
+ linesDone++;
+ } // while
+ } // for i
+ } // for j
+
+ // bitMapBuffer will be deleted by the Image destructor
+}
+
+void DisplayMan::doTransition(TransitionType transitionType, const Common::String filename) {
+ switch (transitionType) {
+ case kTransitionWipe:
+ case kTransitionTransporter:
+ doTransWipe(filename);
+ break;
+ case kTransitionScrollWipe: // only used in scene 7 (street, when teleporting to the surreal maze)
+ doScrollWipe(filename);
+ break;
+ case kTransitionScrollBlack: // only used in scene 7 (street, when teleporting to the surreal maze)
+ doScrollBlack();
+ break;
+ case kTransitionScrollBounce: // only used in scene 7 (street, when teleporting to the surreal maze)
+ doScrollBounce();
+ break;
+ case kTransitionReadFirstFrame: // only used in scene 7 (street, when teleporting to the surreal maze)
+ readPict(filename, false);
+ break;
+ case kTransitionReadNextFrame: // only used in scene 7 (street, when teleporting to the surreal maze)
+ _vm->_anim->diffNextFrame();
+ break;
+ case kTransitionNone:
+ default:
+ break;
+ }
+}
+
+void DisplayMan::blackScreen() {
+ byte pal[256 * 3];
+ memset(pal, 0, 248 * 3);
+ writeColorRegs(pal, 8, 248);
+
+ _vm->_system->delayMillis(32);
+}
+
+void DisplayMan::whiteScreen() {
+ byte pal[256 * 3];
+ memset(pal, 255, 248 * 3);
+ writeColorRegs(pal, 8, 248);
+}
+
+void DisplayMan::blackAllScreen() {
+ byte pal[256 * 3];
+ memset(pal, 0, 256 * 3);
+ writeColorRegs(pal, 0, 256);
+
+ _vm->_system->delayMillis(32);
+}
+
+void DisplayMan::scrollDisplayX(int16 dx, uint16 x1, uint16 y1, uint16 x2, uint16 y2, byte *buffer) {
+ Image img(_vm);
+ img.setData(buffer, false);
+
+ if (x1 > x2)
+ SWAP<uint16>(x1, x2);
+
+ if (y1 > y2)
+ SWAP<uint16>(y1, y2);
+
+ if (dx > 0) {
+ img._width = x2 - x1 + 1 - dx;
+ img._height = y2 - y1 + 1;
+
+ img.readScreenImage(x1, y1);
+ img.drawImage(x1 + dx, y1);
+
+ rectFill(x1, y1, x1 + dx - 1, y2, 0);
+ } else if (dx < 0) {
+ img._width = x2 - x1 + 1 + dx;
+ img._height = y2 - y1 + 1;
+
+ img.readScreenImage(x1 - dx, y1);
+ img.drawImage(x1, y1);
+
+ rectFill(x2 + dx + 1, y1, x2, y2, 0);
+ }
+}
+
+void DisplayMan::scrollDisplayY(int16 dy, uint16 x1, uint16 y1, uint16 x2, uint16 y2, byte *buffer) {
+ Image img(_vm);
+ img.setData(buffer, false);
+
+ if (x1 > x2)
+ SWAP<uint16>(x1, x2);
+
+ if (y1 > y2)
+ SWAP<uint16>(y1, y2);
+
+ if (dy > 0) {
+ img._width = x2 - x1 + 1;
+ img._height = y2 - y1 + 1 - dy;
+
+ img.readScreenImage(x1, y1);
+ img.drawImage(x1, y1 + dy);
+
+ rectFill(x1, y1, x2, y1 + dy - 1, 0);
+ } else if (dy < 0) {
+ img._width = x2 - x1 + 1;
+ img._height = y2 - y1 + 1 + dy;
+
+ img.readScreenImage(x1, y1 - dy);
+ img.drawImage(x1, y1);
+
+ rectFill(x1, y2 + dy + 1, x2, y2, 0);
+ }
+}
+
+uint16 DisplayMan::fadeNumIn(uint16 num, uint16 res, uint16 counter) {
+ return (num - ((((int32)(15 - counter)) * ((int32)(num - res))) / 15));
+}
+
+uint16 DisplayMan::fadeNumOut(uint16 num, uint16 res, uint16 counter) {
+ return (num - ((((int32) counter) * ((int32)(num - res))) / 15));
+}
+
+void DisplayMan::fade(bool fadeIn) {
+ uint16 newPal[16];
+
+ for (int i = 0; i < 16; i++) {
+ for (int palIdx = 0; palIdx < 16; palIdx++) {
+ if (fadeIn)
+ newPal[palIdx] =
+ (0x00F & fadeNumIn(0x00F & _fadePalette[palIdx], 0, i)) +
+ (0x0F0 & fadeNumIn(0x0F0 & _fadePalette[palIdx], 0, i)) +
+ (0xF00 & fadeNumIn(0xF00 & _fadePalette[palIdx], 0, i));
+ else
+ newPal[palIdx] =
+ (0x00F & fadeNumOut(0x00F & _fadePalette[palIdx], 0, i)) +
+ (0x0F0 & fadeNumOut(0x0F0 & _fadePalette[palIdx], 0, i)) +
+ (0xF00 & fadeNumOut(0xF00 & _fadePalette[palIdx], 0, i));
+ }
+
+ setAmigaPal(newPal);
+ _vm->updateEvents();
+ _vm->waitTOF();
+ _vm->waitTOF();
+ }
+}
+
+} // End of namespace Lab
diff --git a/engines/lab/dispman.h b/engines/lab/dispman.h
new file mode 100644
index 0000000000..d83d4fb73e
--- /dev/null
+++ b/engines/lab/dispman.h
@@ -0,0 +1,274 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#ifndef LAB_DISPMAN_H
+#define LAB_DISPMAN_H
+
+namespace Lab {
+
+class LabEngine;
+class Image;
+
+struct TextFont {
+ uint32 _dataLength;
+ uint16 _height;
+ byte _widths[256];
+ uint16 _offsets[256];
+ byte *_data;
+};
+
+enum TransitionType {
+ kTransitionNone,
+ kTransitionWipe,
+ kTransitionScrollWipe,
+ kTransitionScrollBlack,
+ kTransitionScrollBounce,
+ kTransitionTransporter,
+ kTransitionReadFirstFrame,
+ kTransitionReadNextFrame
+};
+
+class DisplayMan {
+private:
+ LabEngine *_vm;
+
+ /**
+ * Does the fading of the Palette on the screen.
+ */
+ uint16 fadeNumIn(uint16 num, uint16 res, uint16 counter);
+ uint16 fadeNumOut(uint16 num, uint16 res, uint16 counter);
+
+ /**
+ * Extracts the first word from a string.
+ */
+ Common::String getWord(const char *mainBuffer);
+
+ void createBox(uint16 y2);
+
+ /**
+ * Sets up either a low-res or a high-res 256 color screen.
+ */
+ void createScreen(bool hiRes);
+
+ /**
+ * Scrolls the display to black.
+ */
+ void doScrollBlack();
+ void copyPage(uint16 width, uint16 height, uint16 nheight, uint16 startline, byte *mem);
+
+ /**
+ * Scrolls the display to a new picture from a black screen.
+ */
+ void doScrollWipe(const Common::String filename);
+
+ /**
+ * Does the scroll bounce. Assumes bitmap already in memory.
+ */
+ void doScrollBounce();
+
+ /**
+ * Does the transporter wipe.
+ */
+ void doTransWipe(const Common::String filename);
+
+ /**
+ * Draws a vertical line.
+ */
+ void drawHLine(uint16 x, uint16 y1, uint16 y2, byte color);
+
+ /**
+ * Draws a horizontal line.
+ */
+ void drawVLine(uint16 x1, uint16 y, uint16 x2, byte color);
+
+ /**
+ * Draws the text to the screen.
+ */
+ void drawText(TextFont *tf, uint16 x, uint16 y, uint16 color, const Common::String text);
+
+ /**
+ * Gets a line of text for flowText; makes sure that its length is less than
+ * or equal to the maximum width.
+ */
+ Common::String getLine(TextFont *tf, const char **mainBuffer, uint16 lineWidth);
+
+ /**
+ * Returns the length of a text in the specified font.
+ */
+ uint16 textLength(TextFont *font, const Common::String text);
+
+ bool _actionMessageShown;
+ Common::File *_curBitmap;
+ byte _curVgaPal[256 * 3];
+ byte *_currentDisplayBuffer;
+
+public:
+ DisplayMan(LabEngine *lab);
+ virtual ~DisplayMan();
+
+ void loadPict(const Common::String filename);
+ void loadBackPict(const Common::String fileName, uint16 *highPal);
+
+ /**
+ * Reads in a picture into the display bitmap.
+ */
+ void readPict(const Common::String filename, bool playOnce = true, bool onlyDiffData = false, byte *memoryBuffer = nullptr);
+ void freePict();
+
+ /**
+ * Does a certain number of pre-programmed wipes.
+ */
+ void doTransition(TransitionType transitionType, const Common::String filename);
+
+ /**
+ * Changes the front screen to black.
+ */
+ void blackScreen();
+
+ /**
+ * Changes the front screen to white.
+ */
+ void whiteScreen();
+
+ /**
+ * Changes the entire screen to black.
+ */
+ void blackAllScreen();
+
+ /**
+ * Draws the control panel display.
+ */
+ void drawPanel();
+
+ /**
+ * Sets up the Labyrinth screens, and opens up the initial windows.
+ */
+ void setUpScreens();
+
+ int longDrawMessage(Common::String str, bool isActionMessage);
+
+ /**
+ * Draws a message to the message box.
+ */
+ void drawMessage(Common::String str, bool isActionMessage);
+
+ void setActionMessage(bool val) { _actionMessageShown = val; }
+
+ /**
+ * Fills in a rectangle.
+ */
+ void rectFill(uint16 x1, uint16 y1, uint16 x2, uint16 y2, byte color);
+ void rectFill(Common::Rect fillRect, byte color);
+ void rectFillScaled(uint16 x1, uint16 y1, uint16 x2, uint16 y2, byte color);
+ /**
+ * Dumps a chunk of text to an arbitrary box; flows it within that box and
+ * optionally centers it. Returns the number of characters that were processed.
+ * @note Every individual word MUST be int16 enough to fit on a line, and
+ * each line less than 255 characters.
+ * @param font Pointer on the font used
+ * @param spacing How much vertical spacing between the lines
+ * @param penColor Pen number to use for text
+ * @param backPen Background color
+ * @param fillBack Whether to fill the background
+ * @param centerh Whether to center the text horizontally
+ * @param centerv Whether to center the text vertically
+ * @param output Whether to output any text
+ * @param textRect Coords
+ * @param text The text itself
+ */
+ int flowText(TextFont *font, int16 spacing, byte penColor, byte backPen, bool fillBack,
+ bool centerh, bool centerv, bool output, Common::Rect textRect, const char *text, Image *targetImage = nullptr);
+
+ void screenUpdate();
+
+ /**
+ * Converts a 16-color Amiga palette to a VGA palette, then sets
+ * the VGA palette.
+ */
+ void setAmigaPal(uint16 *pal);
+
+ /**
+ * Writes any number of the 256 color registers.
+ * @param buf A char pointer which contains the selected color registers.
+ * Each value representing a color register occupies 3 bytes in the array. The
+ * order is red, green then blue. The first byte in the array is the red component
+ * of the first element selected. The length of the buffer is 3 times the number
+ * of registers selected.
+ * @param first The number of the first color register to write.
+ * @param numReg The number of registers to write.
+ */
+ void writeColorRegs(byte *buf, uint16 first, uint16 numReg);
+ void setPalette(void *newPal, uint16 numColors);
+
+ /**
+ * Overlays a region on the screen using the desired pen color.
+ */
+ void checkerBoardEffect(uint16 penColor, uint16 x1, uint16 y1, uint16 x2, uint16 y2);
+
+ /**
+ * Returns the base address of the current VGA display.
+ */
+ byte *getCurrentDrawingBuffer();
+
+ /**
+ * Scrolls the display in the x direction by blitting.
+ * The _tempScrollData variable must be initialized to some memory, or this
+ * function will fail.
+ */
+ void scrollDisplayX(int16 dx, uint16 x1, uint16 y1, uint16 x2, uint16 y2, byte *buffer);
+
+ /**
+ * Scrolls the display in the y direction by blitting.
+ */
+ void scrollDisplayY(int16 dy, uint16 x1, uint16 y1, uint16 x2, uint16 y2, byte *buffer);
+ void fade(bool fadein);
+
+ /**
+ * Closes a font and frees all memory associated with it.
+ */
+ void freeFont(TextFont **font);
+
+ /**
+ * Returns the height of a specified font.
+ */
+ uint16 textHeight(TextFont *tf);
+
+ bool _longWinInFront;
+ bool _lastMessageLong;
+ uint32 _screenBytesPerPage;
+ int _screenWidth;
+ int _screenHeight;
+ byte *_displayBuffer;
+ uint16 *_fadePalette;
+};
+
+} // End of namespace Lab
+
+#endif // LAB_DISPMAN_H
diff --git a/engines/lab/engine.cpp b/engines/lab/engine.cpp
new file mode 100644
index 0000000000..4f0a0da777
--- /dev/null
+++ b/engines/lab/engine.cpp
@@ -0,0 +1,1124 @@
+/* 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 Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#include "common/config-manager.h"
+#include "common/file.h"
+
+#include "gui/message.h"
+
+#include "lab/lab.h"
+#include "lab/anim.h"
+#include "lab/dispman.h"
+#include "lab/eventman.h"
+#include "lab/image.h"
+#include "lab/interface.h"
+#include "lab/intro.h"
+#include "lab/labsets.h"
+#include "lab/music.h"
+#include "lab/processroom.h"
+#include "lab/resource.h"
+#include "lab/speciallocks.h"
+#include "lab/utils.h"
+
+namespace Lab {
+
+enum SpecialLock {
+ kLockCombination = 100,
+ kLockTiles = 101,
+ kLockTileSolution = 102
+};
+
+enum Items {
+ kItemHelmet = 1,
+ kItemBelt = 3,
+ kItemPithHelmet = 7,
+ kItemJournal = 9,
+ kItemNotes = 12,
+ kItemWestPaper = 18,
+ kItemWhiskey = 25,
+ kItemLamp = 27,
+ kItemMap = 28,
+ kItemQuarter = 30
+};
+
+enum Monitors {
+ kMonitorMuseum = 71,
+ kMonitorGramophone = 72,
+ kMonitorUnicycle = 73,
+ kMonitorStatue = 74,
+ kMonitorTalisman = 75,
+ kMonitorLute = 76,
+ kMonitorClock = 77,
+ kMonitorWindow = 78,
+ //kMonitorBelt = 79,
+ kMonitorLibrary = 80,
+ kMonitorTerminal = 81
+ //kMonitorLevers = 82
+};
+
+enum AltButtons {
+ kButtonMainDisplay,
+ kButtonSaveLoad,
+ kButtonUseItem,
+ kButtonLookAtItem,
+ kButtonPrevItem,
+ kButtonNextItem,
+ kButtonBreadCrumbs,
+ kButtonFollowCrumbs
+};
+
+static char initColors[] = { '\x00', '\x00', '\x00', '\x30',
+ '\x30', '\x30', '\x10', '\x10',
+ '\x10', '\x14', '\x14', '\x14',
+ '\x20', '\x20', '\x20', '\x24',
+ '\x24', '\x24', '\x2c', '\x2c',
+ '\x2c', '\x08', '\x08', '\x08' };
+
+void LabEngine::handleTrialWarning() {
+ // Check if this is the Wyrmkeep trial
+ Common::File roomFile;
+ bool knownVersion = true;
+ bool roomFileOpened = roomFile.open("rooms/48");
+
+ if (!roomFileOpened)
+ knownVersion = false;
+ else if (roomFile.size() != 892)
+ knownVersion = false;
+ else {
+ roomFile.seek(352);
+ byte checkByte = roomFile.readByte();
+ if (checkByte == 0x00) {
+ // Full Windows version
+ }
+ else if (checkByte == 0x80) {
+ // Wyrmkeep trial version
+ _extraGameFeatures = GF_WINDOWS_TRIAL;
+
+ GUI::MessageDialog trialMessage("This is a trial Windows version of the game. To play the full version, you will need to use the original interpreter and purchase a key from Wyrmkeep");
+ trialMessage.runModal();
+ }
+ else {
+ knownVersion = false;
+ }
+
+ roomFile.close();
+ }
+
+ if (!knownVersion)
+ error("Unknown Windows version found, please report this version to the ScummVM team");
+}
+
+uint16 LabEngine::getQuarters() {
+ return _inventory[kItemQuarter]._quantity;
+}
+
+void LabEngine::setQuarters(uint16 quarters) {
+ _inventory[kItemQuarter]._quantity = quarters;
+}
+
+void LabEngine::drawRoomMessage(uint16 curInv, const CloseData *closePtr) {
+ if (_lastTooLong) {
+ _lastTooLong = false;
+ return;
+ }
+
+ if (_alternate) {
+ if ((curInv <= _numInv) && _conditions->in(curInv) && !_inventory[curInv]._bitmapName.empty()) {
+ if ((curInv == kItemLamp) && _conditions->in(kCondLampOn))
+ // LAB: Labyrinth specific
+ drawStaticMessage(kTextkLampOn);
+ else if (_inventory[curInv]._quantity > 1) {
+ Common::String roomMessage = _inventory[curInv]._name + " (" + Common::String::format("%d", _inventory[curInv]._quantity) + ")";
+ _graphics->drawMessage(roomMessage.c_str(), false);
+ } else
+ _graphics->drawMessage(_inventory[curInv]._name.c_str(), false);
+ }
+ } else
+ drawDirection(closePtr);
+
+ _lastTooLong = _graphics->_lastMessageLong;
+}
+
+void LabEngine::freeScreens() {
+ for (int i = 0; i < 20; i++) {
+ delete _moveImages[i];
+ _moveImages[i] = nullptr;
+ }
+
+ for (int imgIdx = 0; imgIdx < 10; imgIdx++) {
+ delete _invImages[imgIdx];
+ _invImages[imgIdx] = nullptr;
+ }
+
+ // We can't use freeButtonList() here, because some buttons are shared
+ // between the two lists.
+ for (ButtonList::iterator buttonIter = _moveButtonList.begin(); buttonIter != _moveButtonList.end(); ++buttonIter) {
+ delete *buttonIter;
+ }
+ _moveButtonList.clear();
+
+ for (ButtonList::iterator buttonIter = _invButtonList.begin(); buttonIter != _invButtonList.end(); ++buttonIter) {
+ delete *buttonIter;
+ }
+ _invButtonList.clear();
+}
+
+void LabEngine::perFlipButton(uint16 buttonId) {
+ for (ButtonList::iterator button = _moveButtonList.begin(); button != _moveButtonList.end(); ++button) {
+ Button *topButton = *button;
+ if (topButton->_buttonId == buttonId) {
+ SWAP<Image *>(topButton->_image, topButton->_altImage);
+
+ if (!_alternate)
+ topButton->_image->drawImage(topButton->_x, topButton->_y);
+
+ break;
+ }
+ }
+}
+
+void LabEngine::eatMessages() {
+ IntuiMessage *msg;
+
+ do {
+ msg = _event->getMsg();
+ } while (msg && !shouldQuit());
+}
+
+void LabEngine::handleMonitorCloseup() {
+ if (!_closeDataPtr)
+ return;
+
+ Common::Rect textRect(2, 2, 317, 165);
+ bool isInteractive = false;
+
+ switch (_closeDataPtr->_closeUpType) {
+ case kMonitorMuseum:
+ case kMonitorLibrary:
+ case kMonitorWindow:
+ break;
+ case kMonitorGramophone:
+ textRect.right = 171;
+ break;
+ case kMonitorUnicycle:
+ textRect.left = 100;
+ break;
+ case kMonitorStatue:
+ textRect.left = 117;
+ break;
+ case kMonitorTalisman:
+ textRect.right = 184;
+ break;
+ case kMonitorLute:
+ textRect.right = 128;
+ break;
+ case kMonitorClock:
+ textRect.right = 206;
+ break;
+ case kMonitorTerminal:
+ isInteractive = true;
+ break;
+ default:
+ return;
+ }
+
+ doMonitor(_closeDataPtr->_graphicName, _closeDataPtr->_message, isInteractive, textRect);
+
+ _curFileName = " ";
+ _graphics->drawPanel();
+
+ _closeDataPtr = nullptr;
+ _interface->mayShowCrumbIndicator();
+ _graphics->screenUpdate();
+}
+
+Common::String LabEngine::getInvName(uint16 curInv) {
+ if (_mainDisplay)
+ return _inventory[curInv]._bitmapName;
+
+ if ((curInv == kItemLamp) && _conditions->in(kCondLampOn))
+ return "P:Mines/120";
+
+ if ((curInv == kItemBelt) && _conditions->in(kCondBeltGlowing))
+ return "P:Future/BeltGlow";
+
+ if (curInv == kItemWestPaper) {
+ _curFileName = _inventory[curInv]._bitmapName;
+ _anim->_noPalChange = true;
+ _graphics->readPict(_curFileName, false);
+ _anim->_noPalChange = false;
+ doWestPaper();
+ } else if (curInv == kItemNotes) {
+ _curFileName = _inventory[curInv]._bitmapName;
+ _anim->_noPalChange = true;
+ _graphics->readPict(_curFileName, false);
+ _anim->_noPalChange = false;
+ doNotes();
+ }
+
+ return _inventory[curInv]._bitmapName;
+}
+
+void LabEngine::interfaceOff() {
+ _interface->attachButtonList(nullptr);
+ _event->mouseHide();
+}
+
+void LabEngine::interfaceOn() {
+ if (_graphics->_longWinInFront)
+ _interface->attachButtonList(nullptr);
+ else if (_alternate)
+ _interface->attachButtonList(&_invButtonList);
+ else
+ _interface->attachButtonList(&_moveButtonList);
+
+ _event->mouseShow();
+}
+
+bool LabEngine::doUse(uint16 curInv) {
+ switch (curInv) {
+ case kItemMap:
+ drawStaticMessage(kTextUseMap);
+ interfaceOff();
+ _anim->stopDiff();
+ _curFileName = " ";
+ _closeDataPtr = nullptr;
+ doMap();
+ _graphics->setPalette(initColors, 8);
+ _graphics->drawMessage("", false);
+ _graphics->drawPanel();
+ return true;
+ case kItemJournal:
+ drawStaticMessage(kTextUseJournal);
+ interfaceOff();
+ _anim->stopDiff();
+ _curFileName = " ";
+ _closeDataPtr = nullptr;
+ doJournal();
+ _graphics->drawPanel();
+ _graphics->drawMessage("", false);
+ return true;
+ case kItemLamp:
+ interfaceOff();
+
+ if (_conditions->in(kCondLampOn)) {
+ drawStaticMessage(kTextTurnLampOff);
+ _conditions->exclElement(kCondLampOn);
+ } else {
+ drawStaticMessage(kTextTurnkLampOn);
+ _conditions->inclElement(kCondLampOn);
+ }
+
+ _anim->_doBlack = false;
+ _anim->_waitForEffect = true;
+ _graphics->readPict("Music:Click");
+ _anim->_waitForEffect = false;
+
+ _anim->_doBlack = false;
+ _nextFileName = getInvName(curInv);
+ return true;
+ case kItemBelt:
+ if (!_conditions->in(kCondBeltGlowing))
+ _conditions->inclElement(kCondBeltGlowing);
+
+ _anim->_doBlack = false;
+ _nextFileName = getInvName(curInv);
+ return true;
+ case kItemWhiskey:
+ _conditions->inclElement(kCondUsedHelmet);
+ drawStaticMessage(kTextUseWhiskey);
+ return true;
+ case kItemPithHelmet:
+ _conditions->inclElement(kCondUsedHelmet);
+ drawStaticMessage(kTextUsePith);
+ return true;
+ case kItemHelmet:
+ _conditions->inclElement(kCondUsedHelmet);
+ drawStaticMessage(kTextUseHelmet);
+ return true;
+ default:
+ return false;
+ }
+}
+
+void LabEngine::decIncInv(uint16 *curInv, bool decreaseFl) {
+ int8 step = (decreaseFl) ? -1 : 1;
+ uint newInv = *curInv + step;
+
+ // Handle wrapping
+ if (newInv < 1)
+ newInv = _numInv;
+ if (newInv > _numInv)
+ newInv = 1;
+
+ interfaceOff();
+
+ while (newInv && (newInv <= _numInv)) {
+ if (_conditions->in(newInv) && !_inventory[newInv]._bitmapName.empty()) {
+ _nextFileName = getInvName(newInv);
+ *curInv = newInv;
+ break;
+ }
+
+ newInv += step;
+
+ // Handle wrapping
+ if (newInv < 1)
+ newInv = _numInv;
+ if (newInv > _numInv)
+ newInv = 1;
+ }
+}
+
+void LabEngine::mainGameLoop() {
+ _graphics->setPalette(initColors, 8);
+
+ _closeDataPtr = nullptr;
+ _roomNum = 1;
+ _direction = kDirectionNorth;
+
+ _resource->readRoomData("LAB:Doors");
+ if (!(_inventory = _resource->readInventory("LAB:Inventor")))
+ return;
+
+ if (!(_conditions = new LargeSet(_highestCondition + 1, this)))
+ return;
+
+ if (!(_roomsFound = new LargeSet(_manyRooms + 1, this)))
+ return;
+
+ _conditions->readInitialConditions("LAB:Conditio");
+
+ _graphics->_longWinInFront = false;
+ _graphics->drawPanel();
+
+ uint16 actionMode = 4;
+ perFlipButton(actionMode);
+
+ // Load saved slot from the launcher, if requested
+ if (ConfMan.hasKey("save_slot")) {
+ loadGame(ConfMan.getInt("save_slot"));
+
+ // Since the intro hasn't been shown, init the background music here
+ _music->resetMusic(false);
+ }
+
+ uint16 curInv = kItemMap;
+ bool forceDraw = false;
+ bool gotMessage = true;
+ // Set up initial picture.
+ while (1) {
+ _event->processInput();
+ _system->delayMillis(10);
+
+ if (gotMessage) {
+ if (_quitLab || shouldQuit()) {
+ _anim->stopDiff();
+ break;
+ }
+
+ handleMonitorCloseup();
+
+ // Sets the current picture properly on the screen
+ if (_mainDisplay)
+ _nextFileName = getPictName(true);
+
+ if (_noUpdateDiff) {
+ // Potentially entered another room
+ _roomsFound->inclElement(_roomNum);
+ forceDraw |= (_nextFileName != _curFileName);
+
+ _noUpdateDiff = false;
+ _curFileName = _nextFileName;
+ } else if (_nextFileName != _curFileName) {
+ interfaceOff();
+ // Potentially entered another room
+ _roomsFound->inclElement(_roomNum);
+ _curFileName = _nextFileName;
+
+ if (_closeDataPtr && _mainDisplay) {
+ switch (_closeDataPtr->_closeUpType) {
+ case kLockCombination:
+ _specialLocks->showCombinationLock(_curFileName);
+ break;
+ case kLockTiles:
+ case kLockTileSolution:
+ _specialLocks->showTileLock(_curFileName, (_closeDataPtr->_closeUpType == kLockTileSolution));
+ break;
+ default:
+ _graphics->readPict(_curFileName, false);
+ break;
+ }
+ } else
+ _graphics->readPict(_curFileName, false);
+
+ drawRoomMessage(curInv, _closeDataPtr);
+ forceDraw = false;
+
+ _interface->mayShowCrumbIndicator();
+ _graphics->screenUpdate();
+
+ if (!_followingCrumbs)
+ eatMessages();
+ }
+
+ if (forceDraw) {
+ drawRoomMessage(curInv, _closeDataPtr);
+ forceDraw = false;
+ _graphics->screenUpdate();
+ }
+ }
+
+ // Make sure we check the music at least after every message
+ updateEvents();
+ interfaceOn();
+ IntuiMessage *curMsg = _event->getMsg();
+ if (shouldQuit()) {
+ _quitLab = true;
+ return;
+ }
+
+ if (!curMsg) {
+ // Does music load and next animation frame when you've run out of messages
+ gotMessage = false;
+ updateEvents();
+ _anim->diffNextFrame();
+
+ if (_followingCrumbs) {
+ MainButton code = followCrumbs();
+
+ if (code == kButtonForward || code == kButtonLeft || code == kButtonRight) {
+ gotMessage = true;
+ _interface->mayShowCrumbIndicator();
+ _graphics->screenUpdate();
+ if (!processEvent(kMessageButtonUp, code, 0, _event->updateAndGetMousePos(), curInv, curMsg, forceDraw, code, actionMode))
+ break;
+ }
+ }
+
+ _interface->mayShowCrumbIndicator();
+ _graphics->screenUpdate();
+ } else {
+ gotMessage = true;
+ _followingCrumbs = false;
+ if (!processEvent(curMsg->_msgClass, curMsg->_code, curMsg->_qualifier, curMsg->_mouse, curInv, curMsg, forceDraw, curMsg->_code, actionMode))
+ break;
+ }
+ }
+}
+
+void LabEngine::showLab2Teaser() {
+ _graphics->blackAllScreen();
+ _graphics->readPict("P:End/L2In.1");
+
+ for (int i = 0; i < 120; i++) {
+ updateEvents();
+ waitTOF();
+ }
+
+ _graphics->readPict("P:End/L2In.9");
+ _graphics->readPict("P:End/Lost");
+
+ while (!_event->getMsg() && !shouldQuit()) {
+ updateEvents();
+ _anim->diffNextFrame();
+ waitTOF();
+ }
+}
+
+bool LabEngine::processEvent(MessageClass tmpClass, uint16 code, uint16 qualifier, Common::Point tmpPos,
+ uint16 &curInv, IntuiMessage *curMsg, bool &forceDraw, uint16 buttonId, uint16 &actionMode) {
+
+ if (shouldQuit())
+ return false;
+
+ MessageClass msgClass = tmpClass;
+ Common::Point curPos = tmpPos;
+ uint16 oldDirection = 0;
+ uint16 lastInv = kItemMap;
+
+ if (code == Common::KEYCODE_RETURN)
+ msgClass = kMessageLeftClick;
+
+ bool leftButtonClick = (msgClass == kMessageLeftClick);
+ bool rightButtonClick = (msgClass == kMessageRightClick);
+
+ _anim->_doBlack = false;
+
+ if (_graphics->_longWinInFront) {
+ if (msgClass == kMessageRawKey || leftButtonClick || rightButtonClick) {
+ _graphics->_longWinInFront = false;
+ _graphics->drawPanel();
+ drawRoomMessage(curInv, _closeDataPtr);
+ _graphics->screenUpdate();
+ }
+ } else if (msgClass == kMessageRawKey) {
+ return processKey(curMsg, msgClass, qualifier, curPos, curInv, forceDraw, code);
+ } else if (msgClass == kMessageButtonUp) {
+ if (!_alternate)
+ processMainButton(curInv, lastInv, oldDirection, forceDraw, buttonId, actionMode);
+ else
+ processAltButton(curInv, lastInv, buttonId, actionMode);
+ } else if (leftButtonClick && _mainDisplay) {
+ interfaceOff();
+ _mainDisplay = true;
+
+ if (_closeDataPtr && _closeDataPtr->_closeUpType == kLockCombination)
+ _specialLocks->combinationClick(curPos);
+ else if (_closeDataPtr && _closeDataPtr->_closeUpType == kLockTiles)
+ _specialLocks->tileClick(curPos);
+ else
+ performAction(actionMode, curPos, curInv);
+
+ _interface->mayShowCrumbIndicator();
+ _graphics->screenUpdate();
+ } else if (rightButtonClick) {
+ eatMessages();
+ _alternate = !_alternate;
+ _anim->_doBlack = true;
+ _mainDisplay = true;
+ // Sets the correct button list
+ interfaceOn();
+
+ if (_alternate) {
+ if (lastInv && _conditions->in(lastInv))
+ curInv = lastInv;
+ else
+ decIncInv(&curInv, false);
+ }
+
+ _graphics->drawPanel();
+ drawRoomMessage(curInv, _closeDataPtr);
+
+ _interface->mayShowCrumbIndicator();
+ _graphics->screenUpdate();
+ }
+
+ return true;
+}
+
+bool LabEngine::processKey(IntuiMessage *curMsg, uint32 msgClass, uint16 &qualifier, Common::Point &curPos, uint16 &curInv, bool &forceDraw, uint16 code) {
+ if ((getPlatform() == Common::kPlatformWindows) && (code == Common::KEYCODE_b)) {
+ // Start bread crumbs
+ _breadCrumbs[0]._crumbRoomNum = 0;
+ _numCrumbs = 0;
+ _droppingCrumbs = true;
+ _interface->mayShowCrumbIndicator();
+ _graphics->screenUpdate();
+ } else if (getPlatform() == Common::kPlatformWindows && (code == Common::KEYCODE_f || code == Common::KEYCODE_r)) {
+ // Follow bread crumbs
+ if (_droppingCrumbs) {
+ if (_numCrumbs > 0) {
+ _followingCrumbs = true;
+ _followCrumbsFast = (code == Common::KEYCODE_r);
+ _isCrumbTurning = false;
+ _isCrumbWaiting = false;
+ _crumbTimestamp = _system->getMillis();
+
+ if (_alternate) {
+ eatMessages();
+ _alternate = false;
+ _anim->_doBlack = true;
+
+ _mainDisplay = true;
+ // Sets the correct button list
+ interfaceOn();
+ _graphics->drawPanel();
+ drawRoomMessage(curInv, _closeDataPtr);
+ _graphics->screenUpdate();
+ }
+ } else {
+ _breadCrumbs[0]._crumbRoomNum = 0;
+ _droppingCrumbs = false;
+
+ _interface->mayShowCrumbIndicatorOff();
+ _graphics->screenUpdate();
+ }
+ }
+ } else if ((code == Common::KEYCODE_x) || (code == Common::KEYCODE_q)) {
+ // Quit?
+ _graphics->drawMessage("Do you want to quit? (Y/N)", false);
+ eatMessages();
+ interfaceOff();
+
+ while (1) {
+ // Make sure we check the music at least after every message
+ updateEvents();
+ curMsg = _event->getMsg();
+
+ if (shouldQuit())
+ return false;
+
+ if (!curMsg) {
+ // Does music load and next animation frame when you've run out of messages
+ updateEvents();
+ _anim->diffNextFrame();
+ } else if (curMsg->_msgClass == kMessageRawKey) {
+ if ((curMsg->_code == Common::KEYCODE_y) || (curMsg->_code == Common::KEYCODE_q)) {
+ _anim->stopDiff();
+ return false;
+ } else if (curMsg->_code < 128)
+ break;
+ } else if ((curMsg->_msgClass == kMessageLeftClick) || (curMsg->_msgClass == kMessageRightClick))
+ break;
+ }
+
+ forceDraw = true;
+ interfaceOn();
+ } else if (code == Common::KEYCODE_ESCAPE) {
+ _closeDataPtr = nullptr;
+ } else if (code == Common::KEYCODE_TAB) {
+ const CloseData *tmpClosePtr = _closeDataPtr;
+
+ // get next close-up in list after the one pointed to by curPos
+ setCurrentClose(curPos, &tmpClosePtr, true, true);
+
+ if (tmpClosePtr != _closeDataPtr)
+ _event->setMousePos(Common::Point(_utils->scaleX((tmpClosePtr->_x1 + tmpClosePtr->_x2) / 2), _utils->scaleY((tmpClosePtr->_y1 + tmpClosePtr->_y2) / 2)));
+ }
+
+ eatMessages();
+
+ return true;
+}
+
+void LabEngine::processMainButton(uint16 &curInv, uint16 &lastInv, uint16 &oldDirection, bool &forceDraw, uint16 buttonId, uint16 &actionMode) {
+ switch (buttonId) {
+ case kButtonPickup:
+ case kButtonUse:
+ case kButtonOpen:
+ case kButtonClose:
+ case kButtonLook:
+ if ((actionMode == 4) && (buttonId == kButtonLook) && _closeDataPtr) {
+ doMainView();
+
+ _anim->_doBlack = true;
+ _closeDataPtr = nullptr;
+ _interface->mayShowCrumbIndicator();
+ } else {
+ uint16 oldActionMode = actionMode;
+ actionMode = buttonId;
+
+ if (oldActionMode < 5)
+ perFlipButton(oldActionMode);
+
+ perFlipButton(actionMode);
+ drawStaticMessage(kTextTakeWhat + buttonId);
+ }
+ break;
+
+ case kButtonInventory:
+ eatMessages();
+
+ _alternate = true;
+ _anim->_doBlack = true;
+ // Sets the correct button list
+ interfaceOn();
+ _mainDisplay = false;
+
+ if (lastInv && _conditions->in(lastInv)) {
+ curInv = lastInv;
+ _nextFileName = getInvName(curInv);
+ } else
+ decIncInv(&curInv, false);
+
+ _graphics->drawPanel();
+ drawRoomMessage(curInv, _closeDataPtr);
+
+ _interface->mayShowCrumbIndicator();
+ break;
+
+ case kButtonLeft:
+ case kButtonRight: {
+ _closeDataPtr = nullptr;
+ if (buttonId == kButtonLeft)
+ drawStaticMessage(kTextTurnLeft);
+ else
+ drawStaticMessage(kTextTurnRight);
+
+ _curFileName = " ";
+ oldDirection = _direction;
+
+ uint16 newDir = processArrow(_direction, buttonId - 6);
+ doTurn(_direction, newDir);
+ _anim->_doBlack = true;
+ _direction = newDir;
+ forceDraw = true;
+ _interface->mayShowCrumbIndicator();
+ }
+ break;
+
+ case kButtonForward: {
+ _closeDataPtr = nullptr;
+ int oldRoomNum = _roomNum;
+
+ if (doGoForward()) {
+ if (oldRoomNum == _roomNum)
+ _anim->_doBlack = true;
+ } else {
+ _anim->_doBlack = true;
+ _direction = processArrow(_direction, buttonId - 6);
+
+ if (oldRoomNum != _roomNum) {
+ drawStaticMessage(kTextGoForward);
+ // Potentially entered a new room
+ _roomsFound->inclElement(_roomNum);
+ _curFileName = " ";
+ forceDraw = true;
+ } else {
+ _anim->_doBlack = true;
+ drawStaticMessage(kTextNoPath);
+ }
+ }
+
+ if (_followingCrumbs) {
+ if (_isCrumbTurning) {
+ if (_direction == oldDirection)
+ _followingCrumbs = false;
+ } else if (_roomNum == oldRoomNum) { // didn't get there?
+ _followingCrumbs = false;
+ }
+ } else if (_droppingCrumbs && (oldRoomNum != _roomNum)) {
+ // If in surreal maze, turn off DroppingCrumbs.
+ if ((_roomNum >= 245) && (_roomNum <= 280)) {
+ _followingCrumbs = false;
+ _droppingCrumbs = false;
+ _numCrumbs = 0;
+ _breadCrumbs[0]._crumbRoomNum = 0;
+ } else {
+ bool intersect = false;
+ for (int idx = 0; idx < _numCrumbs; idx++) {
+ if (_breadCrumbs[idx]._crumbRoomNum == _roomNum) {
+ _numCrumbs = idx + 1;
+ _breadCrumbs[_numCrumbs]._crumbRoomNum = 0;
+ intersect = true;
+ }
+ }
+
+ if (!intersect) {
+ if (_numCrumbs == MAX_CRUMBS) {
+ _numCrumbs = MAX_CRUMBS - 1;
+ memcpy(&_breadCrumbs[0], &_breadCrumbs[1], _numCrumbs * sizeof _breadCrumbs[0]);
+ }
+
+ _breadCrumbs[_numCrumbs]._crumbRoomNum = _roomNum;
+ _breadCrumbs[_numCrumbs++]._crumbDirection = _direction;
+ }
+ }
+ }
+
+ _interface->mayShowCrumbIndicator();
+ }
+ break;
+
+ case kButtonMap:
+ doUse(kItemMap);
+
+ _interface->mayShowCrumbIndicator();
+ break;
+ }
+
+ _graphics->screenUpdate();
+}
+
+void LabEngine::processAltButton(uint16 &curInv, uint16 &lastInv, uint16 buttonId, uint16 &actionMode) {
+ _anim->_doBlack = true;
+
+ switch (buttonId) {
+ case kButtonMainDisplay:
+ eatMessages();
+ _alternate = false;
+ _anim->_doBlack = true;
+
+ _mainDisplay = true;
+ // Sets the correct button list
+ interfaceOn();
+ _graphics->drawPanel();
+ drawRoomMessage(curInv, _closeDataPtr);
+ break;
+
+ case kButtonSaveLoad: {
+ interfaceOff();
+ _anim->stopDiff();
+ _curFileName = " ";
+
+ bool saveRestoreSuccessful = saveRestoreGame();
+ _closeDataPtr = nullptr;
+ _mainDisplay = true;
+
+ curInv = lastInv = kItemMap;
+ _nextFileName = getInvName(curInv);
+
+ _graphics->drawPanel();
+
+ if (!saveRestoreSuccessful) {
+ _graphics->drawMessage("Save/restore aborted", false);
+ _graphics->setPalette(initColors, 8);
+ _system->delayMillis(1000);
+ }
+ }
+ break;
+
+ case kButtonUseItem:
+ if (!doUse(curInv)) {
+ uint16 oldActionMode = actionMode;
+ // Use button
+ actionMode = 5;
+
+ if (oldActionMode < 5)
+ perFlipButton(oldActionMode);
+
+ drawStaticMessage(kTextUseOnWhat);
+ _mainDisplay = true;
+ }
+ break;
+
+ case kButtonLookAtItem:
+ _mainDisplay = !_mainDisplay;
+
+ if ((curInv == 0) || (curInv > _numInv)) {
+ curInv = 1;
+
+ while ((curInv <= _numInv) && !_conditions->in(curInv))
+ curInv++;
+ }
+
+ if ((curInv <= _numInv) && _conditions->in(curInv) && !_inventory[curInv]._bitmapName.empty())
+ _nextFileName = getInvName(curInv);
+
+ break;
+
+ case kButtonPrevItem:
+ decIncInv(&curInv, true);
+ lastInv = curInv;
+ drawRoomMessage(curInv, _closeDataPtr);
+ break;
+
+ case kButtonNextItem:
+ decIncInv(&curInv, false);
+ lastInv = curInv;
+ drawRoomMessage(curInv, _closeDataPtr);
+ break;
+
+ case kButtonBreadCrumbs:
+ _breadCrumbs[0]._crumbRoomNum = 0;
+ _numCrumbs = 0;
+ _droppingCrumbs = true;
+ _interface->mayShowCrumbIndicator();
+ break;
+
+ case kButtonFollowCrumbs:
+ if (_droppingCrumbs) {
+ if (_numCrumbs > 0) {
+ _followingCrumbs = true;
+ _followCrumbsFast = false;
+ _isCrumbTurning = false;
+ _isCrumbWaiting = false;
+ _crumbTimestamp = _system->getMillis();
+
+ eatMessages();
+ _alternate = false;
+ _anim->_doBlack = true;
+
+ _mainDisplay = true;
+ // Sets the correct button list
+ interfaceOn();
+ _graphics->drawPanel();
+ drawRoomMessage(curInv, _closeDataPtr);
+ } else {
+ _breadCrumbs[0]._crumbRoomNum = 0;
+ _droppingCrumbs = false;
+
+ _interface->mayShowCrumbIndicatorOff();
+ }
+ }
+ break;
+ }
+
+ _graphics->screenUpdate();
+}
+
+void LabEngine::performAction(uint16 actionMode, Common::Point curPos, uint16 &curInv) {
+ eatMessages();
+
+ switch (actionMode) {
+ case 0:
+ // Take something.
+ if (doActionRule(curPos, actionMode, _roomNum))
+ _curFileName = _newFileName;
+ else if (takeItem(curPos))
+ drawStaticMessage(kTextTakeItem);
+ else if (doActionRule(curPos, kRuleActionTakeDef, _roomNum))
+ _curFileName = _newFileName;
+ else if (doActionRule(curPos, kRuleActionTake, 0))
+ _curFileName = _newFileName;
+ else if (curPos.y < (_utils->vgaScaleY(149) + _utils->svgaCord(2)))
+ drawStaticMessage(kTextNothing);
+
+ break;
+
+ case 1:
+ case 2:
+ case 3:
+ // Manipulate an object, Open up a "door" or Close a "door"
+ if (doActionRule(curPos, actionMode, _roomNum))
+ _curFileName = _newFileName;
+ else if (!doActionRule(curPos, actionMode, 0)) {
+ if (curPos.y < (_utils->vgaScaleY(149) + _utils->svgaCord(2)))
+ drawStaticMessage(kTextNothing);
+ }
+ break;
+
+ case 4: {
+ // Look at closeups
+ const CloseData *tmpClosePtr = _closeDataPtr;
+ setCurrentClose(curPos, &tmpClosePtr, true);
+
+ if (_closeDataPtr == tmpClosePtr) {
+ if (curPos.y < (_utils->vgaScaleY(149) + _utils->svgaCord(2)))
+ drawStaticMessage(kTextNothing);
+ } else if (!tmpClosePtr->_graphicName.empty()) {
+ _anim->_doBlack = true;
+ _closeDataPtr = tmpClosePtr;
+ } else if (curPos.y < (_utils->vgaScaleY(149) + _utils->svgaCord(2)))
+ drawStaticMessage(kTextNothing);
+ }
+ break;
+
+ case 5:
+ if (_conditions->in(curInv)) {
+ // Use an item on something else
+ if (doOperateRule(curPos, curInv)) {
+ _curFileName = _newFileName;
+
+ if (!_conditions->in(curInv))
+ decIncInv(&curInv, false);
+ }
+ else if (curPos.y < (_utils->vgaScaleY(149) + _utils->svgaCord(2)))
+ drawStaticMessage(kTextNothing);
+ }
+ }
+}
+
+void LabEngine::go() {
+ if (getPlatform() == Common::kPlatformWindows)
+ handleTrialWarning();
+
+ _isHiRes = ((getFeatures() & GF_LOWRES) == 0);
+ _graphics->setUpScreens();
+
+ _event->initMouse();
+ if (_msgFont)
+ _graphics->freeFont(&_msgFont);
+
+ if (getPlatform() != Common::kPlatformAmiga)
+ _msgFont = _resource->getFont("F:AvanteG.12");
+ else
+ _msgFont = _resource->getFont("F:Map.fon");
+
+ // If the user has requested to load a game from the launcher, skip the intro
+ if (!ConfMan.hasKey("save_slot")) {
+ _event->mouseHide();
+ _introPlaying = true;
+ Intro *intro = new Intro(this);
+ intro->play();
+ delete intro;
+ _introPlaying = false;
+ _event->mouseShow();
+ }
+
+ mainGameLoop();
+
+ _graphics->freeFont(&_msgFont);
+ _graphics->freePict();
+
+ freeScreens();
+
+ _music->freeMusic();
+}
+
+MainButton LabEngine::followCrumbs() {
+ // kDirectionNorth, kDirectionSouth, kDirectionEast, kDirectionWest
+ MainButton movement[4][4] = {
+ { kButtonForward, kButtonRight, kButtonRight, kButtonLeft },
+ { kButtonRight, kButtonForward, kButtonLeft, kButtonRight },
+ { kButtonLeft, kButtonRight, kButtonForward, kButtonRight },
+ { kButtonRight, kButtonLeft, kButtonRight, kButtonForward }
+ };
+
+ if (_isCrumbWaiting) {
+ if (_system->getMillis() <= _crumbTimestamp)
+ return kButtonNone;
+
+ _isCrumbWaiting = false;
+ }
+
+ if (!_isCrumbTurning)
+ _breadCrumbs[_numCrumbs--]._crumbRoomNum = 0;
+
+ // Is the current crumb this room? If not, logic error.
+ if (_roomNum != _breadCrumbs[_numCrumbs]._crumbRoomNum) {
+ _numCrumbs = 0;
+ _breadCrumbs[0]._crumbRoomNum = 0;
+ _droppingCrumbs = false;
+ _followingCrumbs = false;
+ return kButtonNone;
+ }
+
+ Direction exitDir;
+ // which direction is last crumb
+ if (_breadCrumbs[_numCrumbs]._crumbDirection == kDirectionEast)
+ exitDir = kDirectionWest;
+ else if (_breadCrumbs[_numCrumbs]._crumbDirection == kDirectionWest)
+ exitDir = kDirectionEast;
+ else if (_breadCrumbs[_numCrumbs]._crumbDirection == kDirectionNorth)
+ exitDir = kDirectionSouth;
+ else
+ exitDir = kDirectionNorth;
+
+ MainButton moveDir = movement[_direction][exitDir];
+
+ if (_numCrumbs == 0) {
+ _isCrumbTurning = false;
+ _breadCrumbs[0]._crumbRoomNum = 0;
+ _droppingCrumbs = false;
+ _followingCrumbs = false;
+ } else {
+ _isCrumbTurning = (moveDir != kButtonForward);
+ _isCrumbWaiting = true;
+
+ int theDelay = (_followCrumbsFast ? 1000 / 4 : 1000);
+ _crumbTimestamp = theDelay + _system->getMillis();
+ }
+
+ return moveDir;
+}
+
+} // End of namespace Lab
diff --git a/engines/lab/eventman.cpp b/engines/lab/eventman.cpp
new file mode 100644
index 0000000000..0a603f7691
--- /dev/null
+++ b/engines/lab/eventman.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.
+ *
+ */
+
+/*
+ * This code is based on Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#include "common/events.h"
+
+#include "graphics/cursorman.h"
+
+#include "lab/lab.h"
+
+#include "lab/dispman.h"
+#include "lab/eventman.h"
+#include "lab/image.h"
+#include "lab/interface.h"
+
+namespace Lab {
+
+static const byte mouseData[] = {
+ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 7, 1, 0, 0, 0, 0, 0, 0, 0,
+ 1, 7, 7, 1, 0, 0, 0, 0, 0, 0,
+ 1, 7, 7, 7, 1, 0, 0, 0, 0, 0,
+ 1, 7, 7, 7, 7, 1, 0, 0, 0, 0,
+ 1, 7, 7, 7, 7, 7, 1, 0, 0, 0,
+ 1, 7, 7, 7, 7, 7, 7, 1, 0, 0,
+ 1, 7, 7, 7, 7, 7, 7, 7, 1, 0,
+ 1, 7, 7, 7, 7, 7, 1, 1, 1, 1,
+ 1, 7, 7, 1, 7, 7, 1, 0, 0, 0,
+ 1, 7, 1, 0, 1, 7, 7, 1, 0, 0,
+ 1, 1, 0, 0, 1, 7, 7, 1, 0, 0,
+ 0, 0, 0, 0, 0, 1, 7, 7, 1, 0,
+ 0, 0, 0, 0, 0, 1, 7, 7, 1, 0,
+ 0, 0, 0, 0, 0, 0, 1, 1, 0, 0
+};
+
+#define MOUSE_WIDTH 10
+#define MOUSE_HEIGHT 15
+
+EventManager::EventManager(LabEngine *vm) : _vm(vm) {
+ _leftClick = false;
+ _rightClick = false;
+ _buttonHit = false;
+ _mousePos = Common::Point(0, 0);
+ _keyPressed = Common::KEYCODE_INVALID;
+}
+
+void EventManager::initMouse() {
+ CursorMan.pushCursor(mouseData, MOUSE_WIDTH, MOUSE_HEIGHT, 0, 0, 0);
+ CursorMan.showMouse(false);
+
+ setMousePos(Common::Point(_vm->_graphics->_screenWidth / 2, _vm->_graphics->_screenHeight / 2));
+}
+
+void EventManager::mouseShow() {
+ CursorMan.showMouse(true);
+}
+
+void EventManager::mouseHide() {
+ CursorMan.showMouse(false);
+}
+
+void EventManager::setMousePos(Common::Point pos) {
+ if (_vm->_isHiRes)
+ _vm->_system->warpMouse(pos.x, pos.y);
+ else
+ _vm->_system->warpMouse(pos.x * 2, pos.y);
+}
+
+void EventManager::processInput() {
+ Common::Event event;
+
+ while (_vm->_system->getEventManager()->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_LBUTTONDOWN:
+ if (_vm->_interface->checkButtonHit(_mousePos))
+ _buttonHit = true;
+ else
+ _leftClick = true;
+ break;
+ case Common::EVENT_RBUTTONDOWN:
+ _rightClick = true;
+ break;
+ case Common::EVENT_MOUSEMOVE:
+ _mousePos = event.mouse;
+ break;
+ case Common::EVENT_KEYDOWN:
+ switch (event.kbd.keycode) {
+ case Common::KEYCODE_LEFTBRACKET:
+ _vm->changeVolume(-1);
+ break;
+ case Common::KEYCODE_RIGHTBRACKET:
+ _vm->changeVolume(1);
+ break;
+ case Common::KEYCODE_d:
+ if (event.kbd.hasFlags(Common::KBD_CTRL)) {
+ // Open debugger console
+ _vm->_console->attach();
+ continue;
+ }
+ // Intentional fall through
+ default:
+ _keyPressed = event.kbd;
+ break;
+ }
+ break;
+ case Common::EVENT_QUIT:
+ case Common::EVENT_RTL:
+ default:
+ break;
+ }
+ }
+}
+
+IntuiMessage *EventManager::getMsg() {
+ static IntuiMessage message;
+
+ _vm->_interface->handlePressedButton();
+ processInput();
+
+ if (_buttonHit) {
+ Button *lastButtonHit = _vm->_interface->checkButtonHit(_mousePos);
+ _buttonHit = false;
+ if (lastButtonHit) {
+ _vm->_interface->handlePressedButton();
+ message._msgClass = kMessageButtonUp;
+ message._code = lastButtonHit->_buttonId;
+ message._qualifier = _keyPressed.flags;
+
+ return &message;
+ } else
+ return nullptr;
+ } else if (_leftClick || _rightClick) {
+ message._msgClass = (_leftClick) ? kMessageLeftClick : kMessageRightClick;
+ message._qualifier = 0;
+ message._mouse = _mousePos;
+ _leftClick = _rightClick = false;
+ return &message;
+ } else if (_keyPressed.keycode != Common::KEYCODE_INVALID) {
+ Button *curButton = _vm->_interface->checkNumButtonHit(_keyPressed.keycode);
+
+ if (curButton) {
+ message._msgClass = kMessageButtonUp;
+ message._code = curButton->_buttonId;
+ } else {
+ message._msgClass = kMessageRawKey;
+ message._code = _keyPressed.keycode;
+ }
+
+ message._qualifier = _keyPressed.flags;
+ message._mouse = _mousePos;
+
+ _keyPressed.keycode = Common::KEYCODE_INVALID;
+
+ return &message;
+ } else
+ return nullptr;
+}
+
+Common::Point EventManager::updateAndGetMousePos() {
+ processInput();
+
+ return _mousePos;
+}
+
+void EventManager::simulateEvent() {
+ // Simulate an event by setting an unused key
+ _keyPressed = Common::KeyState(Common::KEYCODE_SEMICOLON);
+}
+
+} // End of namespace Lab
diff --git a/engines/lab/eventman.h b/engines/lab/eventman.h
new file mode 100644
index 0000000000..e4114edbad
--- /dev/null
+++ b/engines/lab/eventman.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.
+ *
+ */
+
+/*
+ * This code is based on Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#ifndef LAB_EVENTMAN_H
+#define LAB_EVENTMAN_H
+
+#include "common/events.h"
+
+namespace Lab {
+
+class LabEngine;
+class Image;
+
+struct IntuiMessage {
+ MessageClass _msgClass;
+ uint16 _code; // KeyCode or Button Id
+ uint16 _qualifier;
+ Common::Point _mouse;
+};
+
+class EventManager {
+private:
+ LabEngine *_vm;
+
+ bool _leftClick;
+ bool _rightClick;
+ bool _buttonHit;
+
+ Common::Point _mousePos;
+ Common::KeyState _keyPressed;
+
+public:
+ EventManager (LabEngine *vm);
+
+ IntuiMessage *getMsg();
+
+ /**
+ * Initializes the mouse.
+ */
+ void initMouse();
+
+ /**
+ * Shows the mouse.
+ */
+ void mouseShow();
+
+ /**
+ * Hides the mouse.
+ */
+ void mouseHide();
+ void processInput();
+
+ /**
+ * Moves the mouse to new co-ordinates.
+ */
+ void setMousePos(Common::Point pos);
+ Common::Point updateAndGetMousePos();
+
+ /**
+ * Simulates an event for the game main loop, when a game is
+ * loaded or when the user teleports to a scene
+ */
+ void simulateEvent();
+};
+
+} // End of namespace Lab
+
+#endif // LAB_EVENTMAN_H
diff --git a/engines/lab/image.cpp b/engines/lab/image.cpp
new file mode 100644
index 0000000000..ec516718e8
--- /dev/null
+++ b/engines/lab/image.cpp
@@ -0,0 +1,136 @@
+/* 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 Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#include "common/file.h"
+
+#include "lab/lab.h"
+
+#include "lab/dispman.h"
+#include "lab/image.h"
+
+namespace Lab {
+
+Image::Image(Common::File *s, LabEngine *vm) : _vm(vm) {
+ _width = s->readUint16LE();
+ _height = s->readUint16LE();
+ s->skip(4);
+
+ uint32 size = _width * _height;
+ if (size & 1)
+ size++;
+
+ _imageData = new byte[size];
+ s->read(_imageData, size);
+ _autoFree = true;
+}
+
+Image::~Image() {
+ if (_autoFree)
+ delete[] _imageData;
+}
+
+void Image::setData(byte *d, bool autoFree) {
+ if (_autoFree)
+ delete[] _imageData;
+ _imageData = d;
+ _autoFree = autoFree;
+}
+
+void Image::blitBitmap(uint16 srcX, uint16 srcY, Image *imgDest,
+ uint16 destX, uint16 destY, uint16 width, uint16 height, byte masked) {
+ int clipWidth = width;
+ int clipHeight = height;
+ int destWidth = (imgDest) ? imgDest->_width : _vm->_graphics->_screenWidth;
+ int destHeight = (imgDest) ? imgDest->_height : _vm->_graphics->_screenHeight;
+ byte *destBuffer = (imgDest) ? imgDest->_imageData : _vm->_graphics->getCurrentDrawingBuffer();
+
+ if (destX + clipWidth > destWidth)
+ clipWidth = destWidth - destX;
+
+ if (destY + clipHeight > destHeight)
+ clipHeight = destHeight - destY;
+
+ if ((clipWidth > 0) && (clipHeight > 0)) {
+ byte *img = _imageData + srcY * _width + srcX;
+ byte *dest = destBuffer + destY * destWidth + destX;
+
+ if (!masked) {
+ for (int i = 0; i < clipHeight; i++) {
+ memcpy(dest, img, clipWidth);
+ img += _width;
+ dest += destWidth;
+ }
+ } else {
+ for (int i = 0; i < clipHeight; i++) {
+ for (int j = 0; j < clipWidth; j++) {
+ byte c = img[j];
+
+ if (c)
+ dest[j] = c - 1;
+ }
+
+ img += _width;
+ dest += destWidth;
+ }
+ }
+ }
+}
+
+void Image::drawImage(uint16 x, uint16 y) {
+ blitBitmap(0, 0, nullptr, x, y, _width, _height, false);
+}
+
+void Image::drawMaskImage(uint16 x, uint16 y) {
+ blitBitmap(0, 0, nullptr, x, y, _width, _height, true);
+}
+
+void Image::readScreenImage(uint16 x, uint16 y) {
+ int clipWidth = _width;
+ int clipHeight = _height;
+
+ if (x + clipWidth > _vm->_graphics->_screenWidth)
+ clipWidth = _vm->_graphics->_screenWidth - x;
+
+ if (y + clipHeight > _vm->_graphics->_screenHeight)
+ clipHeight = _vm->_graphics->_screenHeight - y;
+
+ if ((clipWidth > 0) && (clipHeight > 0)) {
+ byte *img = _imageData;
+ byte *screen = _vm->_graphics->getCurrentDrawingBuffer() + y * _vm->_graphics->_screenWidth + x;
+
+ while (clipHeight-- > 0) {
+ memcpy(img, screen, clipWidth);
+ img += _width;
+ screen += _vm->_graphics->_screenWidth;
+ }
+ }
+}
+
+} // End of namespace Lab
diff --git a/engines/lab/image.h b/engines/lab/image.h
new file mode 100644
index 0000000000..0f985e09eb
--- /dev/null
+++ b/engines/lab/image.h
@@ -0,0 +1,83 @@
+/* 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 Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#ifndef LAB_IMAGE_H
+#define LAB_IMAGE_H
+
+namespace Common {
+ class File;
+}
+
+namespace Lab {
+
+class LabEngine;
+
+class Image {
+ LabEngine *_vm;
+
+public:
+ uint16 _width;
+ uint16 _height;
+ byte *_imageData;
+
+ Image(LabEngine *vm) : _width(0), _height(0), _imageData(nullptr), _vm(vm), _autoFree(true) {}
+ Image(int w, int h, byte *d, LabEngine *vm, bool autoFree = true) : _width(w), _height(h), _imageData(d), _vm(vm), _autoFree(autoFree) {}
+ Image(Common::File *s, LabEngine *vm);
+ ~Image();
+
+ void setData(byte *d, bool autoFree = true);
+
+ /**
+ * Draws an image to the screen.
+ */
+ void drawImage(uint16 x, uint16 y);
+
+ /**
+ * Draws an image to the screen with transparency.
+ */
+ void drawMaskImage(uint16 x, uint16 y);
+
+ /**
+ * Reads an image from the screen.
+ */
+ void readScreenImage(uint16 x, uint16 y);
+
+ /**
+ * Blits a piece of one image to another.
+ */
+ void blitBitmap(uint16 srcX, uint16 srcY, Image *imgDest, uint16 destX, uint16 destY, uint16 width, uint16 height, byte masked);
+
+private:
+ bool _autoFree; ///< Free _imageData in destructor?
+};
+
+} // End of namespace Lab
+
+#endif // LAB_IMAGE_H
diff --git a/engines/lab/interface.cpp b/engines/lab/interface.cpp
new file mode 100644
index 0000000000..bac1155725
--- /dev/null
+++ b/engines/lab/interface.cpp
@@ -0,0 +1,242 @@
+/* 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 Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#include "common/events.h"
+
+#include "lab/lab.h"
+
+#include "lab/dispman.h"
+#include "lab/interface.h"
+#include "lab/image.h"
+#include "lab/utils.h"
+
+namespace Lab {
+
+#define CRUMBSWIDTH 24
+#define CRUMBSHEIGHT 24
+
+Interface::Interface(LabEngine *vm) : _vm(vm) {
+ _screenButtonList = nullptr;
+ _hitButton = nullptr;
+}
+
+Button *Interface::createButton(uint16 x, uint16 y, uint16 id, Common::KeyCode key, Image *image, Image *altImage) {
+ Button *button = new Button();
+
+ if (button) {
+ button->_x = _vm->_utils->vgaScaleX(x);
+ button->_y = y;
+ button->_buttonId = id;
+ button->_keyEquiv = key;
+ button->_image = image;
+ button->_altImage = altImage;
+ button->_isEnabled = true;
+
+ return button;
+ } else
+ return nullptr;
+}
+
+void Interface::freeButtonList(ButtonList *buttonList) {
+ for (ButtonList::iterator buttonIter = buttonList->begin(); buttonIter != buttonList->end(); ++buttonIter) {
+ Button *button = *buttonIter;
+ delete button->_image;
+ delete button->_altImage;
+ delete button;
+ }
+
+ buttonList->clear();
+}
+
+void Interface::drawButtonList(ButtonList *buttonList) {
+ for (ButtonList::iterator button = buttonList->begin(); button != buttonList->end(); ++button) {
+ toggleButton((*button), 1, true);
+
+ if (!(*button)->_isEnabled)
+ toggleButton((*button), 1, false);
+ }
+}
+
+void Interface::toggleButton(Button *button, uint16 disabledPenColor, bool enable) {
+ if (!enable)
+ _vm->_graphics->checkerBoardEffect(disabledPenColor, button->_x, button->_y, button->_x + button->_image->_width - 1, button->_y + button->_image->_height - 1);
+ else
+ button->_image->drawImage(button->_x, button->_y);
+
+ button->_isEnabled = enable;
+}
+
+Button *Interface::checkNumButtonHit(Common::KeyCode key) {
+ uint16 gkey = key - '0';
+
+ if (!_screenButtonList)
+ return nullptr;
+
+ for (ButtonList::iterator buttonItr = _screenButtonList->begin(); buttonItr != _screenButtonList->end(); ++buttonItr) {
+ Button *button = *buttonItr;
+ if (!button->_isEnabled)
+ continue;
+
+ if ((gkey - 1 == button->_buttonId) || (gkey == 0 && button->_buttonId == 9) || (button->_keyEquiv != Common::KEYCODE_INVALID && key == button->_keyEquiv)) {
+ button->_altImage->drawImage(button->_x, button->_y);
+ _vm->_system->delayMillis(80);
+ button->_image->drawImage(button->_x, button->_y);
+ return button;
+ }
+ }
+
+ return nullptr;
+}
+
+Button *Interface::checkButtonHit(Common::Point pos) {
+ if (!_screenButtonList)
+ return nullptr;
+
+ for (ButtonList::iterator buttonItr = _screenButtonList->begin(); buttonItr != _screenButtonList->end(); ++buttonItr) {
+ Button *button = *buttonItr;
+ Common::Rect buttonRect(button->_x, button->_y, button->_x + button->_image->_width - 1, button->_y + button->_image->_height - 1);
+
+ if (buttonRect.contains(pos) && button->_isEnabled) {
+ _hitButton = button;
+ return button;
+ }
+ }
+
+ return nullptr;
+}
+
+void Interface::handlePressedButton() {
+ if (!_hitButton)
+ return;
+
+ _hitButton->_altImage->drawImage(_hitButton->_x, _hitButton->_y);
+ for (int i = 0; i < 3; i++)
+ _vm->waitTOF();
+ _hitButton->_image->drawImage(_hitButton->_x, _hitButton->_y);
+
+ _hitButton = nullptr;
+ _vm->_graphics->screenUpdate();
+}
+
+void Interface::attachButtonList(ButtonList *buttonList) {
+ _screenButtonList = buttonList;
+}
+
+Button *Interface::getButton(uint16 id) {
+ for (ButtonList::iterator buttonItr = _screenButtonList->begin(); buttonItr != _screenButtonList->end(); ++buttonItr) {
+ Button *button = *buttonItr;
+ if (button->_buttonId == id)
+ return button;
+ }
+
+ return nullptr;
+}
+
+void Interface::mayShowCrumbIndicator() {
+ static byte dropCrumbsImageData[CRUMBSWIDTH * CRUMBSHEIGHT] = {
+ 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0,
+ 0, 4, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 4, 0,
+ 4, 7, 7, 3, 4, 4, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 7, 7, 4,
+ 4, 7, 4, 4, 0, 0, 3, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 7, 4,
+ 4, 7, 4, 0, 0, 0, 3, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 4, 7, 4,
+ 4, 7, 4, 0, 0, 3, 2, 2, 2, 3, 0, 0, 0, 0, 0, 0, 0, 3, 2, 3, 0, 4, 7, 4,
+ 4, 7, 4, 0, 0, 0, 3, 3, 3, 4, 4, 4, 4, 4, 4, 0, 0, 3, 2, 3, 0, 4, 7, 4,
+ 4, 7, 4, 0, 0, 0, 0, 0, 4, 7, 7, 7, 7, 7, 7, 4, 3, 2, 2, 2, 3, 4, 7, 4,
+ 4, 7, 4, 0, 0, 0, 0, 4, 7, 7, 4, 4, 4, 4, 7, 7, 4, 3, 3, 3, 0, 4, 7, 4,
+ 4, 7, 4, 0, 0, 0, 0, 4, 7, 4, 4, 0, 0, 4, 4, 7, 4, 0, 0, 0, 0, 4, 7, 4,
+ 4, 7, 4, 0, 0, 0, 0, 4, 7, 4, 0, 0, 0, 0, 4, 7, 4, 0, 0, 0, 0, 4, 7, 4,
+ 4, 7, 4, 0, 0, 0, 0, 4, 4, 4, 3, 0, 0, 0, 4, 7, 4, 0, 0, 0, 0, 4, 7, 4,
+ 4, 7, 4, 0, 0, 0, 0, 0, 4, 3, 2, 3, 0, 0, 4, 7, 4, 0, 0, 0, 0, 4, 7, 4,
+ 4, 7, 4, 0, 0, 0, 0, 0, 0, 3, 2, 3, 0, 0, 4, 7, 4, 0, 0, 0, 0, 4, 7, 4,
+ 4, 7, 4, 0, 0, 0, 0, 0, 3, 2, 2, 2, 3, 4, 4, 7, 4, 0, 0, 0, 0, 4, 7, 4,
+ 4, 7, 7, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7, 7, 4, 0, 0, 0, 0, 4, 7, 4,
+ 0, 4, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 4, 0, 0, 0, 0, 0, 4, 7, 4,
+ 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 0, 0, 0, 0, 0, 4, 7, 4,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 3, 0, 0, 0, 0, 4, 7, 4,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 3, 0, 0, 0, 0, 4, 7, 4,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 3, 0, 0, 4, 4, 7, 4,
+ 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7, 7, 4,
+ 0, 0, 4, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 4, 0,
+ 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0
+ };
+
+ if (_vm->getPlatform() != Common::kPlatformWindows)
+ return;
+
+ if (_vm->_droppingCrumbs && _vm->isMainDisplay()) {
+ static byte *imgData = new byte[CRUMBSWIDTH * CRUMBSHEIGHT];
+ memcpy(imgData, dropCrumbsImageData, CRUMBSWIDTH * CRUMBSHEIGHT);
+ static Image dropCrumbsImage(CRUMBSWIDTH, CRUMBSHEIGHT, imgData, _vm);
+
+ dropCrumbsImage.drawMaskImage(612, 4);
+ }
+}
+
+void Interface::mayShowCrumbIndicatorOff() {
+ static byte dropCrumbsOffImageData[CRUMBSWIDTH * CRUMBSHEIGHT] = {
+ 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0,
+ 0, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 0,
+ 4, 8, 8, 3, 4, 4, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 8, 8, 4,
+ 4, 8, 4, 4, 0, 0, 3, 8, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 8, 4,
+ 4, 8, 4, 0, 0, 0, 3, 8, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 4, 8, 4,
+ 4, 8, 4, 0, 0, 3, 8, 8, 8, 3, 0, 0, 0, 0, 0, 0, 0, 3, 8, 3, 0, 4, 8, 4,
+ 4, 8, 4, 0, 0, 0, 3, 3, 3, 4, 4, 4, 4, 4, 4, 0, 0, 3, 8, 3, 0, 4, 8, 4,
+ 4, 8, 4, 0, 0, 0, 0, 0, 4, 8, 8, 8, 8, 8, 8, 4, 3, 8, 8, 8, 3, 4, 8, 4,
+ 4, 8, 4, 0, 0, 0, 0, 4, 8, 8, 4, 4, 4, 4, 8, 8, 4, 3, 3, 3, 0, 4, 8, 4,
+ 4, 8, 4, 0, 0, 0, 0, 4, 8, 4, 4, 0, 0, 4, 4, 8, 4, 0, 0, 0, 0, 4, 8, 4,
+ 4, 8, 4, 0, 0, 0, 0, 4, 8, 4, 0, 0, 0, 0, 4, 8, 4, 0, 0, 0, 0, 4, 8, 4,
+ 4, 8, 4, 0, 0, 0, 0, 4, 4, 4, 3, 0, 0, 0, 4, 8, 4, 0, 0, 0, 0, 4, 8, 4,
+ 4, 8, 4, 0, 0, 0, 0, 0, 4, 3, 8, 3, 0, 0, 4, 8, 4, 0, 0, 0, 0, 4, 8, 4,
+ 4, 8, 4, 0, 0, 0, 0, 0, 0, 3, 8, 3, 0, 0, 4, 8, 4, 0, 0, 0, 0, 4, 8, 4,
+ 4, 8, 4, 0, 0, 0, 0, 0, 3, 8, 8, 8, 3, 4, 4, 8, 4, 0, 0, 0, 0, 4, 8, 4,
+ 4, 8, 8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 4, 0, 0, 0, 0, 4, 8, 4,
+ 0, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 0, 0, 0, 0, 0, 4, 8, 4,
+ 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 0, 0, 0, 0, 0, 4, 8, 4,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 8, 3, 0, 0, 0, 0, 4, 8, 4,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 8, 3, 0, 0, 0, 0, 4, 8, 4,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 8, 8, 8, 3, 0, 0, 4, 4, 8, 4,
+ 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 4,
+ 0, 0, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 0,
+ 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0
+ };
+
+ if (_vm->getPlatform() != Common::kPlatformWindows)
+ return;
+
+ if (_vm->isMainDisplay()) {
+ static byte *imgData = new byte[CRUMBSWIDTH * CRUMBSHEIGHT];
+ memcpy(imgData, dropCrumbsOffImageData, CRUMBSWIDTH * CRUMBSHEIGHT);
+ static Image dropCrumbsOffImage(CRUMBSWIDTH, CRUMBSHEIGHT, imgData, _vm);
+
+ dropCrumbsOffImage.drawMaskImage(612, 4);
+ }
+}
+
+} // End of namespace Lab
diff --git a/engines/lab/interface.h b/engines/lab/interface.h
new file mode 100644
index 0000000000..51478dd463
--- /dev/null
+++ b/engines/lab/interface.h
@@ -0,0 +1,91 @@
+/* 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 Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#ifndef LAB_INTERFACE_H
+#define LAB_INTERFACE_H
+
+#include "common/events.h"
+
+namespace Lab {
+
+class LabEngine;
+class Image;
+
+struct Button {
+ uint16 _x, _y, _buttonId;
+ Common::KeyCode _keyEquiv; // the key which activates this button
+ bool _isEnabled;
+ Image *_image, *_altImage;
+};
+
+typedef Common::List<Button *> ButtonList;
+
+class Interface {
+private:
+ LabEngine *_vm;
+
+ Button *_hitButton;
+ ButtonList *_screenButtonList;
+
+public:
+ Interface(LabEngine *vm);
+
+ void attachButtonList(ButtonList *buttonList);
+ Button *createButton(uint16 x, uint16 y, uint16 id, Common::KeyCode key, Image *image, Image *altImage);
+ void toggleButton(Button *button, uint16 penColor, bool enable);
+
+ /**
+ * Draws a button list to the screen.
+ */
+ void drawButtonList(ButtonList *buttonList);
+ void freeButtonList(ButtonList *buttonList);
+ Button *getButton(uint16 id);
+
+ /**
+ * Checks whether or not the coords fall within one of the buttons in a list
+ * of buttons.
+ */
+ Button *checkButtonHit(Common::Point pos);
+
+ /**
+ * Checks whether or not the coords fall within one of the buttons in a list
+ * of buttons.
+ */
+ Button *checkNumButtonHit(Common::KeyCode key);
+
+ void handlePressedButton();
+
+ void mayShowCrumbIndicator();
+ void mayShowCrumbIndicatorOff();
+};
+
+} // End of namespace Lab
+
+#endif // LAB_INTERFACE_H
diff --git a/engines/lab/intro.cpp b/engines/lab/intro.cpp
new file mode 100644
index 0000000000..0184ff7c69
--- /dev/null
+++ b/engines/lab/intro.cpp
@@ -0,0 +1,417 @@
+/* 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 Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#include "common/file.h"
+
+#include "lab/lab.h"
+
+#include "lab/anim.h"
+#include "lab/dispman.h"
+#include "lab/eventman.h"
+#include "lab/intro.h"
+#include "lab/music.h"
+#include "lab/resource.h"
+#include "lab/utils.h"
+
+namespace Lab {
+
+Intro::Intro(LabEngine *vm) : _vm(vm) {
+ _quitIntro = false;
+ _font = _vm->_resource->getFont("F:Map.fon");
+}
+
+Intro::~Intro() {
+ _vm->_graphics->freeFont(&_font);
+}
+
+void Intro::introEatMessages() {
+ while (1) {
+ IntuiMessage *msg = _vm->_event->getMsg();
+
+ if (_vm->shouldQuit()) {
+ _quitIntro = true;
+ return;
+ }
+
+ if (!msg)
+ return;
+
+ if ((msg->_msgClass == kMessageRightClick)
+ || ((msg->_msgClass == kMessageRawKey) && (msg->_code == Common::KEYCODE_ESCAPE)))
+ _quitIntro = true;
+ }
+}
+
+void Intro::doPictText(const Common::String filename, bool isScreen) {
+ Common::String path = Common::String("Lab:rooms/Intro/") + filename;
+
+ uint timeDelay = (isScreen) ? 35 : 7;
+ _vm->updateEvents();
+
+ if (_quitIntro)
+ return;
+
+ uint32 lastMillis = 0;
+ bool drawNextText = true;
+ bool doneFl = false;
+ bool begin = true;
+
+ Common::File *textFile = _vm->_resource->openDataFile(path);
+ char *textBuffer = new char[textFile->size()];
+ textFile->read(textBuffer, textFile->size());
+ delete textFile;
+ const char *curText = textBuffer;
+
+ while (1) {
+ if (drawNextText) {
+ if (begin)
+ begin = false;
+ else if (isScreen)
+ _vm->_graphics->fade(false);
+
+ if (isScreen) {
+ _vm->_graphics->rectFillScaled(10, 10, 310, 190, 7);
+
+ curText += _vm->_graphics->flowText(_font, _vm->_isHiRes ? 0 : -1, 5, 7, false, false, true, true, _vm->_utils->vgaRectScale(14, 11, 306, 189), curText);
+ _vm->_graphics->fade(true);
+ } else
+ curText += _vm->_graphics->longDrawMessage(Common::String(curText), false);
+
+ doneFl = (*curText == 0);
+
+ drawNextText = false;
+ introEatMessages();
+
+ if (_quitIntro) {
+ if (isScreen)
+ _vm->_graphics->fade(false);
+
+ delete[] textBuffer;
+ return;
+ }
+
+ lastMillis = _vm->_system->getMillis();
+ }
+
+ IntuiMessage *msg = _vm->_event->getMsg();
+ if (_vm->shouldQuit()) {
+ _quitIntro = true;
+ return;
+ }
+
+ if (!msg) {
+ _vm->updateEvents();
+ _vm->_anim->diffNextFrame();
+
+ uint32 elapsedSeconds = (_vm->_system->getMillis() - lastMillis) / 1000;
+
+ if (elapsedSeconds > timeDelay) {
+ if (doneFl) {
+ if (isScreen)
+ _vm->_graphics->fade(false);
+
+ delete[] textBuffer;
+ return;
+ } else {
+ drawNextText = true;
+ }
+ }
+ _vm->waitTOF();
+ } else {
+ uint32 msgClass = msg->_msgClass;
+ uint16 code = msg->_code;
+
+ if ((msgClass == kMessageRightClick) ||
+ ((msgClass == kMessageRawKey) && (code == Common::KEYCODE_ESCAPE))) {
+ _quitIntro = true;
+
+ if (isScreen)
+ _vm->_graphics->fade(false);
+
+ delete[] textBuffer;
+ return;
+ } else if ((msgClass == kMessageLeftClick) || (msgClass == kMessageRightClick)) {
+ if (msgClass == kMessageLeftClick) {
+ if (doneFl) {
+ if (isScreen)
+ _vm->_graphics->fade(false);
+
+ delete[] textBuffer;
+ return;
+ } else
+ drawNextText = true;
+ }
+
+ introEatMessages();
+
+ if (_quitIntro) {
+ if (isScreen)
+ _vm->_graphics->fade(false);
+
+ delete[] textBuffer;
+ return;
+ }
+ }
+
+ if (doneFl) {
+ if (isScreen)
+ _vm->_graphics->fade(false);
+
+ delete[] textBuffer;
+ return;
+ } else
+ drawNextText = true;
+ }
+ } // while(1)
+}
+
+void Intro::nReadPict(const Common::String filename, bool playOnce, bool noPalChange, bool doBlack, int wait) {
+ Common::String finalFileName = Common::String("P:Intro/") + filename;
+
+ _vm->updateEvents();
+ introEatMessages();
+
+ if (_quitIntro)
+ return;
+
+ if (noPalChange)
+ _vm->_anim->_noPalChange = true;
+
+ _vm->_anim->_doBlack = doBlack;
+ _vm->_anim->stopDiffEnd();
+ _vm->_graphics->readPict(finalFileName, playOnce);
+
+ if (wait) {
+ for (int i = 0; i < wait / 10; i++) {
+ _vm->updateEvents();
+ introEatMessages();
+ if (_quitIntro)
+ break;
+ _vm->_system->delayMillis(10);
+ }
+ }
+
+ if (noPalChange)
+ _vm->_anim->_noPalChange = false;
+}
+
+void Intro::play() {
+ uint16 palette[16] = {
+ 0x0000, 0x0855, 0x0FF9, 0x0EE7,
+ 0x0ED5, 0x0DB4, 0x0CA2, 0x0C91,
+ 0x0B80, 0x0B80, 0x0B91, 0x0CA2,
+ 0x0CB3, 0x0DC4, 0x0DD6, 0x0EE7
+ };
+
+ if (_vm->getPlatform() == Common::kPlatformDOS) {
+ nReadPict("EA0");
+ nReadPict("EA1");
+ nReadPict("EA2");
+ nReadPict("EA3");
+ } else if (_vm->getPlatform() == Common::kPlatformWindows) {
+ nReadPict("WYRMKEEP", true, false, false, 4000);
+ }
+
+ _vm->_graphics->blackAllScreen();
+ _vm->_music->resetMusic(false);
+
+ if (_vm->getPlatform() == Common::kPlatformDOS)
+ nReadPict("TNDcycle.pic", true, true);
+ else
+ nReadPict("TNDcycle2.pic", true, true);
+
+ _vm->_graphics->_fadePalette = palette;
+
+ for (int i = 0; i < 16; i++) {
+ palette[i] = ((_vm->_anim->_diffPalette[i * 3] >> 2) << 8) +
+ ((_vm->_anim->_diffPalette[i * 3 + 1] >> 2) << 4) +
+ (_vm->_anim->_diffPalette[i * 3 + 2] >> 2);
+ }
+
+ _vm->updateEvents();
+ introEatMessages();
+ if (!_quitIntro)
+ _vm->_graphics->fade(true);
+
+ for (int times = 0; times < 150; times++) {
+ _vm->updateEvents();
+ introEatMessages();
+ if (_quitIntro)
+ break;
+
+ uint16 temp = palette[2];
+
+ for (int i = 2; i < 15; i++)
+ palette[i] = palette[i + 1];
+
+ palette[15] = temp;
+
+ _vm->_graphics->setAmigaPal(palette);
+ _vm->waitTOF();
+ _vm->waitTOF();
+ }
+
+ if (!_quitIntro) {
+ _vm->_graphics->fade(false);
+ _vm->_graphics->blackAllScreen();
+ _vm->updateEvents();
+ introEatMessages();
+ }
+
+ nReadPict("Title.A");
+ nReadPict("AB", true, false, false, 1000);
+ nReadPict("BA");
+ nReadPict("AC", true, false, false, 1000);
+ nReadPict("CA");
+ nReadPict("AD", true, false, false, 1000);
+ nReadPict("DA");
+
+ _vm->_graphics->blackAllScreen();
+ _vm->updateEvents();
+ introEatMessages();
+
+ nReadPict("Intro.1", true, true);
+
+ for (int i = 0; i < 16; i++) {
+ palette[i] = ((_vm->_anim->_diffPalette[i * 3] >> 2) << 8) +
+ ((_vm->_anim->_diffPalette[i * 3 + 1] >> 2) << 4) +
+ (_vm->_anim->_diffPalette[i * 3 + 2] >> 2);
+ }
+
+ doPictText("i.1", true);
+ if (_vm->getPlatform() == Common::kPlatformWindows) {
+ doPictText("i.2A", true);
+ doPictText("i.2B", true);
+ }
+
+ _vm->_graphics->blackAllScreen();
+ _vm->updateEvents();
+ introEatMessages();
+
+ nReadPict("Station1", true, false, true);
+ doPictText("i.3");
+
+ nReadPict("Station2", true, false, true);
+ doPictText("i.4");
+
+ nReadPict("Stiles4", true, false, true);
+ doPictText("i.5");
+
+ nReadPict("Stiles3", true, false, true);
+ doPictText("i.6");
+
+ if (_vm->getPlatform() == Common::kPlatformWindows)
+ nReadPict("Platform2", true, false, true);
+ else
+ nReadPict("Platform", true, false, true);
+ doPictText("i.7");
+
+ nReadPict("Subway.1", true, false, true);
+ doPictText("i.8");
+
+ nReadPict("Subway.2", true, false, true);
+
+ doPictText("i.9");
+ doPictText("i.10");
+ doPictText("i.11");
+
+ for (int i = 0; i < 50; i++) {
+ _vm->updateEvents();
+ introEatMessages();
+ if (_quitIntro)
+ break;
+
+ for (int idx = (8 * 3); idx < (255 * 3); idx++)
+ _vm->_anim->_diffPalette[idx] = 255 - _vm->_anim->_diffPalette[idx];
+
+ _vm->waitTOF();
+ _vm->_graphics->setPalette(_vm->_anim->_diffPalette, 256);
+ _vm->waitTOF();
+ _vm->waitTOF();
+ }
+
+ doPictText("i.12");
+ doPictText("i.13");
+
+ nReadPict("Daed0");
+ doPictText("i.14");
+
+ nReadPict("Daed1");
+ doPictText("i.15");
+
+ nReadPict("Daed2");
+ doPictText("i.16");
+ doPictText("i.17");
+ doPictText("i.18");
+
+ nReadPict("Daed3");
+ doPictText("i.19");
+ doPictText("i.20");
+
+ nReadPict("Daed4");
+ doPictText("i.21");
+
+ nReadPict("Daed5");
+ doPictText("i.22");
+ doPictText("i.23");
+ doPictText("i.24");
+
+ nReadPict("Daed6");
+ doPictText("i.25");
+ doPictText("i.26");
+
+ nReadPict("Daed7", false);
+ doPictText("i.27");
+ doPictText("i.28");
+
+ nReadPict("Daed8");
+ doPictText("i.29");
+ doPictText("i.30");
+
+ nReadPict("Daed9");
+ doPictText("i.31");
+ doPictText("i.32");
+ doPictText("i.33");
+
+ nReadPict("Daed9a");
+ nReadPict("Daed10");
+ doPictText("i.34");
+ doPictText("i.35");
+ doPictText("i.36");
+
+ nReadPict("SubX");
+
+ if (_quitIntro) {
+ _vm->_graphics->rectFill(0, 0, _vm->_graphics->_screenWidth - 1, _vm->_graphics->_screenHeight - 1, 0);
+ _vm->_anim->_doBlack = true;
+ }
+}
+
+} // End of namespace Lab
diff --git a/engines/lab/intro.h b/engines/lab/intro.h
new file mode 100644
index 0000000000..f86d3baf69
--- /dev/null
+++ b/engines/lab/intro.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.
+ *
+ */
+
+ /*
+ * This code is based on Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#ifndef LAB_INTRO_H
+#define LAB_INTRO_H
+
+namespace Lab {
+
+class Intro {
+public:
+ Intro(LabEngine *vm);
+ ~Intro();
+
+ /**
+ * Does the introduction sequence for Labyrinth.
+ */
+ void play();
+
+private:
+ /**
+ * Goes through, and responds to all the intuition messages currently in the
+ * message queue.
+ */
+ void introEatMessages();
+
+ /**
+ * Reads in a picture.
+ */
+ void doPictText(const Common::String filename, bool isScreen = false);
+
+ void nReadPict(const Common::String filename, bool playOnce = true, bool noPalChange = false, bool doBlack = false, int wait = 0);
+
+ LabEngine *_vm;
+ bool _quitIntro;
+ TextFont *_font;
+};
+
+} // End of namespace Lab
+
+#endif // LAB_INTRO_H
diff --git a/engines/lab/lab.cpp b/engines/lab/lab.cpp
new file mode 100644
index 0000000000..39b2feb93d
--- /dev/null
+++ b/engines/lab/lab.cpp
@@ -0,0 +1,234 @@
+/* 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 Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#include "common/config-manager.h"
+#include "common/debug-channels.h"
+#include "common/error.h"
+#include "common/file.h"
+
+#include "engines/util.h"
+
+#include "lab/lab.h"
+
+#include "lab/anim.h"
+#include "lab/console.h"
+#include "lab/dispman.h"
+#include "lab/eventman.h"
+#include "lab/image.h"
+#include "lab/interface.h"
+#include "lab/music.h"
+#include "lab/processroom.h"
+#include "lab/resource.h"
+#include "lab/speciallocks.h"
+#include "lab/utils.h"
+
+namespace Lab {
+LabEngine::LabEngine(OSystem *syst, const ADGameDescription *gameDesc)
+ : Engine(syst), _gameDescription(gameDesc), _extraGameFeatures(0) {
+ _lastWaitTOFTicks = 0;
+
+ _isHiRes = false;
+ _roomNum = -1;
+ for (int i = 0; i < MAX_CRUMBS; i++) {
+ _breadCrumbs[i]._crumbRoomNum = 0;
+ _breadCrumbs[i]._crumbDirection = kDirectionNorth;
+ }
+
+ _numCrumbs = 0;
+ _droppingCrumbs = false;
+ _followingCrumbs = false;
+ _followCrumbsFast = false;
+ _isCrumbTurning = false;
+ _isCrumbWaiting = false;
+ _noUpdateDiff = false;
+ _quitLab = false;
+ _mainDisplay = true;
+
+ _numInv = 0;
+ _manyRooms = 0;
+ _direction = 0;
+ _highestCondition = 0;
+ _crumbTimestamp = 0;
+ _maxRooms = 0;
+
+ _event = nullptr;
+ _interface = nullptr;
+ _resource = nullptr;
+ _music = nullptr;
+ _anim = nullptr;
+ _closeDataPtr = nullptr;
+ _conditions = nullptr;
+ _graphics = nullptr;
+ _rooms = nullptr;
+ _roomsFound = nullptr;
+ _specialLocks = nullptr;
+ _utils = nullptr;
+ _console = nullptr;
+ _journalBackImage = nullptr;
+
+ _lastTooLong = false;
+ _alternate = false;
+
+ for (int i = 0; i < 20; i++)
+ _moveImages[i] = nullptr;
+
+ for (int i = 0; i < 10; i++)
+ _invImages[i] = nullptr;
+
+ _curFileName = " ";
+ _msgFont = nullptr;
+ _inventory = nullptr;
+
+ _imgMap = nullptr;
+ _imgRoom = nullptr;
+ _imgUpArrowRoom = nullptr;
+ _imgDownArrowRoom = nullptr;
+ _imgBridge = nullptr;
+ _imgHRoom = nullptr;
+ _imgVRoom = nullptr;
+ _imgMaze = nullptr;
+ _imgHugeMaze = nullptr;
+ _imgPath = nullptr;
+ for (int i = 0; i < 4; i++)
+ _imgMapX[i] = nullptr;
+ _maps = nullptr;
+
+ _blankJournal = nullptr;
+ _journalFont = nullptr;
+ _journalPage = 0;
+ _lastPage = false;
+ _monitorPage = 0;
+ _monitorTextFilename = "";
+ _monitorButton = nullptr;
+ _monitorButtonHeight = 1;
+ for (int i = 0; i < 20; i++)
+ _highPalette[i] = 0;
+ _introPlaying = false;
+
+ const Common::FSNode gameDataDir(ConfMan.get("path"));
+ SearchMan.addSubDirectoryMatching(gameDataDir, "game", 0, 4);
+}
+
+LabEngine::~LabEngine() {
+ // Remove all of our debug levels here
+ DebugMan.clearAllDebugChannels();
+
+ freeMapData();
+ delete[] _rooms;
+ delete[] _inventory;
+
+ delete _conditions;
+ delete _roomsFound;
+ delete _event;
+ delete _interface;
+ delete _resource;
+ delete _music;
+ delete _anim;
+ delete _graphics;
+ delete _specialLocks;
+ delete _utils;
+ delete _console;
+ delete _journalBackImage;
+}
+
+Common::Error LabEngine::run() {
+ if (getFeatures() & GF_LOWRES)
+ initGraphics(320, 200, false);
+ else
+ initGraphics(640, 480, true);
+
+ _interface = new Interface(this);
+ _event = new EventManager(this);
+ _resource = new Resource(this);
+ _music = new Music(this);
+ _graphics = new DisplayMan(this);
+ _anim = new Anim(this);
+ _specialLocks = new SpecialLocks(this);
+ _utils = new Utils(this);
+ _console = new Console(this);
+ _journalBackImage = new Image(this);
+
+ go();
+
+ return Common::kNoError;
+}
+
+Common::String LabEngine::generateSaveFileName(uint slot) {
+ return Common::String::format("%s.%03u", _targetName.c_str(), slot);
+}
+
+void LabEngine::drawStaticMessage(byte index) {
+ _graphics->drawMessage(_resource->getStaticText((StaticText)index), false);
+}
+
+void LabEngine::changeVolume(int delta) {
+ int sfxPrev = _mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType);
+ int musicPrev = _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType);
+ int sfxNew = (delta > 0) ? MIN<int>(sfxPrev + 10, Audio::Mixer::kMaxMixerVolume) : MAX<int>(sfxPrev - 10, 0);
+ int musicNew = (delta > 0) ? MIN<int>(musicPrev + 10, Audio::Mixer::kMaxMixerVolume) : MAX<int>(musicPrev - 10, 0);
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, sfxNew);
+ _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, musicNew);
+}
+
+void LabEngine::waitTOF() {
+ _graphics->screenUpdate();
+
+ uint32 now;
+
+ for (now = _system->getMillis(); now - _lastWaitTOFTicks <= 0xF; now = _system->getMillis() )
+ _system->delayMillis(_lastWaitTOFTicks - now + 17);
+
+ _lastWaitTOFTicks = now;
+}
+
+void LabEngine::updateEvents() {
+ _event->processInput();
+ _interface->handlePressedButton();
+}
+
+Common::Error LabEngine::loadGameState(int slot) {
+ bool result = loadGame(slot);
+ return (result) ? Common::kNoError : Common::kUserCanceled;
+}
+
+Common::Error LabEngine::saveGameState(int slot, const Common::String &desc) {
+ bool result = saveGame(slot, desc);
+ return (result) ? Common::kNoError : Common::kUserCanceled;
+}
+
+bool LabEngine::canLoadGameStateCurrently() {
+ return !_introPlaying;
+}
+
+bool LabEngine::canSaveGameStateCurrently() {
+ return !_introPlaying;
+}
+
+} // End of namespace Lab
diff --git a/engines/lab/lab.h b/engines/lab/lab.h
new file mode 100644
index 0000000000..2a1e527098
--- /dev/null
+++ b/engines/lab/lab.h
@@ -0,0 +1,509 @@
+/* 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 Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#ifndef LAB_LAB_H
+#define LAB_LAB_H
+
+#include "common/system.h"
+#include "common/random.h"
+#include "common/rect.h"
+#include "common/savefile.h"
+#include "engines/engine.h"
+#include "engines/savestate.h"
+
+#include "lab/console.h"
+#include "lab/image.h"
+#include "lab/labsets.h"
+
+struct ADGameDescription;
+
+namespace Lab {
+
+struct MapData;
+struct Action;
+struct CloseData;
+struct Button;
+struct IntuiMessage;
+struct InventoryData;
+struct RoomData;
+struct Rule;
+struct TextFont;
+struct ViewData;
+
+class Anim;
+class DisplayMan;
+class EventManager;
+class Interface;
+class Image;
+class Music;
+class Resource;
+class SpecialLocks;
+class Utils;
+
+struct SaveGameHeader {
+ byte _version;
+ SaveStateDescriptor _descr;
+ uint16 _roomNumber;
+ uint16 _direction;
+};
+
+enum GameFeatures {
+ GF_LOWRES = 1 << 0,
+ GF_WINDOWS_TRIAL = 1 << 1
+};
+
+typedef Common::List<Button *> ButtonList;
+
+struct CrumbData {
+ uint16 _crumbRoomNum;
+ uint16 _crumbDirection;
+};
+
+#define MAX_CRUMBS 128
+
+typedef Common::List<Rule> RuleList;
+typedef Common::List<Action> ActionList;
+typedef Common::List<CloseData> CloseDataList;
+typedef Common::List<ViewData> ViewDataList;
+
+enum Direction {
+ kDirectionNorth,
+ kDirectionSouth,
+ kDirectionEast,
+ kDirectionWest
+};
+
+enum MainButton {
+ kButtonNone = -1,
+ kButtonPickup,
+ kButtonUse,
+ kButtonOpen,
+ kButtonClose,
+ kButtonLook,
+ kButtonInventory,
+ kButtonLeft,
+ kButtonForward,
+ kButtonRight,
+ kButtonMap
+};
+
+enum MessageClass {
+ kMessageLeftClick,
+ kMessageRightClick,
+ kMessageButtonUp,
+ kMessageRawKey
+};
+
+class LabEngine : public Engine {
+ friend class Console;
+
+private:
+ bool _isCrumbWaiting;
+ bool _lastTooLong;
+ bool _lastPage;
+ bool _mainDisplay;
+ bool _noUpdateDiff;
+ bool _quitLab;
+
+ byte *_blankJournal;
+
+ int _lastWaitTOFTicks;
+
+ uint16 _direction;
+ uint16 _highPalette[20];
+ uint16 _journalPage;
+ uint16 _maxRooms;
+ uint16 _monitorPage;
+ uint16 _monitorButtonHeight;
+
+ uint32 _extraGameFeatures;
+
+ Common::String _journalText;
+ Common::String _journalTextTitle;
+ Common::String _nextFileName;
+ Common::String _newFileName;
+ Common::String _monitorTextFilename;
+
+ const CloseData *_closeDataPtr;
+ ButtonList _journalButtonList;
+ ButtonList _mapButtonList;
+ Image *_imgMap, *_imgRoom, *_imgUpArrowRoom, *_imgDownArrowRoom, *_imgBridge;
+ Image *_imgHRoom, *_imgVRoom, *_imgMaze, *_imgHugeMaze, *_imgPath;
+ Image *_imgMapX[4];
+ InventoryData *_inventory;
+ MapData *_maps;
+ Image *_monitorButton;
+ Image *_journalBackImage;
+ TextFont *_journalFont;
+ bool _introPlaying;
+
+public:
+ bool _alternate;
+ bool _droppingCrumbs;
+ bool _followingCrumbs;
+ bool _followCrumbsFast;
+ bool _isCrumbTurning;
+ bool _isHiRes;
+
+ int _roomNum;
+
+ uint16 _highestCondition;
+ uint16 _manyRooms;
+ uint16 _numCrumbs;
+ uint16 _numInv;
+
+ uint32 _crumbTimestamp;
+
+ Common::String _curFileName;
+
+ Anim *_anim;
+ CrumbData _breadCrumbs[MAX_CRUMBS];
+ DisplayMan *_graphics;
+ EventManager *_event;
+ Interface *_interface;
+ ButtonList _invButtonList;
+ ButtonList _moveButtonList;
+ Image *_invImages[10];
+ Image *_moveImages[20];
+ LargeSet *_conditions, *_roomsFound;
+ Music *_music;
+ Resource *_resource;
+ RoomData *_rooms;
+ TextFont *_msgFont;
+ SpecialLocks *_specialLocks;
+ Utils *_utils;
+ Console *_console;
+ GUI::Debugger *getDebugger() { return _console; }
+
+public:
+ LabEngine(OSystem *syst, const ADGameDescription *gameDesc);
+ ~LabEngine();
+
+ virtual Common::Error run();
+ void go();
+
+ const ADGameDescription *_gameDescription;
+ Common::Platform getPlatform() const;
+ uint32 getFeatures() const;
+
+ bool hasFeature(EngineFeature f) const;
+ Common::String generateSaveFileName(uint slot);
+
+ void changeVolume(int delta);
+ uint16 getDirection() { return _direction; }
+
+ /**
+ * Returns the current picture name.
+ */
+ Common::String getPictName(bool useClose);
+ uint16 getQuarters();
+ void setQuarters(uint16 quarters);
+ void updateEvents();
+ void waitTOF();
+
+ Common::Error loadGameState(int slot);
+ Common::Error saveGameState(int slot, const Common::String &desc);
+ bool canLoadGameStateCurrently();
+ bool canSaveGameStateCurrently();
+
+ bool isMainDisplay() const { return _mainDisplay; }
+
+private:
+ /**
+ * Checks whether all the conditions in a condition list are met.
+ */
+ bool checkConditions(const Common::Array<int16> &cond);
+
+ /**
+ * Decrements the current inventory number.
+ */
+ void decIncInv(uint16 *CurInv, bool dec);
+
+ /**
+ * Processes the action list.
+ */
+ void doActions(const ActionList &actionList);
+
+ /**
+ * Goes through the rules if an action is taken.
+ */
+ bool doActionRule(Common::Point pos, int16 action, int16 roomNum);
+
+ /**
+ * Does the work for doActionRule.
+ */
+ bool doActionRuleSub(int16 action, int16 roomNum, const CloseData *closePtr, bool allowDefaults);
+
+ /**
+ * Handles monitor closeups
+ */
+ void handleMonitorCloseup();
+
+ /**
+ * Goes through the rules if the user tries to go forward.
+ */
+ bool doGoForward();
+
+ /**
+ * Does the journal processing.
+ */
+ void doJournal();
+
+ /**
+ * Goes through the rules if the user tries to go to the main view
+ */
+ bool doMainView();
+
+ /**
+ * Does the map processing.
+ */
+ void doMap();
+
+ /**
+ * Does what's necessary for the monitor.
+ */
+ void doMonitor(const Common::String background, const Common::String textfile, bool isinteractive, Common::Rect textRect);
+
+ /**
+ * Does the things to properly set up the detective notes.
+ */
+ void doNotes();
+
+ /**
+ * Does the work for doActionRule.
+ */
+ bool doOperateRuleSub(int16 itemNum, int16 roomNum, const CloseData *closePtr, bool allowDefaults);
+
+ /**
+ * Goes through the rules if the user tries to operate an item on an object.
+ */
+ bool doOperateRule(Common::Point pos, int16 ItemNum);
+
+ /**
+ * Goes through the rules if the user tries to turn.
+ */
+ bool doTurn(uint16 from, uint16 to);
+
+ /**
+ * If the user hits the "Use" button; things that can get used on themselves.
+ */
+ bool doUse(uint16 curInv);
+
+ /**
+ * Does the things to properly set up the old west newspaper. Assumes that
+ * OpenHiRes already called.
+ */
+ void doWestPaper();
+
+ /**
+ * Draws the current direction to the screen.
+ */
+ void drawDirection(const CloseData *closePtr);
+
+ /**
+ * Draws the journal from page x.
+ */
+ void drawJournal(uint16 wipenum, bool needFade);
+
+ /**
+ * Draws the text to the back journal screen to the appropriate Page number
+ */
+ void drawJournalText();
+
+ /**
+ * Draws the map
+ */
+ void drawMap(uint16 curRoom, uint16 curMsg, uint16 floorNum, bool fadeIn);
+
+ /**
+ * Draws the text for the monitor.
+ */
+ void drawMonText(const char *text, TextFont *monitorFont, Common::Rect textRect, bool isinteractive);
+
+ /**
+ * Draws a room map.
+ */
+ void drawRoomMap(uint16 curRoom, bool drawMarkFl);
+
+ /**
+ * Draws the message for the room.
+ */
+ void drawRoomMessage(uint16 curInv, const CloseData *closePtr);
+ void drawStaticMessage(byte index);
+
+ /**
+ * Eats all the available messages.
+ */
+ void eatMessages();
+
+ /**
+ * Goes through the list of closeups to find a match.
+ * @note Known bug here. If there are two objects that have closeups, and
+ * some of the closeups have the same hit boxes, then this returns the first
+ * occurrence of the object with the same hit box.
+ */
+ const CloseData *findClosePtrMatch(const CloseData *closePtr, const CloseDataList &list);
+
+ /**
+ * Checks if a floor has been visited.
+ */
+ bool floorVisited(uint16 floorNum);
+
+ /**
+ * New code to allow quick(er) return navigation in game.
+ */
+ MainButton followCrumbs();
+ void freeMapData();
+ void freeScreens();
+ bool processEvent(MessageClass tmpClass, uint16 code, uint16 qualifier, Common::Point tmpPos,
+ uint16 &curInv, IntuiMessage *curMsg, bool &forceDraw, uint16 buttonId, uint16 &actionMode);
+
+ /**
+ * Gets the current inventory name.
+ */
+ Common::String getInvName(uint16 curInv);
+
+ /**
+ * Returns the floor to show when the down arrow is pressed
+ * @note The original did not show all the visited floors, but we do
+ */
+ uint16 getLowerFloor(uint16 floorNum);
+
+ /**
+ * Gets an object, if any, from the user's click on the screen.
+ */
+ const CloseData *getObject(Common::Point pos, const CloseData *closePtr);
+
+ /**
+ * Returns the floor to show when the up arrow is pressed
+ * @note The original did not show all the visited floors, but we do
+ */
+ uint16 getUpperFloor(uint16 floorNum);
+
+ /**
+ * Gets the current ViewDataPointer.
+ */
+ ViewData *getViewData(uint16 roomNum, uint16 direction);
+
+ /**
+ * Turns the interface off.
+ */
+ void interfaceOff();
+
+ /**
+ * Turns the interface on.
+ */
+ void interfaceOn();
+
+ /**
+ * Loads in the data for the journal.
+ */
+ void loadJournalData();
+
+ /**
+ * Loads in the map data.
+ */
+ void loadMapData();
+
+ /**
+ * The main game loop.
+ */
+ void mainGameLoop();
+ void showLab2Teaser();
+
+ /**
+ * Permanently flips the imagery of a button.
+ */
+ void perFlipButton(uint16 buttonId);
+
+ /**
+ * process a arrow button movement.
+ */
+ uint16 processArrow(uint16 curDirection, uint16 arrow);
+
+ /**
+ * Processes user input.
+ */
+ void processJournal();
+
+ /**
+ * Processes the map.
+ */
+ void processMap(uint16 curRoom);
+
+ /**
+ * Processes user input.
+ */
+ void processMonitor(const Common::String &ntext, TextFont *monitorFont, bool isInteractive, Common::Rect textRect);
+
+ /**
+ * Figures out what a room's coordinates should be.
+ */
+ Common::Rect roomCoords(uint16 curRoom);
+ bool saveRestoreGame();
+
+ /**
+ * Sets the current close up data.
+ */
+ void setCurrentClose(Common::Point pos, const CloseData **closePtrList, bool useAbsoluteCoords, bool next=false);
+
+ /**
+ * Takes the currently selected item.
+ */
+ bool takeItem(Common::Point pos);
+
+ /**
+ * Does the turn page wipe.
+ */
+ void turnPage(bool fromLeft);
+ bool processKey(IntuiMessage *curMsg, uint32 msgClass, uint16 &qualifier, Common::Point &curPos, uint16 &curInv, bool &forceDraw, uint16 code);
+ void processMainButton(uint16 &curInv, uint16 &lastInv, uint16 &oldDirection, bool &forceDraw, uint16 buttonId, uint16 &actionMode);
+ void processAltButton(uint16 &curInv, uint16 &lastInv, uint16 buttonId, uint16 &actionMode);
+ void performAction(uint16 actionMode, Common::Point curPos, uint16 &curInv);
+
+ /**
+ * Writes the game out to disk.
+ */
+ bool saveGame(int slot, const Common::String desc);
+
+ /**
+ * Reads the game from disk.
+ */
+ bool loadGame(int slot);
+ void writeSaveGameHeader(Common::OutSaveFile *out, const Common::String &saveName);
+
+ void handleTrialWarning();
+};
+
+bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &header);
+
+} // End of namespace Lab
+
+#endif // LAB_LAB_H
diff --git a/engines/lab/labsets.cpp b/engines/lab/labsets.cpp
new file mode 100644
index 0000000000..3e84275fa4
--- /dev/null
+++ b/engines/lab/labsets.cpp
@@ -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.
+ *
+ */
+
+/*
+ * This code is based on Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#include "common/file.h"
+
+#include "lab/lab.h"
+
+#include "lab/labsets.h"
+#include "lab/resource.h"
+
+namespace Lab {
+
+LargeSet::LargeSet(uint16 last, LabEngine *vm) : _vm(vm) {
+ last = (((last + 15) >> 4) << 4);
+
+ _array = new uint16[last >> 3];
+ memset(_array, 0, last >> 3);
+ _lastElement = last;
+}
+
+LargeSet::~LargeSet() {
+ delete[] _array;
+}
+
+bool LargeSet::in(uint16 element) {
+ return ((1 << ((element - 1) % 16)) & (_array[(element - 1) >> 4])) > 0;
+}
+
+void LargeSet::inclElement(uint16 element) {
+ _array[(element - 1) >> 4] |= 1 << ((element - 1) % 16);
+}
+
+void LargeSet::exclElement(uint16 element) {
+ _array[(element - 1) >> 4] &= ~(1 << ((element - 1) % 16));
+}
+
+bool LargeSet::readInitialConditions(const Common::String fileName) {
+ Common::File *file = _vm->_resource->openDataFile(fileName, MKTAG('C', 'O', 'N', '0'));
+
+ uint16 conditions = file->readUint16LE();
+ for (int i = 0; i < conditions; i++) {
+ inclElement(file->readUint16LE());
+ }
+
+ delete file;
+ return true;
+}
+
+
+} // End of namespace Lab
diff --git a/engines/lab/labsets.h b/engines/lab/labsets.h
new file mode 100644
index 0000000000..afd997e9eb
--- /dev/null
+++ b/engines/lab/labsets.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.
+ *
+ */
+
+ /*
+ * This code is based on Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#ifndef LAB_LABSETS_H
+#define LAB_LABSETS_H
+
+namespace Lab {
+
+//---------------------------
+//----- From LabSets.c ------
+//---------------------------
+
+class LabEngine;
+
+class LargeSet {
+public:
+ LargeSet(uint16 last, LabEngine *vm);
+ ~LargeSet();
+ bool in(uint16 element);
+ void inclElement(uint16 element);
+ void exclElement(uint16 element);
+ bool readInitialConditions(const Common::String fileName);
+
+private:
+ LabEngine *_vm;
+
+public:
+ uint16 _lastElement;
+ uint16 *_array;
+};
+
+} // End of namespace Lab
+
+#endif // LAB_LABSETS_H
diff --git a/engines/lab/map.cpp b/engines/lab/map.cpp
new file mode 100644
index 0000000000..057cac3589
--- /dev/null
+++ b/engines/lab/map.cpp
@@ -0,0 +1,559 @@
+/* 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 Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#include "common/file.h"
+
+#include "lab/lab.h"
+
+#include "lab/dispman.h"
+#include "lab/eventman.h"
+#include "lab/image.h"
+#include "lab/interface.h"
+#include "lab/labsets.h"
+#include "lab/music.h"
+#include "lab/processroom.h"
+#include "lab/resource.h"
+#include "lab/utils.h"
+
+namespace Lab {
+
+/*---------------------------------------------------------------------------*/
+/*------------------------------ The Map stuff ------------------------------*/
+/*---------------------------------------------------------------------------*/
+
+enum MapFloor {
+ kFloorNone,
+ kFloorLower,
+ kFloorMiddle,
+ kFloorUpper,
+ kFloorMedMaze,
+ kFloorHedgeMaze,
+ kFloorSurMaze,
+ kFloorCarnival
+};
+
+void LabEngine::loadMapData() {
+ Common::File *mapImages = _resource->openDataFile("P:MapImage");
+
+ _imgMap = new Image(mapImages, this);
+ _imgRoom = new Image(mapImages, this);
+ _imgUpArrowRoom = new Image(mapImages, this);
+ _imgDownArrowRoom = new Image(mapImages, this);
+ _imgHRoom = new Image(mapImages, this);
+ _imgVRoom = new Image(mapImages, this);
+ _imgMaze = new Image(mapImages, this);
+ _imgHugeMaze = new Image(mapImages, this);
+
+ _imgMapX[kDirectionNorth] = new Image(mapImages, this);
+ _imgMapX[kDirectionEast] = new Image(mapImages, this);
+ _imgMapX[kDirectionSouth] = new Image(mapImages, this);
+ _imgMapX[kDirectionWest] = new Image(mapImages, this);
+ _imgPath = new Image(mapImages, this);
+ _imgBridge = new Image(mapImages, this);
+
+ _mapButtonList.push_back(_interface->createButton( 8, _utils->vgaScaleY(105), 0, Common::KEYCODE_ESCAPE, new Image(mapImages, this), new Image(mapImages, this))); // back
+ _mapButtonList.push_back(_interface->createButton( 55, _utils->vgaScaleY(105), 1, Common::KEYCODE_UP, new Image(mapImages, this), new Image(mapImages, this))); // up
+ _mapButtonList.push_back(_interface->createButton(101, _utils->vgaScaleY(105), 2, Common::KEYCODE_DOWN, new Image(mapImages, this), new Image(mapImages, this))); // down
+
+ delete mapImages;
+
+ Common::File *mapFile = _resource->openDataFile("Lab:Maps", MKTAG('M', 'A', 'P', '0'));
+ updateEvents();
+
+ _maxRooms = mapFile->readUint16LE();
+ _maps = new MapData[_maxRooms + 1]; // will be freed when the user exits the map
+ for (int i = 0; i <= _maxRooms; i++) {
+ _maps[i]._x = mapFile->readUint16LE();
+ _maps[i]._y = mapFile->readUint16LE();
+ _maps[i]._pageNumber = mapFile->readUint16LE();
+ _maps[i]._specialID = (SpecialRoom) mapFile->readUint16LE();
+ _maps[i]._mapFlags = mapFile->readUint32LE();
+ }
+
+ delete mapFile;
+}
+
+void LabEngine::freeMapData() {
+ _interface->freeButtonList(&_mapButtonList);
+
+ delete _imgMap;
+ delete _imgRoom;
+ delete _imgUpArrowRoom;
+ delete _imgDownArrowRoom;
+ delete _imgBridge;
+ delete _imgHRoom;
+ delete _imgVRoom;
+ delete _imgMaze;
+ delete _imgHugeMaze;
+ delete _imgPath;
+ for (int i = 0; i < 4; i++)
+ delete _imgMapX[i];
+ delete[] _maps;
+
+ _imgMap = nullptr;
+ _imgRoom = nullptr;
+ _imgUpArrowRoom = nullptr;
+ _imgDownArrowRoom = nullptr;
+ _imgBridge = nullptr;
+ _imgHRoom = nullptr;
+ _imgVRoom = nullptr;
+ _imgMaze = nullptr;
+ _imgHugeMaze = nullptr;
+ _imgPath = nullptr;
+ for (int i = 0; i < 4; i++)
+ _imgMapX[i] = nullptr;
+ _maps = nullptr;
+}
+
+Common::Rect LabEngine::roomCoords(uint16 curRoom) {
+ Image *curRoomImg = nullptr;
+
+ switch (_maps[curRoom]._specialID) {
+ case kNormalRoom:
+ case kUpArrowRoom:
+ case kDownArrowRoom:
+ curRoomImg = _imgRoom;
+ break;
+ case kBridgeRoom:
+ curRoomImg = _imgBridge;
+ break;
+ case kVerticalCorridor:
+ curRoomImg = _imgVRoom;
+ break;
+ case kHorizontalCorridor:
+ curRoomImg = _imgHRoom;
+ break;
+ default:
+ // Some rooms (like the map) do not have an image
+ break;
+ }
+
+ int x1 = _utils->mapScaleX(_maps[curRoom]._x);
+ int y1 = _utils->mapScaleY(_maps[curRoom]._y);
+ int x2 = x1;
+ int y2 = y1;
+
+ if (curRoomImg) {
+ x2 += curRoomImg->_width;
+ y2 += curRoomImg->_height;
+ }
+
+ return Common::Rect(x1, y1, x2, y2);
+}
+
+void LabEngine::drawRoomMap(uint16 curRoom, bool drawMarkFl) {
+ uint16 drawX, drawY, offset;
+
+ uint16 x = _utils->mapScaleX(_maps[curRoom]._x);
+ uint16 y = _utils->mapScaleY(_maps[curRoom]._y);
+ uint32 flags = _maps[curRoom]._mapFlags;
+
+ switch (_maps[curRoom]._specialID) {
+ case kNormalRoom:
+ case kUpArrowRoom:
+ case kDownArrowRoom:
+ if (_maps[curRoom]._specialID == kNormalRoom)
+ _imgRoom->drawImage(x, y);
+ else if (_maps[curRoom]._specialID == kDownArrowRoom)
+ _imgDownArrowRoom->drawImage(x, y);
+ else
+ _imgUpArrowRoom->drawImage(x, y);
+
+ offset = (_imgRoom->_width - _imgPath->_width) / 2;
+
+ if ((kDoorLeftNorth & flags) && (y >= _imgPath->_height))
+ _imgPath->drawImage(x + offset, y - _imgPath->_height);
+
+ if (kDoorLeftSouth & flags)
+ _imgPath->drawImage(x + offset, y + _imgRoom->_height);
+
+ offset = (_imgRoom->_height - _imgPath->_height) / 2;
+
+ if (kDoorLeftEast & flags)
+ _imgPath->drawImage(x + _imgRoom->_width, y + offset);
+
+ if (kDoorLeftWest & flags)
+ _imgPath->drawImage(x - _imgPath->_width, y + offset);
+
+ drawX = x + (_imgRoom->_width - _imgMapX[_direction]->_width) / 2;
+ drawY = y + (_imgRoom->_height - _imgMapX[_direction]->_height) / 2;
+
+ break;
+
+ case kBridgeRoom:
+ _imgBridge->drawImage(x, y);
+
+ drawX = x + (_imgBridge->_width - _imgMapX[_direction]->_width) / 2;
+ drawY = y + (_imgBridge->_height - _imgMapX[_direction]->_height) / 2;
+
+ break;
+
+ case kVerticalCorridor:
+ _imgVRoom->drawImage(x, y);
+
+ offset = (_imgVRoom->_width - _imgPath->_width) / 2;
+
+ if (kDoorLeftNorth & flags)
+ _imgPath->drawImage(x + offset, y - _imgPath->_height);
+
+ if (kDoorLeftSouth & flags)
+ _imgPath->drawImage(x + offset, y + _imgVRoom->_height);
+
+ offset = (_imgRoom->_height - _imgPath->_height) / 2;
+
+ if (kDoorLeftEast & flags)
+ _imgPath->drawImage(x + _imgVRoom->_width, y + offset);
+
+ if (kDoorLeftWest & flags)
+ _imgPath->drawImage(x - _imgPath->_width, y + offset);
+
+ if (kDoorBottomEast & flags)
+ _imgPath->drawImage(x + _imgVRoom->_width, y - offset - _imgPath->_height + _imgVRoom->_height);
+
+ if (kDoorBottomWest & flags)
+ _imgPath->drawImage(x - _imgPath->_width, y - offset - _imgPath->_height + _imgVRoom->_height);
+
+ offset = (_imgVRoom->_height - _imgPath->_height) / 2;
+
+ if (kDoorMiddleEast & flags)
+ _imgPath->drawImage(x + _imgVRoom->_width, y - offset - _imgPath->_height + _imgVRoom->_height);
+
+ if (kDoorMiddleWest & flags)
+ _imgPath->drawImage(x - _imgPath->_width, y - offset - _imgPath->_height + _imgVRoom->_height);
+
+ drawX = x + (_imgVRoom->_width - _imgMapX[_direction]->_width) / 2;
+ drawY = y + (_imgVRoom->_height - _imgMapX[_direction]->_height) / 2;
+
+ break;
+
+ case kHorizontalCorridor:
+ _imgHRoom->drawImage(x, y);
+
+ offset = (_imgRoom->_width - _imgPath->_width) / 2;
+
+ if (kDoorLeftNorth & flags)
+ _imgPath->drawImage(x + offset, y - _imgPath->_height);
+
+ if (kDoorLeftSouth & flags)
+ _imgPath->drawImage(x + offset, y + _imgRoom->_height);
+
+ if (kDoorRightNorth & flags)
+ _imgPath->drawImage(x - offset - _imgPath->_width + _imgHRoom->_width, y - _imgPath->_height);
+
+ if (kDoorRightSouth & flags)
+ _imgPath->drawImage(x - offset - _imgPath->_width + _imgHRoom->_width, y + _imgRoom->_height);
+
+ offset = (_imgHRoom->_width - _imgPath->_width) / 2;
+
+ if (kDoorMiddleNorth & flags)
+ _imgPath->drawImage(x - offset - _imgPath->_width + _imgHRoom->_width, y - _imgPath->_height);
+
+ if (kDoorMiddleSouth & flags)
+ _imgPath->drawImage(x - offset - _imgPath->_width + _imgHRoom->_width, y + _imgRoom->_height);
+
+ offset = (_imgRoom->_height - _imgPath->_height) / 2;
+
+ if (kDoorLeftEast & flags)
+ _imgPath->drawImage(x + _imgHRoom->_width, y + offset);
+
+ if (kDoorLeftWest & flags)
+ _imgPath->drawImage(x - _imgPath->_width, y + offset);
+
+ drawX = x + (_imgHRoom->_width - _imgMapX[_direction]->_width) / 2;
+ drawY = y + (_imgHRoom->_height - _imgMapX[_direction]->_height) / 2;
+
+ break;
+
+ default:
+ return;
+ }
+
+ if (drawMarkFl)
+ _imgMapX[_direction]->drawImage(drawX, drawY);
+}
+
+bool LabEngine::floorVisited(uint16 floorNum) {
+ for (int i = 0; i < _maxRooms; i++) {
+ if ((_maps[i]._pageNumber == floorNum) && _roomsFound->in(i) && _maps[i]._x)
+ return true;
+ }
+
+ return false;
+}
+
+uint16 LabEngine::getUpperFloor(uint16 floorNum) {
+ if ((floorNum == kFloorCarnival) || (floorNum == kFloorNone))
+ return kFloorNone;
+
+ for (int i = floorNum; i < kFloorCarnival; i++)
+ if (floorVisited(i + 1))
+ return i + 1;
+
+ return kFloorNone;
+}
+
+uint16 LabEngine::getLowerFloor(uint16 floorNum) {
+ if ((floorNum == kFloorLower) || (floorNum == kFloorNone))
+ return kFloorNone;
+
+ for (int i = floorNum; i > kFloorLower; i--)
+ if (floorVisited(i - 1))
+ return i - 1;
+
+ return kFloorNone;
+}
+
+void LabEngine::drawMap(uint16 curRoom, uint16 curMsg, uint16 floorNum, bool fadeIn) {
+ _graphics->rectFill(0, 0, _graphics->_screenWidth - 1, _graphics->_screenHeight - 1, 0);
+ _imgMap->drawImage(0, 0);
+ _interface->drawButtonList(&_mapButtonList);
+
+ for (int i = 1; i <= _maxRooms; i++) {
+ if ((_maps[i]._pageNumber == floorNum) && _roomsFound->in(i) && _maps[i]._x) {
+ drawRoomMap(i, (bool)(i == curRoom));
+ }
+ }
+
+ updateEvents();
+
+ // Makes sure the X is drawn in corridors
+ // NOTE: this here on purpose just in case there's some weird
+ // condition, like the surreal maze where there are no rooms
+ if ((_maps[curRoom]._pageNumber == floorNum) && _roomsFound->in(curRoom) && _maps[curRoom]._x)
+ drawRoomMap(curRoom, true);
+
+ _interface->toggleButton(_interface->getButton(1), 12, (getUpperFloor(floorNum) != kFloorNone)); // up button
+ _interface->toggleButton(_interface->getButton(2), 12, (getLowerFloor(floorNum) != kFloorNone)); // down button
+
+ // Labyrinth specific code
+ if (floorNum == kFloorLower) {
+ if (floorVisited(kFloorSurMaze))
+ _imgMaze->drawImage(_utils->mapScaleX(538), _utils->mapScaleY(277));
+ } else if (floorNum == kFloorMiddle) {
+ if (floorVisited(kFloorCarnival))
+ _imgMaze->drawImage(_utils->mapScaleX(358), _utils->mapScaleY(72));
+
+ if (floorVisited(kFloorMedMaze))
+ _imgMaze->drawImage(_utils->mapScaleX(557), _utils->mapScaleY(325));
+ } else if (floorNum == kFloorUpper) {
+ if (floorVisited(kFloorHedgeMaze))
+ _imgHugeMaze->drawImage(_utils->mapScaleX(524), _utils->mapScaleY(97));
+ } else if (floorNum == kFloorSurMaze) {
+ Common::Rect textRect = Common::Rect(_utils->mapScaleX(360), 0, _utils->mapScaleX(660), _utils->mapScaleY(450));
+ const char *textPtr = _resource->getStaticText(kTextSurmazeMessage).c_str();
+ _graphics->flowText(_msgFont, 0, 7, 0, true, true, true, true, textRect, textPtr);
+ }
+
+ if ((floorNum >= kFloorLower) && (floorNum <= kFloorCarnival)) {
+ const char *textPrt = _resource->getStaticText(floorNum - 1).c_str();
+ _graphics->flowText(_msgFont, 0, 5, 3, true, true, true, true, _utils->vgaRectScale(14, 75, 134, 97), textPrt);
+ }
+
+ if (!_rooms[curMsg]._roomMsg.empty())
+ _graphics->flowText(_msgFont, 0, 5, 3, true, true, true, true, _utils->vgaRectScale(14, 148, 134, 186), _rooms[curMsg]._roomMsg.c_str());
+
+ if (fadeIn)
+ _graphics->fade(true);
+}
+
+void LabEngine::processMap(uint16 curRoom) {
+ byte place = 1;
+ uint16 curMsg = curRoom;
+ uint16 curFloor = _maps[curRoom]._pageNumber;
+
+ while (1) {
+ IntuiMessage *msg = _event->getMsg();
+ if (shouldQuit()) {
+ _quitLab = true;
+ return;
+ }
+
+ updateEvents();
+ _graphics->screenUpdate();
+ _system->delayMillis(10);
+
+ if (!msg) {
+ updateEvents();
+
+ byte newcolor[3];
+
+ if (place <= 14) {
+ newcolor[0] = 14 << 2;
+ newcolor[1] = place << 2;
+ newcolor[2] = newcolor[1];
+ } else {
+ newcolor[0] = 14 << 2;
+ newcolor[1] = (28 - place) << 2;
+ newcolor[2] = newcolor[1];
+ }
+
+ waitTOF();
+ _graphics->writeColorRegs(newcolor, 1, 1);
+ _interface->handlePressedButton();
+ waitTOF();
+
+ place++;
+
+ if (place >= 28)
+ place = 1;
+
+ } else {
+ uint32 msgClass = msg->_msgClass;
+ uint16 msgCode = msg->_code;
+ uint16 mouseX = msg->_mouse.x;
+ uint16 mouseY = msg->_mouse.y;
+
+ if ((msgClass == kMessageRightClick) || ((msgClass == kMessageRawKey) && (msgCode == Common::KEYCODE_ESCAPE)))
+ return;
+
+ if (msgClass == kMessageButtonUp) {
+ if (msgCode == 0) {
+ // Quit menu button
+ return;
+ } else if (msgCode == 1) {
+ // Up arrow
+ uint16 upperFloor = getUpperFloor(curFloor);
+ if (upperFloor != kFloorNone) {
+ curFloor = upperFloor;
+ _graphics->fade(false);
+ drawMap(curRoom, curMsg, curFloor, false);
+ _graphics->fade(true);
+ }
+ } else if (msgCode == 2) {
+ // Down arrow
+ uint16 lowerFloor = getLowerFloor(curFloor);
+ if (lowerFloor != kFloorNone) {
+ curFloor = lowerFloor;
+ _graphics->fade(false);
+ drawMap(curRoom, curMsg, curFloor, false);
+ _graphics->fade(true);
+ }
+ }
+ } else if (msgClass == kMessageLeftClick) {
+ if ((curFloor == kFloorLower) && _utils->mapRectScale(538, 277, 633, 352).contains(mouseX, mouseY)
+ && floorVisited(kFloorSurMaze)) {
+ curFloor = kFloorSurMaze;
+
+ _graphics->fade(false);
+ drawMap(curRoom, curMsg, curFloor, false);
+ _graphics->fade(true);
+ } else if ((curFloor == kFloorMiddle) && _utils->mapRectScale(358, 71, 452, 147).contains(mouseX, mouseY)
+ && floorVisited(kFloorCarnival)) {
+ curFloor = kFloorCarnival;
+
+ _graphics->fade(false);
+ drawMap(curRoom, curMsg, curFloor, false);
+ _graphics->fade(true);
+ } else if ((curFloor == kFloorMiddle) && _utils->mapRectScale(557, 325, 653, 401).contains(mouseX, mouseY)
+ && floorVisited(kFloorMedMaze)) {
+ curFloor = kFloorMedMaze;
+
+ _graphics->fade(false);
+ drawMap(curRoom, curMsg, curFloor, false);
+ _graphics->fade(true);
+ } else if ((curFloor == kFloorUpper) && _utils->mapRectScale(524, 97, 645, 207).contains(mouseX, mouseY)
+ && floorVisited(kFloorHedgeMaze)) {
+ curFloor = kFloorHedgeMaze;
+
+ _graphics->fade(false);
+ drawMap(curRoom, curMsg, curFloor, false);
+ _graphics->fade(true);
+ } else if (mouseX > _utils->mapScaleX(314)) {
+ uint16 oldMsg = curMsg;
+ Common::Rect curCoords;
+
+ for (int i = 1; i <= _maxRooms; i++) {
+ curCoords = roomCoords(i);
+
+ if ((_maps[i]._pageNumber == curFloor)
+ && _roomsFound->in(i) && curCoords.contains(Common::Point(mouseX, mouseY))) {
+ curMsg = i;
+ }
+ }
+
+ if (oldMsg != curMsg) {
+ if (!_rooms[curMsg]._roomMsg.empty())
+ _resource->readViews(curMsg);
+
+ const char *sptr;
+ if ((sptr = _rooms[curMsg]._roomMsg.c_str())) {
+ _graphics->rectFillScaled(13, 148, 135, 186, 3);
+ _graphics->flowText(_msgFont, 0, 5, 3, true, true, true, true, _utils->vgaRectScale(14, 148, 134, 186), sptr);
+
+ if (_maps[oldMsg]._pageNumber == curFloor)
+ drawRoomMap(oldMsg, (bool)(oldMsg == curRoom));
+
+ curCoords = roomCoords(curMsg);
+ int right = (curCoords.left + curCoords.right) / 2;
+ int left = right - 1;
+ int top, bottom;
+ top = bottom = (curCoords.top + curCoords.bottom) / 2;
+
+ if ((curMsg != curRoom) && (_maps[curMsg]._pageNumber == curFloor))
+ _graphics->rectFill(left, top, right, bottom, 1);
+ }
+ }
+ }
+ }
+
+ _graphics->screenUpdate();
+ }
+ } // while
+}
+
+void LabEngine::doMap() {
+ static uint16 amigaMapPalette[] = {
+ 0x0BA8, 0x0C11, 0x0A74, 0x0076,
+ 0x0A96, 0x0DCB, 0x0CCA, 0x0222,
+ 0x0444, 0x0555, 0x0777, 0x0999,
+ 0x0AAA, 0x0ED0, 0x0EEE, 0x0694
+ };
+
+ _graphics->_fadePalette = amigaMapPalette;
+
+ updateEvents();
+ loadMapData();
+ _graphics->blackAllScreen();
+ _interface->attachButtonList(&_mapButtonList);
+ drawMap(_roomNum, _roomNum, _maps[_roomNum]._pageNumber, true);
+ _event->mouseShow();
+ _graphics->screenUpdate();
+ processMap(_roomNum);
+ _event->mouseHide();
+ _interface->attachButtonList(nullptr);
+ _graphics->fade(false);
+ _graphics->blackAllScreen();
+ _graphics->rectFill(0, 0, _graphics->_screenWidth - 1, _graphics->_screenHeight - 1, 0);
+ freeMapData();
+ _event->mouseShow();
+ _graphics->screenUpdate();
+}
+
+} // End of namespace Lab
diff --git a/engines/lab/module.mk b/engines/lab/module.mk
new file mode 100644
index 0000000000..7bb86c8c1e
--- /dev/null
+++ b/engines/lab/module.mk
@@ -0,0 +1,30 @@
+MODULE := engines/lab
+
+MODULE_OBJS := \
+ anim.o \
+ console.o \
+ detection.o \
+ dispman.o \
+ engine.o \
+ eventman.o \
+ image.o \
+ interface.o \
+ intro.o \
+ lab.o \
+ labsets.o \
+ map.o \
+ music.o \
+ processroom.o \
+ resource.o \
+ savegame.o \
+ special.o \
+ speciallocks.o \
+ utils.o
+
+# This module can be built as a plugin
+ifeq ($(ENABLE_LAB), DYNAMIC_PLUGIN)
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/engines/lab/music.cpp b/engines/lab/music.cpp
new file mode 100644
index 0000000000..579f450456
--- /dev/null
+++ b/engines/lab/music.cpp
@@ -0,0 +1,171 @@
+/* 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 Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#include "common/file.h"
+#include "audio/audiostream.h"
+#include "audio/decoders/raw.h"
+
+#include "lab/lab.h"
+
+#include "lab/anim.h"
+#include "lab/eventman.h"
+#include "lab/music.h"
+#include "lab/resource.h"
+
+namespace Lab {
+
+#define CLOWNROOM 123
+#define DIMROOM 80
+
+Music::Music(LabEngine *vm) : _vm(vm) {
+ _musicFile = nullptr;
+ _storedPos = 0;
+}
+
+byte Music::getSoundFlags() {
+ byte soundFlags = Audio::FLAG_LITTLE_ENDIAN;
+ if (_vm->getPlatform() == Common::kPlatformWindows)
+ soundFlags |= Audio::FLAG_16BITS;
+ else if (_vm->getPlatform() == Common::kPlatformDOS)
+ soundFlags |= Audio::FLAG_UNSIGNED;
+
+ return soundFlags;
+}
+
+void Music::loadSoundEffect(const Common::String filename, bool loop, bool waitTillFinished) {
+ stopSoundEffect();
+
+ Common::File *file = _vm->_resource->openDataFile(filename, MKTAG('D', 'I', 'F', 'F'));
+ if (!file)
+ return;
+
+ _vm->_anim->_doBlack = false;
+
+ uint32 magicBytes = file->readUint32LE();
+ if (magicBytes != 1219009121) {
+ warning("readSound: Bad signature, skipping");
+ return;
+ }
+ uint32 soundTag = file->readUint32LE();
+ uint32 soundSize = file->readUint32LE();
+
+ if (soundTag != 0)
+ return;
+
+ file->skip(soundSize); // skip the header
+
+ while (soundTag != 65535) {
+ _vm->updateEvents();
+ soundTag = file->readUint32LE();
+ soundSize = file->readUint32LE() - 8;
+
+ if ((soundTag == 30) || (soundTag == 31)) {
+ if (waitTillFinished) {
+ while (isSoundEffectActive()) {
+ _vm->updateEvents();
+ _vm->waitTOF();
+ }
+ }
+
+ file->skip(4);
+
+ uint16 sampleRate = file->readUint16LE();
+ file->skip(2);
+ playSoundEffect(sampleRate, soundSize, loop, file);
+ } else if (soundTag == 65535) {
+ if (waitTillFinished) {
+ while (isSoundEffectActive()) {
+ _vm->updateEvents();
+ _vm->waitTOF();
+ }
+ }
+ } else
+ file->skip(soundSize);
+ }
+}
+
+void Music::playSoundEffect(uint16 sampleSpeed, uint32 length, bool loop, Common::File *dataFile) {
+ stopSoundEffect();
+
+ // NOTE: We need to use malloc(), cause this will be freed with free()
+ // by the music code
+ byte *soundData = (byte *)malloc(length);
+ dataFile->read(soundData, length);
+
+ Audio::SeekableAudioStream *audioStream = Audio::makeRawStream((const byte *)soundData, length, MAX<uint16>(sampleSpeed, 4000), getSoundFlags());
+ _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandle, new Audio::LoopingAudioStream(audioStream, (loop) ? 0 : 1));
+}
+
+void Music::stopSoundEffect() {
+ if (isSoundEffectActive())
+ _vm->_mixer->stopHandle(_sfxHandle);
+}
+
+bool Music::isSoundEffectActive() const {
+ return _vm->_mixer->isSoundHandleActive(_sfxHandle);
+}
+
+void Music::changeMusic(const Common::String filename, bool storeCurPos, bool seektoStoredPos) {
+ if (storeCurPos)
+ _storedPos = _musicFile->pos();
+
+ stopSoundEffect();
+ freeMusic();
+ _musicFile = _vm->_resource->openDataFile(filename);
+ if (seektoStoredPos)
+ _musicFile->seek(_storedPos);
+
+ Audio::SeekableAudioStream *audioStream = Audio::makeRawStream(_musicFile, 15000, getSoundFlags());
+ _vm->_mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle, new Audio::LoopingAudioStream(audioStream, 0));
+}
+
+void Music::resetMusic(bool seektoStoredPos) {
+ if (_vm->getPlatform() != Common::kPlatformAmiga)
+ changeMusic("Music:BackGrou", false, seektoStoredPos);
+ else
+ changeMusic("Music:BackGround", false, seektoStoredPos);
+}
+
+void Music::checkRoomMusic(uint16 prevRoom, uint16 newRoom) {
+ if (newRoom == CLOWNROOM)
+ changeMusic("Music:Laugh", true, false);
+ else if (newRoom == DIMROOM)
+ changeMusic("Music:Rm81", true, false);
+ else if (prevRoom == CLOWNROOM || prevRoom == DIMROOM)
+ resetMusic(true);
+}
+
+void Music::freeMusic() {
+ _vm->_mixer->stopHandle(_musicHandle);
+ _vm->_mixer->stopHandle(_sfxHandle);
+ _musicFile = nullptr;
+}
+
+} // End of namespace Lab
diff --git a/engines/lab/music.h b/engines/lab/music.h
new file mode 100644
index 0000000000..8175e350f1
--- /dev/null
+++ b/engines/lab/music.h
@@ -0,0 +1,96 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#ifndef LAB_MUSIC_H
+#define LAB_MUSIC_H
+
+#include "audio/mixer.h"
+
+namespace Common {
+class File;
+}
+
+namespace Lab {
+
+class LabEngine;
+
+//---------------------------
+//----- From LabMusic.c -----
+//---------------------------
+
+#define MAXBUFFERS 5
+
+class Music {
+private:
+ LabEngine *_vm;
+
+ Common::File *_musicFile;
+ uint32 _storedPos;
+
+ Audio::SoundHandle _musicHandle;
+ Audio::SoundHandle _sfxHandle;
+
+private:
+ byte getSoundFlags();
+
+public:
+ Music(LabEngine *vm);
+
+ /**
+ * Changes the background music to something else.
+ */
+ void changeMusic(const Common::String filename, bool storeCurPos, bool seektoStoredPos);
+
+ void resetMusic(bool seekToStoredPos);
+
+ /**
+ * Checks the music that should be playing in a particular room.
+ */
+ void checkRoomMusic(uint16 prevRoom, uint16 newRoom);
+
+ /**
+ * Frees up the music buffers and closes the file.
+ */
+ void freeMusic();
+
+ bool isSoundEffectActive() const;
+ void playSoundEffect(uint16 sampleSpeed, uint32 length, bool loop, Common::File *dataFile);
+
+ /**
+ * Reads in a sound effect file. Ignores any graphics.
+ */
+ void loadSoundEffect(const Common::String filename, bool loop, bool waitTillFinished);
+
+ void stopSoundEffect();
+};
+
+} // End of namespace Lab
+
+#endif // LAB_MUSIC_H
diff --git a/engines/lab/processroom.cpp b/engines/lab/processroom.cpp
new file mode 100644
index 0000000000..68e6e63c1d
--- /dev/null
+++ b/engines/lab/processroom.cpp
@@ -0,0 +1,629 @@
+/* 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 Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#include "gui/message.h"
+
+#include "lab/lab.h"
+
+#include "lab/anim.h"
+#include "lab/dispman.h"
+#include "lab/labsets.h"
+#include "lab/music.h"
+#include "lab/processroom.h"
+#include "lab/resource.h"
+#include "lab/utils.h"
+
+namespace Lab {
+
+#define NOFILE "no file"
+
+bool LabEngine::checkConditions(const Common::Array<int16> &condition) {
+ for (unsigned int i = 0; i < condition.size(); ++i)
+ if (!_conditions->in(condition[i]))
+ return false;
+
+ return true;
+}
+
+ViewData *LabEngine::getViewData(uint16 roomNum, uint16 direction) {
+ if (_rooms[roomNum]._roomMsg.empty())
+ _resource->readViews(roomNum);
+
+ ViewDataList &views = _rooms[roomNum]._view[direction];
+ ViewDataList::iterator view;
+
+ for (view = views.begin(); view != views.end(); ++view) {
+ if (checkConditions(view->_condition))
+ return &(*view);
+ }
+
+ error("No view with matching condition found");
+}
+
+const CloseData *LabEngine::getObject(Common::Point pos, const CloseData *closePtr) {
+ const CloseDataList *list;
+ if (!closePtr)
+ list = &(getViewData(_roomNum, _direction)->_closeUps);
+ else
+ list = &(closePtr->_subCloseUps);
+
+ CloseDataList::const_iterator wrkClosePtr;
+
+ for (wrkClosePtr = list->begin(); wrkClosePtr != list->end(); ++wrkClosePtr) {
+ Common::Rect objRect;
+ objRect = _utils->rectScale(wrkClosePtr->_x1, wrkClosePtr->_y1, wrkClosePtr->_x2, wrkClosePtr->_y2);
+ if (objRect.contains(pos))
+ return &(*wrkClosePtr);
+ }
+
+ return nullptr;
+}
+
+const CloseData *LabEngine::findClosePtrMatch(const CloseData *closePtr, const CloseDataList &list) {
+ CloseDataList::const_iterator i;
+
+ for (i = list.begin(); i != list.end(); ++i) {
+ if ((closePtr->_x1 == i->_x1) && (closePtr->_x2 == i->_x2) &&
+ (closePtr->_y1 == i->_y1) && (closePtr->_y2 == i->_y2) &&
+ (closePtr->_depth == i->_depth))
+ return &(*i);
+
+ const CloseData *resClosePtr = findClosePtrMatch(closePtr, i->_subCloseUps);
+
+ if (resClosePtr)
+ return resClosePtr;
+ }
+
+ return nullptr;
+}
+
+Common::String LabEngine::getPictName(bool useClose) {
+ ViewData *viewPtr = getViewData(_roomNum, _direction);
+
+ if (useClose && _closeDataPtr) {
+ _closeDataPtr = findClosePtrMatch(_closeDataPtr, viewPtr->_closeUps);
+
+ if (_closeDataPtr)
+ return _closeDataPtr->_graphicName;
+ }
+
+ return viewPtr->_graphicName;
+}
+
+void LabEngine::drawDirection(const CloseData *closePtr) {
+ if (closePtr && !closePtr->_message.empty()) {
+ _graphics->drawMessage(closePtr->_message, false);
+ return;
+ }
+
+ Common::String message;
+
+ if (!_rooms[_roomNum]._roomMsg.empty())
+ message = _rooms[_roomNum]._roomMsg + ", ";
+
+ if (_direction == kDirectionNorth)
+ message += _resource->getStaticText(kTextFacingNorth);
+ else if (_direction == kDirectionEast)
+ message += _resource->getStaticText(kTextFacingEast);
+ else if (_direction == kDirectionSouth)
+ message += _resource->getStaticText(kTextFacingSouth);
+ else if (_direction == kDirectionWest)
+ message += _resource->getStaticText(kTextFacingWest);
+
+ _graphics->drawMessage(message, false);
+}
+
+uint16 LabEngine::processArrow(uint16 curDirection, uint16 arrow) {
+ if (arrow == 1) { // Forward
+ uint16 room = _rooms[_roomNum]._doors[curDirection];
+ if (room != 0) {
+ _music->checkRoomMusic(_roomNum, room);
+ _roomNum = room;
+ }
+
+ return curDirection;
+ } else if (arrow == 0) { // Left
+ if (curDirection == kDirectionNorth)
+ return kDirectionWest;
+ else if (curDirection == kDirectionWest)
+ return kDirectionSouth;
+ else if (curDirection == kDirectionSouth)
+ return kDirectionEast;
+ else
+ return kDirectionNorth;
+ } else if (arrow == 2) { // Right
+ if (curDirection == kDirectionNorth)
+ return kDirectionEast;
+ else if (curDirection == kDirectionEast)
+ return kDirectionSouth;
+ else if (curDirection == kDirectionSouth)
+ return kDirectionWest;
+ else
+ return kDirectionNorth;
+ }
+
+ // Should never reach here!
+ return curDirection;
+}
+
+void LabEngine::setCurrentClose(Common::Point pos, const CloseData **closePtrList, bool useAbsoluteCoords, bool next) {
+ const CloseDataList *list;
+
+ if (!*closePtrList)
+ list = &(getViewData(_roomNum, _direction)->_closeUps);
+ else
+ list = &((*closePtrList)->_subCloseUps);
+
+ CloseDataList::const_iterator closePtr;
+ for (closePtr = list->begin(); closePtr != list->end(); ++closePtr) {
+ Common::Rect target;
+ if (!useAbsoluteCoords)
+ target = Common::Rect(closePtr->_x1, closePtr->_y1, closePtr->_x2, closePtr->_y2);
+ else
+ target = _utils->rectScale(closePtr->_x1, closePtr->_y1, closePtr->_x2, closePtr->_y2);
+
+ if (target.contains(pos) && (next || !closePtr->_graphicName.empty())) {
+
+ if (next) {
+ // cycle to the next one
+ ++closePtr;
+ if (closePtr == list->end())
+ closePtr = list->begin();
+ }
+ *closePtrList = &(*closePtr);
+
+ return;
+ }
+ }
+
+ // If we got here, no match was found. If we want the "next" close-up,
+ // return the first one in the list, if any.
+ if (next) {
+ if (!list->empty())
+ *closePtrList = &(*list->begin());
+ }
+}
+
+bool LabEngine::takeItem(Common::Point pos) {
+ const CloseDataList *list;
+ if (!_closeDataPtr) {
+ list = &(getViewData(_roomNum, _direction)->_closeUps);
+ } else if (_closeDataPtr->_closeUpType < 0) {
+ _conditions->inclElement(abs(_closeDataPtr->_closeUpType));
+ return true;
+ } else
+ list = &(_closeDataPtr->_subCloseUps);
+
+ CloseDataList::const_iterator closePtr;
+ for (closePtr = list->begin(); closePtr != list->end(); ++closePtr) {
+ Common::Rect objRect;
+ objRect = _utils->rectScale(closePtr->_x1, closePtr->_y1, closePtr->_x2, closePtr->_y2);
+ if (objRect.contains(pos) && (closePtr->_closeUpType < 0)) {
+ _conditions->inclElement(abs(closePtr->_closeUpType));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+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:
+ _music->loadSoundEffect(action->_messages[0], false, true);
+ break;
+
+ case kActionPlaySoundNoWait: // only used in scene 7 (street, when teleporting to the surreal maze)
+ _music->loadSoundEffect(action->_messages[0], false, false);
+ break;
+
+ case kActionPlaySoundLooping:
+ _music->loadSoundEffect(action->_messages[0], true, false);
+ break;
+
+ case kActionShowDiff:
+ _graphics->readPict(action->_messages[0], true);
+ break;
+
+ case kActionShowDiffLooping: // used in scene 44 (heart of the labyrinth, minotaur)
+ _graphics->readPict(action->_messages[0], false);
+ break;
+
+ case kActionLoadDiff:
+ if (!action->_messages[0].empty())
+ // Puts a file into memory
+ _graphics->loadPict(action->_messages[0]);
+ break;
+
+ case kActionLoadBitmap:
+ error("Unused opcode kActionLoadBitmap has been called");
+
+ case kActionShowBitmap:
+ error("Unused opcode kActionShowBitmap has been called");
+
+ case kActionTransition:
+ _graphics->doTransition((TransitionType)action->_param1, action->_messages[0].c_str());
+ break;
+
+ case kActionNoUpdate:
+ _noUpdateDiff = true;
+ _anim->_doBlack = false;
+ break;
+
+ case kActionForceUpdate:
+ _curFileName = " ";
+ break;
+
+ case kActionShowCurPict: {
+ Common::String test = getPictName(true);
+
+ if (test != _curFileName) {
+ _curFileName = test;
+ _graphics->readPict(_curFileName);
+ }
+ }
+ break;
+
+ case kActionSetElement:
+ _conditions->inclElement(action->_param1);
+ break;
+
+ case kActionUnsetElement:
+ _conditions->exclElement(action->_param1);
+ break;
+
+ case kActionShowMessage:
+ if (_graphics->_longWinInFront)
+ _graphics->longDrawMessage(action->_messages[0], true);
+ else
+ _graphics->drawMessage(action->_messages[0], true);
+ break;
+
+ case kActionCShowMessage:
+ if (!_closeDataPtr)
+ _graphics->drawMessage(action->_messages[0], true);
+ break;
+
+ case kActionShowMessages:
+ _graphics->drawMessage(action->_messages[_utils->getRandom(action->_param1)], true);
+ break;
+
+ case kActionChangeRoom:
+ if (action->_param1 & 0x8000) {
+ // This is a Wyrmkeep Windows trial version, thus stop at this
+ // point, since we can't check for game payment status
+ _graphics->readPict(getPictName(true));
+ GUI::MessageDialog trialMessage("This is the end of the trial version. You can play the full game using the original interpreter from Wyrmkeep");
+ trialMessage.runModal();
+ break;
+ }
+
+ _music->checkRoomMusic(_roomNum, action->_param1);
+ _roomNum = action->_param1;
+ _direction = action->_param2 - 1;
+ _closeDataPtr = nullptr;
+ _anim->_doBlack = true;
+ break;
+
+ case kActionSetCloseup: {
+ Common::Point curPos = Common::Point(_utils->scaleX(action->_param1), _utils->scaleY(action->_param2));
+ const CloseData *tmpClosePtr = getObject(curPos, _closeDataPtr);
+
+ if (tmpClosePtr)
+ _closeDataPtr = tmpClosePtr;
+ }
+ break;
+
+ case kActionMainView:
+ _closeDataPtr = nullptr;
+ break;
+
+ case kActionSubInv:
+ if (_inventory[action->_param1]._quantity)
+ (_inventory[action->_param1]._quantity)--;
+
+ if (_inventory[action->_param1]._quantity == 0)
+ _conditions->exclElement(action->_param1);
+
+ break;
+
+ case kActionAddInv:
+ (_inventory[action->_param1]._quantity) += action->_param2;
+ _conditions->inclElement(action->_param1);
+ break;
+
+ case kActionShowDir:
+ _graphics->setActionMessage(false);
+ break;
+
+ case kActionWaitSecs: {
+ uint32 targetMillis = _system->getMillis() + action->_param1 * 1000;
+
+ _graphics->screenUpdate();
+
+ while (_system->getMillis() < targetMillis) {
+ updateEvents();
+ if (_quitLab || shouldQuit())
+ return;
+ _anim->diffNextFrame();
+ }
+ }
+ break;
+
+ case kActionStopMusic: // used in scene 44 (heart of the labyrinth, minotaur)
+ _music->freeMusic();
+ break;
+
+ case kActionStartMusic: // unused
+ error("Unused opcode kActionStartMusic has been called");
+ break;
+
+ case kActionChangeMusic: // used in scene 46 (museum exhibit, for the alarm)
+ _music->changeMusic(action->_messages[0], true, false);
+ break;
+
+ case kActionResetMusic: // used in scene 45 (sheriff's office, after museum)
+ _music->resetMusic(true);
+ break;
+
+ case kActionFillMusic:
+ error("Unused opcode kActionFillMusic has been called");
+ break;
+
+ case kActionWaitSound: // used in scene 44 (heart of the labyrinth / ending)
+ while (_music->isSoundEffectActive()) {
+ updateEvents();
+ if (_quitLab || shouldQuit())
+ return;
+ _anim->diffNextFrame();
+ waitTOF();
+ }
+ break;
+
+ case kActionClearSound:
+ _music->stopSoundEffect();
+ break;
+
+ case kActionWinMusic: // used in scene 44 (heart of the labyrinth / ending)
+ _music->freeMusic();
+ _music->changeMusic("Music:WinGame", false, false);
+ break;
+
+ case kActionWinGame: // used in scene 44 (heart of the labyrinth / ending)
+ _quitLab = true;
+ showLab2Teaser();
+ break;
+
+ case kActionLostGame:
+ error("Unused opcode kActionLostGame has been called");
+
+ case kActionResetBuffer:
+ _graphics->freePict();
+ break;
+
+ case kActionSpecialCmd:
+ if (action->_param1 == 0)
+ _anim->_doBlack = true;
+ else if (action->_param1 == 1)
+ _anim->_doBlack = (_closeDataPtr == nullptr);
+ else if (action->_param1 == 2)
+ _anim->_doBlack = (_closeDataPtr != nullptr);
+ else if (action->_param1 == 5) {
+ // inverse the palette
+ for (int idx = (8 * 3); idx < (255 * 3); idx++)
+ _anim->_diffPalette[idx] = 255 - _anim->_diffPalette[idx];
+
+ waitTOF();
+ _graphics->setPalette(_anim->_diffPalette, 256);
+ waitTOF();
+ waitTOF();
+ } else if (action->_param1 == 4) {
+ // white the palette
+ _graphics->whiteScreen();
+ waitTOF();
+ waitTOF();
+ } else if (action->_param1 == 6) {
+ // Restore the palette
+ waitTOF();
+ _graphics->setPalette(_anim->_diffPalette, 256);
+ waitTOF();
+ waitTOF();
+ } else if (action->_param1 == 7) {
+ // Quick pause
+ waitTOF();
+ waitTOF();
+ waitTOF();
+ }
+
+ break;
+ }
+ }
+
+ _music->stopSoundEffect();
+}
+
+bool LabEngine::doActionRuleSub(int16 action, int16 roomNum, const CloseData *closePtr, bool allowDefaults) {
+ action++;
+
+ if (closePtr) {
+ RuleList *rules = &(_rooms[_roomNum]._rules);
+
+ if (rules->empty() && (roomNum == 0)) {
+ _resource->readViews(roomNum);
+ rules = &(_rooms[roomNum]._rules);
+ }
+
+ for (RuleList::iterator rule = rules->begin(); rule != rules->end(); ++rule) {
+ if ((rule->_ruleType == kRuleTypeAction) &&
+ ((rule->_param1 == action) || ((rule->_param1 == 0) && allowDefaults))) {
+ if (((rule->_param2 == closePtr->_closeUpType) ||
+ ((rule->_param2 == 0) && allowDefaults)) ||
+ ((action == 1) && (rule->_param2 == -closePtr->_closeUpType))) {
+ if (checkConditions(rule->_condition)) {
+ doActions(rule->_actionList);
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool LabEngine::doActionRule(Common::Point pos, int16 action, int16 roomNum) {
+ if (roomNum)
+ _newFileName = NOFILE;
+ else
+ _newFileName = _curFileName;
+
+ const CloseData *curClosePtr = getObject(pos, _closeDataPtr);
+
+ if (doActionRuleSub(action, roomNum, curClosePtr, false))
+ return true;
+ else if (doActionRuleSub(action, roomNum, _closeDataPtr, false))
+ return true;
+ else if (doActionRuleSub(action, roomNum, curClosePtr, true))
+ return true;
+ else if (doActionRuleSub(action, roomNum, _closeDataPtr, true))
+ return true;
+
+ return false;
+}
+
+bool LabEngine::doOperateRuleSub(int16 itemNum, int16 roomNum, const CloseData *closePtr, bool allowDefaults) {
+ if (closePtr)
+ if (closePtr->_closeUpType > 0) {
+ RuleList *rules = &(_rooms[roomNum]._rules);
+
+ if (rules->empty() && (roomNum == 0)) {
+ _resource->readViews(roomNum);
+ rules = &(_rooms[roomNum]._rules);
+ }
+
+ for (RuleList::iterator rule = rules->begin(); rule != rules->end(); ++rule) {
+ if ((rule->_ruleType == kRuleTypeOperate) &&
+ ((rule->_param1 == itemNum) || ((rule->_param1 == 0) && allowDefaults)) &&
+ ((rule->_param2 == closePtr->_closeUpType) || ((rule->_param2 == 0) && allowDefaults))) {
+ if (checkConditions(rule->_condition)) {
+ doActions(rule->_actionList);
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool LabEngine::doOperateRule(Common::Point pos, int16 ItemNum) {
+ _newFileName = NOFILE;
+ const CloseData *closePtr = getObject(pos, _closeDataPtr);
+
+ if (doOperateRuleSub(ItemNum, _roomNum, closePtr, false))
+ return true;
+ else if (doOperateRuleSub(ItemNum, _roomNum, _closeDataPtr, false))
+ return true;
+ else if (doOperateRuleSub(ItemNum, _roomNum, closePtr, true))
+ return true;
+ else if (doOperateRuleSub(ItemNum, _roomNum, _closeDataPtr, true))
+ return true;
+ else {
+ _newFileName = _curFileName;
+
+ if (doOperateRuleSub(ItemNum, 0, closePtr, false))
+ return true;
+ else if (doOperateRuleSub(ItemNum, 0, _closeDataPtr, false))
+ return true;
+ else if (doOperateRuleSub(ItemNum, 0, closePtr, true))
+ return true;
+ else if (doOperateRuleSub(ItemNum, 0, _closeDataPtr, true))
+ return true;
+ }
+
+ return false;
+}
+
+bool LabEngine::doGoForward() {
+ RuleList &rules = _rooms[_roomNum]._rules;
+
+ for (RuleList::iterator rule = rules.begin(); rule != rules.end(); ++rule) {
+ if ((rule->_ruleType == kRuleTypeGoForward) && (rule->_param1 == (_direction + 1))) {
+ if (checkConditions(rule->_condition)) {
+ doActions(rule->_actionList);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool LabEngine::doTurn(uint16 from, uint16 to) {
+ from++;
+ to++;
+
+ RuleList &rules = _rooms[_roomNum]._rules;
+
+ for (RuleList::iterator rule = rules.begin(); rule != rules.end(); ++rule) {
+ if ((rule->_ruleType == kRuleTypeTurn) ||
+ ((rule->_ruleType == kRuleTypeTurnFromTo) &&
+ (rule->_param1 == from) && (rule->_param2 == to))) {
+ if (checkConditions(rule->_condition)) {
+ doActions(rule->_actionList);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool LabEngine::doMainView() {
+ RuleList &rules = _rooms[_roomNum]._rules;
+ for (RuleList::iterator rule = rules.begin(); rule != rules.end(); ++rule) {
+ if (rule->_ruleType == kRuleTypeGoMainView) {
+ if (checkConditions(rule->_condition)) {
+ doActions(rule->_actionList);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+} // End of namespace Lab
diff --git a/engines/lab/processroom.h b/engines/lab/processroom.h
new file mode 100644
index 0000000000..1d53ce01af
--- /dev/null
+++ b/engines/lab/processroom.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.
+ *
+ */
+
+/*
+ * This code is based on Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#ifndef LAB_PROCESSROOM_H
+#define LAB_PROCESSROOM_H
+
+namespace Lab {
+
+enum ActionType {
+ kActionPlaySound = 1,
+ kActionPlaySoundLooping = 2,
+ kActionShowDiff = 3,
+ kActionShowDiffLooping = 4,
+ kActionLoadDiff = 5,
+ kActionLoadBitmap = 6, // unused
+ kActionShowBitmap = 7, // unused
+ kActionTransition = 8,
+ kActionNoUpdate = 9,
+ kActionForceUpdate = 10,
+ kActionShowCurPict = 11,
+ kActionSetElement = 12,
+ kActionUnsetElement = 13,
+ kActionShowMessage = 14,
+ kActionShowMessages = 15,
+ kActionChangeRoom = 16,
+ kActionSetCloseup = 17,
+ kActionMainView = 18,
+ kActionSubInv = 19,
+ kActionAddInv = 20,
+ kActionShowDir = 21,
+ kActionWaitSecs = 22,
+ kActionStopMusic = 23,
+ kActionStartMusic = 24,
+ kActionChangeMusic = 25,
+ kActionResetMusic = 26,
+ kActionFillMusic = 27,
+ kActionWaitSound = 28,
+ kActionClearSound = 29,
+ kActionWinMusic = 30,
+ kActionWinGame = 31,
+ kActionLostGame = 32, // unused
+ kActionResetBuffer = 33,
+ kActionSpecialCmd = 34,
+ kActionCShowMessage = 35,
+ kActionPlaySoundNoWait = 36
+};
+
+enum RuleType {
+ kRuleTypeNone = 0,
+ kRuleTypeAction = 1,
+ kRuleTypeOperate = 2,
+ kRuleTypeGoForward = 3,
+ kRuleTypeConditions = 4, // unused?
+ kRuleTypeTurn = 5,
+ kRuleTypeGoMainView = 6,
+ kRuleTypeTurnFromTo = 7
+};
+
+enum RuleAction {
+ kRuleActionTake = 0,
+ kRuleActionMove = 1, // unused?
+ kRuleActionOpenDoor = 2, // unused?
+ kRuleActionCloseDoor = 3, // unused?
+ kRuleActionTakeDef = 4
+};
+
+enum Condition {
+ kCondBeltGlowing = 70,
+ kCondBridge1 = 104,
+ kCondNoNews = 135,
+ kCondBridge0 = 148,
+ kCondLampOn = 151,
+ kCondNoClean = 152,
+ kCondDirty = 175,
+ kCondUsedHelmet = 184
+};
+
+enum MapDoors {
+ kDoorLeftNorth = 1,
+ kDoorLeftEast = 2,
+ kDoorLeftSouth = 4,
+ kDoorLeftWest = 8,
+
+ kDoorMiddleNorth = 16,
+ kDoorRightNorth = 32,
+ kDoorMiddleSouth = 64,
+ kDoorRightSouth = 128,
+
+ kDoorMiddleEast = 16,
+ kDoorBottomEast = 32,
+ kDoorMiddleWest = 64,
+ kDoorBottomWest = 128
+};
+
+enum SpecialRoom {
+ kNormalRoom = 0,
+ kUpArrowRoom,
+ kDownArrowRoom,
+ kBridgeRoom,
+ kVerticalCorridor,
+ kHorizontalCorridor,
+ kMedMaze,
+ kHedgeMaze,
+ kSurMaze,
+ kMultiMazeF1,
+ kMultiMazeF2,
+ kMultiMazeF3
+};
+
+struct CloseData {
+ uint16 _x1, _y1, _x2, _y2;
+ int16 _closeUpType; // if > 0, an object. If < 0, an item
+ uint16 _depth; // Level of the closeup.
+ Common::String _graphicName;
+ Common::String _message;
+ CloseDataList _subCloseUps;
+};
+
+struct ViewData {
+ Common::Array<int16> _condition;
+ Common::String _graphicName;
+ CloseDataList _closeUps;
+};
+
+struct Action {
+ ActionType _actionType;
+ int16 _param1;
+ int16 _param2;
+ int16 _param3;
+ Common::Array<Common::String> _messages;
+};
+
+struct Rule {
+ RuleType _ruleType;
+ int16 _param1;
+ int16 _param2;
+ Common::Array<int16> _condition;
+ ActionList _actionList;
+};
+
+struct RoomData {
+ uint16 _doors[4];
+ byte _transitionType;
+ ViewDataList _view[4];
+ RuleList _rules;
+ Common::String _roomMsg;
+};
+
+struct InventoryData {
+ uint16 _quantity;
+ Common::String _name;
+ Common::String _bitmapName;
+};
+
+struct MapData {
+ uint16 _x, _y, _pageNumber;
+ SpecialRoom _specialID;
+ uint32 _mapFlags;
+};
+
+} // End of namespace Lab
+
+#endif // LAB_PROCESSROOM_H
diff --git a/engines/lab/resource.cpp b/engines/lab/resource.cpp
new file mode 100644
index 0000000000..9cb35d1088
--- /dev/null
+++ b/engines/lab/resource.cpp
@@ -0,0 +1,343 @@
+/* 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 Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#include "common/file.h"
+
+#include "lab/lab.h"
+
+#include "lab/dispman.h"
+#include "lab/music.h"
+#include "lab/processroom.h"
+#include "lab/resource.h"
+
+namespace Lab {
+
+Resource::Resource(LabEngine *vm) : _vm(vm) {
+ readStaticText();
+}
+
+void Resource::readStaticText() {
+ Common::File *labTextFile = openDataFile("Lab:Rooms/LabText");
+
+ for (int i = 0; i < 48; i++)
+ _staticText[i] = labTextFile->readLine();
+
+ delete labTextFile;
+}
+
+TextFont *Resource::getFont(const Common::String fileName) {
+ // TODO: Add support for the font format of the Amiga version
+ Common::File *dataFile = openDataFile(fileName, MKTAG('V', 'G', 'A', 'F'));
+
+ uint32 headerSize = 4 + 2 + 256 * 3 + 4;
+ uint32 fileSize = dataFile->size();
+ if (fileSize <= headerSize)
+ return nullptr;
+
+ TextFont *textfont = new TextFont();
+ textfont->_dataLength = fileSize - headerSize;
+ textfont->_height = dataFile->readUint16LE();
+ dataFile->read(textfont->_widths, 256);
+ for (int i = 0; i < 256; i++)
+ textfont->_offsets[i] = dataFile->readUint16LE();
+ dataFile->skip(4);
+ textfont->_data = new byte[textfont->_dataLength + 4];
+ dataFile->read(textfont->_data, textfont->_dataLength);
+ delete dataFile;
+ return textfont;
+}
+
+Common::String Resource::getText(const Common::String fileName) {
+ Common::File *dataFile = openDataFile(fileName);
+
+ uint32 count = dataFile->size();
+ byte *buffer = new byte[count];
+ byte *text = buffer;
+ dataFile->read(buffer, count);
+
+ while (text && (*text != '\0'))
+ *text++ -= (byte)95;
+
+ delete dataFile;
+
+ Common::String str = (char *)buffer;
+ delete[] buffer;
+
+ return str;
+}
+
+void Resource::readRoomData(const Common::String fileName) {
+ Common::File *dataFile = openDataFile(fileName, MKTAG('D', 'O', 'R', '1'));
+
+ _vm->_manyRooms = dataFile->readUint16LE();
+ _vm->_highestCondition = dataFile->readUint16LE();
+ _vm->_rooms = new RoomData[_vm->_manyRooms + 1];
+
+ for (int i = 1; i <= _vm->_manyRooms; i++) {
+ RoomData *curRoom = &_vm->_rooms[i];
+ curRoom->_doors[kDirectionNorth] = dataFile->readUint16LE();
+ curRoom->_doors[kDirectionSouth] = dataFile->readUint16LE();
+ curRoom->_doors[kDirectionEast] = dataFile->readUint16LE();
+ curRoom->_doors[kDirectionWest] = dataFile->readUint16LE();
+ curRoom->_transitionType = dataFile->readByte();
+ }
+
+ delete dataFile;
+}
+
+InventoryData *Resource::readInventory(const Common::String fileName) {
+ Common::File *dataFile = openDataFile(fileName, MKTAG('I', 'N', 'V', '1'));
+
+ _vm->_numInv = dataFile->readUint16LE();
+ InventoryData *inventory = new InventoryData[_vm->_numInv + 1];
+
+ for (int i = 1; i <= _vm->_numInv; i++) {
+ inventory[i]._quantity = dataFile->readUint16LE();
+ inventory[i]._name = readString(dataFile);
+ inventory[i]._bitmapName = readString(dataFile);
+ }
+
+ delete dataFile;
+ return inventory;
+}
+
+void Resource::readViews(uint16 roomNum) {
+ Common::String fileName = "LAB:Rooms/" + Common::String::format("%d", roomNum);
+ Common::File *dataFile = openDataFile(fileName, MKTAG('R', 'O', 'M', '4'));
+
+ RoomData *curRoom = &_vm->_rooms[roomNum];
+
+ curRoom->_roomMsg = readString(dataFile);
+ readView(dataFile, curRoom->_view[kDirectionNorth]);
+ readView(dataFile, curRoom->_view[kDirectionSouth]);
+ readView(dataFile, curRoom->_view[kDirectionEast]);
+ readView(dataFile, curRoom->_view[kDirectionWest]);
+ readRule(dataFile, curRoom->_rules);
+
+ delete dataFile;
+}
+
+Common::String Resource::translateFileName(const Common::String filename) {
+ Common::String upperFilename;
+
+ // The DOS and Windows version aren't looking for the right file,
+ if (!filename.compareToIgnoreCase("P:ZigInt/BLK") && (_vm->getPlatform() != Common::kPlatformAmiga))
+ upperFilename = "P:ZigInt/ZIGINT.BLK";
+ else
+ upperFilename = filename;
+
+ upperFilename.toUppercase();
+ Common::String fileNameStrFinal;
+
+ if (upperFilename.hasPrefix("P:") || upperFilename.hasPrefix("F:")) {
+ if (_vm->_isHiRes)
+ fileNameStrFinal = "SPICT/";
+ else
+ fileNameStrFinal = "PICT/";
+
+ if (_vm->getPlatform() == Common::kPlatformAmiga) {
+ if (upperFilename.hasPrefix("P:")) {
+ fileNameStrFinal = "PICT/";
+ } else {
+ fileNameStrFinal = "LABFONTS/";
+ upperFilename += "T"; // all the Amiga fonts have a ".FONT" suffix
+ }
+ }
+ } else if (upperFilename.hasPrefix("LAB:")) {
+ // Look inside the game folder
+ } else if (upperFilename.hasPrefix("MUSIC:")) {
+ fileNameStrFinal = "MUSIC/";
+ }
+
+ if (upperFilename.contains(':')) {
+ while (upperFilename[0] != ':') {
+ upperFilename.deleteChar(0);
+ }
+
+ upperFilename.deleteChar(0);
+ }
+
+ if (_vm->getPlatform() == Common::kPlatformDOS) {
+ // Some script of the DOS version uses names used in the Amiga (and Windows) version,
+ // which isn't limited to 8.3 characters. We need to parse upperFilename to detect
+ // the filename, and fix it if required so it matches a DOS filename.
+ while (upperFilename.contains('/') && upperFilename.size()) {
+ fileNameStrFinal += upperFilename[0];
+ upperFilename.deleteChar(0);
+ }
+
+ for (int i = 0; (i < 8) && upperFilename.size() && (upperFilename[0] != '.'); i++) {
+ fileNameStrFinal += upperFilename[0];
+ upperFilename.deleteChar(0);
+ }
+
+ // Remove the extra character in the filename
+ while (upperFilename.size() && (upperFilename[0] != '.'))
+ upperFilename.deleteChar(0);
+
+ // copy max 4 characters for the extension ('.foo')
+ for (int i = 0; (i < 4) && upperFilename.size(); i++) {
+ fileNameStrFinal += upperFilename[0];
+ upperFilename.deleteChar(0);
+ }
+
+ // Skip the extra characters of the extension
+ upperFilename.clear();
+ }
+
+ fileNameStrFinal += upperFilename;
+
+ return fileNameStrFinal;
+}
+
+Common::File *Resource::openDataFile(const Common::String filename, uint32 fileHeader) {
+ Common::File *dataFile = new Common::File();
+ dataFile->open(translateFileName(filename));
+
+ if (!dataFile->isOpen()) {
+ // The DOS version is known to have some missing files
+ if (_vm->getPlatform() == Common::kPlatformDOS) {
+ warning("Incomplete DOS version, skipping file %s", filename.c_str());
+ return nullptr;
+ } else
+ error("openDataFile: Couldn't open %s (%s)", translateFileName(filename).c_str(), filename.c_str());
+ }
+ if (fileHeader > 0) {
+ uint32 headerTag = dataFile->readUint32BE();
+ if (headerTag != fileHeader) {
+ dataFile->close();
+ error("openDataFile: Unexpected header in %s (%s) - expected: %d, got: %d", translateFileName(filename).c_str(), filename.c_str(), fileHeader, headerTag);
+ }
+ }
+
+ return dataFile;
+}
+
+Common::String Resource::readString(Common::File *file) {
+ byte size = file->readByte();
+ if (!size)
+ return Common::String("");
+
+ char *str = new char[size];
+ for (int i = 0; i < size; i++) {
+ char c = file->readByte();
+ // Decrypt char
+ c = (i < size - 1) ? c - 95 : '\0';
+ str[i] = c;
+ }
+
+ Common::String result = str;
+ delete[] str;
+ return result;
+}
+
+Common::Array<int16> Resource::readConditions(Common::File *file) {
+ int16 cond;
+ Common::Array<int16> list;
+
+ while ((cond = file->readUint16LE()) != 0)
+ list.push_back(cond);
+
+ if (list.size() > 24) {
+ // The original only allocated 24 elements, and silently
+ // dropped remaining parts.
+ warning("More than 24 parts in condition");
+ }
+
+ return list;
+}
+
+void Resource::readRule(Common::File *file, RuleList &rules) {
+ rules.clear();
+ while (file->readByte() == 1) {
+ rules.push_back(Rule());
+ Rule &rule = rules.back();
+
+ rule._ruleType = (RuleType)file->readSint16LE();
+ rule._param1 = file->readSint16LE();
+ rule._param2 = file->readSint16LE();
+ rule._condition = readConditions(file);
+ readAction(file, rule._actionList);
+ }
+}
+
+void Resource::readAction(Common::File *file, ActionList &list) {
+ list.clear();
+
+ while (file->readByte() == 1) {
+ list.push_back(Action());
+ Action &action = list.back();
+
+ action._actionType = (ActionType)file->readSint16LE();
+ action._param1 = file->readSint16LE();
+ action._param2 = file->readSint16LE();
+ action._param3 = file->readSint16LE();
+
+ if (action._actionType == kActionShowMessages) {
+ action._messages.reserve(action._param1);
+ for (int i = 0; i < action._param1; i++)
+ action._messages.push_back(readString(file));
+ } else {
+ action._messages.push_back(readString(file));
+ }
+ }
+}
+
+void Resource::readCloseUps(uint16 depth, Common::File *file, CloseDataList &list) {
+ list.clear();
+ while (file->readByte() != '\0') {
+ list.push_back(CloseData());
+ CloseData &closeup = list.back();
+
+ closeup._x1 = file->readUint16LE();
+ closeup._y1 = file->readUint16LE();
+ closeup._x2 = file->readUint16LE();
+ closeup._y2 = file->readUint16LE();
+ closeup._closeUpType = file->readSint16LE();
+ closeup._depth = depth;
+ closeup._graphicName = readString(file);
+ closeup._message = readString(file);
+ readCloseUps(depth + 1, file, closeup._subCloseUps);
+ }
+}
+
+void Resource::readView(Common::File *file, ViewDataList &list) {
+ list.clear();
+ while (file->readByte() == 1) {
+ list.push_back(ViewData());
+ ViewData &view = list.back();
+
+ view._condition = readConditions(file);
+ view._graphicName = readString(file);
+ readCloseUps(0, file, view._closeUps);
+ }
+}
+
+} // End of namespace Lab
diff --git a/engines/lab/resource.h b/engines/lab/resource.h
new file mode 100644
index 0000000000..9a242b13e0
--- /dev/null
+++ b/engines/lab/resource.h
@@ -0,0 +1,124 @@
+/* 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 Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#ifndef LAB_RESOURCE_H
+#define LAB_RESOURCE_H
+
+namespace Lab {
+
+struct ViewData;
+
+enum StaticText {
+ kTextLowerFloor,
+ kTextMiddleFloor,
+ kTextUpperFloor,
+ kTextMedMazeFloor,
+ kTextHedgeMazeFloor,
+ kTextSurMazeFloor,
+ kTextCarnivalFloor,
+
+ kTextSurmazeMessage,
+
+ kTextFacingNorth,
+ kTextFacingEast,
+ kTextFacingSouth,
+ kTextFacingWest,
+
+ kTextkLampOn,
+
+ kTextTurnLeft,
+ kTextTurnRight,
+ kTextGoForward,
+ kTextNoPath,
+ kTextTakeItem,
+ kTextSave,
+ kTextLoad,
+ kTextBookmark,
+ kTextPersonal,
+ kTextDisk,
+ kTextSaveBook,
+ kTextRestoreBook,
+ kTextSaveFlash,
+ kTextRestoreFlash,
+ kTextSaveDisk,
+ kTextRestoreDisk,
+ kTextNoDiskInDrive,
+ kTextWriteProtected,
+ kTextSelectDisk,
+ kTextFormatFloppy,
+ kTextFormatting,
+
+ kTextNothing,
+ kTextUseOnWhat,
+ kTextTakeWhat,
+ kTextMoveWhat,
+ kTextOpenWhat,
+ kTextCloseWhat,
+ kTextLookWhat,
+
+ kTextUseMap,
+ kTextUseJournal,
+ kTextTurnkLampOn,
+ kTextTurnLampOff,
+ kTextUseWhiskey,
+ kTextUsePith,
+ kTextUseHelmet
+};
+
+class Resource {
+public:
+ Resource(LabEngine *vm);
+ ~Resource() {}
+
+ Common::File *openDataFile(const Common::String filename, uint32 fileHeader = 0);
+ void readRoomData(const Common::String fileName);
+ InventoryData *readInventory(const Common::String fileName);
+ void readViews(uint16 roomNum);
+ TextFont *getFont(const Common::String fileName);
+ Common::String getText(const Common::String fileName);
+ Common::String getStaticText(byte index) const { return _staticText[index]; }
+
+private:
+ LabEngine *_vm;
+ Common::String readString(Common::File *file);
+ Common::Array<int16> readConditions(Common::File *file);
+ void readRule(Common::File *file, RuleList &rules);
+ void readAction(Common::File *file, ActionList &action);
+ void readCloseUps(uint16 depth, Common::File *file, CloseDataList &close);
+ void readView(Common::File *file, ViewDataList &view);
+ void readStaticText();
+ Common::String translateFileName(const Common::String filename);
+
+ Common::String _staticText[48];
+};
+
+} // End of namespace Lab
+
+#endif // LAB_RESOURCE_H
diff --git a/engines/lab/savegame.cpp b/engines/lab/savegame.cpp
new file mode 100644
index 0000000000..656595e3e5
--- /dev/null
+++ b/engines/lab/savegame.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.
+ *
+ */
+
+/*
+ * This code is based on Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#include "common/savefile.h"
+#include "common/translation.h"
+
+#include "gui/message.h"
+#include "gui/saveload.h"
+
+#include "graphics/thumbnail.h"
+#include "engines/savestate.h"
+
+#include "lab/lab.h"
+#include "lab/dispman.h"
+#include "lab/eventman.h"
+#include "lab/labsets.h"
+#include "lab/music.h"
+#include "lab/processroom.h"
+#include "lab/speciallocks.h"
+
+namespace Lab {
+
+#define SAVEGAME_ID MKTAG('L', 'O', 'T', 'S')
+#define SAVEGAME_VERSION 1
+
+void LabEngine::writeSaveGameHeader(Common::OutSaveFile *out, const Common::String &saveName) {
+ out->writeUint32BE(SAVEGAME_ID);
+
+ // Write version
+ out->writeByte(SAVEGAME_VERSION);
+
+ // Write savegame name
+ out->writeString(saveName);
+ out->writeByte(0);
+
+ // Save the game thumbnail
+ Graphics::saveThumbnail(*out);
+
+ // Creation date/time
+ TimeDate curTime;
+ _system->getTimeAndDate(curTime);
+
+ uint32 saveDate = ((curTime.tm_mday & 0xFF) << 24) | (((curTime.tm_mon + 1) & 0xFF) << 16) | ((curTime.tm_year + 1900) & 0xFFFF);
+ uint16 saveTime = ((curTime.tm_hour & 0xFF) << 8) | ((curTime.tm_min) & 0xFF);
+ uint32 playTime = getTotalPlayTime() / 1000;
+
+ out->writeUint32BE(saveDate);
+ out->writeUint16BE(saveTime);
+ out->writeUint32BE(playTime);
+}
+
+bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &header) {
+ uint32 id = in->readUint32BE();
+
+ // Check if it's a valid ScummVM savegame
+ if (id != SAVEGAME_ID)
+ return false;
+
+ // Read in the version
+ header._version = in->readByte();
+
+ // Check that the save version isn't newer than this binary
+ if (header._version > SAVEGAME_VERSION)
+ return false;
+
+ // Read in the save name
+ Common::String saveName;
+ char ch;
+ while ((ch = (char)in->readByte()) != '\0')
+ saveName += ch;
+ header._descr.setDescription(saveName);
+
+ // Get the thumbnail
+ header._descr.setThumbnail(Graphics::loadThumbnail(*in));
+
+ uint32 saveDate = in->readUint32BE();
+ uint16 saveTime = in->readUint16BE();
+ uint32 playTime = in->readUint32BE();
+
+ int day = (saveDate >> 24) & 0xFF;
+ int month = (saveDate >> 16) & 0xFF;
+ int year = saveDate & 0xFFFF;
+ header._descr.setSaveDate(year, month, day);
+
+ int hour = (saveTime >> 8) & 0xFF;
+ int minutes = saveTime & 0xFF;
+ header._descr.setSaveTime(hour, minutes);
+
+ header._descr.setPlayTime(playTime * 1000);
+ if (g_engine)
+ g_engine->setTotalPlayTime(playTime * 1000);
+
+ return true;
+}
+
+bool LabEngine::saveGame(int slot, const Common::String desc) {
+ Common::String fileName = generateSaveFileName(slot);
+ Common::SaveFileManager *saveFileManager = _system->getSavefileManager();
+ Common::OutSaveFile *file = saveFileManager->openForSaving(fileName);
+
+ if (!file)
+ return false;
+
+ // Load scene pic
+ _graphics->readPict(getPictName(false));
+
+
+ writeSaveGameHeader(file, desc);
+ file->writeUint16LE(_roomNum);
+ file->writeUint16LE(getDirection());
+ file->writeUint16LE(getQuarters());
+
+ // Conditions
+ for (int i = 0; i < _conditions->_lastElement / (8 * 2); i++)
+ file->writeUint16LE(_conditions->_array[i]);
+
+ // Rooms found
+ for (int i = 0; i < _roomsFound->_lastElement / (8 * 2); i++)
+ file->writeUint16LE(_roomsFound->_array[i]);
+
+ _specialLocks->save(file);
+
+ // Breadcrumbs
+ for (uint i = 0; i < MAX_CRUMBS; i++) {
+ file->writeUint16LE(_breadCrumbs[i]._crumbRoomNum);
+ file->writeUint16LE(_breadCrumbs[i]._crumbDirection);
+ }
+
+ file->flush();
+ file->finalize();
+ delete file;
+
+ _mainDisplay = true;
+ _alternate = false;
+ _event->simulateEvent();
+ _graphics->screenUpdate();
+
+ return true;
+}
+
+bool LabEngine::loadGame(int slot) {
+ Common::String fileName = generateSaveFileName(slot);
+ Common::SaveFileManager *saveFileManager = _system->getSavefileManager();
+ Common::InSaveFile *file = saveFileManager->openForLoading(fileName);
+
+ if (!file)
+ return false;
+
+ SaveGameHeader header;
+ readSaveGameHeader(file, header);
+ _roomNum = file->readUint16LE();
+ _music->checkRoomMusic(1, _roomNum);
+ _direction = file->readUint16LE();
+ setQuarters(file->readUint16LE());
+
+ // Conditions
+ for (int i = 0; i < _conditions->_lastElement / (8 * 2); i++)
+ _conditions->_array[i] = file->readUint16LE();
+
+ // Rooms found
+ for (int i = 0; i < _roomsFound->_lastElement / (8 * 2); i++)
+ _roomsFound->_array[i] = file->readUint16LE();
+
+ _specialLocks->load(file);
+
+ // Breadcrumbs
+ for (int i = 0; i < MAX_CRUMBS; i++) {
+ _breadCrumbs[i]._crumbRoomNum = file->readUint16LE();
+ _breadCrumbs[i]._crumbDirection = file->readUint16LE();
+ }
+
+ _droppingCrumbs = (_breadCrumbs[0]._crumbRoomNum != 0);
+ _followingCrumbs = false;
+
+ for (int i = 0; i < MAX_CRUMBS; i++) {
+ if (_breadCrumbs[i]._crumbRoomNum == 0)
+ break;
+ _numCrumbs = i;
+ }
+
+ delete file;
+
+ _curFileName = " ";
+ _closeDataPtr = nullptr;
+ _followingCrumbs = false;
+ _graphics->_longWinInFront = false;
+ _event->initMouse();
+
+ _mainDisplay = true;
+ _alternate = false;
+ _event->simulateEvent();
+ _graphics->screenUpdate();
+
+ return true;
+}
+
+bool LabEngine::saveRestoreGame() {
+ bool isOK = false;
+
+ // The original had one screen for saving/loading. We have two.
+ // Ask the user which screen to use.
+ GUI::MessageDialog saveOrLoad(_("Would you like to save or restore a game?"), _("Save"), _("Restore"));
+
+ int choice = saveOrLoad.runModal();
+ if (choice == GUI::kMessageOK) {
+ // Save
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
+ int slot = dialog->runModalWithCurrentTarget();
+ if (slot >= 0) {
+ Common::String desc = dialog->getResultString();
+
+ if (desc.empty()) {
+ // create our own description for the saved game, the user didn't enter it
+ desc = dialog->createDefaultSaveDescription(slot);
+ }
+
+ isOK = saveGame(slot, desc);
+ }
+ delete dialog;
+ } else {
+ // Restore
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false);
+ int slot = dialog->runModalWithCurrentTarget();
+ if (slot >= 0) {
+ isOK = loadGame(slot);
+ }
+ delete dialog;
+ }
+
+ return isOK;
+}
+
+} // End of namespace Lab
diff --git a/engines/lab/special.cpp b/engines/lab/special.cpp
new file mode 100644
index 0000000000..7c3cb39931
--- /dev/null
+++ b/engines/lab/special.cpp
@@ -0,0 +1,477 @@
+/* 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 Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#include "common/file.h"
+
+#include "lab/lab.h"
+
+#include "lab/anim.h"
+#include "lab/dispman.h"
+#include "lab/eventman.h"
+#include "lab/image.h"
+#include "lab/interface.h"
+#include "lab/labsets.h"
+#include "lab/music.h"
+#include "lab/processroom.h"
+#include "lab/resource.h"
+#include "lab/utils.h"
+
+namespace Lab {
+
+void LabEngine::doNotes() {
+ TextFont *noteFont = _resource->getFont("F:Note.fon");
+ Common::String noteText = _resource->getText("Lab:Rooms/Notes");
+
+ Common::Rect textRect = Common::Rect(_utils->vgaScaleX(25) + _utils->svgaCord(15), _utils->vgaScaleY(50), _utils->vgaScaleX(295) - _utils->svgaCord(15), _utils->vgaScaleY(148));
+ _graphics->flowText(noteFont, -2 + _utils->svgaCord(1), 0, 0, false, false, true, true, textRect, noteText.c_str());
+ _graphics->setPalette(_anim->_diffPalette, 256);
+ _graphics->freeFont(&noteFont);
+}
+
+void LabEngine::doWestPaper() {
+ TextFont *paperFont = _resource->getFont("F:News22.fon");
+ Common::String paperText = _resource->getText("Lab:Rooms/Date");
+
+ Common::Rect textRect = Common::Rect(_utils->vgaScaleX(57), _utils->vgaScaleY(77) + _utils->svgaCord(2), _utils->vgaScaleX(262), _utils->vgaScaleY(91));
+ _graphics->flowText(paperFont, 0, 0, 0, false, true, false, true, textRect, paperText.c_str());
+ _graphics->freeFont(&paperFont);
+
+ paperFont = _resource->getFont("F:News32.fon");
+ paperText = _resource->getText("Lab:Rooms/Headline");
+
+ int fileLen = paperText.size() - 1;
+ textRect = Common::Rect(_utils->vgaScaleX(57), _utils->vgaScaleY(86) - _utils->svgaCord(2), _utils->vgaScaleX(262), _utils->vgaScaleY(118));
+ int charsPrinted = _graphics->flowText(paperFont, -8, 0, 0, false, true, false, true, textRect, paperText.c_str());
+
+ uint16 y;
+
+ if (charsPrinted < fileLen) {
+ y = 130 - _utils->svgaCord(5);
+ textRect = Common::Rect(_utils->vgaScaleX(57), _utils->vgaScaleY(86) - _utils->svgaCord(2), _utils->vgaScaleX(262), _utils->vgaScaleY(132));
+ _graphics->flowText(paperFont, -8 - _utils->svgaCord(1), 0, 0, false, true, false, true, textRect, paperText.c_str());
+ } else
+ y = 115 - _utils->svgaCord(5);
+
+ _graphics->freeFont(&paperFont);
+
+ paperFont = _resource->getFont("F:Note.fon");
+ paperText = _resource->getText("Lab:Rooms/Col1");
+ _graphics->flowText(paperFont, -4, 0, 0, false, false, false, true, _utils->vgaRectScale(45, y, 158, 148), paperText.c_str());
+
+ paperText = _resource->getText("Lab:Rooms/Col2");
+ _graphics->flowText(paperFont, -4, 0, 0, false, false, false, true, _utils->vgaRectScale(162, y, 275, 148), paperText.c_str());
+
+ _graphics->freeFont(&paperFont);
+ _graphics->setPalette(_anim->_diffPalette, 256);
+}
+
+void LabEngine::loadJournalData() {
+ if (_journalFont)
+ _graphics->freeFont(&_journalFont);
+
+ _journalFont = _resource->getFont("F:Journal.fon");
+ updateEvents();
+
+ Common::String filename = "Lab:Rooms/j";
+
+ bool bridge = _conditions->in(kCondBridge0) || _conditions->in(kCondBridge1);
+ bool dirty = _conditions->in(kCondDirty);
+ bool news = !_conditions->in(kCondNoNews);
+ bool clean = !_conditions->in(kCondNoClean);
+
+ if (bridge && clean && news)
+ filename += '8';
+ else if (clean && news)
+ filename += '9';
+ else if (bridge && clean)
+ filename += '6';
+ else if (clean)
+ filename += '7';
+ else if (bridge && dirty && news)
+ filename += '4';
+ else if (dirty && news)
+ filename += '5';
+ else if (bridge && dirty)
+ filename += '2';
+ else if (dirty)
+ filename += '3';
+ else if (bridge)
+ filename += '1';
+ else
+ filename += '0';
+
+ _journalText = _resource->getText(filename);
+ _journalTextTitle = _resource->getText("Lab:Rooms/jt");
+
+ Common::File *journalFile = _resource->openDataFile("P:JImage");
+ _journalButtonList.push_back(_interface->createButton( 80, _utils->vgaScaleY(162) + _utils->svgaCord(1), 0, Common::KEYCODE_LEFT, new Image(journalFile, this), new Image(journalFile, this))); // back
+ _journalButtonList.push_back(_interface->createButton(194, _utils->vgaScaleY(162) + _utils->svgaCord(1), 2, Common::KEYCODE_RIGHT, new Image(journalFile, this), new Image(journalFile, this))); // forward
+ _journalButtonList.push_back(_interface->createButton(144, _utils->vgaScaleY(164) - _utils->svgaCord(1), 1, Common::KEYCODE_ESCAPE, new Image(journalFile, this), new Image(journalFile, this))); // cancel
+ delete journalFile;
+
+ _anim->_noPalChange = true;
+ _journalBackImage->setData(new byte[_graphics->_screenBytesPerPage]);
+ _graphics->readPict("P:Journal.pic", true, false, _journalBackImage->_imageData);
+ _anim->_noPalChange = false;
+
+ // Keep a copy of the blank journal
+ _blankJournal = new byte[_graphics->_screenBytesPerPage];
+ memcpy(_blankJournal, _journalBackImage->_imageData, _graphics->_screenBytesPerPage);
+}
+
+void LabEngine::drawJournalText() {
+ uint16 drawingToPage = 1;
+ const char *curText = _journalText.c_str();
+
+ assert((_journalPage & 1) == 0);
+
+ while (drawingToPage < _journalPage) {
+ updateEvents();
+
+ // flowText without output
+ curText += _graphics->flowText(_journalFont, -2, 2, 0, false, false, false, false, _utils->vgaRectScale(52, 32, 152, 148), curText);
+
+ _lastPage = (*curText == 0);
+
+ if (_lastPage) {
+ // Reset _journalPage to this page, in case it was set too high
+ _journalPage = (drawingToPage / 2) * 2;
+ break;
+ }
+
+ drawingToPage++;
+ }
+
+ if (_journalPage == 0) {
+ // draw title page centered
+ _graphics->flowText(_journalFont, -2, 2, 0, false, true, true, true, _utils->vgaRectScale(52, 32, 152, 148), _journalTextTitle.c_str(), _journalBackImage);
+ } else {
+ curText += _graphics->flowText(_journalFont, -2, 2, 0, false, false, false, true, _utils->vgaRectScale(52, 32, 152, 148), curText, _journalBackImage);
+ }
+
+ updateEvents();
+ curText += _graphics->flowText(_journalFont, -2, 2, 0, false, false, false, true, _utils->vgaRectScale(171, 32, 271, 148), curText, _journalBackImage);
+
+ _lastPage = (*curText == 0);
+}
+
+void LabEngine::turnPage(bool fromLeft) {
+ if (fromLeft) {
+ for (int i = 0; i < _graphics->_screenWidth; i += 8) {
+ updateEvents();
+ waitTOF();
+ _journalBackImage->blitBitmap(i, 0, nullptr, i, 0, 8, _graphics->_screenHeight, false);
+ }
+ } else {
+ for (int i = (_graphics->_screenWidth - 8); i > 0; i -= 8) {
+ updateEvents();
+ waitTOF();
+ _journalBackImage->blitBitmap(i, 0, nullptr, i, 0, 8, _graphics->_screenHeight, false);
+ }
+ }
+}
+
+void LabEngine::drawJournal(uint16 wipenum, bool needFade) {
+ _event->mouseHide();
+ updateEvents();
+ drawJournalText();
+ _graphics->loadBackPict("P:Journal.pic", _highPalette);
+
+ if (wipenum == 0)
+ _journalBackImage->blitBitmap(0, 0, nullptr, 0, 0, _graphics->_screenWidth, _graphics->_screenHeight, false);
+ else
+ turnPage((wipenum == 1));
+
+ _interface->toggleButton(_interface->getButton(0), 15, (_journalPage > 0)); // back button
+ _interface->toggleButton(_interface->getButton(2), 15, (!_lastPage)); // forward button
+
+ if (needFade)
+ _graphics->fade(true);
+
+ // Reset the journal background, so that all the text that has been blitted on it is erased
+ memcpy(_journalBackImage->_imageData, _blankJournal, _graphics->_screenBytesPerPage);
+
+ eatMessages();
+ _event->mouseShow();
+}
+
+void LabEngine::processJournal() {
+ while (1) {
+ IntuiMessage *msg = _event->getMsg();
+ if (shouldQuit()) {
+ _quitLab = true;
+ return;
+ }
+
+ updateEvents();
+ _graphics->screenUpdate();
+ _system->delayMillis(10);
+
+ if (!msg)
+ continue;
+
+ MessageClass msgClass = msg->_msgClass;
+
+ if ((msgClass == kMessageRightClick) ||
+ ((msgClass == kMessageRawKey) && (msg->_code == Common::KEYCODE_ESCAPE)))
+ return;
+ else if (msgClass == kMessageButtonUp) {
+ uint16 buttonId = msg->_code;
+ if (buttonId == 0) {
+ if (_journalPage >= 2) {
+ _journalPage -= 2;
+ drawJournal(1, false);
+ }
+ } else if (buttonId == 1) {
+ return;
+ } else if (buttonId == 2) {
+ if (!_lastPage) {
+ _journalPage += 2;
+ drawJournal(2, false);
+ }
+ }
+ }
+ } // while
+}
+
+void LabEngine::doJournal() {
+ _graphics->blackAllScreen();
+ _lastPage = false;
+
+ _journalBackImage->_width = _graphics->_screenWidth;
+ _journalBackImage->_height = _graphics->_screenHeight;
+ _journalBackImage->setData(nullptr, true);
+
+ updateEvents();
+ loadJournalData();
+ _interface->attachButtonList(&_journalButtonList);
+ drawJournal(0, true);
+ _event->mouseShow();
+ processJournal();
+ _interface->attachButtonList(nullptr);
+ _graphics->fade(false);
+ _event->mouseHide();
+
+ delete[] _blankJournal;
+ _blankJournal = nullptr;
+ _journalBackImage->setData(nullptr, true);
+
+ _interface->freeButtonList(&_journalButtonList);
+ _graphics->freeFont(&_journalFont);
+
+ _graphics->rectFill(0, 0, _graphics->_screenWidth - 1, _graphics->_screenHeight - 1, 0);
+ _graphics->blackScreen();
+}
+
+void LabEngine::drawMonText(const char *text, TextFont *monitorFont, Common::Rect textRect, bool isinteractive) {
+ uint16 drawingToPage = 0, yspacing = 0;
+
+ _event->mouseHide();
+
+ if (*text == '%') {
+ text++;
+ uint16 numlines = (*text - '0') * 10;
+ text++;
+ numlines += (*text - '0');
+ text += 2;
+
+ uint16 fheight = _graphics->textHeight(monitorFont);
+ textRect.left = _monitorButton->_width + _utils->vgaScaleX(3);
+ _monitorButtonHeight = _monitorButton->_height + _utils->vgaScaleY(3);
+
+ if (_monitorButtonHeight > fheight)
+ yspacing = _monitorButtonHeight - fheight;
+ else
+ _monitorButtonHeight = fheight;
+
+ _graphics->rectFill(0, 0, _graphics->_screenWidth - 1, textRect.bottom, 0);
+
+ for (int i = 0; i < numlines; i++)
+ _monitorButton->drawImage(0, i * _monitorButtonHeight);
+ } else if (isinteractive) {
+ _graphics->rectFill(0, 0, _graphics->_screenWidth - 1, textRect.bottom, 0);
+ } else {
+ _graphics->rectFill(textRect, 0);
+ }
+
+ const char *curText = text;
+ while (drawingToPage < _monitorPage) {
+ updateEvents();
+ curText += _graphics->flowText(monitorFont, yspacing, 0, 0, false, false, false, false, textRect, curText);
+ _lastPage = (*curText == 0);
+
+ if (_lastPage)
+ _monitorPage = drawingToPage;
+ else
+ drawingToPage++;
+ }
+
+ curText += _graphics->flowText(monitorFont, yspacing, 2, 0, false, false, false, true, textRect, curText);
+ _lastPage = (*curText == 0);
+ _event->mouseShow();
+}
+
+void LabEngine::processMonitor(const Common::String &ntext, TextFont *monitorFont, bool isInteractive, Common::Rect textRect) {
+ Common::String startFileName = _monitorTextFilename;
+ const CloseData *startClosePtr = _closeDataPtr, *lastClosePtr[10];
+ uint16 depth = 0;
+ Common::String text = ntext;
+
+ lastClosePtr[0] = _closeDataPtr;
+
+ while (1) {
+ if (isInteractive) {
+ if (!_closeDataPtr)
+ _closeDataPtr = startClosePtr;
+
+ Common::String filename;
+ if (_closeDataPtr == startClosePtr)
+ filename = startFileName;
+ else
+ filename = _closeDataPtr->_graphicName;
+
+ if (filename != _monitorTextFilename) {
+ _monitorPage = 0;
+ _monitorTextFilename = filename;
+
+ text = _resource->getText(_monitorTextFilename);
+ _graphics->fade(false);
+ drawMonText(text.c_str(), monitorFont, textRect, isInteractive);
+ _graphics->fade(true);
+ }
+ }
+
+ IntuiMessage *msg = _event->getMsg();
+ if (shouldQuit()) {
+ _quitLab = true;
+ return;
+ }
+
+ updateEvents();
+ _graphics->screenUpdate();
+ _system->delayMillis(10);
+
+ if (!msg)
+ continue;
+
+ MessageClass msgClass = msg->_msgClass;
+
+ if ((msgClass == kMessageRightClick) ||
+ ((msgClass == kMessageRawKey) && (msg->_code == Common::KEYCODE_ESCAPE)))
+ return;
+
+ if (msgClass == kMessageLeftClick) {
+ int16 mouseX = msg->_mouse.x;
+ int16 mouseY = msg->_mouse.y;
+
+ // Check if mouse was in button bar
+ if ((mouseY >= _utils->vgaScaleY(171)) && (mouseY <= _utils->vgaScaleY(200))) {
+ if (mouseX <= _utils->vgaScaleX(31)) {
+ // Exit button
+ return;
+ }
+
+ if (mouseX <= _utils->vgaScaleX(59)) {
+ // Back button
+ if (isInteractive) {
+ _monitorPage = 0;
+
+ if (depth) {
+ depth--;
+ _closeDataPtr = lastClosePtr[depth];
+ }
+ } else if (_monitorPage > 0) {
+ _monitorPage = 0;
+ drawMonText(text.c_str(), monitorFont, textRect, isInteractive);
+ }
+ } else if (mouseX < _utils->vgaScaleX(259)) {
+ // empty region; ignore
+ } else if (mouseX <= _utils->vgaScaleX(289)) {
+ // Page down button
+ if (!_lastPage) {
+ _monitorPage += 1;
+ drawMonText(text.c_str(), monitorFont, textRect, isInteractive);
+ }
+ } else if (_monitorPage >= 1) {
+ // Page up button
+ _monitorPage -= 1;
+ drawMonText(text.c_str(), monitorFont, textRect, isInteractive);
+ }
+ } else if (isInteractive) {
+ const CloseData *tmpClosePtr = _closeDataPtr;
+ mouseY = 64 + (mouseY / _monitorButtonHeight) * 42;
+ mouseX = 101;
+ setCurrentClose(Common::Point(mouseX, mouseY), &_closeDataPtr, false);
+
+ if (tmpClosePtr != _closeDataPtr) {
+ lastClosePtr[depth] = tmpClosePtr;
+ depth++;
+ }
+ }
+ }
+ } // while
+}
+
+void LabEngine::doMonitor(const Common::String background, const Common::String textfile, bool isinteractive, Common::Rect textRect) {
+ Common::Rect scaledRect = _utils->vgaRectScale(textRect.left, textRect.top, textRect.right, textRect.bottom);
+ _monitorTextFilename = textfile;
+
+ _graphics->blackAllScreen();
+ _graphics->readPict("P:Mon/Monitor.1");
+ _graphics->readPict("P:Mon/NWD1");
+ _graphics->readPict("P:Mon/NWD2");
+ _graphics->readPict("P:Mon/NWD3");
+ _graphics->blackAllScreen();
+
+ _monitorPage = 0;
+ _lastPage = false;
+ _graphics->_fadePalette = _highPalette;
+
+ TextFont *monitorFont = _resource->getFont("F:Map.fon");
+ Common::File *buttonFile = _resource->openDataFile("P:MonImage");
+ _monitorButton = new Image(buttonFile, this);
+ delete buttonFile;
+
+ Common::String ntext = _resource->getText(textfile);
+ _graphics->loadBackPict(background, _highPalette);
+ drawMonText(ntext.c_str(), monitorFont, scaledRect, isinteractive);
+ _event->mouseShow();
+ _graphics->fade(true);
+ processMonitor(ntext, monitorFont, isinteractive, scaledRect);
+ _graphics->fade(false);
+ _event->mouseHide();
+ _graphics->freeFont(&monitorFont);
+
+ _graphics->rectFill(0, 0, _graphics->_screenWidth - 1, _graphics->_screenHeight - 1, 0);
+ _graphics->blackAllScreen();
+ _graphics->freePict();
+}
+
+} // End of namespace Lab
diff --git a/engines/lab/speciallocks.cpp b/engines/lab/speciallocks.cpp
new file mode 100644
index 0000000000..3104d9d4dd
--- /dev/null
+++ b/engines/lab/speciallocks.cpp
@@ -0,0 +1,395 @@
+/* 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 Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#include "common/file.h"
+
+#include "gui/message.h"
+
+#include "lab/lab.h"
+#include "lab/anim.h"
+#include "lab/dispman.h"
+#include "lab/image.h"
+#include "lab/labsets.h"
+#include "lab/resource.h"
+#include "lab/speciallocks.h"
+#include "lab/utils.h"
+
+namespace Lab {
+
+#define BRICKOPEN 115
+#define COMBINATIONUNLOCKED 130
+
+enum TileScroll {
+ kScrollLeft = 1,
+ kScrollRight = 2,
+ kScrollUp = 3,
+ kScrollDown = 4
+};
+
+const uint16 INIT_TILE[4][4] = {
+ { 1, 5, 9, 13 },
+ { 2, 6, 10, 14 },
+ { 3, 7, 11, 15 },
+ { 4, 8, 12, 0 }
+};
+
+const uint16 SOLUTION[4][4] = {
+ { 7, 1, 8, 3 },
+ { 2, 11, 15, 4 },
+ { 9, 5, 14, 6 },
+ { 10, 13, 12, 0 }
+};
+
+const int COMBINATION_X[6] = { 45, 83, 129, 166, 211, 248 };
+
+SpecialLocks::SpecialLocks(LabEngine *vm) : _vm(vm) {
+ for (int i = 0; i < 16; i++)
+ _tiles[i] = nullptr;
+
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++)
+ _curTile[i][j] = INIT_TILE[i][j];
+ }
+
+ for (int i = 0; i < 6; i++)
+ _combination[i] = 0;
+
+ for (int i = 0; i < 10; i++)
+ _numberImages[i] = nullptr;
+}
+
+SpecialLocks::~SpecialLocks() {
+ for (int i = 0; i < 16; i++)
+ delete _tiles[i];
+
+ for (int imgIdx = 0; imgIdx < 10; imgIdx++) {
+ delete _numberImages[imgIdx];
+ _numberImages[imgIdx] = nullptr;
+ }
+}
+
+void SpecialLocks::tileClick(Common::Point pos) {
+ Common::Point realPos = _vm->_utils->vgaUnscale(pos);
+
+ if ((realPos.x < 101) || (realPos.y < 26))
+ return;
+
+ int tileX = (realPos.x - 101) / 30;
+ int tileY = (realPos.y - 26) / 25;
+
+ if ((tileX < 4) && (tileY < 4))
+ changeTile(tileX, tileY);
+}
+
+void SpecialLocks::changeTile(uint16 col, uint16 row) {
+ int16 scrolltype = -1;
+
+ if (row > 0) {
+ if (_curTile[col][row - 1] == 0) {
+ _curTile[col][row - 1] = _curTile[col][row];
+ _curTile[col][row] = 0;
+ scrolltype = kScrollDown;
+ }
+ }
+
+ if (col > 0) {
+ if (_curTile[col - 1][row] == 0) {
+ _curTile[col - 1][row] = _curTile[col][row];
+ _curTile[col][row] = 0;
+ scrolltype = kScrollRight;
+ }
+ }
+
+ if (row < 3) {
+ if (_curTile[col][row + 1] == 0) {
+ _curTile[col][row + 1] = _curTile[col][row];
+ _curTile[col][row] = 0;
+ scrolltype = kScrollUp;
+ }
+ }
+
+ if (col < 3) {
+ if (_curTile[col + 1][row] == 0) {
+ _curTile[col + 1][row] = _curTile[col][row];
+ _curTile[col][row] = 0;
+ scrolltype = kScrollLeft;
+ }
+ }
+
+ if (scrolltype != -1) {
+ if (_vm->getFeatures() & GF_WINDOWS_TRIAL) {
+ GUI::MessageDialog trialMessage("This puzzle is not available in the trial version of the game");
+ trialMessage.runModal();
+ return;
+ }
+
+ doTileScroll(col, row, scrolltype);
+ bool check = true;
+ row = 0;
+ col = 0;
+
+ while (row < 4) {
+ while (col < 4) {
+ check &= (_curTile[row][col] == SOLUTION[row][col]);
+ col++;
+ }
+
+ row++;
+ col = 0;
+ }
+
+ if (check) {
+ // unlocked combination
+ _vm->_conditions->inclElement(BRICKOPEN);
+ _vm->_anim->_doBlack = true;
+ _vm->_graphics->readPict("p:Up/BDOpen");
+ }
+ }
+}
+
+void SpecialLocks::combinationClick(Common::Point pos) {
+ Common::Point realPos = _vm->_utils->vgaUnscale(pos);
+
+ if (!Common::Rect(44, 63, 285, 99).contains(realPos))
+ return;
+
+ uint16 number = 0;
+ if (realPos.x < 83)
+ number = 0;
+ else if (realPos.x < 127)
+ number = 1;
+ else if (realPos.x < 165)
+ number = 2;
+ else if (realPos.x < 210)
+ number = 3;
+ else if (realPos.x < 245)
+ number = 4;
+ else if (realPos.x < 286)
+ number = 5;
+
+ changeCombination(number);
+}
+
+void SpecialLocks::doTile(bool showsolution) {
+ uint16 row = 0, col = 0, rowm, colm, num;
+ int16 rows, cols;
+
+ if (showsolution) {
+ rowm = _vm->_utils->vgaScaleY(23);
+ colm = _vm->_utils->vgaScaleX(27);
+
+ rows = _vm->_utils->vgaScaleY(31);
+ cols = _vm->_utils->vgaScaleX(105);
+ } else {
+ _vm->_graphics->rectFillScaled(97, 22, 220, 126, 0);
+
+ rowm = _vm->_utils->vgaScaleY(25);
+ colm = _vm->_utils->vgaScaleX(30);
+
+ rows = _vm->_utils->vgaScaleY(25);
+ cols = _vm->_utils->vgaScaleX(100);
+ }
+
+ while (row < 4) {
+ while (col < 4) {
+ if (showsolution)
+ num = SOLUTION[col][row];
+ else
+ num = _curTile[col][row];
+
+ if (showsolution || num)
+ _tiles[num]->drawImage(cols + (col * colm), rows + (row * rowm));
+
+ col++;
+ }
+
+ row++;
+ col = 0;
+ }
+}
+
+void SpecialLocks::showTileLock(const Common::String filename, bool showSolution) {
+ _vm->_anim->_doBlack = true;
+ _vm->_anim->_noPalChange = true;
+ _vm->_graphics->readPict(filename);
+ _vm->_anim->_noPalChange = false;
+ _vm->_graphics->blackScreen();
+
+ Common::File *tileFile;
+ if (_vm->getPlatform() == Common::kPlatformDOS)
+ tileFile = _vm->_resource->openDataFile(showSolution ? "P:TileSolu" : "P:Tile");
+ else
+ // Windows and Amiga versions use TileSolution and Tile
+ tileFile = _vm->_resource->openDataFile(showSolution ? "P:TileSolution" : "P:Tile");
+
+ int start = showSolution ? 0 : 1;
+
+ for (int curBit = start; curBit < 16; curBit++)
+ _tiles[curBit] = new Image(tileFile, _vm);
+
+ delete tileFile;
+
+ doTile(showSolution);
+ _vm->_graphics->setPalette(_vm->_anim->_diffPalette, 256);
+}
+
+void SpecialLocks::doTileScroll(uint16 col, uint16 row, uint16 scrolltype) {
+ int16 dX = 0, dY = 0, dx = 0, dy = 0, sx = 0, sy = 0;
+ int last = 0;
+
+ if (scrolltype == kScrollLeft) {
+ dX = _vm->_utils->vgaScaleX(5);
+ sx = _vm->_utils->vgaScaleX(5);
+ last = 6;
+ } else if (scrolltype == kScrollRight) {
+ dX = _vm->_utils->vgaScaleX(-5);
+ dx = _vm->_utils->vgaScaleX(-5);
+ sx = _vm->_utils->vgaScaleX(5);
+ last = 6;
+ } else if (scrolltype == kScrollUp) {
+ dY = _vm->_utils->vgaScaleY(5);
+ sy = _vm->_utils->vgaScaleY(5);
+ last = 5;
+ } else if (scrolltype == kScrollDown) {
+ dY = _vm->_utils->vgaScaleY(-5);
+ dy = _vm->_utils->vgaScaleY(-5);
+ sy = _vm->_utils->vgaScaleY(5);
+ last = 5;
+ }
+
+ sx += _vm->_utils->svgaCord(2);
+
+ uint16 x1 = _vm->_utils->vgaScaleX(100) + (col * _vm->_utils->vgaScaleX(30)) + dx;
+ uint16 y1 = _vm->_utils->vgaScaleY(25) + (row * _vm->_utils->vgaScaleY(25)) + dy;
+
+ byte *buffer = new byte[_tiles[1]->_width * _tiles[1]->_height * 2];
+
+ for (int i = 0; i < last; i++) {
+ _vm->waitTOF();
+ scrollRaster(dX, dY, x1, y1, x1 + _vm->_utils->vgaScaleX(28) + sx, y1 + _vm->_utils->vgaScaleY(23) + sy, buffer);
+ x1 += dX;
+ y1 += dY;
+ }
+
+ delete[] buffer;
+}
+
+void SpecialLocks::scrollRaster(int16 dx, int16 dy, uint16 x1, uint16 y1, uint16 x2, uint16 y2, byte *buffer) {
+ if (dx)
+ _vm->_graphics->scrollDisplayX(dx, x1, y1, x2, y2, buffer);
+
+ if (dy)
+ _vm->_graphics->scrollDisplayY(dy, x1, y1, x2, y2, buffer);
+}
+
+void SpecialLocks::changeCombination(uint16 number) {
+ const int solution[6] = { 0, 4, 0, 8, 7, 2 };
+
+ Image display(_vm);
+
+ if (_combination[number] < 9)
+ (_combination[number])++;
+ else
+ _combination[number] = 0;
+
+ uint16 combnum = _combination[number];
+
+ display.setData(_vm->_graphics->getCurrentDrawingBuffer(), false);
+ display._width = _vm->_graphics->_screenWidth;
+ display._height = _vm->_graphics->_screenHeight;
+
+ byte *buffer = new byte[_numberImages[1]->_width * _numberImages[1]->_height * 2];
+
+ for (int i = 1; i <= (_numberImages[combnum]->_height / 2); i++) {
+ if (i & 1)
+ _vm->waitTOF();
+
+ display.setData(_vm->_graphics->getCurrentDrawingBuffer(), false);
+ _vm->_graphics->scrollDisplayY(2, _vm->_utils->vgaScaleX(COMBINATION_X[number]), _vm->_utils->vgaScaleY(65), _vm->_utils->vgaScaleX(COMBINATION_X[number]) + (_numberImages[combnum])->_width - 1, _vm->_utils->vgaScaleY(65) + (_numberImages[combnum])->_height, buffer);
+ _numberImages[combnum]->blitBitmap(0, (_numberImages[combnum])->_height - (2 * i), &(display), _vm->_utils->vgaScaleX(COMBINATION_X[number]), _vm->_utils->vgaScaleY(65), (_numberImages[combnum])->_width, 2, false);
+ }
+
+ delete[] buffer;
+
+ bool unlocked = true;
+ for (int i = 0; i < 6; i++)
+ unlocked &= (_combination[i] == solution[i]);
+
+ if (unlocked)
+ _vm->_conditions->inclElement(COMBINATIONUNLOCKED);
+ else
+ _vm->_conditions->exclElement(COMBINATIONUNLOCKED);
+}
+
+void SpecialLocks::showCombinationLock(const Common::String filename) {
+ _vm->_anim->_doBlack = true;
+ _vm->_anim->_noPalChange = true;
+ _vm->_graphics->readPict(filename);
+ _vm->_anim->_noPalChange = false;
+
+ _vm->_graphics->blackScreen();
+
+ Common::File *numFile = _vm->_resource->openDataFile("P:Numbers");
+
+ for (int i = 0; i < 10; i++) {
+ _numberImages[i] = new Image(numFile, _vm);
+ }
+
+ delete numFile;
+
+ for (int i = 0; i <= 5; i++)
+ _numberImages[_combination[i]]->drawImage(_vm->_utils->vgaScaleX(COMBINATION_X[i]), _vm->_utils->vgaScaleY(65));
+
+ _vm->_graphics->setPalette(_vm->_anim->_diffPalette, 256);
+}
+
+void SpecialLocks::save(Common::OutSaveFile *file) {
+ // Combination lock
+ for (int i = 0; i < 6; i++)
+ file->writeByte(_combination[i]);
+
+ // Tiles
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ file->writeUint16LE(_curTile[i][j]);
+}
+
+void SpecialLocks::load(Common::InSaveFile *file) {
+ // Combination lock
+ for (int i = 0; i < 6; i++)
+ _combination[i] = file->readByte();
+
+ // Tiles
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ _curTile[i][j] = file->readUint16LE();
+}
+
+} // End of namespace Lab
diff --git a/engines/lab/speciallocks.h b/engines/lab/speciallocks.h
new file mode 100644
index 0000000000..424eba242a
--- /dev/null
+++ b/engines/lab/speciallocks.h
@@ -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.
+ *
+ */
+
+/*
+ * This code is based on Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#ifndef LAB_TILEPUZZLE_H
+#define LAB_TILEPUZZLE_H
+
+#include "common/savefile.h"
+
+namespace Lab {
+
+class LabEngine;
+
+class SpecialLocks {
+private:
+ LabEngine *_vm;
+ Image *_tiles[16];
+ Image *_numberImages[10];
+ uint16 _curTile[4][4];
+ byte _combination[6];
+
+public:
+ SpecialLocks(LabEngine *vm);
+ ~SpecialLocks();
+
+ void showTileLock(const Common::String filename, bool showSolution);
+
+ /**
+ * Processes mouse clicks and changes tile positions.
+ */
+ void tileClick(Common::Point pos);
+
+ void showCombinationLock(const Common::String filename);
+
+ /**
+ * Processes mouse clicks and changes the door combination.
+ */
+ void combinationClick(Common::Point pos);
+
+ void save(Common::OutSaveFile *file);
+ void load(Common::InSaveFile *file);
+
+private:
+ /**
+ * Changes the combination number of one of the slots
+ */
+ void changeCombination(uint16 number);
+
+ /**
+ * Changes the tile positions in the tile puzzle
+ */
+ void changeTile(uint16 col, uint16 row);
+
+ /**
+ * Draws the images of the combination lock to the display bitmap.
+ */
+ void doTile(bool showsolution);
+
+ /**
+ * Does the scrolling for the tiles on the tile puzzle.
+ */
+ void doTileScroll(uint16 col, uint16 row, uint16 scrolltype);
+ void scrollRaster(int16 dx, int16 dy, uint16 x1, uint16 y1, uint16 x2, uint16 y2, byte *buffer);
+};
+
+} // End of namespace Lab
+
+#endif // LAB_TILEPUZZLE_H
diff --git a/engines/lab/utils.cpp b/engines/lab/utils.cpp
new file mode 100644
index 0000000000..957e996c03
--- /dev/null
+++ b/engines/lab/utils.cpp
@@ -0,0 +1,272 @@
+/* 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 Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#include "common/file.h"
+
+#include "lab/lab.h"
+#include "lab/utils.h"
+
+namespace Lab {
+Utils::Utils(LabEngine *vm) : _vm(vm), _rnd("lab") {
+ _dataBytesPerRow = 0;
+}
+
+uint16 Utils::scaleX(uint16 x) {
+ if (_vm->_isHiRes)
+ return (uint16)((x * 16) / 9);
+ else
+ return (uint16)((x * 8) / 9);
+}
+
+uint16 Utils::scaleY(uint16 y) {
+ if (_vm->_isHiRes)
+ return (y + (y / 14));
+ else
+ return ((y * 10) / 24);
+}
+
+Common::Rect Utils::rectScale(int16 x1, int16 y1, int16 x2, int16 y2) {
+ return Common::Rect(scaleX(x1), scaleY(y1), scaleX(x2), scaleY(y2));
+}
+
+uint16 Utils::mapScaleX(uint16 x) {
+ if (_vm->_isHiRes)
+ return (x - 45);
+ else
+ return ((x - 45) >> 1);
+}
+
+uint16 Utils::mapScaleY(uint16 y) {
+ if (_vm->_isHiRes)
+ return y;
+ else
+ return ((y - 35) >> 1) - (y >> 6);
+}
+
+Common::Rect Utils::mapRectScale(int16 x1, int16 y1, int16 x2, int16 y2) {
+ return Common::Rect(mapScaleX(x1), mapScaleY(y1), mapScaleX(x2), mapScaleY(y2));
+}
+
+int16 Utils::vgaScaleX(int16 x) {
+ if (_vm->_isHiRes)
+ return (x * 2);
+ else
+ return x;
+}
+
+int16 Utils::vgaScaleY(int16 y) {
+ if (_vm->_isHiRes)
+ return ((y * 12) / 5);
+ else
+ return y;
+}
+
+Common::Rect Utils::vgaRectScale(int16 x1, int16 y1, int16 x2, int16 y2) {
+ return Common::Rect(vgaScaleX(x1), vgaScaleY(y1), vgaScaleX(x2), vgaScaleY(y2));
+}
+
+uint16 Utils::svgaCord(uint16 cord) {
+ if (_vm->_isHiRes)
+ return cord;
+ else
+ return 0;
+}
+
+Common::Point Utils::vgaUnscale(Common::Point pos) {
+ Common::Point result;
+ if (_vm->_isHiRes) {
+ result.x = pos.x / 2;
+ result.y = (pos.y * 5) / 12;
+ } else
+ result = pos;
+
+ return result;
+}
+
+template<typename T>
+void Utils::unDiff(T *dest, Common::File *sourceFile) {
+ byte bytesPerWord = sizeof(T);
+
+ while (1) {
+ uint16 skip = sourceFile->readByte();
+ uint16 copy = sourceFile->readByte();
+
+ if (skip == 255) {
+ if (copy == 0) {
+ skip = sourceFile->readUint16LE();
+ copy = sourceFile->readUint16LE();
+ } else if (copy == 255)
+ return;
+ }
+
+ dest += skip;
+
+ if (bytesPerWord == 1) {
+ sourceFile->read(dest, copy);
+ dest += copy;
+ } else {
+ while (copy) {
+ *dest = sourceFile->readUint16LE();
+ dest++;
+ copy--;
+ }
+ }
+ }
+}
+
+template<typename T>
+void Utils::verticalUnDiff(T *dest, Common::File *sourceFile, uint16 bytesPerRow) {
+ uint16 counter = 0;
+ byte bytesPerWord = sizeof(T);
+ uint16 wordsPerRow = bytesPerRow / bytesPerWord;
+
+ while (counter < wordsPerRow) {
+ T *curPtr = dest + counter;
+
+ for (;;) {
+ uint16 skip = sourceFile->readByte();
+ uint16 copy = sourceFile->readByte();
+
+ if (skip == 255) {
+ counter += copy;
+ break;
+ } else {
+ curPtr += (skip * wordsPerRow);
+
+ while (copy) {
+ if (bytesPerWord == 1)
+ *curPtr = sourceFile->readByte();
+ else if (bytesPerWord == 2)
+ *curPtr = sourceFile->readUint16LE();
+ else if (bytesPerWord == 4)
+ *curPtr = sourceFile->readUint32LE();
+ else
+ error("verticalUnDiff: Invalid bytesPerWord (%d)", bytesPerWord);
+ curPtr += wordsPerRow;
+ copy--;
+ }
+ }
+ }
+ }
+}
+
+void Utils::runLengthDecode(byte *dest, Common::File *sourceFile) {
+ int8 num;
+ int16 count;
+
+ while (1) {
+ num = sourceFile->readSByte();
+
+ if (num == 127) {
+ return;
+ } else if (num > '\0') {
+ sourceFile->read(dest, num);
+ dest += num;
+ } else {
+ count = (int16)(-num);
+ num = sourceFile->readSByte();
+
+ while (count) {
+ *dest = num;
+ dest++;
+ count--;
+ }
+ }
+ }
+}
+
+void Utils::verticalRunLengthDecode(byte *dest, Common::File *sourceFile, uint16 bytesPerRow) {
+ int16 count;
+ byte *top = dest;
+
+ for (int i = 0; i < _dataBytesPerRow; i++) {
+ dest = top;
+ dest += i;
+
+ int8 num = sourceFile->readSByte();
+
+ while (num != 127) {
+ if (num > '\0') {
+ while (num) {
+ *dest = sourceFile->readByte();
+ dest += bytesPerRow;
+ num--;
+ }
+ } else {
+ count = (int16)(-num);
+ num = sourceFile->readSByte();
+
+ while (count) {
+ *dest = num;
+ dest += bytesPerRow;
+ count--;
+ }
+ }
+
+ num = sourceFile->readSByte();
+ }
+ }
+}
+
+void Utils::unDiff(byte *newBuf, byte *oldBuf, Common::File *sourceFile, uint16 bytesPerRow, bool isVertical) {
+ sourceFile->skip(1);
+ byte bufType = sourceFile->readByte();
+
+ if (isVertical) {
+ if (bufType == 0)
+ verticalUnDiff<byte>(newBuf, sourceFile, bytesPerRow);
+ else if (bufType == 1)
+ verticalUnDiff<uint16>((uint16 *)newBuf, sourceFile, bytesPerRow);
+ else if (bufType == 3)
+ verticalUnDiff<uint32>((uint32 *)newBuf, sourceFile, bytesPerRow);
+ else
+ error("Unexpected variable compression scheme %d", bufType);
+ } else {
+ if (bufType == 0)
+ unDiff<byte>(newBuf, sourceFile);
+ else if (bufType == 1)
+ unDiff<uint16>((uint16 *)newBuf, sourceFile);
+ else
+ error("Unexpected compression scheme %d", bufType);
+ }
+}
+
+void Utils::setBytesPerRow(int num) {
+ _dataBytesPerRow = num;
+}
+
+uint16 Utils::getRandom(uint16 max) {
+ if (max > 1)
+ return _rnd.getRandomNumber(max - 1);
+ else
+ return 0;
+}
+
+} // End of namespace Lab
diff --git a/engines/lab/utils.h b/engines/lab/utils.h
new file mode 100644
index 0000000000..a7bb42007e
--- /dev/null
+++ b/engines/lab/utils.h
@@ -0,0 +1,105 @@
+/* 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 Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#ifndef LAB_UTILS_H
+#define LAB_UTILS_H
+
+namespace Lab {
+
+class Utils {
+private:
+ LabEngine *_vm;
+ uint16 _dataBytesPerRow;
+
+ /**
+ * Undiffs a piece of memory based on the header size.
+ */
+ template<typename T>
+ void unDiff(T *dest, Common::File *sourceFile);
+
+ /**
+ * Undiffs a piece of memory when header size is a byte, and copy/skip size
+ * is a byte or a word or a double word.
+ */
+ template<typename T>
+ void verticalUnDiff(T *dest, Common::File *sourceFile, uint16 bytesPerRow);
+
+public:
+ Utils(LabEngine *vm);
+
+ Common::RandomSource _rnd;
+
+ /**
+ * Scales the x co-ordinates to that of the new display. In the room parser
+ * file, co-ordinates are set up on a 360x336 display.
+ */
+ uint16 scaleX(uint16 x);
+
+ /**
+ * Scales the y co-ordinates to that of the new display. In the room parser
+ * file, co-ordinates are set up on a 368x336 display.
+ */
+ uint16 scaleY(uint16 y);
+ Common::Rect rectScale(int16 x1, int16 y1, int16 x2, int16 y2);
+
+ /**
+ * Scales the VGA x coords to SVGA if necessary; otherwise, returns VGA coords.
+ */
+ int16 vgaScaleX(int16 x);
+
+ /**
+ * Scales the VGA y coords to SVGA if necessary; otherwise, returns VGA coords.
+ */
+ int16 vgaScaleY(int16 y);
+ Common::Rect vgaRectScale(int16 x1, int16 y1, int16 x2, int16 y2);
+ uint16 svgaCord(uint16 cord);
+ uint16 mapScaleX(uint16 x);
+ uint16 mapScaleY(uint16 y);
+ Common::Rect mapRectScale(int16 x1, int16 y1, int16 x2, int16 y2);
+
+ /**
+ * Converts SVGA coords to VGA if necessary, otherwise returns VGA coords.
+ */
+ Common::Point vgaUnscale(Common::Point pos);
+
+ /**
+ * Does the undiffing between the bitmaps.
+ */
+ void unDiff(byte *newBuf, byte *oldBuf, Common::File *sourceFile, uint16 bytesPerRow, bool isVertical);
+ void runLengthDecode(byte *dest, Common::File *sourceFile);
+ void verticalRunLengthDecode(byte *dest, Common::File *sourceFile, uint16 bytesPerRow);
+ void setBytesPerRow(int num);
+ uint16 getRandom(uint16 max);
+};
+
+
+} // End of namespace Lab
+
+#endif // LAB_UTILS_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/game/savegame.cpp b/engines/lastexpress/game/savegame.cpp
index d9f2993c17..e2682ba0d1 100644
--- a/engines/lastexpress/game/savegame.cpp
+++ b/engines/lastexpress/game/savegame.cpp
@@ -497,9 +497,6 @@ void SaveLoad::loadLastGame() {
return;
}
- if (!_savegame)
- error("[SaveLoad::loadGame] No savegame stream present");
-
// Load the last entry
_savegame->seek(header.offsetEntry);
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/logo_data.h b/engines/logo_data.h
new file mode 100644
index 0000000000..2eaff6930f
--- /dev/null
+++ b/engines/logo_data.h
@@ -0,0 +1,1099 @@
+/* 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 is a BMP file dumped into array.
+// recode ../d1 <dists/scummvm_logo.bmp >logo_data.h
+// The tool is from https://github.com/pinard/Recode
+
+byte logo_data[] = {
+ 66, 77, 180, 62, 0, 0, 0, 0, 0, 0, 54, 4, 0, 0, 40,
+ 0, 0, 0, 44, 1, 0, 0, 83, 0, 0, 0, 1, 0, 8, 0,
+ 1, 0, 0, 0, 126, 58, 0, 0, 19, 11, 0, 0, 19, 11, 0,
+ 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 2,
+ 0, 0, 0, 1, 9, 0, 0, 4, 1, 0, 1, 5, 3, 0, 2,
+ 4, 11, 0, 5, 7, 14, 0, 6, 10, 7, 0, 0, 10, 11, 0,
+ 0, 8, 18, 0, 3, 15, 14, 0, 5, 14, 21, 0, 13, 16, 14,
+ 0, 1, 16, 28, 0, 1, 20, 16, 0, 0, 22, 18, 0, 7, 19,
+ 31, 0, 3, 21, 35, 0, 2, 26, 21, 0, 22, 24, 23, 0, 12,
+ 26, 23, 0, 0, 29, 25, 0, 4, 24, 43, 0, 0, 33, 28, 0,
+ 2, 27, 48, 0, 29, 31, 29, 0, 8, 31, 52, 0, 4, 32, 57,
+ 0, 13, 39, 33, 0, 0, 41, 34, 0, 36, 38, 36, 0, 4, 36,
+ 64, 0, 8, 48, 40, 0, 42, 45, 43, 0, 5, 41, 73, 0, 2,
+ 52, 42, 0, 25, 53, 49, 0, 5, 46, 83, 0, 49, 52, 50, 0,
+ 0, 58, 47, 0, 54, 57, 55, 0, 6, 52, 92, 0, 4, 68, 56,
+ 0, 59, 62, 60, 0, 31, 67, 59, 0, 5, 57, 102, 0, 23, 70,
+ 61, 0, 63, 66, 64, 0, 0, 75, 62, 0, 3, 62, 110, 0, 7,
+ 63, 116, 0, 69, 71, 70, 0, 2, 67, 121, 0, 43, 79, 71, 0,
+ 6, 85, 70, 0, 75, 77, 76, 0, 7, 71, 126, 0, 38, 85, 77,
+ 0, 78, 81, 79, 0, 0, 91, 73, 0, 4, 74, 136, 0, 81, 84,
+ 82, 0, 9, 97, 77, 0, 10, 78, 141, 0, 85, 87, 86, 0, 1,
+ 80, 144, 0, 88, 91, 89, 0, 0, 103, 80, 0, 1, 106, 71, 0,
+ 0, 102, 85, 0, 5, 83, 148, 0, 41, 98, 86, 0, 3, 110, 67,
+ 0, 10, 85, 154, 0, 92, 95, 93, 0, 0, 112, 72, 0, 96, 99,
+ 97, 0, 6, 89, 162, 0, 0, 112, 87, 0, 0, 117, 76, 0, 2,
+117, 82, 0, 28, 111, 94, 0, 100, 102, 101, 0, 0, 95, 169, 0,
+ 0, 122, 80, 0, 0, 121, 87, 0, 103, 106, 104, 0, 3, 96, 172,
+ 0, 10, 97, 179, 0, 0, 126, 86, 0, 0, 128, 81, 0, 0, 123,
+ 98, 0, 107, 110, 108, 0, 1, 127, 94, 0, 19, 124, 101, 0, 110,
+113, 111, 0, 61, 120, 105, 0, 0, 132, 87, 0, 4, 103, 186, 0,
+114, 117, 115, 0, 0, 136, 91, 0, 0, 135, 96, 0, 0, 132, 107,
+ 0, 12, 107, 192, 0, 0, 135, 103, 0, 1, 140, 87, 0, 118, 121,
+119, 0, 2, 109, 199, 0, 5, 142, 89, 0, 0, 145, 94, 0, 122,
+125, 123, 0, 0, 143, 105, 0, 12, 140, 112, 0, 0, 145, 101, 0,
+ 11, 113, 206, 0, 0, 144, 115, 0, 1, 150, 99, 0, 127, 130, 128,
+ 0, 53, 140, 120, 0, 2, 118, 212, 0, 6, 152, 101, 0, 131, 134,
+132, 0, 41, 146, 123, 0, 0, 154, 111, 0, 0, 156, 106, 0, 0,
+153, 117, 0, 0, 158, 101, 0, 135, 138, 136, 0, 78, 147, 130, 0,
+ 4, 163, 106, 0, 139, 142, 140, 0, 0, 167, 111, 0, 0, 164, 122,
+ 0, 0, 169, 106, 0, 0, 166, 117, 0, 144, 147, 145, 0, 0, 171,
+115, 0, 21, 165, 136, 0, 6, 172, 124, 0, 44, 165, 137, 0, 7,
+176, 113, 0, 9, 175, 120, 0, 2, 171, 137, 0, 151, 154, 152, 0,
+ 0, 178, 124, 0, 0, 180, 118, 0, 82, 164, 146, 0, 30, 178, 122,
+ 0, 155, 158, 156, 0, 3, 186, 117, 0, 5, 186, 124, 0, 4, 185,
+131, 0, 0, 183, 145, 0, 0, 191, 123, 0, 29, 186, 131, 0, 40,
+185, 132, 0, 161, 164, 162, 0, 0, 190, 130, 0, 51, 185, 134, 0,
+ 32, 182, 155, 0, 46, 183, 151, 0, 0, 195, 127, 0, 4, 199, 123,
+ 0, 80, 181, 158, 0, 63, 184, 154, 0, 10, 196, 136, 0, 47, 189,
+147, 0, 169, 172, 170, 0, 21, 192, 153, 0, 0, 202, 128, 0, 26,
+195, 143, 0, 66, 191, 143, 0, 0, 201, 134, 0, 0, 199, 141, 0,
+ 57, 194, 145, 0, 42, 196, 144, 0, 0, 199, 154, 0, 0, 206, 132,
+ 0, 98, 188, 166, 0, 4, 211, 129, 0, 4, 206, 147, 0, 177, 180,
+178, 0, 6, 208, 142, 0, 84, 197, 153, 0, 28, 206, 146, 0, 0,
+212, 139, 0, 37, 205, 152, 0, 0, 215, 134, 0, 61, 202, 161, 0,
+ 58, 206, 156, 0, 43, 205, 166, 0, 0, 211, 163, 0, 183, 187, 185,
+ 0, 0, 215, 155, 0, 0, 218, 145, 0, 0, 220, 140, 0, 25, 216,
+151, 0, 5, 223, 135, 0, 25, 213, 162, 0, 0, 224, 137, 0, 43,
+215, 154, 0, 67, 207, 175, 0, 46, 213, 162, 0, 188, 191, 189, 0,
+ 0, 226, 139, 0, 101, 209, 171, 0, 192, 195, 193, 0, 67, 216, 165,
+ 0, 19, 227, 146, 0, 0, 228, 150, 0, 24, 227, 155, 0, 25, 230,
+149, 0, 109, 211, 187, 0, 196, 200, 198, 0, 120, 214, 179, 0, 44,
+230, 157, 0, 45, 225, 180, 0, 34, 227, 181, 0, 201, 204, 202, 0,
+ 7, 235, 164, 0, 59, 232, 164, 0, 65, 229, 179, 0, 61, 232, 173,
+ 0, 71, 234, 167, 0, 205, 209, 207, 0, 53, 234, 176, 0, 81, 235,
+174, 0, 210, 213, 211, 0, 92, 237, 178, 0, 93, 232, 195, 0, 213,
+216, 214, 0, 100, 236, 186, 0, 120, 229, 203, 0, 101, 238, 180, 0,
+108, 236, 186, 0, 28, 244, 188, 0, 34, 243, 199, 0, 121, 234, 202,
+ 0, 120, 239, 191, 0, 218, 221, 219, 0, 56, 247, 189, 0, 223, 226,
+224, 0, 83, 249, 202, 0, 98, 250, 200, 0, 130, 246, 204, 0, 110,
+250, 200, 0, 227, 230, 228, 0, 231, 234, 232, 0, 125, 252, 212, 0,
+117, 253, 214, 0, 105, 255, 215, 0, 234, 237, 235, 0, 134, 253, 222,
+ 0, 137, 255, 234, 0, 240, 243, 241, 0, 244, 247, 245, 0, 255, 119,
+ 24, 119, 0, 13, 114, 107, 103, 98, 88, 87, 77, 73, 70, 63, 70,
+ 77, 107, 0, 8, 119, 0, 0, 255, 119, 20, 119, 0, 5, 114, 87,
+ 65, 60, 60, 0, 11, 63, 1, 60, 1, 88, 7, 119, 0, 0, 255,
+119, 19, 119, 0, 3, 98, 63, 63, 0, 4, 65, 0, 9, 70, 63,
+ 60, 52, 50, 45, 45, 50, 65, 0, 3, 63, 1, 98, 6, 119, 0,
+ 0, 251, 119, 0, 6, 107, 98, 88, 77, 73, 63, 3, 60, 1, 77,
+ 1, 114, 11, 119, 0, 13, 114, 65, 52, 49, 41, 31, 22, 11, 4,
+ 1, 1, 4, 1, 0, 3, 4, 0, 5, 2, 49, 65, 63, 65, 0,
+ 6, 119, 0, 0, 204, 119, 4, 114, 41, 119, 1, 88, 1, 60, 5,
+ 63, 1, 65, 1, 65, 4, 63, 1, 88, 10, 119, 1, 52, 3, 4,
+ 1, 1, 3, 4, 1, 1, 4, 4, 1, 1, 4, 4, 0, 4, 45,
+ 65, 63, 103, 5, 119, 0, 0, 203, 119, 1, 77, 5, 63, 0, 4,
+ 77, 98, 114, 114, 16, 119, 5, 114, 14, 119, 0, 11, 70, 65, 65,
+ 63, 60, 60, 56, 52, 45, 45, 56, 0, 4, 63, 1, 88, 8, 119,
+ 1, 77, 4, 4, 0, 5, 1, 4, 1, 4, 1, 0, 3, 4, 1,
+ 1, 1, 1, 3, 4, 0, 5, 1, 1, 60, 63, 88, 0, 5, 119,
+ 0, 0, 202, 119, 4, 65, 8, 63, 1, 70, 1, 88, 6, 119, 0,
+ 4, 107, 87, 77, 70, 9, 63, 1, 77, 11, 119, 0, 4, 77, 56,
+ 24, 1, 3, 4, 0, 7, 1, 4, 1, 4, 1, 1, 52, 0, 3,
+ 63, 1, 107, 6, 119, 0, 7, 114, 1, 1, 4, 1, 4, 1, 0,
+ 3, 4, 0, 14, 1, 1, 4, 4, 1, 4, 4, 1, 4, 1, 4,
+ 31, 65, 87, 5, 119, 0, 0, 80, 119, 1, 114, 1, 88, 3, 77,
+ 1, 87, 1, 107, 4, 119, 0, 4, 103, 87, 83, 87, 3, 88, 0,
+ 4, 98, 98, 103, 114, 99, 119, 0, 6, 88, 45, 16, 9, 27, 49,
+ 10, 63, 0, 4, 114, 119, 119, 107, 15, 63, 1, 65, 10, 119, 1,
+ 16, 6, 4, 1, 1, 1, 1, 5, 4, 0, 4, 37, 65, 63, 73,
+ 6, 119, 1, 37, 4, 4, 1, 1, 5, 4, 0, 3, 19, 30, 33,
+ 0, 3, 43, 0, 7, 4, 4, 1, 4, 11, 70, 77, 0, 5, 119,
+ 0, 0, 15, 119, 0, 3, 107, 77, 65, 0, 8, 63, 1, 73, 1,
+ 98, 21, 119, 0, 3, 114, 88, 70, 0, 6, 63, 1, 77, 1, 98,
+ 16, 119, 1, 114, 1, 77, 25, 63, 0, 3, 65, 98, 98, 0, 7,
+ 77, 0, 8, 87, 88, 98, 114, 119, 119, 103, 70, 12, 63, 1, 77,
+ 6, 119, 0, 11, 114, 98, 77, 70, 63, 65, 77, 114, 119, 119, 98,
+ 0, 7, 77, 0, 8, 87, 88, 98, 114, 119, 119, 98, 70, 12, 63,
+ 1, 77, 6, 119, 0, 8, 107, 98, 77, 70, 63, 65, 83, 114, 7,
+119, 0, 3, 114, 4, 1, 0, 3, 4, 0, 8, 1, 4, 2, 4,
+ 17, 41, 60, 65, 4, 63, 0, 16, 119, 107, 63, 63, 65, 65, 63,
+ 56, 45, 34, 27, 17, 4, 4, 22, 56, 3, 63, 1, 77, 8, 119,
+ 0, 20, 13, 4, 1, 4, 1, 1, 4, 4, 1, 4, 1, 4, 1,
+ 1, 4, 4, 50, 63, 63, 98, 5, 119, 1, 4, 1, 4, 3, 1,
+ 1, 40, 3, 43, 0, 4, 47, 12, 47, 43, 4, 47, 0, 7, 7,
+ 4, 1, 4, 4, 70, 77, 0, 5, 119, 0, 0, 12, 119, 0, 3,
+ 88, 65, 65, 0, 14, 63, 0, 3, 65, 77, 114, 0, 14, 119, 0,
+ 3, 98, 65, 65, 0, 12, 63, 1, 65, 1, 83, 11, 119, 1, 98,
+ 1, 65, 3, 63, 6, 65, 5, 63, 10, 65, 17, 63, 1, 65, 1,
+ 65, 15, 63, 5, 65, 9, 63, 1, 65, 13, 63, 1, 65, 1, 65,
+ 15, 63, 5, 65, 9, 63, 1, 77, 6, 119, 1, 22, 5, 4, 0,
+ 4, 1, 4, 4, 1, 3, 4, 0, 18, 1, 11, 65, 63, 63, 107,
+ 70, 17, 4, 4, 2, 4, 1, 1, 4, 4, 1, 4, 3, 1, 0,
+ 5, 13, 65, 63, 63, 107, 0, 6, 119, 0, 4, 45, 4, 1, 1,
+ 3, 4, 0, 14, 1, 1, 4, 1, 4, 1, 1, 4, 4, 1, 1,
+ 65, 63, 65, 5, 119, 1, 1, 3, 4, 1, 19, 5, 47, 1, 19,
+ 1, 43, 5, 47, 0, 7, 19, 4, 4, 1, 1, 70, 73, 0, 5,
+119, 0, 0, 10, 119, 0, 14, 77, 65, 63, 63, 65, 70, 52, 37,
+ 31, 26, 26, 27, 34, 45, 3, 65, 5, 63, 1, 70, 1, 107, 10,
+119, 0, 12, 88, 65, 63, 63, 65, 70, 60, 45, 41, 37, 41, 50,
+ 3, 65, 4, 63, 1, 65, 1, 83, 8, 119, 0, 8, 70, 63, 65,
+ 63, 37, 13, 4, 4, 3, 1, 0, 11, 4, 11, 37, 56, 34, 9,
+ 4, 2, 4, 5, 2, 0, 4, 4, 0, 6, 5, 17, 45, 70, 65,
+ 65, 6, 70, 4, 65, 3, 63, 0, 15, 70, 56, 37, 31, 27, 27,
+ 26, 22, 17, 16, 13, 16, 34, 60, 65, 0, 6, 63, 0, 11, 65,
+ 65, 70, 65, 60, 70, 65, 63, 63, 65, 65, 0, 6, 70, 4, 65,
+ 3, 63, 0, 15, 70, 56, 37, 31, 27, 27, 26, 22, 17, 13, 13,
+ 16, 34, 63, 65, 0, 5, 63, 3, 65, 0, 5, 70, 65, 60, 70,
+ 65, 0, 3, 63, 1, 87, 4, 119, 1, 88, 4, 4, 0, 4, 1,
+ 1, 4, 1, 4, 4, 0, 7, 1, 4, 1, 4, 65, 63, 52, 0,
+ 3, 1, 4, 4, 1, 1, 1, 1, 6, 4, 0, 5, 1, 13, 70,
+ 63, 88, 0, 6, 119, 0, 15, 7, 4, 4, 1, 4, 4, 19, 30,
+ 38, 43, 43, 47, 43, 2, 1, 0, 3, 4, 0, 4, 37, 65, 63,
+ 87, 4, 119, 0, 6, 1, 4, 4, 1, 12, 51, 3, 47, 0, 3,
+ 51, 25, 40, 0, 4, 47, 0, 8, 51, 30, 1, 1, 4, 1, 60,
+ 70, 5, 119, 0, 0, 8, 119, 0, 8, 103, 65, 65, 70, 41, 16,
+ 5, 2, 9, 1, 0, 5, 4, 11, 31, 60, 65, 0, 4, 63, 1,
+ 77, 7, 119, 0, 8, 114, 70, 63, 70, 45, 22, 9, 4, 7, 1,
+ 0, 5, 4, 11, 37, 65, 65, 0, 3, 63, 1, 65, 1, 114, 4,
+119, 0, 5, 107, 65, 63, 22, 5, 0, 26, 1, 1, 4, 1, 9,
+ 3, 4, 0, 12, 2, 2, 4, 2, 4, 4, 5, 9, 22, 41, 17,
+ 4, 13, 1, 0, 17, 9, 52, 63, 49, 37, 24, 11, 9, 4, 4,
+ 1, 1, 2, 6, 27, 27, 9, 0, 3, 4, 0, 12, 2, 2, 4,
+ 2, 4, 4, 5, 9, 24, 41, 16, 2, 13, 1, 0, 9, 11, 52,
+ 60, 49, 37, 24, 11, 9, 4, 0, 4, 1, 0, 6, 5, 45, 65,
+ 63, 63, 114, 3, 119, 5, 4, 5, 1, 6, 4, 0, 3, 1, 22,
+ 63, 0, 3, 1, 0, 5, 4, 1, 1, 4, 1, 0, 3, 4, 1,
+ 1, 1, 1, 3, 4, 0, 5, 1, 1, 41, 63, 77, 0, 5, 119,
+ 0, 6, 114, 4, 4, 1, 4, 25, 3, 51, 1, 47, 5, 51, 5,
+ 4, 0, 4, 60, 63, 63, 114, 3, 119, 0, 5, 5, 1, 1, 4,
+ 7, 0, 5, 51, 1, 30, 1, 38, 5, 51, 0, 7, 33, 1, 4,
+ 4, 1, 52, 65, 0, 5, 119, 0, 0, 7, 119, 0, 4, 77, 65,
+ 50, 13, 18, 1, 0, 3, 9, 34, 70, 0, 3, 63, 1, 70, 1,
+114, 4, 119, 0, 5, 98, 65, 60, 17, 4, 0, 15, 1, 0, 3,
+ 13, 56, 65, 0, 3, 63, 0, 6, 103, 119, 119, 107, 65, 26, 119,
+ 1, 0, 7, 31, 65, 63, 98, 119, 119, 56, 0, 3, 1, 0, 22,
+ 4, 5, 40, 40, 38, 33, 19, 7, 1, 1, 4, 1, 4, 1, 4,
+ 11, 4, 4, 1, 1, 4, 4, 6, 1, 1, 7, 1, 5, 3, 1,
+ 0, 4, 4, 16, 70, 77, 5, 119, 1, 41, 3, 4, 1, 1, 1,
+ 43, 9, 51, 0, 9, 19, 1, 4, 1, 1, 24, 65, 63, 77, 0,
+ 3, 119, 0, 5, 22, 4, 4, 1, 1, 0, 5, 51, 1, 38, 1,
+ 33, 5, 51, 1, 43, 1, 1, 3, 4, 1, 49, 1, 63, 5, 119,
+ 0, 0, 6, 119, 0, 3, 70, 60, 13, 0, 22, 1, 0, 3, 4,
+ 41, 65, 0, 3, 63, 0, 6, 114, 119, 119, 98, 65, 24, 20, 1,
+ 1, 22, 1, 65, 3, 63, 0, 4, 98, 107, 56, 9, 121, 1, 0,
+ 5, 49, 63, 77, 119, 103, 0, 4, 4, 0, 3, 1, 40, 43, 0,
+ 5, 47, 0, 4, 43, 38, 4, 4, 4, 1, 3, 4, 0, 7, 2,
+ 33, 40, 43, 43, 47, 51, 0, 3, 55, 0, 8, 58, 12, 1, 1,
+ 4, 4, 70, 70, 5, 119, 0, 8, 5, 1, 4, 1, 1, 55, 55,
+ 51, 3, 55, 1, 51, 3, 55, 0, 24, 58, 4, 4, 1, 4, 4,
+ 50, 63, 63, 103, 119, 119, 37, 4, 4, 1, 1, 51, 55, 51, 55,
+ 55, 40, 30, 3, 55, 3, 51, 0, 6, 1, 1, 4, 4, 41, 63,
+ 5, 119, 0, 0, 5, 119, 1, 70, 1, 34, 26, 1, 1, 22, 1,
+ 70, 3, 63, 0, 4, 107, 98, 50, 5, 22, 1, 0, 6, 6, 56,
+ 65, 63, 63, 45, 10, 1, 0, 4, 8, 21, 23, 21, 6, 1, 0,
+ 6, 4, 10, 8, 4, 4, 0, 97, 1, 0, 5, 22, 65, 73, 119,
+ 31, 0, 4, 4, 1, 19, 9, 47, 1, 38, 3, 1, 0, 6, 4,
+ 1, 4, 1, 1, 38, 3, 55, 1, 58, 3, 55, 0, 10, 58, 55,
+ 58, 33, 1, 4, 1, 4, 56, 63, 5, 119, 1, 2, 3, 4, 1,
+ 25, 1, 58, 3, 55, 0, 20, 58, 55, 58, 58, 55, 58, 55, 33,
+ 1, 1, 4, 1, 11, 70, 63, 70, 119, 119, 50, 4, 3, 1, 0,
+ 20, 51, 58, 55, 58, 55, 43, 12, 38, 43, 58, 55, 58, 61, 1,
+ 1, 4, 1, 37, 63, 107, 4, 119, 0, 0, 4, 119, 1, 73, 1,
+ 22, 9, 1, 0, 4, 29, 48, 59, 62, 3, 67, 0, 4, 59, 48,
+ 35, 8, 8, 1, 1, 5, 1, 60, 3, 63, 1, 41, 9, 1, 0,
+ 9, 21, 39, 48, 54, 59, 59, 48, 32, 4, 0, 8, 1, 0, 3,
+ 50, 65, 50, 0, 7, 1, 0, 11, 18, 54, 78, 93, 89, 80, 79,
+ 89, 93, 78, 42, 0, 3, 1, 0, 4, 112, 89, 85, 85, 5, 93,
+ 1, 104, 1, 21, 3, 1, 0, 7, 8, 23, 21, 21, 18, 15, 14,
+ 0, 3, 8, 6, 1, 0, 3, 59, 62, 62, 0, 5, 67, 0, 3,
+ 78, 78, 8, 0, 9, 1, 0, 4, 4, 21, 35, 42, 5, 1, 0,
+ 10, 8, 23, 21, 21, 18, 14, 14, 8, 8, 4, 5, 1, 0, 4,
+ 10, 59, 62, 62, 5, 67, 0, 3, 78, 78, 4, 0, 9, 1, 0,
+ 4, 8, 21, 35, 48, 5, 1, 0, 3, 65, 63, 77, 0, 3, 4,
+ 0, 7, 1, 4, 51, 47, 47, 51, 51, 0, 5, 47, 0, 5, 43,
+ 4, 4, 1, 1, 0, 4, 4, 1, 33, 10, 58, 0, 8, 47, 2,
+ 1, 4, 4, 45, 63, 114, 3, 119, 1, 70, 1, 4, 3, 1, 1,
+ 47, 10, 58, 0, 3, 55, 61, 7, 0, 4, 4, 0, 11, 37, 63,
+ 63, 88, 119, 65, 4, 1, 4, 1, 51, 0, 4, 58, 0, 15, 55,
+ 40, 33, 25, 19, 61, 58, 61, 4, 4, 1, 1, 31, 63, 98, 0,
+ 4, 119, 0, 0, 3, 119, 1, 77, 1, 11, 7, 1, 0, 17, 35,
+ 67, 93, 79, 75, 72, 72, 68, 72, 75, 72, 72, 80, 93, 78, 42,
+ 4, 0, 7, 1, 0, 3, 60, 65, 41, 0, 7, 1, 0, 5, 29,
+ 59, 93, 85, 79, 0, 3, 75, 0, 6, 72, 72, 80, 93, 67, 35,
+ 7, 1, 1, 27, 1, 4, 5, 1, 0, 5, 14, 67, 89, 75, 75,
+ 0, 5, 79, 0, 7, 75, 68, 80, 93, 29, 1, 104, 0, 5, 79,
+ 0, 5, 72, 68, 68, 79, 32, 0, 3, 1, 0, 5, 115, 89, 89,
+ 85, 85, 0, 3, 89, 0, 3, 93, 93, 67, 0, 4, 1, 0, 12,
+ 18, 89, 75, 75, 79, 75, 75, 72, 68, 68, 80, 8, 3, 1, 0,
+ 11, 35, 42, 54, 67, 78, 93, 93, 85, 80, 80, 35, 0, 4, 1,
+ 1, 102, 1, 89, 6, 85, 0, 3, 89, 93, 59, 0, 4, 1, 0,
+ 4, 39, 89, 79, 79, 3, 75, 0, 19, 72, 68, 68, 80, 4, 1,
+ 1, 4, 35, 42, 54, 67, 78, 93, 93, 89, 80, 80, 14, 0, 4,
+ 1, 0, 8, 52, 65, 11, 4, 1, 1, 4, 33, 10, 51, 1, 47,
+ 1, 1, 5, 4, 0, 3, 1, 4, 19, 0, 4, 61, 1, 58, 1,
+ 58, 3, 61, 0, 9, 58, 61, 1, 4, 4, 1, 37, 63, 98, 0,
+ 3, 119, 0, 7, 16, 1, 4, 1, 1, 55, 58, 0, 4, 61, 0,
+ 3, 58, 61, 58, 0, 4, 61, 0, 17, 47, 2, 4, 4, 1, 5,
+ 65, 63, 65, 119, 88, 4, 4, 1, 1, 47, 58, 0, 7, 61, 1,
+ 2, 3, 19, 0, 7, 4, 1, 4, 1, 26, 65, 88, 0, 4, 119,
+ 0, 0, 0, 4, 119, 119, 98, 9, 6, 1, 0, 5, 32, 91, 79,
+ 75, 79, 0, 8, 90, 0, 7, 89, 79, 72, 68, 72, 93, 48, 0,
+ 6, 1, 1, 2, 1, 31, 6, 1, 0, 18, 18, 78, 85, 72, 79,
+ 79, 89, 90, 100, 100, 90, 79, 79, 75, 72, 79, 78, 18, 11, 1,
+ 0, 28, 39, 101, 79, 90, 90, 100, 100, 105, 105, 108, 105, 97, 90,
+ 89, 79, 101, 67, 100, 109, 120, 109, 108, 100, 90, 79, 72, 80, 29,
+ 3, 1, 0, 11, 125, 90, 89, 79, 89, 89, 79, 75, 68, 68, 67,
+ 0, 4, 1, 1, 8, 1, 113, 4, 100, 0, 5, 90, 90, 75, 68,
+ 80, 0, 3, 1, 1, 35, 1, 89, 3, 79, 0, 7, 89, 90, 90,
+ 75, 68, 72, 62, 0, 4, 1, 0, 11, 112, 79, 79, 90, 89, 79,
+ 79, 72, 68, 68, 78, 0, 4, 1, 0, 16, 39, 120, 100, 97, 100,
+100, 90, 90, 79, 72, 80, 4, 1, 1, 54, 89, 7, 79, 0, 3,
+ 75, 68, 42, 0, 4, 1, 0, 7, 45, 37, 1, 4, 4, 1, 7,
+ 0, 3, 51, 1, 55, 4, 51, 0, 4, 55, 51, 51, 55, 3, 1,
+ 5, 4, 1, 7, 1, 64, 5, 61, 0, 15, 64, 61, 64, 61, 64,
+ 4, 1, 4, 4, 31, 63, 88, 119, 119, 114, 0, 3, 4, 1, 1,
+ 1, 12, 4, 64, 4, 61, 1, 64, 4, 61, 0, 29, 64, 19, 1,
+ 1, 4, 4, 27, 65, 63, 77, 114, 1, 1, 4, 2, 47, 61, 61,
+ 64, 61, 61, 64, 61, 61, 58, 51, 55, 55, 7, 0, 3, 4, 0,
+ 3, 22, 65, 87, 0, 4, 119, 0, 0, 0, 3, 119, 119, 13, 0,
+ 6, 1, 0, 8, 67, 89, 79, 90, 97, 109, 129, 129, 3, 126, 3,
+109, 0, 9, 105, 100, 90, 79, 75, 72, 80, 93, 18, 0, 11, 1,
+ 0, 20, 39, 101, 79, 79, 90, 90, 109, 116, 109, 108, 109, 109, 100,
+ 97, 97, 89, 75, 68, 93, 32, 9, 1, 0, 29, 39, 89, 89, 100,
+109, 116, 109, 105, 109, 116, 126, 126, 116, 109, 108, 105, 109, 109, 120,
+131, 136, 129, 116, 108, 109, 108, 84, 79, 23, 0, 3, 1, 0, 11,
+168, 116, 109, 109, 108, 109, 116, 108, 84, 72, 67, 0, 5, 1, 0,
+ 10, 124, 120, 124, 126, 120, 116, 97, 79, 72, 80, 4, 1, 1, 124,
+ 4, 109, 0, 6, 126, 116, 90, 75, 68, 91, 4, 1, 1, 132, 4,
+109, 0, 6, 100, 97, 89, 75, 72, 78, 4, 1, 0, 4, 35, 136,
+126, 116, 3, 109, 0, 9, 108, 90, 79, 85, 4, 1, 1, 23, 124,
+ 0, 3, 108, 0, 7, 109, 109, 100, 100, 89, 72, 78, 0, 4, 1,
+ 0, 7, 34, 4, 1, 1, 4, 1, 47, 0, 12, 55, 0, 4, 19,
+ 4, 1, 1, 4, 4, 1, 1, 4, 64, 1, 66, 1, 61, 4, 64,
+ 0, 11, 66, 7, 1, 1, 4, 22, 65, 77, 119, 119, 98, 0, 4,
+ 4, 0, 4, 43, 64, 64, 61, 5, 64, 1, 66, 4, 64, 0, 3,
+ 61, 61, 4, 0, 4, 1, 0, 9, 60, 63, 63, 114, 5, 1, 4,
+ 4, 47, 0, 5, 64, 1, 61, 5, 64, 0, 8, 66, 12, 1, 1,
+ 4, 13, 70, 77, 4, 119, 0, 0, 1, 119, 1, 41, 5, 1, 0,
+ 13, 10, 104, 79, 90, 108, 116, 116, 109, 126, 147, 147, 141, 136, 0,
+ 5, 126, 0, 8, 109, 97, 90, 89, 75, 72, 93, 21, 9, 1, 0,
+ 22, 54, 89, 90, 105, 109, 105, 105, 116, 126, 116, 120, 126, 129, 126,
+116, 116, 109, 100, 79, 72, 80, 32, 7, 1, 0, 14, 21, 113, 90,
+100, 109, 124, 129, 129, 120, 120, 126, 129, 131, 129, 6, 126, 0, 10,
+129, 133, 131, 126, 109, 109, 116, 97, 89, 21, 3, 1, 0, 11, 191,
+133, 131, 129, 126, 109, 109, 129, 116, 79, 78, 0, 5, 1, 0, 3,
+145, 129, 126, 0, 3, 129, 0, 4, 116, 97, 79, 80, 4, 1, 1,
+151, 3, 129, 3, 126, 0, 4, 109, 90, 72, 91, 4, 1, 1, 152,
+ 1, 131, 3, 129, 0, 6, 126, 120, 100, 79, 72, 91, 4, 1, 0,
+ 12, 32, 150, 136, 136, 126, 109, 116, 116, 109, 90, 93, 4, 3, 1,
+ 0, 3, 170, 129, 129, 0, 3, 126, 0, 5, 120, 109, 90, 79, 104,
+ 0, 4, 1, 5, 4, 0, 7, 7, 51, 58, 58, 55, 58, 55, 0,
+ 7, 58, 0, 5, 33, 4, 4, 1, 1, 0, 3, 4, 1, 1, 1,
+ 58, 3, 66, 0, 25, 64, 66, 66, 64, 66, 64, 66, 12, 4, 4,
+ 1, 11, 70, 73, 119, 119, 37, 1, 4, 4, 1, 55, 66, 66, 64,
+ 0, 6, 66, 0, 20, 64, 64, 66, 64, 66, 66, 30, 1, 1, 4,
+ 4, 13, 65, 63, 65, 5, 1, 4, 1, 38, 5, 66, 1, 64, 4,
+ 66, 0, 9, 64, 66, 12, 4, 1, 4, 6, 70, 77, 0, 4, 119,
+ 0, 0, 1, 83, 5, 1, 0, 28, 8, 125, 90, 108, 120, 129, 131,
+131, 126, 126, 136, 147, 147, 136, 133, 129, 129, 133, 133, 129, 116, 100,
+ 90, 90, 79, 75, 85, 8, 7, 1, 0, 24, 42, 101, 100, 109, 126,
+133, 129, 126, 120, 126, 129, 129, 136, 147, 141, 133, 131, 129, 126, 108,
+ 90, 72, 85, 14, 6, 1, 0, 30, 115, 108, 116, 109, 109, 116, 129,
+147, 141, 133, 133, 136, 141, 141, 136, 136, 133, 129, 133, 133, 131, 133,
+136, 136, 129, 116, 109, 97, 89, 14, 3, 1, 0, 11, 217, 147, 147,
+141, 136, 126, 109, 116, 109, 84, 78, 0, 5, 1, 0, 10, 154, 141,
+129, 126, 126, 131, 136, 120, 90, 85, 4, 1, 0, 5, 190, 147, 147,
+136, 131, 0, 3, 129, 0, 3, 109, 79, 80, 0, 4, 1, 0, 11,
+168, 158, 147, 136, 136, 133, 131, 120, 90, 75, 91, 0, 4, 1, 0,
+ 12, 23, 170, 147, 147, 133, 126, 116, 109, 109, 105, 101, 4, 3, 1,
+ 0, 12, 160, 155, 147, 136, 131, 129, 129, 120, 105, 89, 104, 4, 4,
+ 1, 0, 12, 4, 4, 1, 4, 33, 7, 19, 47, 58, 61, 58, 61,
+ 5, 58, 0, 11, 61, 51, 4, 1, 4, 4, 1, 4, 4, 1, 47,
+ 0, 10, 66, 1, 19, 3, 1, 0, 10, 2, 70, 70, 119, 119, 4,
+ 1, 4, 1, 2, 16, 66, 0, 14, 74, 7, 1, 4, 4, 1, 50,
+ 63, 63, 5, 4, 1, 1, 33, 12, 66, 1, 25, 1, 1, 3, 4,
+ 1, 70, 1, 73, 4, 119, 0, 0, 1, 37, 4, 1, 0, 17, 8,
+132, 109, 116, 126, 129, 133, 136, 136, 131, 129, 136, 136, 147, 147, 136,
+133, 0, 4, 129, 0, 8, 126, 116, 108, 100, 90, 79, 72, 102, 6,
+ 1, 0, 16, 14, 123, 105, 120, 126, 129, 133, 133, 129, 131, 136, 141,
+136, 136, 147, 147, 3, 136, 0, 6, 133, 126, 109, 79, 68, 112, 5,
+ 1, 0, 10, 32, 113, 116, 126, 126, 120, 116, 120, 131, 141, 3, 136,
+ 0, 7, 147, 147, 155, 147, 147, 136, 136, 0, 4, 133, 0, 7, 136,
+131, 126, 116, 100, 89, 8, 0, 3, 1, 0, 11, 217, 155, 147, 147,
+141, 131, 116, 116, 105, 79, 78, 0, 5, 1, 0, 10, 154, 147, 131,
+126, 116, 126, 131, 126, 90, 80, 4, 1, 0, 11, 122, 171, 147, 141,
+136, 133, 129, 129, 116, 90, 80, 0, 4, 1, 0, 3, 166, 158, 147,
+ 0, 4, 136, 0, 4, 129, 105, 79, 91, 4, 1, 0, 11, 18, 170,
+136, 133, 131, 129, 120, 109, 100, 90, 104, 0, 4, 1, 0, 12, 122,
+171, 158, 147, 136, 133, 129, 126, 109, 90, 85, 8, 4, 1, 0, 4,
+ 4, 4, 1, 33, 3, 61, 0, 12, 25, 1, 25, 51, 61, 64, 61,
+ 58, 61, 61, 64, 55, 4, 1, 1, 4, 3, 1, 0, 35, 40, 74,
+ 66, 74, 74, 66, 74, 74, 66, 74, 74, 33, 1, 4, 4, 1, 60,
+ 65, 119, 103, 4, 1, 1, 4, 33, 74, 66, 74, 74, 66, 74, 74,
+ 66, 74, 66, 0, 4, 74, 0, 16, 66, 66, 74, 43, 1, 4, 1,
+ 4, 4, 65, 63, 4, 1, 4, 1, 25, 4, 74, 0, 5, 66, 66,
+ 74, 74, 66, 0, 3, 74, 1, 33, 3, 1, 0, 3, 4, 65, 70,
+ 0, 4, 119, 0, 0, 1, 17, 4, 1, 0, 5, 168, 126, 129, 131,
+133, 0, 3, 136, 0, 5, 141, 141, 136, 147, 158, 0, 3, 171, 0,
+ 14, 155, 136, 131, 129, 129, 126, 129, 126, 108, 90, 89, 75, 80, 32,
+ 5, 1, 0, 6, 104, 109, 126, 129, 129, 133, 3, 136, 0, 3, 131,
+140, 147, 0, 3, 155, 0, 11, 158, 147, 147, 141, 136, 129, 124, 100,
+ 79, 72, 39, 0, 4, 1, 1, 91, 1, 109, 3, 126, 0, 14, 129,
+126, 116, 120, 129, 133, 136, 147, 158, 171, 183, 171, 171, 155, 3, 136,
+ 0, 9, 133, 136, 136, 133, 126, 116, 100, 101, 4, 0, 3, 1, 0,
+ 11, 217, 155, 147, 136, 136, 133, 126, 120, 108, 79, 78, 0, 5, 1,
+ 0, 5, 154, 147, 136, 133, 126, 0, 3, 109, 1, 90, 1, 80, 4,
+ 1, 0, 12, 32, 171, 158, 147, 136, 133, 131, 131, 126, 100, 79, 14,
+ 3, 1, 0, 11, 170, 155, 147, 136, 136, 133, 131, 126, 109, 79, 102,
+ 0, 4, 1, 0, 11, 14, 165, 136, 133, 129, 126, 126, 120, 100, 79,
+ 93, 0, 4, 1, 0, 12, 71, 171, 171, 155, 141, 131, 131, 126, 116,
+ 90, 79, 8, 4, 1, 0, 4, 4, 1, 12, 66, 3, 64, 0, 31,
+ 61, 64, 51, 12, 1, 38, 64, 64, 61, 64, 64, 61, 1, 1, 4,
+ 4, 1, 4, 1, 1, 33, 76, 76, 66, 64, 66, 55, 40, 30, 12,
+ 1, 0, 4, 4, 0, 10, 1, 50, 63, 119, 63, 1, 1, 4, 4,
+ 64, 6, 74, 3, 76, 4, 74, 0, 6, 76, 66, 74, 74, 76, 12,
+ 4, 1, 1, 34, 1, 63, 4, 4, 0, 8, 19, 76, 74, 76, 76,
+ 74, 76, 76, 3, 74, 0, 9, 76, 66, 43, 1, 4, 1, 4, 56,
+ 65, 0, 4, 119, 0, 0, 1, 9, 3, 1, 0, 6, 14, 186, 147,
+155, 147, 147, 4, 141, 0, 12, 147, 158, 183, 183, 205, 214, 205, 205,
+171, 147, 136, 136, 3, 131, 0, 6, 126, 100, 97, 89, 75, 104, 4,
+ 1, 0, 14, 21, 134, 129, 136, 131, 131, 136, 136, 141, 147, 147, 141,
+147, 158, 4, 183, 0, 10, 158, 155, 141, 136, 129, 124, 100, 79, 112,
+ 4, 3, 1, 0, 21, 168, 129, 131, 131, 129, 131, 131, 124, 116, 129,
+136, 136, 155, 188, 205, 214, 214, 183, 171, 158, 147, 0, 4, 136, 0,
+ 5, 141, 136, 124, 97, 89, 0, 4, 1, 0, 4, 216, 155, 147, 136,
+ 3, 131, 0, 4, 129, 116, 90, 78, 5, 1, 0, 10, 166, 147, 141,
+141, 131, 116, 109, 109, 89, 80, 5, 1, 0, 11, 188, 171, 155, 141,
+136, 136, 131, 129, 109, 89, 35, 0, 3, 1, 0, 11, 170, 155, 147,
+141, 136, 131, 129, 124, 109, 89, 102, 0, 4, 1, 0, 11, 8, 186,
+147, 136, 136, 131, 129, 129, 108, 79, 93, 0, 4, 1, 0, 12, 18,
+207, 171, 155, 141, 141, 136, 129, 120, 100, 79, 15, 4, 1, 0, 3,
+ 4, 1, 51, 0, 3, 66, 0, 16, 61, 64, 64, 66, 66, 74, 12,
+ 66, 64, 64, 66, 64, 66, 2, 4, 4, 3, 1, 1, 4, 1, 1,
+ 4, 4, 0, 9, 7, 25, 40, 55, 74, 82, 82, 66, 1, 0, 3,
+ 4, 0, 4, 37, 63, 107, 13, 4, 1, 0, 4, 74, 76, 76, 74,
+ 6, 76, 1, 74, 8, 76, 1, 61, 1, 1, 3, 4, 0, 9, 1,
+ 65, 5, 4, 4, 1, 7, 82, 74, 0, 10, 76, 0, 7, 51, 1,
+ 1, 4, 4, 49, 65, 0, 4, 119, 0, 0, 1, 27, 4, 1, 0,
+ 5, 71, 171, 183, 171, 158, 0, 5, 155, 0, 3, 189, 201, 44, 0,
+ 3, 1, 0, 15, 7, 205, 158, 155, 141, 141, 136, 140, 131, 120, 109,
+100, 79, 80, 4, 0, 3, 1, 0, 5, 102, 129, 136, 141, 141, 0,
+ 4, 136, 0, 23, 141, 141, 155, 175, 229, 163, 212, 232, 214, 205, 171,
+155, 154, 141, 136, 126, 100, 89, 23, 1, 1, 23, 165, 0, 3, 141,
+ 0, 9, 136, 140, 136, 131, 124, 129, 141, 176, 62, 0, 3, 1, 0,
+ 8, 57, 237, 205, 171, 158, 141, 136, 136, 3, 131, 0, 3, 126, 100,
+ 93, 0, 4, 1, 0, 11, 216, 158, 147, 141, 141, 136, 131, 131, 126,
+100, 78, 0, 5, 1, 0, 10, 175, 155, 141, 141, 136, 126, 116, 116,
+100, 80, 5, 1, 0, 11, 188, 171, 158, 155, 141, 136, 131, 124, 100,
+ 79, 54, 0, 3, 1, 0, 11, 170, 147, 155, 141, 141, 136, 131, 129,
+116, 89, 104, 0, 4, 1, 0, 11, 8, 186, 155, 154, 141, 136, 136,
+131, 116, 89, 104, 0, 5, 1, 1, 207, 1, 155, 4, 141, 0, 5,
+136, 124, 100, 79, 32, 0, 5, 1, 1, 25, 7, 66, 0, 5, 64,
+ 66, 74, 12, 74, 0, 4, 66, 0, 11, 74, 25, 1, 4, 1, 4,
+ 1, 4, 1, 7, 86, 0, 3, 82, 4, 76, 0, 16, 82, 76, 86,
+ 4, 4, 1, 4, 27, 63, 77, 1, 1, 4, 4, 19, 82, 4, 76,
+ 1, 82, 8, 76, 1, 82, 3, 76, 0, 22, 82, 82, 33, 1, 4,
+ 1, 1, 17, 17, 1, 4, 4, 1, 86, 82, 76, 76, 82, 82, 76,
+ 76, 82, 3, 76, 0, 7, 66, 1, 4, 1, 4, 41, 63, 0, 4,
+119, 0, 0, 1, 50, 5, 1, 0, 10, 163, 214, 214, 205, 171, 174,
+155, 198, 94, 0, 6, 1, 1, 32, 1, 174, 3, 154, 0, 9, 141,
+141, 140, 131, 116, 116, 89, 80, 18, 0, 3, 1, 0, 6, 132, 131,
+140, 141, 154, 154, 5, 140, 1, 217, 1, 14, 4, 1, 0, 15, 128,
+214, 214, 183, 171, 166, 155, 140, 129, 100, 104, 1, 1, 48, 157, 0,
+ 3, 154, 1, 141, 3, 140, 0, 4, 129, 126, 151, 29, 5, 1, 0,
+ 6, 7, 237, 183, 174, 158, 154, 3, 140, 0, 4, 131, 124, 100, 93,
+ 4, 1, 0, 11, 216, 166, 155, 154, 141, 140, 140, 136, 124, 100, 78,
+ 0, 5, 1, 0, 10, 189, 174, 155, 154, 141, 136, 120, 116, 97, 85,
+ 5, 1, 0, 11, 188, 174, 155, 155, 154, 140, 136, 129, 109, 89, 69,
+ 0, 3, 1, 0, 11, 170, 155, 155, 154, 141, 141, 140, 131, 124, 97,
+104, 0, 4, 1, 0, 11, 8, 186, 155, 154, 154, 141, 140, 136, 126,
+ 90, 104, 0, 5, 1, 0, 3, 166, 155, 141, 0, 3, 140, 0, 5,
+141, 136, 116, 79, 48, 0, 4, 1, 1, 4, 4, 74, 1, 66, 1,
+ 74, 3, 66, 0, 10, 74, 74, 6, 76, 74, 66, 74, 66, 66, 40,
+ 3, 1, 0, 11, 4, 1, 4, 4, 1, 82, 82, 86, 86, 82, 86,
+ 0, 4, 82, 1, 86, 1, 7, 3, 4, 0, 3, 22, 65, 52, 0,
+ 4, 1, 0, 4, 58, 82, 86, 76, 5, 82, 0, 6, 86, 82, 86,
+ 82, 86, 76, 5, 82, 0, 9, 86, 74, 1, 1, 4, 1, 1, 24,
+ 4, 0, 3, 1, 0, 3, 76, 82, 86, 0, 4, 82, 0, 13, 86,
+ 82, 86, 82, 82, 86, 1, 4, 1, 4, 37, 63, 114, 0, 3, 119,
+ 0, 0, 1, 119, 6, 1, 0, 7, 232, 214, 214, 205, 188, 142, 4,
+ 0, 8, 1, 0, 21, 10, 170, 154, 145, 145, 141, 145, 145, 136, 124,
+120, 100, 79, 39, 1, 1, 14, 151, 136, 145, 145, 0, 4, 154, 0,
+ 4, 145, 145, 191, 8, 6, 1, 0, 24, 53, 214, 214, 205, 183, 174,
+155, 150, 180, 112, 1, 1, 81, 154, 154, 144, 145, 145, 136, 145, 140,
+124, 116, 91, 7, 1, 1, 28, 1, 205, 3, 174, 0, 7, 154, 154,
+144, 145, 131, 100, 93, 0, 4, 1, 0, 11, 216, 174, 154, 154, 144,
+145, 144, 145, 124, 100, 94, 0, 5, 1, 0, 10, 189, 154, 151, 145,
+144, 136, 124, 116, 90, 85, 5, 1, 0, 11, 160, 174, 166, 154, 155,
+154, 151, 140, 124, 100, 91, 0, 3, 1, 1, 190, 1, 166, 3, 154,
+ 0, 6, 144, 136, 136, 124, 100, 104, 4, 1, 0, 11, 8, 202, 154,
+154, 145, 145, 136, 131, 129, 97, 104, 0, 5, 1, 0, 4, 139, 166,
+144, 136, 3, 145, 0, 4, 144, 131, 90, 59, 4, 1, 1, 33, 1,
+ 76, 4, 74, 1, 66, 3, 74, 0, 4, 76, 82, 4, 76, 5, 74,
+ 1, 64, 1, 1, 6, 4, 0, 5, 1, 66, 86, 86, 82, 0, 3,
+ 86, 1, 82, 3, 86, 0, 7, 12, 4, 4, 1, 16, 70, 27, 0,
+ 3, 4, 0, 4, 1, 19, 19, 7, 4, 86, 1, 82, 5, 86, 1,
+ 82, 8, 86, 1, 47, 4, 1, 1, 4, 1, 4, 3, 1, 0, 4,
+ 74, 86, 86, 82, 8, 86, 0, 8, 95, 4, 4, 1, 1, 31, 63,
+103, 3, 119, 0, 0, 1, 119, 1, 87, 5, 1, 0, 5, 4, 232,
+214, 229, 57, 0, 10, 1, 0, 20, 142, 150, 145, 145, 144, 145, 144,
+145, 136, 131, 131, 116, 89, 42, 1, 1, 59, 144, 131, 145, 3, 150,
+ 0, 5, 151, 154, 145, 134, 29, 0, 8, 1, 0, 8, 128, 214, 205,
+237, 229, 122, 21, 8, 3, 1, 0, 12, 94, 175, 151, 145, 144, 145,
+144, 136, 136, 124, 113, 32, 7, 1, 0, 12, 4, 229, 174, 175, 154,
+175, 175, 150, 145, 136, 100, 85, 4, 1, 0, 11, 217, 175, 154, 145,
+145, 150, 145, 144, 136, 100, 91, 0, 5, 1, 0, 10, 170, 151, 150,
+145, 145, 141, 131, 124, 100, 85, 5, 1, 0, 11, 102, 189, 175, 154,
+151, 151, 154, 145, 129, 100, 102, 0, 3, 1, 0, 11, 168, 175, 151,
+150, 150, 144, 131, 136, 131, 100, 104, 0, 4, 1, 0, 11, 8, 202,
+175, 150, 144, 144, 141, 131, 124, 100, 104, 0, 5, 1, 0, 11, 122,
+175, 145, 131, 145, 150, 145, 144, 136, 100, 69, 0, 4, 1, 1, 38,
+ 7, 76, 0, 7, 74, 76, 76, 82, 61, 1, 55, 0, 3, 82, 0,
+ 6, 76, 74, 1, 4, 4, 1, 3, 4, 1, 1, 1, 51, 7, 86,
+ 0, 21, 92, 86, 92, 25, 4, 4, 1, 4, 70, 1, 1, 4, 4,
+ 1, 86, 95, 7, 92, 86, 86, 92, 0, 5, 86, 1, 40, 9, 86,
+ 0, 3, 92, 4, 4, 0, 3, 1, 0, 5, 4, 1, 4, 1, 66,
+ 0, 6, 86, 1, 92, 4, 86, 1, 95, 1, 7, 3, 1, 0, 3,
+ 24, 63, 98, 0, 3, 119, 0, 0, 0, 3, 119, 119, 56, 0, 5,
+ 1, 0, 3, 36, 249, 36, 0, 10, 1, 0, 6, 69, 151, 150, 150,
+145, 145, 3, 150, 0, 12, 145, 136, 136, 124, 100, 48, 1, 1, 115,
+170, 144, 144, 4, 150, 0, 3, 144, 129, 137, 0, 9, 1, 0, 4,
+ 7, 146, 46, 14, 7, 1, 0, 3, 94, 175, 170, 0, 5, 150, 0,
+ 4, 144, 124, 100, 21, 8, 1, 0, 11, 242, 188, 175, 170, 150, 150,
+145, 144, 131, 100, 91, 0, 4, 1, 0, 11, 217, 175, 170, 150, 145,
+150, 150, 145, 141, 116, 93, 0, 5, 1, 0, 10, 186, 170, 170, 157,
+150, 145, 136, 124, 100, 93, 5, 1, 0, 11, 54, 186, 175, 170, 170,
+150, 150, 136, 124, 100, 115, 0, 3, 1, 0, 11, 190, 157, 157, 150,
+150, 145, 136, 136, 124, 100, 104, 0, 4, 1, 0, 4, 8, 198, 175,
+157, 3, 150, 0, 5, 144, 136, 100, 104, 4, 0, 4, 1, 0, 11,
+ 81, 189, 170, 141, 136, 150, 150, 144, 124, 101, 67, 0, 4, 1, 0,
+ 7, 40, 82, 76, 76, 82, 82, 76, 0, 3, 82, 0, 13, 76, 82,
+ 76, 76, 19, 6, 7, 7, 33, 76, 1, 4, 1, 0, 4, 4, 1,
+ 1, 1, 40, 3, 92, 1, 95, 1, 38, 5, 12, 0, 14, 4, 1,
+ 1, 4, 1, 52, 4, 1, 1, 4, 40, 92, 95, 7, 4, 92, 1,
+ 86, 3, 92, 0, 3, 47, 4, 95, 0, 8, 92, 0, 3, 95, 64,
+ 1, 0, 4, 4, 0, 4, 1, 4, 1, 64, 9, 92, 0, 10, 86,
+ 92, 92, 12, 1, 4, 1, 17, 65, 88, 3, 119, 0, 0, 3, 119,
+ 1, 34, 5, 1, 1, 7, 10, 1, 0, 3, 91, 134, 145, 0, 5,
+157, 0, 13, 165, 170, 165, 157, 144, 124, 113, 29, 1, 1, 137, 170,
+170, 0, 4, 157, 0, 4, 150, 136, 113, 102, 20, 1, 0, 4, 94,
+175, 170, 170, 5, 157, 0, 3, 131, 101, 21, 0, 8, 1, 0, 11,
+216, 189, 170, 170, 157, 144, 136, 134, 134, 113, 91, 0, 4, 1, 0,
+ 11, 217, 175, 165, 145, 144, 145, 145, 136, 124, 113, 93, 0, 5, 1,
+ 1, 186, 4, 170, 0, 5, 165, 150, 136, 113, 93, 0, 5, 1, 1,
+ 35, 1, 202, 3, 170, 0, 6, 157, 145, 134, 113, 101, 115, 3, 1,
+ 0, 11, 190, 175, 170, 170, 157, 144, 131, 136, 134, 100, 104, 0, 4,
+ 1, 0, 4, 8, 198, 170, 170, 4, 157, 0, 4, 145, 113, 104, 4,
+ 4, 1, 0, 11, 54, 202, 175, 157, 145, 150, 157, 145, 134, 101, 67,
+ 0, 4, 1, 0, 13, 38, 82, 82, 86, 82, 86, 82, 86, 86, 82,
+ 82, 86, 82, 0, 5, 86, 1, 33, 1, 19, 3, 4, 1, 1, 1,
+ 1, 3, 4, 1, 7, 3, 19, 1, 5, 1, 51, 5, 82, 1, 47,
+ 1, 1, 3, 4, 1, 27, 1, 1, 3, 4, 0, 8, 86, 95, 99,
+ 7, 95, 92, 95, 95, 3, 92, 0, 8, 95, 12, 4, 19, 92, 95,
+ 92, 95, 4, 92, 0, 11, 95, 95, 19, 4, 4, 1, 4, 1, 4,
+ 1, 61, 0, 5, 95, 0, 8, 92, 95, 92, 95, 95, 92, 95, 19,
+ 3, 4, 0, 3, 13, 65, 77, 0, 3, 119, 0, 0, 4, 119, 1,
+ 11, 13, 1, 0, 4, 39, 115, 124, 144, 4, 165, 0, 3, 157, 151,
+150, 0, 3, 165, 0, 8, 157, 134, 123, 4, 1, 1, 159, 186, 4,
+165, 0, 5, 157, 157, 141, 113, 62, 0, 20, 1, 0, 12, 94, 189,
+189, 186, 165, 157, 144, 144, 157, 136, 101, 23, 8, 1, 0, 11, 217,
+189, 186, 165, 165, 157, 144, 136, 134, 124, 91, 0, 4, 1, 0, 4,
+216, 189, 186, 150, 3, 144, 0, 4, 124, 113, 101, 93, 5, 1, 0,
+ 4, 202, 184, 165, 157, 3, 165, 0, 3, 144, 113, 104, 0, 5, 1,
+ 0, 3, 18, 202, 186, 0, 3, 165, 0, 5, 157, 144, 124, 100, 115,
+ 0, 3, 1, 0, 11, 201, 189, 188, 189, 186, 157, 134, 134, 124, 101,
+104, 0, 4, 1, 0, 6, 14, 216, 186, 186, 165, 157, 3, 144, 0,
+ 3, 124, 104, 4, 0, 4, 1, 0, 11, 42, 198, 184, 165, 165, 157,
+157, 150, 136, 100, 69, 0, 4, 1, 1, 40, 3, 86, 1, 82, 8,
+ 86, 1, 82, 5, 86, 0, 4, 51, 1, 4, 1, 3, 4, 0, 7,
+ 1, 1, 19, 82, 76, 76, 92, 0, 6, 95, 0, 3, 76, 1, 1,
+ 0, 4, 4, 0, 8, 1, 4, 4, 95, 95, 99, 7, 99, 6, 95,
+ 1, 92, 3, 1, 1, 86, 9, 95, 1, 86, 1, 1, 6, 4, 6,
+ 12, 1, 76, 4, 95, 0, 9, 99, 95, 25, 4, 4, 1, 11, 70,
+ 73, 0, 3, 119, 0, 0, 4, 119, 1, 114, 11, 1, 0, 6, 14,
+ 91, 111, 123, 151, 165, 4, 184, 0, 9, 165, 157, 144, 151, 165, 165,
+157, 138, 152, 0, 3, 1, 0, 3, 160, 186, 184, 0, 3, 173, 0,
+ 5, 165, 173, 151, 113, 59, 0, 20, 1, 0, 12, 81, 207, 189, 186,
+184, 165, 151, 141, 136, 124, 101, 29, 8, 1, 1, 236, 1, 186, 3,
+184, 0, 6, 165, 157, 157, 144, 123, 91, 4, 1, 0, 11, 217, 207,
+186, 165, 144, 144, 151, 144, 124, 101, 93, 0, 5, 1, 0, 11, 198,
+186, 173, 157, 151, 157, 157, 151, 124, 101, 4, 0, 4, 1, 0, 11,
+ 14, 198, 186, 184, 173, 184, 165, 157, 134, 113, 115, 0, 3, 1, 1,
+190, 1, 207, 3, 186, 0, 6, 184, 144, 124, 123, 113, 104, 4, 1,
+ 0, 12, 29, 216, 186, 186, 184, 173, 157, 138, 134, 113, 104, 4, 4,
+ 1, 0, 11, 48, 198, 184, 165, 165, 172, 165, 157, 151, 113, 69, 0,
+ 4, 1, 1, 40, 3, 86, 1, 92, 11, 86, 0, 5, 92, 86, 86,
+ 92, 47, 0, 3, 1, 4, 4, 1, 0, 1, 110, 4, 99, 1, 95,
+ 4, 99, 0, 3, 106, 1, 1, 0, 6, 4, 0, 6, 25, 99, 99,
+106, 7, 106, 6, 99, 0, 5, 82, 1, 1, 4, 12, 0, 10, 99,
+ 0, 14, 38, 1, 1, 4, 1, 4, 4, 40, 92, 92, 86, 95, 40,
+ 76, 3, 99, 0, 4, 95, 99, 99, 30, 4, 4, 1, 70, 1, 73,
+ 3, 119, 0, 0, 5, 119, 1, 98, 9, 1, 0, 9, 59, 115, 101,
+113, 144, 173, 180, 184, 184, 0, 4, 180, 1, 173, 3, 157, 0, 3,
+151, 134, 115, 0, 3, 1, 0, 3, 139, 207, 202, 0, 3, 180, 0,
+ 5, 172, 172, 165, 123, 91, 0, 20, 1, 0, 12, 62, 207, 202, 202,
+200, 180, 173, 151, 138, 123, 101, 35, 8, 1, 0, 11, 236, 200, 184,
+180, 200, 184, 173, 144, 138, 113, 78, 0, 4, 1, 0, 11, 236, 207,
+207, 200, 173, 157, 173, 157, 134, 101, 104, 0, 4, 1, 0, 12, 21,
+180, 200, 180, 173, 157, 157, 151, 144, 124, 101, 32, 4, 1, 1, 35,
+ 1, 193, 5, 180, 0, 4, 173, 138, 113, 91, 3, 1, 0, 11, 190,
+184, 180, 180, 202, 202, 173, 151, 134, 113, 112, 0, 4, 1, 0, 3,
+ 54, 193, 200, 0, 3, 184, 0, 6, 172, 151, 138, 113, 101, 8, 4,
+ 1, 0, 11, 54, 198, 200, 180, 172, 172, 173, 165, 157, 123, 54, 0,
+ 4, 1, 1, 47, 8, 92, 1, 86, 6, 92, 0, 5, 86, 86, 92,
+ 92, 82, 0, 3, 4, 1, 1, 1, 4, 3, 1, 3, 99, 1, 106,
+ 6, 99, 0, 15, 110, 7, 1, 4, 4, 1, 1, 4, 1, 74, 99,
+ 99, 110, 7, 106, 0, 3, 99, 0, 9, 106, 99, 106, 43, 1, 4,
+ 1, 4, 76, 0, 6, 99, 1, 106, 3, 99, 4, 1, 0, 9, 4,
+ 1, 38, 106, 99, 106, 99, 43, 74, 0, 3, 99, 0, 10, 106, 99,
+ 99, 38, 1, 4, 1, 4, 70, 70, 3, 119, 0, 0, 5, 119, 1,
+114, 7, 1, 0, 11, 29, 104, 113, 124, 124, 134, 144, 157, 182, 182,
+180, 0, 5, 182, 0, 6, 172, 172, 165, 144, 134, 8, 3, 1, 0,
+ 4, 118, 231, 207, 198, 4, 182, 0, 3, 161, 134, 115, 0, 9, 1,
+ 0, 3, 4, 48, 29, 0, 8, 1, 0, 4, 48, 221, 202, 200, 3,
+182, 0, 5, 165, 144, 134, 100, 48, 0, 8, 1, 0, 11, 236, 200,
+200, 196, 196, 198, 182, 144, 136, 113, 78, 0, 4, 1, 1, 236, 3,
+200, 0, 7, 198, 182, 172, 165, 136, 113, 104, 0, 4, 1, 1, 69,
+ 4, 182, 0, 7, 172, 172, 161, 144, 124, 100, 69, 0, 4, 1, 1,
+ 78, 1, 193, 6, 182, 0, 3, 144, 113, 69, 0, 3, 1, 0, 11,
+202, 200, 182, 182, 196, 200, 196, 182, 150, 124, 115, 0, 4, 1, 0,
+ 3, 102, 182, 198, 0, 4, 182, 0, 5, 165, 145, 134, 100, 48, 0,
+ 4, 1, 0, 4, 91, 196, 200, 180, 3, 182, 0, 4, 172, 157, 124,
+ 39, 4, 1, 0, 5, 58, 95, 92, 95, 92, 0, 4, 95, 0, 7,
+ 92, 92, 95, 95, 92, 95, 92, 0, 3, 95, 0, 11, 92, 92, 1,
+ 4, 1, 4, 1, 4, 4, 1, 74, 0, 7, 106, 0, 4, 99, 106,
+110, 19, 5, 4, 0, 8, 1, 4, 106, 99, 106, 110, 7, 110, 6,
+106, 1, 4, 1, 4, 3, 1, 1, 7, 10, 106, 0, 8, 58, 4,
+ 4, 1, 1, 4, 30, 110, 3, 106, 1, 43, 1, 66, 6, 106, 0,
+ 7, 51, 1, 1, 4, 4, 60, 70, 0, 3, 119, 0, 0, 5, 119,
+ 1, 34, 6, 1, 0, 13, 54, 125, 124, 136, 150, 145, 136, 144, 150,
+177, 194, 196, 196, 0, 5, 185, 0, 4, 177, 172, 150, 115, 4, 1,
+ 0, 4, 46, 229, 207, 200, 3, 196, 0, 5, 185, 172, 144, 113, 18,
+ 0, 8, 1, 0, 8, 59, 101, 101, 111, 91, 48, 29, 4, 3, 1,
+ 0, 12, 35, 225, 200, 196, 194, 185, 185, 182, 157, 136, 113, 59, 8,
+ 1, 1, 236, 1, 200, 5, 196, 0, 4, 172, 144, 120, 78, 4, 1,
+ 1, 236, 4, 196, 0, 7, 194, 182, 172, 145, 113, 101, 18, 0, 3,
+ 1, 0, 3, 168, 172, 177, 0, 3, 185, 0, 6, 172, 172, 161, 144,
+124, 115, 4, 1, 0, 11, 152, 177, 194, 194, 196, 196, 194, 194, 161,
+124, 42, 0, 3, 1, 0, 12, 202, 196, 185, 172, 185, 196, 196, 185,
+161, 136, 113, 4, 3, 1, 0, 4, 142, 177, 196, 196, 3, 185, 0,
+ 5, 177, 161, 144, 124, 125, 0, 4, 1, 0, 11, 151, 185, 196, 196,
+194, 185, 185, 177, 157, 124, 21, 0, 4, 1, 1, 74, 4, 95, 1,
+ 99, 3, 95, 0, 3, 92, 61, 99, 0, 5, 95, 1, 99, 3, 95,
+ 3, 4, 0, 11, 1, 4, 4, 1, 1, 51, 106, 106, 110, 106, 106,
+ 0, 3, 110, 0, 6, 106, 110, 30, 1, 4, 1, 3, 4, 1, 7,
+ 3, 106, 0, 16, 117, 7, 110, 106, 110, 110, 106, 106, 95, 1, 4,
+ 4, 1, 4, 1, 64, 3, 110, 3, 106, 0, 16, 110, 106, 110, 110,
+ 7, 4, 1, 4, 1, 19, 117, 110, 106, 110, 47, 74, 3, 106, 3,
+110, 1, 64, 3, 1, 0, 3, 4, 50, 65, 0, 3, 119, 0, 0,
+ 4, 119, 1, 77, 6, 1, 0, 11, 91, 124, 131, 161, 177, 185, 177,
+161, 153, 161, 185, 0, 9, 194, 1, 177, 1, 168, 6, 1, 0, 12,
+221, 221, 200, 196, 194, 194, 185, 161, 145, 124, 115, 4, 6, 1, 0,
+ 4, 29, 111, 100, 113, 4, 100, 0, 16, 125, 91, 1, 1, 23, 225,
+222, 196, 194, 187, 194, 185, 172, 145, 116, 78, 7, 1, 0, 4, 4,
+235, 196, 196, 4, 194, 0, 4, 177, 150, 124, 67, 4, 1, 0, 18,
+235, 194, 196, 196, 194, 194, 196, 194, 177, 140, 116, 115, 23, 14, 59,
+157, 177, 177, 5, 194, 0, 10, 177, 172, 145, 124, 91, 18, 14, 78,
+145, 172, 4, 194, 0, 5, 185, 177, 153, 134, 10, 0, 3, 1, 0,
+ 17, 198, 194, 177, 161, 177, 194, 194, 185, 194, 172, 136, 125, 23, 14,
+ 69, 157, 185, 0, 3, 194, 0, 22, 185, 194, 185, 177, 161, 145, 120,
+ 67, 15, 15, 91, 150, 177, 185, 185, 194, 194, 185, 177, 145, 113, 8,
+ 4, 1, 8, 99, 0, 3, 106, 19, 30, 0, 10, 99, 0, 3, 4,
+ 4, 1, 0, 3, 4, 0, 3, 1, 1, 38, 0, 10, 117, 0, 8,
+ 38, 1, 4, 4, 1, 4, 4, 47, 3, 117, 1, 121, 1, 12, 6,
+117, 0, 3, 76, 4, 4, 0, 5, 1, 10, 117, 0, 7, 99, 1,
+ 1, 4, 4, 7, 121, 0, 3, 117, 1, 47, 1, 76, 6, 117, 0,
+ 7, 92, 1, 4, 1, 1, 45, 63, 0, 3, 119, 0, 0, 3, 119,
+ 1, 114, 6, 1, 0, 8, 104, 109, 136, 145, 161, 187, 194, 194, 4,
+195, 0, 4, 194, 210, 194, 194, 3, 210, 0, 4, 194, 187, 180, 8,
+ 6, 1, 0, 13, 201, 226, 220, 215, 194, 195, 195, 177, 153, 131, 100,
+115, 21, 0, 3, 1, 0, 26, 8, 42, 111, 109, 124, 131, 124, 120,
+113, 100, 100, 112, 1, 1, 4, 240, 220, 215, 210, 194, 195, 195, 177,
+145, 120, 115, 7, 1, 0, 12, 4, 235, 215, 210, 210, 194, 195, 185,
+177, 149, 124, 69, 4, 1, 1, 235, 1, 195, 3, 187, 0, 29, 177,
+194, 194, 195, 177, 150, 140, 136, 151, 161, 177, 185, 195, 195, 194, 195,
+187, 187, 185, 161, 150, 140, 124, 123, 134, 136, 153, 177, 187, 0, 3,
+195, 0, 4, 187, 177, 145, 123, 4, 1, 0, 42, 198, 215, 195, 161,
+161, 169, 185, 169, 161, 177, 162, 145, 144, 151, 150, 169, 195, 194, 195,
+195, 194, 195, 195, 187, 172, 153, 136, 116, 124, 134, 136, 153, 177, 177,
+185, 187, 195, 187, 177, 145, 132, 4, 3, 1, 1, 12, 1, 110, 7,
+106, 0, 4, 92, 0, 4, 106, 3, 99, 4, 106, 0, 12, 99, 99,
+ 33, 1, 4, 1, 1, 4, 1, 4, 30, 127, 5, 121, 0, 6, 127,
+127, 121, 127, 61, 1, 3, 4, 0, 10, 1, 1, 127, 127, 121, 127,
+130, 12, 127, 127, 3, 121, 0, 11, 127, 38, 1, 4, 1, 4, 1,
+ 1, 4, 58, 127, 0, 3, 121, 0, 12, 127, 127, 121, 127, 121, 127,
+ 25, 1, 4, 4, 1, 130, 3, 121, 0, 3, 51, 86, 127, 0, 6,
+121, 1, 1, 3, 4, 1, 37, 1, 63, 3, 119, 0, 0, 3, 119,
+ 1, 41, 5, 1, 0, 4, 115, 126, 136, 145, 3, 161, 0, 4, 177,
+195, 195, 187, 3, 195, 1, 210, 1, 220, 4, 215, 0, 3, 210, 210,
+ 14, 0, 7, 1, 0, 5, 118, 228, 226, 215, 210, 0, 3, 195, 0,
+ 20, 187, 153, 131, 116, 113, 115, 91, 115, 123, 126, 131, 140, 145, 149,
+145, 131, 124, 109, 100, 39, 3, 1, 0, 11, 240, 226, 220, 220, 215,
+210, 208, 195, 153, 124, 125, 0, 7, 1, 0, 4, 4, 235, 215, 210,
+ 3, 208, 0, 5, 195, 177, 149, 124, 59, 0, 4, 1, 1, 235, 1,
+208, 3, 187, 0, 11, 169, 161, 177, 187, 179, 162, 161, 161, 162, 179,
+208, 0, 4, 210, 0, 13, 215, 208, 187, 177, 169, 153, 145, 149, 145,
+145, 153, 177, 187, 0, 5, 195, 0, 3, 179, 145, 125, 0, 4, 1,
+ 0, 18, 216, 215, 215, 195, 177, 169, 177, 177, 153, 149, 161, 169, 153,
+161, 177, 187, 195, 210, 3, 215, 3, 210, 0, 17, 187, 162, 149, 140,
+133, 145, 161, 162, 177, 187, 187, 195, 195, 187, 177, 145, 115, 0, 4,
+ 1, 1, 38, 8, 106, 0, 3, 7, 4, 1, 0, 10, 106, 0, 10,
+ 55, 1, 1, 4, 4, 1, 4, 4, 19, 135, 9, 130, 0, 7, 95,
+ 1, 4, 4, 1, 4, 12, 0, 4, 130, 1, 135, 1, 12, 3, 130,
+ 0, 7, 127, 130, 130, 1, 4, 1, 4, 0, 5, 1, 1, 121, 1,
+127, 5, 130, 0, 9, 127, 130, 130, 135, 4, 1, 4, 1, 127, 0,
+ 3, 130, 1, 51, 1, 92, 6, 130, 0, 10, 135, 1, 1, 4, 1,
+ 27, 63, 107, 119, 119, 0, 0, 0, 3, 119, 119, 107, 0, 5, 1,
+ 0, 13, 78, 145, 162, 177, 179, 187, 195, 179, 177, 179, 162, 177, 195,
+ 0, 3, 208, 4, 215, 1, 211, 1, 191, 10, 1, 0, 4, 245, 228,
+220, 210, 3, 208, 0, 20, 199, 177, 153, 145, 140, 131, 131, 140, 149,
+162, 187, 187, 179, 187, 187, 177, 145, 126, 123, 8, 3, 1, 0, 5,
+221, 220, 220, 215, 211, 0, 3, 208, 0, 4, 187, 140, 123, 8, 6,
+ 1, 0, 3, 8, 219, 211, 0, 4, 208, 0, 5, 195, 177, 149, 126,
+ 54, 0, 4, 1, 0, 12, 240, 215, 208, 204, 197, 197, 187, 177, 179,
+162, 161, 177, 3, 187, 3, 208, 1, 211, 1, 211, 3, 215, 0, 18,
+211, 208, 187, 162, 153, 161, 162, 161, 177, 187, 195, 197, 197, 208, 209,
+187, 145, 54, 4, 1, 0, 5, 216, 220, 215, 211, 208, 0, 4, 195,
+ 0, 9, 177, 162, 162, 149, 161, 179, 195, 197, 204, 0, 5, 211, 0,
+ 8, 215, 210, 208, 195, 187, 169, 153, 161, 3, 177, 0, 7, 187, 197,
+199, 187, 177, 145, 32, 0, 4, 1, 1, 40, 5, 110, 0, 3, 106,
+110, 76, 0, 3, 1, 0, 4, 99, 110, 110, 106, 6, 110, 0, 10,
+106, 1, 4, 4, 1, 4, 1, 4, 4, 148, 10, 135, 1, 1, 1,
+ 1, 3, 4, 1, 33, 4, 135, 0, 3, 143, 12, 143, 0, 4, 135,
+ 1, 117, 1, 1, 3, 4, 0, 6, 5, 4, 4, 1, 1, 47, 10,
+135, 1, 43, 3, 1, 1, 117, 3, 135, 1, 55, 1, 99, 6, 135,
+ 0, 10, 143, 7, 1, 1, 4, 22, 63, 98, 119, 119, 0, 0, 0,
+ 3, 119, 119, 65, 0, 4, 1, 0, 16, 4, 151, 177, 199, 209, 204,
+199, 197, 197, 187, 187, 177, 187, 199, 208, 211, 4, 215, 1, 219, 1,
+115, 11, 1, 0, 26, 146, 231, 226, 215, 208, 197, 197, 187, 169, 153,
+153, 179, 179, 169, 177, 169, 177, 195, 208, 208, 204, 199, 197, 177, 145,
+ 59, 4, 1, 0, 12, 188, 220, 215, 215, 211, 208, 204, 204, 195, 149,
+124, 14, 6, 1, 0, 12, 10, 219, 208, 204, 195, 187, 187, 177, 161,
+133, 116, 54, 3, 1, 0, 14, 4, 240, 220, 215, 211, 208, 199, 199,
+197, 187, 177, 179, 197, 204, 4, 208, 0, 5, 211, 208, 208, 211, 215,
+ 0, 3, 220, 0, 10, 215, 209, 179, 177, 177, 162, 177, 187, 187, 195,
+ 3, 187, 1, 162, 1, 138, 5, 1, 1, 225, 1, 215, 3, 211, 0,
+ 11, 208, 208, 204, 197, 197, 195, 187, 177, 187, 197, 204, 0, 3, 208,
+ 0, 4, 211, 215, 211, 211, 4, 215, 0, 14, 211, 208, 187, 177, 179,
+179, 177, 187, 195, 195, 187, 161, 144, 4, 4, 1, 0, 4, 33, 30,
+121, 121, 4, 117, 0, 11, 1, 4, 1, 1, 86, 121, 117, 117, 121,
+117, 117, 0, 4, 86, 1, 4, 3, 1, 0, 8, 4, 1, 4, 1,
+135, 143, 148, 148, 6, 143, 0, 19, 156, 7, 1, 4, 4, 1, 110,
+143, 143, 148, 143, 148, 12, 148, 143, 148, 148, 143, 82, 0, 3, 1,
+ 1, 4, 1, 60, 3, 4, 0, 6, 1, 1, 121, 148, 143, 148, 3,
+143, 0, 13, 148, 143, 143, 156, 12, 4, 1, 110, 143, 143, 148, 64,
+106, 0, 6, 143, 0, 10, 156, 19, 4, 1, 4, 17, 65, 88, 119,
+119, 0, 0, 0, 3, 119, 119, 27, 0, 4, 1, 0, 21, 142, 161,
+177, 197, 208, 208, 204, 199, 197, 199, 195, 179, 195, 208, 208, 211, 215,
+215, 210, 217, 10, 0, 13, 1, 0, 13, 229, 234, 226, 211, 195, 187,
+179, 169, 161, 153, 187, 199, 187, 0, 3, 177, 1, 187, 4, 208, 0,
+ 4, 199, 179, 176, 4, 4, 1, 0, 12, 139, 223, 220, 211, 208, 199,
+197, 187, 169, 145, 124, 23, 6, 1, 0, 12, 14, 219, 208, 197, 187,
+177, 169, 162, 149, 129, 109, 48, 3, 1, 0, 12, 4, 240, 220, 215,
+215, 208, 208, 209, 208, 209, 197, 209, 5, 211, 4, 208, 0, 20, 211,
+215, 215, 220, 220, 215, 211, 204, 197, 197, 187, 177, 195, 197, 204, 197,
+187, 179, 161, 69, 5, 1, 0, 4, 225, 215, 208, 208, 3, 211, 3,
+208, 0, 3, 211, 208, 199, 0, 4, 208, 3, 211, 1, 210, 3, 215,
+ 0, 6, 211, 211, 215, 210, 208, 208, 3, 197, 0, 7, 179, 187, 197,
+197, 187, 161, 39, 0, 4, 1, 0, 4, 25, 135, 64, 12, 4, 127,
+ 1, 58, 3, 4, 0, 4, 1, 86, 127, 130, 3, 127, 0, 7, 121,
+ 4, 64, 61, 61, 4, 1, 0, 3, 4, 0, 6, 1, 4, 1, 106,
+156, 148, 5, 156, 0, 15, 148, 156, 156, 25, 1, 1, 4, 7, 156,
+156, 148, 156, 148, 156, 12, 0, 5, 127, 0, 26, 30, 1, 1, 4,
+ 4, 63, 45, 1, 1, 4, 4, 38, 156, 156, 148, 156, 148, 156, 156,
+148, 156, 148, 95, 1, 1, 99, 3, 156, 1, 66, 1, 110, 4, 156,
+ 0, 12, 148, 148, 156, 25, 1, 1, 4, 16, 65, 77, 119, 119, 0,
+ 0, 1, 119, 1, 119, 5, 1, 0, 14, 182, 179, 187, 195, 199, 204,
+199, 199, 197, 197, 187, 177, 195, 208, 3, 215, 1, 240, 1, 32, 15,
+ 1, 0, 6, 28, 248, 234, 226, 220, 215, 3, 208, 0, 15, 187, 197,
+209, 208, 197, 197, 187, 187, 204, 208, 211, 208, 197, 193, 14, 0, 5,
+ 1, 0, 5, 118, 228, 226, 215, 208, 0, 3, 197, 0, 4, 179, 149,
+120, 39, 6, 1, 0, 12, 14, 215, 211, 208, 204, 199, 195, 187, 177,
+149, 116, 42, 3, 1, 0, 6, 4, 225, 223, 220, 215, 215, 3, 211,
+ 0, 19, 208, 209, 225, 220, 223, 223, 220, 215, 215, 211, 208, 211, 220,
+242, 221, 226, 223, 220, 215, 0, 3, 211, 0, 9, 204, 187, 197, 208,
+211, 211, 208, 195, 142, 0, 6, 1, 0, 3, 222, 223, 215, 0, 6,
+211, 0, 4, 215, 225, 215, 211, 6, 215, 0, 8, 220, 220, 242, 226,
+226, 220, 215, 215, 3, 211, 0, 9, 208, 211, 211, 197, 197, 208, 204,
+195, 142, 0, 5, 1, 0, 9, 86, 130, 135, 110, 1, 121, 135, 127,
+ 1, 0, 3, 4, 0, 4, 1, 61, 135, 130, 3, 135, 0, 16, 130,
+ 4, 135, 130, 135, 7, 4, 4, 1, 4, 1, 4, 1, 64, 156, 167,
+ 7, 156, 0, 7, 167, 38, 1, 4, 1, 25, 167, 0, 4, 156, 0,
+ 22, 167, 76, 74, 76, 76, 74, 66, 1, 4, 1, 1, 6, 77, 119,
+ 6, 4, 4, 1, 1, 117, 156, 167, 7, 156, 0, 4, 167, 25, 1,
+ 86, 3, 156, 1, 74, 1, 117, 6, 156, 0, 10, 167, 33, 4, 1,
+ 1, 11, 70, 73, 119, 119, 0, 0, 1, 119, 1, 88, 4, 1, 0,
+ 18, 23, 209, 209, 199, 195, 197, 195, 197, 197, 199, 197, 179, 169, 195,
+208, 211, 235, 42, 18, 1, 0, 16, 36, 252, 238, 233, 226, 220, 215,
+215, 208, 211, 211, 215, 215, 211, 208, 208, 3, 211, 0, 3, 208, 219,
+ 29, 0, 6, 1, 0, 12, 71, 231, 233, 226, 215, 211, 211, 215, 208,
+179, 133, 59, 6, 1, 0, 12, 20, 220, 220, 215, 211, 208, 208, 204,
+197, 162, 129, 39, 3, 1, 0, 6, 4, 243, 233, 228, 223, 220, 4,
+215, 0, 24, 168, 14, 250, 233, 233, 228, 226, 223, 220, 215, 220, 221,
+ 1, 36, 248, 238, 234, 228, 223, 220, 220, 215, 208, 211, 3, 215, 1,
+209, 1, 168, 7, 1, 0, 16, 243, 233, 228, 223, 220, 215, 215, 220,
+220, 201, 10, 243, 226, 228, 228, 226, 3, 223, 0, 19, 226, 201, 1,
+ 36, 248, 238, 233, 228, 226, 223, 220, 215, 215, 220, 215, 211, 211, 209,
+168, 0, 5, 1, 0, 10, 12, 148, 143, 143, 135, 135, 4, 82, 40,
+ 4, 3, 1, 0, 3, 4, 38, 148, 0, 5, 143, 0, 6, 4, 148,
+143, 143, 38, 1, 3, 4, 0, 4, 1, 4, 4, 40, 10, 167, 0,
+ 5, 55, 4, 1, 1, 76, 0, 11, 167, 0, 15, 121, 1, 1, 4,
+ 4, 37, 114, 119, 63, 4, 1, 4, 1, 25, 181, 0, 9, 167, 0,
+ 3, 148, 1, 74, 0, 3, 167, 1, 76, 1, 117, 7, 167, 0, 9,
+ 40, 4, 1, 4, 4, 70, 70, 119, 119, 0, 0, 0, 1, 119, 1,
+ 73, 4, 1, 0, 17, 78, 211, 211, 208, 199, 199, 197, 199, 199, 208,
+208, 195, 162, 179, 219, 91, 4, 0, 20, 1, 0, 20, 10, 252, 244,
+238, 233, 226, 223, 220, 215, 215, 223, 223, 220, 220, 215, 220, 215, 210,
+235, 18, 7, 1, 0, 12, 46, 234, 238, 238, 233, 226, 223, 223, 220,
+195, 153, 115, 6, 1, 0, 12, 28, 228, 228, 226, 223, 220, 215, 211,
+209, 179, 136, 39, 3, 1, 0, 6, 4, 248, 244, 238, 234, 233, 3,
+226, 0, 29, 223, 139, 1, 12, 232, 244, 238, 234, 233, 226, 222, 188,
+ 4, 1, 1, 12, 212, 244, 238, 234, 233, 233, 228, 226, 223, 223, 220,
+235, 54, 0, 8, 1, 0, 5, 249, 244, 244, 234, 228, 0, 3, 226,
+ 0, 12, 223, 122, 1, 7, 229, 248, 238, 234, 233, 226, 226, 164, 3,
+ 1, 0, 7, 10, 232, 244, 238, 238, 234, 233, 0, 3, 228, 0, 4,
+226, 215, 235, 42, 6, 1, 1, 127, 6, 148, 0, 9, 30, 4, 4,
+ 1, 1, 4, 1, 19, 156, 0, 5, 148, 0, 7, 4, 156, 148, 148,
+ 82, 1, 1, 0, 4, 4, 1, 1, 1, 30, 8, 181, 0, 8, 167,
+181, 86, 1, 4, 1, 181, 167, 4, 181, 1, 167, 3, 181, 0, 4,
+167, 181, 66, 4, 3, 1, 1, 65, 3, 119, 1, 11, 3, 4, 0,
+ 6, 1, 95, 167, 181, 181, 167, 3, 181, 0, 5, 167, 181, 181, 43,
+ 61, 0, 3, 181, 1, 95, 1, 86, 7, 181, 0, 9, 55, 1, 4,
+ 1, 4, 70, 70, 119, 119, 0, 0, 0, 1, 119, 1, 63, 4, 1,
+ 0, 15, 137, 215, 215, 211, 208, 204, 199, 199, 204, 199, 197, 195, 153,
+170, 18, 0, 8, 1, 0, 3, 4, 104, 104, 0, 13, 1, 0, 17,
+ 57, 252, 244, 238, 234, 233, 228, 226, 226, 233, 228, 226, 226, 223, 240,
+ 94, 4, 0, 8, 1, 0, 12, 10, 253, 252, 252, 248, 249, 250, 250,
+242, 235, 219, 191, 6, 1, 0, 12, 44, 234, 238, 234, 233, 233, 226,
+223, 215, 195, 161, 35, 3, 1, 0, 7, 4, 237, 252, 253, 252, 249,
+250, 0, 3, 242, 1, 81, 3, 1, 0, 6, 20, 96, 163, 163, 81,
+ 18, 6, 1, 0, 11, 20, 128, 248, 248, 249, 249, 250, 242, 139, 28,
+ 4, 0, 9, 1, 0, 10, 232, 252, 253, 252, 249, 250, 250, 242, 242,
+ 46, 3, 1, 0, 6, 20, 96, 163, 163, 81, 14, 6, 1, 0, 11,
+ 20, 146, 248, 248, 249, 245, 250, 229, 122, 28, 4, 0, 6, 1, 1,
+ 95, 6, 156, 0, 10, 167, 19, 4, 1, 4, 4, 1, 4, 1, 167,
+ 5, 156, 0, 17, 4, 167, 156, 156, 148, 1, 4, 1, 4, 4, 1,
+ 4, 19, 203, 181, 181, 192, 0, 3, 181, 0, 8, 192, 181, 192, 127,
+ 1, 1, 25, 192, 10, 181, 0, 7, 192, 25, 1, 4, 4, 5, 65,
+ 0, 3, 119, 1, 87, 1, 1, 3, 4, 1, 12, 1, 206, 6, 181,
+ 0, 10, 192, 181, 181, 192, 47, 192, 181, 181, 148, 25, 7, 181, 0,
+ 9, 76, 1, 1, 4, 4, 65, 65, 119, 119, 0, 0, 0, 1, 119,
+ 1, 63, 4, 1, 1, 137, 3, 220, 0, 10, 210, 211, 208, 208, 209,
+195, 187, 179, 157, 23, 8, 1, 0, 5, 39, 111, 100, 100, 78, 0,
+ 13, 1, 0, 6, 4, 28, 128, 252, 248, 248, 3, 245, 0, 5, 250,
+250, 164, 46, 8, 0, 12, 1, 3, 4, 3, 7, 0, 4, 8, 8,
+ 10, 4, 6, 1, 0, 12, 44, 248, 252, 252, 248, 245, 245, 226, 223,
+219, 210, 35, 9, 1, 0, 4, 4, 4, 8, 8, 19, 1, 0, 4,
+ 7, 8, 12, 4, 18, 1, 0, 4, 4, 4, 8, 8, 19, 1, 0,
+ 4, 7, 8, 8, 4, 9, 1, 1, 66, 7, 167, 0, 10, 121, 1,
+ 1, 4, 4, 1, 4, 4, 1, 148, 4, 167, 1, 156, 1, 7, 4,
+167, 0, 5, 4, 1, 1, 4, 1, 0, 3, 4, 1, 213, 9, 192,
+ 0, 4, 167, 1, 1, 51, 11, 192, 1, 181, 1, 1, 3, 4, 1,
+ 16, 1, 88, 4, 119, 1, 22, 3, 4, 1, 1, 1, 66, 10, 192,
+ 1, 181, 4, 192, 1, 1, 7, 192, 1, 117, 1, 1, 3, 4, 0,
+ 4, 56, 65, 119, 119, 0, 0, 1, 119, 1, 70, 4, 1, 0, 13,
+ 94, 220, 220, 215, 215, 210, 211, 208, 208, 197, 187, 153, 134, 0, 7,
+ 1, 0, 8, 15, 91, 113, 109, 108, 100, 113, 18, 5, 1, 1, 24,
+ 1, 4, 9, 1, 0, 6, 7, 20, 28, 28, 18, 10, 33, 1, 1,
+ 10, 3, 20, 4, 28, 1, 32, 1, 32, 90, 1, 0, 12, 106, 181,
+181, 167, 181, 167, 181, 167, 181, 4, 4, 1, 4, 4, 0, 9, 1,
+ 1, 135, 167, 167, 181, 167, 167, 7, 0, 4, 181, 1, 12, 6, 4,
+ 1, 1, 1, 181, 5, 203, 3, 206, 0, 8, 203, 213, 1, 1, 148,
+203, 206, 206, 3, 203, 1, 206, 4, 203, 0, 6, 117, 1, 1, 4,
+ 1, 45, 5, 119, 0, 9, 103, 1, 1, 4, 1, 7, 213, 203, 206,
+ 0, 3, 203, 1, 206, 7, 203, 0, 3, 206, 47, 181, 0, 6, 203,
+ 0, 9, 143, 1, 1, 4, 1, 45, 65, 119, 119, 0, 0, 0, 1,
+119, 1, 87, 4, 1, 0, 14, 32, 223, 220, 215, 215, 211, 211, 208,
+208, 209, 187, 145, 124, 29, 4, 1, 0, 10, 35, 78, 113, 109, 126,
+140, 133, 109, 105, 115, 5, 1, 0, 3, 41, 63, 34, 0, 22, 1,
+ 0, 4, 31, 114, 119, 13, 74, 1, 0, 4, 11, 88, 114, 17, 41,
+ 1, 1, 25, 1, 156, 8, 181, 1, 95, 1, 1, 3, 4, 0, 6,
+ 9, 4, 4, 1, 1, 117, 5, 181, 1, 4, 4, 181, 1, 19, 1,
+ 4, 3, 1, 0, 8, 4, 1, 1, 121, 206, 213, 206, 213, 5, 206,
+ 0, 4, 218, 25, 12, 218, 4, 206, 1, 213, 5, 206, 0, 7, 213,
+ 58, 4, 1, 4, 4, 70, 0, 6, 119, 0, 6, 34, 1, 4, 4,
+ 1, 51, 14, 206, 1, 148, 1, 61, 6, 206, 1, 181, 1, 1, 3,
+ 4, 0, 4, 37, 63, 119, 119, 0, 0, 1, 119, 1, 119, 5, 1,
+ 0, 28, 228, 226, 215, 215, 211, 208, 197, 195, 187, 179, 149, 116, 123,
+ 67, 69, 78, 111, 113, 116, 131, 145, 153, 177, 177, 140, 109, 105, 59,
+ 4, 1, 0, 5, 27, 63, 119, 77, 11, 0, 19, 1, 1, 63, 3,
+119, 1, 114, 1, 24, 54, 1, 0, 5, 9, 45, 87, 88, 41, 0,
+ 12, 1, 1, 31, 1, 73, 4, 119, 1, 34, 21, 1, 0, 5, 11,
+ 45, 88, 87, 37, 0, 12, 1, 0, 3, 47, 130, 206, 0, 8, 192,
+ 1, 181, 3, 1, 0, 8, 4, 4, 98, 4, 1, 4, 4, 95, 5,
+192, 1, 7, 1, 135, 3, 192, 0, 3, 47, 1, 1, 0, 3, 4,
+ 0, 4, 1, 1, 66, 218, 6, 213, 0, 6, 206, 213, 218, 40, 43,
+218, 10, 213, 1, 224, 1, 12, 3, 4, 1, 9, 1, 73, 6, 119,
+ 1, 114, 1, 1, 4, 4, 1, 206, 13, 213, 1, 192, 1, 7, 6,
+213, 1, 218, 1, 1, 3, 4, 0, 4, 31, 63, 114, 119, 0, 0,
+ 0, 3, 119, 119, 22, 0, 4, 1, 0, 28, 229, 228, 220, 211, 211,
+208, 197, 199, 195, 187, 169, 145, 133, 131, 129, 129, 133, 133, 149, 162,
+169, 187, 195, 197, 169, 133, 109, 125, 4, 1, 1, 13, 1, 77, 3,
+119, 1, 73, 1, 31, 14, 1, 1, 24, 1, 60, 7, 119, 0, 7,
+ 77, 45, 31, 22, 17, 17, 16, 0, 3, 13, 0, 7, 11, 11, 17,
+ 37, 73, 119, 56, 0, 16, 1, 0, 21, 41, 56, 41, 34, 31, 27,
+ 27, 24, 17, 16, 17, 34, 56, 107, 119, 103, 70, 52, 52, 70, 107,
+ 0, 6, 119, 0, 10, 87, 52, 34, 17, 13, 16, 24, 37, 52, 87,
+ 8, 119, 0, 21, 98, 56, 41, 31, 31, 27, 27, 22, 17, 16, 17,
+ 34, 56, 114, 119, 103, 65, 50, 52, 70, 107, 0, 6, 119, 0, 3,
+ 87, 52, 4, 0, 3, 1, 0, 9, 4, 30, 99, 156, 213, 206, 203,
+203, 206, 0, 6, 203, 0, 14, 206, 64, 4, 4, 1, 4, 22, 119,
+ 5, 1, 4, 1, 55, 206, 4, 203, 0, 10, 192, 4, 206, 203, 203,
+110, 1, 4, 4, 1, 3, 4, 1, 33, 5, 218, 1, 213, 1, 213,
+ 3, 218, 0, 20, 64, 117, 218, 218, 213, 218, 218, 213, 218, 218, 213,
+218, 218, 181, 1, 1, 4, 1, 24, 98, 7, 119, 0, 6, 45, 1,
+ 4, 1, 1, 33, 7, 218, 1, 213, 4, 218, 0, 4, 213, 218, 12,
+224, 5, 218, 0, 9, 227, 4, 4, 1, 4, 22, 63, 98, 119, 0,
+ 0, 0, 0, 3, 119, 119, 56, 0, 4, 1, 0, 5, 28, 231, 226,
+215, 211, 0, 5, 208, 0, 18, 195, 177, 162, 177, 177, 162, 177, 179,
+195, 197, 187, 195, 199, 204, 195, 161, 138, 35, 4, 1, 1, 27, 7,
+119, 0, 5, 87, 50, 31, 17, 5, 0, 3, 1, 0, 4, 11, 27,
+ 41, 73, 27, 119, 0, 5, 114, 45, 24, 11, 4, 0, 4, 1, 1,
+ 4, 3, 1, 0, 3, 11, 34, 88, 0, 73, 119, 0, 10, 107, 4,
+ 1, 1, 4, 1, 181, 206, 206, 213, 10, 206, 0, 14, 167, 1, 1,
+ 4, 1, 4, 119, 119, 5, 1, 4, 4, 33, 218, 4, 206, 0, 7,
+213, 19, 218, 213, 213, 192, 1, 0, 3, 4, 0, 5, 1, 4, 4,
+ 25, 227, 0, 4, 218, 3, 224, 0, 4, 218, 218, 121, 218, 4, 224,
+ 1, 218, 5, 224, 0, 3, 218, 99, 1, 0, 3, 4, 1, 52, 9,
+119, 0, 9, 5, 4, 4, 1, 1, 203, 224, 218, 224, 0, 3, 218,
+ 0, 3, 224, 224, 218, 0, 4, 224, 1, 86, 1, 156, 5, 227, 0,
+ 9, 239, 19, 4, 4, 1, 13, 63, 88, 119, 0, 0, 0, 0, 3,
+119, 119, 98, 0, 5, 1, 0, 19, 163, 234, 228, 220, 215, 211, 211,
+215, 215, 211, 197, 179, 187, 204, 208, 209, 208, 211, 208, 0, 3, 211,
+ 0, 4, 208, 199, 193, 29, 5, 1, 1, 77, 135, 119, 0, 6, 11,
+ 4, 4, 1, 1, 82, 13, 213, 1, 224, 1, 40, 3, 1, 0, 10,
+ 4, 37, 119, 119, 13, 4, 1, 4, 1, 224, 4, 213, 0, 6, 218,
+ 7, 43, 43, 40, 43, 4, 1, 3, 4, 0, 4, 12, 239, 227, 227,
+ 7, 224, 0, 7, 227, 224, 227, 224, 224, 227, 227, 0, 4, 224, 0,
+ 4, 227, 230, 43, 1, 3, 4, 1, 73, 9, 119, 1, 56, 3, 4,
+ 1, 1, 1, 19, 3, 227, 4, 224, 4, 227, 0, 18, 224, 224, 206,
+ 19, 51, 51, 47, 43, 43, 47, 7, 1, 1, 4, 11, 65, 77, 119,
+ 0, 0, 3, 119, 1, 27, 5, 1, 0, 13, 212, 238, 231, 226, 215,
+208, 211, 215, 215, 210, 208, 208, 211, 0, 3, 215, 5, 220, 1, 219,
+ 1, 176, 6, 1, 1, 4, 135, 119, 1, 73, 3, 4, 1, 1, 1,
+ 7, 14, 218, 0, 6, 148, 1, 4, 1, 1, 4, 3, 119, 0, 6,
+ 37, 4, 4, 1, 1, 213, 5, 218, 0, 6, 203, 203, 192, 203, 206,
+ 19, 3, 1, 4, 4, 1, 241, 16, 227, 1, 230, 4, 227, 0, 7,
+241, 4, 4, 1, 4, 11, 77, 0, 10, 119, 0, 6, 9, 4, 1,
+ 4, 1, 167, 10, 227, 0, 3, 230, 227, 227, 0, 5, 213, 0, 10,
+206, 218, 40, 4, 4, 1, 9, 65, 73, 119, 0, 0, 3, 119, 1,
+107, 6, 1, 0, 7, 178, 244, 238, 233, 220, 215, 220, 0, 3, 215,
+ 0, 4, 210, 215, 215, 220, 3, 215, 0, 4, 220, 220, 225, 94, 6,
+ 1, 1, 2, 1, 103, 135, 119, 1, 4, 4, 1, 1, 148, 4, 224,
+ 1, 218, 5, 224, 0, 5, 218, 224, 224, 230, 25, 0, 3, 4, 1,
+ 1, 1, 52, 3, 119, 0, 6, 60, 1, 1, 4, 1, 181, 4, 224,
+ 1, 218, 5, 224, 0, 9, 30, 4, 1, 1, 4, 1, 4, 1, 206,
+ 0, 4, 230, 0, 3, 227, 230, 227, 0, 5, 230, 3, 227, 0, 8,
+230, 230, 227, 227, 230, 230, 167, 1, 3, 4, 1, 31, 1, 103, 10,
+119, 0, 9, 77, 4, 1, 4, 1, 4, 230, 227, 227, 0, 7, 230,
+ 3, 227, 3, 230, 3, 227, 0, 9, 239, 58, 4, 4, 1, 6, 70,
+ 65, 119, 0, 0, 0, 4, 119, 1, 73, 6, 1, 0, 6, 57, 237,
+244, 234, 228, 226, 3, 223, 0, 9, 220, 220, 223, 226, 226, 220, 215,
+225, 139, 0, 7, 1, 1, 4, 1, 107, 135, 119, 1, 41, 1, 1,
+ 3, 4, 0, 7, 33, 230, 224, 227, 224, 227, 224, 0, 4, 227, 0,
+ 10, 224, 227, 224, 227, 110, 1, 4, 1, 1, 13, 4, 119, 0, 10,
+103, 4, 1, 4, 1, 143, 227, 227, 224, 227, 5, 224, 0, 3, 227,
+ 55, 1, 0, 5, 4, 1, 1, 1, 127, 4, 230, 1, 239, 3, 230,
+ 0, 19, 239, 230, 230, 239, 230, 239, 230, 227, 230, 239, 230, 230, 239,
+ 74, 1, 4, 4, 1, 60, 0, 12, 119, 1, 17, 4, 1, 0, 3,
+135, 230, 239, 0, 10, 230, 1, 227, 6, 230, 0, 8, 82, 1, 1,
+ 4, 4, 70, 65, 119, 0, 0, 5, 119, 1, 37, 7, 1, 0, 7,
+ 53, 212, 237, 238, 234, 233, 231, 0, 4, 228, 0, 3, 231, 201, 42,
+ 0, 8, 1, 1, 11, 136, 119, 0, 7, 107, 1, 4, 4, 1, 1,
+203, 0, 3, 227, 0, 17, 230, 230, 227, 227, 230, 227, 230, 230, 227,
+227, 241, 12, 1, 4, 1, 1, 77, 0, 5, 119, 0, 5, 2, 1,
+ 4, 1, 110, 0, 3, 227, 1, 224, 1, 230, 5, 227, 0, 4, 130,
+ 1, 4, 1, 3, 4, 0, 3, 1, 58, 230, 0, 6, 239, 0, 5,
+230, 230, 239, 239, 230, 0, 7, 239, 0, 8, 230, 246, 33, 1, 4,
+ 4, 9, 77, 12, 119, 1, 88, 3, 4, 0, 3, 1, 1, 230, 0,
+ 7, 239, 1, 230, 3, 239, 0, 9, 230, 230, 239, 239, 230, 239, 239,
+110, 1, 0, 3, 4, 0, 3, 70, 65, 119, 0, 0, 0, 6, 119,
+ 1, 31, 9, 1, 1, 2, 1, 36, 3, 71, 1, 57, 1, 18, 11,
+ 1, 1, 41, 137, 119, 0, 10, 11, 4, 1, 4, 4, 95, 239, 230,
+227, 227, 3, 230, 0, 3, 227, 230, 227, 0, 4, 230, 0, 6, 61,
+ 1, 1, 4, 1, 24, 6, 119, 0, 5, 4, 1, 4, 4, 74, 0,
+ 10, 230, 0, 11, 218, 1, 4, 4, 1, 4, 4, 1, 25, 241, 241,
+ 0, 3, 239, 0, 3, 241, 239, 241, 0, 9, 239, 3, 241, 1, 247,
+ 4, 1, 1, 17, 1, 87, 13, 119, 0, 14, 31, 1, 1, 4, 4,
+ 99, 239, 241, 239, 241, 239, 241, 239, 241, 6, 239, 0, 12, 241, 239,
+241, 239, 135, 1, 1, 4, 4, 60, 65, 119, 0, 0, 7, 119, 1,
+ 60, 1, 2, 23, 1, 1, 5, 1, 107, 137, 119, 1, 77, 4, 4,
+ 0, 4, 1, 227, 239, 230, 5, 239, 1, 230, 1, 230, 3, 239, 0,
+ 8, 230, 241, 4, 1, 1, 4, 1, 107, 6, 119, 0, 30, 11, 1,
+ 4, 4, 40, 241, 230, 239, 230, 239, 239, 230, 239, 230, 239, 247, 7,
+ 4, 4, 1, 4, 4, 1, 19, 206, 203, 203, 206, 203, 224, 8, 241,
+ 1, 239, 3, 241, 0, 4, 239, 241, 148, 1, 3, 4, 1, 37, 1,
+114, 13, 119, 0, 9, 103, 4, 4, 1, 4, 1, 227, 241, 239, 0,
+ 15, 241, 0, 8, 167, 1, 4, 1, 4, 50, 65, 119, 0, 0, 8,
+119, 1, 114, 1, 11, 21, 1, 1, 63, 138, 119, 0, 7, 114, 4,
+ 4, 1, 4, 1, 135, 0, 3, 192, 1, 224, 10, 239, 1, 33, 1,
+ 1, 3, 4, 1, 37, 7, 119, 0, 7, 11, 4, 4, 1, 12, 247,
+241, 0, 3, 239, 0, 8, 230, 239, 241, 241, 239, 241, 25, 1, 6,
+ 4, 1, 117, 3, 110, 0, 3, 121, 7, 246, 0, 9, 241, 0, 10,
+246, 246, 241, 241, 47, 4, 1, 4, 1, 70, 15, 119, 0, 8, 45,
+ 1, 1, 4, 4, 61, 241, 246, 9, 241, 0, 3, 239, 241, 246, 0,
+ 3, 241, 1, 206, 1, 1, 3, 4, 0, 3, 41, 63, 119, 0, 0,
+ 0, 10, 119, 1, 88, 1, 11, 16, 1, 1, 16, 1, 87, 140, 119,
+ 1, 45, 4, 4, 1, 25, 3, 117, 1, 51, 1, 130, 9, 241, 0,
+ 6, 218, 1, 4, 1, 4, 4, 8, 119, 0, 9, 31, 1, 4, 4,
+ 1, 247, 241, 241, 239, 0, 3, 241, 0, 19, 246, 241, 239, 241, 38,
+ 4, 1, 4, 4, 1, 4, 1, 251, 241, 241, 246, 241, 25, 206, 0,
+ 6, 241, 1, 246, 4, 241, 0, 8, 246, 251, 25, 1, 4, 4, 11,
+ 77, 15, 119, 1, 114, 3, 4, 0, 3, 1, 1, 218, 0, 3, 241,
+ 1, 246, 8, 241, 1, 246, 3, 241, 0, 8, 239, 1, 1, 4, 1,
+ 31, 63, 114, 0, 0, 12, 119, 0, 3, 114, 88, 37, 0, 9, 1,
+ 0, 4, 11, 49, 98, 114, 141, 119, 0, 7, 98, 1, 1, 4, 4,
+ 1, 230, 0, 3, 241, 1, 117, 1, 130, 4, 241, 1, 246, 4, 241,
+ 0, 6, 19, 1, 4, 1, 1, 50, 8, 119, 0, 6, 50, 1, 1,
+ 4, 1, 213, 10, 241, 1, 66, 1, 1, 3, 4, 0, 4, 1, 4,
+ 1, 206, 4, 246, 0, 7, 127, 121, 247, 241, 241, 246, 241, 0, 4,
+246, 0, 10, 241, 246, 241, 246, 1, 4, 1, 4, 27, 88, 16, 119,
+ 0, 9, 60, 1, 4, 4, 1, 33, 255, 251, 254, 0, 3, 251, 1,
+254, 1, 251, 3, 246, 1, 241, 4, 246, 0, 8, 254, 1, 4, 1,
+ 1, 22, 63, 107, 0, 0, 16, 119, 1, 114, 1, 103, 4, 98, 1,
+107, 1, 114, 145, 119, 0, 6, 22, 1, 4, 4, 1, 82, 3, 241,
+ 0, 3, 246, 110, 130, 0, 3, 241, 0, 11, 246, 241, 246, 246, 241,
+148, 1, 1, 4, 4, 11, 0, 9, 119, 1, 87, 3, 4, 0, 21,
+ 1, 156, 241, 246, 246, 247, 241, 241, 246, 247, 241, 246, 143, 1, 4,
+ 1, 4, 1, 4, 1, 117, 0, 4, 247, 0, 5, 251, 19, 254, 246,
+247, 0, 7, 246, 0, 8, 247, 246, 121, 1, 1, 4, 1, 45, 18,
+119, 1, 1, 1, 4, 3, 1, 1, 33, 4, 40, 0, 4, 38, 38,
+ 12, 247, 6, 246, 0, 9, 247, 254, 12, 4, 1, 1, 11, 63, 98,
+ 0, 0, 0, 168, 119, 0, 27, 70, 4, 1, 4, 4, 1, 246, 246,
+241, 246, 241, 117, 130, 241, 241, 246, 241, 246, 241, 246, 246, 7, 4,
+ 1, 4, 1, 70, 0, 10, 119, 0, 24, 1, 1, 4, 4, 33, 58,
+ 55, 55, 4, 239, 246, 246, 241, 246, 241, 230, 1, 4, 1, 1, 4,
+ 1, 1, 47, 3, 247, 0, 12, 246, 251, 25, 213, 241, 239, 241, 241,
+239, 241, 241, 239, 3, 241, 1, 33, 4, 4, 1, 73, 18, 119, 1,
+ 77, 4, 4, 0, 3, 19, 254, 251, 0, 3, 247, 0, 18, 254, 38,
+241, 246, 247, 246, 246, 247, 247, 246, 251, 33, 1, 4, 4, 9, 65,
+ 87, 0, 0, 168, 119, 0, 6, 5, 4, 4, 1, 1, 167, 4, 246,
+ 0, 3, 241, 117, 143, 0, 3, 255, 0, 10, 251, 241, 241, 246, 99,
+ 1, 4, 4, 1, 24, 11, 119, 0, 5, 4, 1, 4, 4, 82, 0,
+ 3, 247, 1, 213, 1, 4, 5, 246, 0, 15, 254, 4, 4, 1, 4,
+ 1, 4, 4, 19, 247, 246, 246, 247, 247, 143, 0, 3, 58, 3, 61,
+ 0, 12, 58, 58, 61, 58, 55, 61, 4, 1, 4, 4, 17, 87, 19,
+119, 1, 6, 4, 1, 0, 3, 148, 247, 246, 0, 3, 247, 0, 17,
+192, 66, 246, 247, 247, 246, 246, 247, 247, 251, 47, 4, 4, 1, 9,
+ 65, 77, 0, 0, 0, 167, 119, 0, 7, 45, 4, 1, 4, 4, 25,
+247, 0, 5, 246, 1, 143, 3, 30, 0, 5, 19, 61, 255, 254, 251,
+ 0, 4, 1, 1, 4, 1, 88, 11, 119, 0, 10, 11, 1, 1, 4,
+ 47, 251, 247, 246, 247, 0, 3, 247, 0, 5, 246, 247, 251, 30, 1,
+ 0, 3, 4, 0, 8, 1, 4, 12, 251, 251, 246, 247, 247, 11, 251,
+ 0, 3, 254, 239, 1, 0, 3, 4, 1, 34, 1, 98, 19, 119, 0,
+ 7, 98, 4, 1, 4, 4, 7, 251, 0, 4, 247, 0, 6, 241, 4,
+251, 247, 251, 251, 3, 247, 0, 8, 251, 66, 4, 1, 1, 4, 65,
+ 65, 0, 0, 166, 119, 0, 11, 98, 4, 4, 1, 4, 4, 239, 247,
+246, 247, 246, 0, 3, 247, 0, 7, 254, 251, 251, 254, 47, 25, 25,
+ 0, 5, 4, 1, 37, 12, 119, 0, 6, 16, 1, 4, 4, 30, 254,
+ 3, 247, 1, 1, 4, 247, 0, 3, 246, 247, 47, 0, 6, 4, 1,
+ 7, 1, 251, 14, 247, 0, 8, 251, 247, 82, 1, 1, 4, 4, 50,
+ 21, 119, 0, 7, 17, 1, 1, 4, 1, 117, 251, 0, 3, 247, 0,
+ 5, 251, 38, 246, 247, 246, 0, 4, 247, 0, 8, 251, 95, 1, 1,
+ 4, 4, 65, 65, 0, 0, 166, 119, 0, 6, 27, 4, 1, 4, 1,
+ 61, 12, 247, 0, 9, 251, 255, 241, 1, 4, 1, 1, 4, 107, 0,
+ 12, 119, 1, 26, 3, 4, 1, 1, 1, 255, 3, 247, 1, 1, 1,
+251, 5, 247, 1, 86, 1, 1, 3, 4, 3, 1, 1, 251, 1, 251,
+ 6, 247, 1, 251, 7, 247, 0, 7, 251, 19, 1, 4, 4, 2, 77,
+ 0, 21, 119, 1, 114, 1, 2, 4, 1, 1, 246, 4, 247, 0, 3,
+203, 74, 251, 0, 6, 247, 0, 7, 127, 1, 1, 4, 2, 70, 65,
+ 0, 0, 0, 166, 119, 0, 6, 1, 4, 1, 1, 7, 255, 8, 247,
+ 1, 251, 4, 247, 0, 3, 251, 30, 4, 0, 3, 1, 1, 52, 13,
+119, 0, 11, 45, 4, 4, 1, 1, 241, 247, 251, 251, 1, 251, 0,
+ 5, 247, 0, 5, 156, 1, 4, 4, 1, 0, 3, 4, 1, 192, 1,
+251, 8, 247, 0, 13, 251, 247, 251, 251, 247, 247, 254, 7, 4, 1,
+ 1, 24, 88, 0, 22, 119, 1, 27, 3, 4, 0, 8, 1, 74, 251,
+251, 247, 247, 246, 1, 6, 247, 0, 8, 251, 148, 1, 4, 1, 4,
+ 65, 65, 0, 0, 166, 119, 1, 1, 3, 4, 0, 9, 1, 95, 181,
+227, 254, 254, 251, 247, 251, 0, 6, 247, 0, 7, 192, 1, 1, 4,
+ 1, 1, 114, 0, 13, 119, 1, 70, 4, 1, 0, 5, 181, 247, 251,
+251, 1, 0, 4, 247, 0, 6, 251, 247, 230, 1, 1, 4, 4, 1,
+ 0, 3, 99, 251, 251, 0, 8, 247, 3, 251, 0, 4, 247, 247, 206,
+ 1, 3, 4, 1, 41, 1, 107, 23, 119, 0, 15, 5, 4, 1, 4,
+ 1, 230, 247, 251, 247, 251, 33, 241, 251, 247, 247, 0, 3, 251, 0,
+ 7, 181, 1, 4, 1, 4, 52, 77, 0, 0, 0, 166, 119, 0, 5,
+ 11, 1, 4, 1, 4, 0, 4, 1, 0, 6, 55, 135, 206, 230, 254,
+251, 4, 247, 4, 4, 1, 1, 1, 77, 14, 119, 0, 6, 114, 1,
+ 4, 1, 1, 130, 3, 247, 1, 1, 1, 251, 4, 247, 1, 251, 1,
+255, 5, 4, 0, 3, 1, 1, 38, 0, 3, 251, 0, 3, 247, 251,
+247, 0, 3, 251, 0, 3, 247, 247, 251, 0, 3, 247, 1, 51, 3,
+ 1, 1, 4, 1, 56, 24, 119, 0, 25, 41, 4, 4, 1, 4, 43,
+251, 251, 247, 247, 192, 82, 247, 251, 247, 251, 247, 247, 203, 1, 4,
+ 4, 1, 45, 114, 0, 0, 0, 166, 119, 0, 4, 45, 4, 1, 1,
+ 4, 4, 5, 1, 0, 6, 4, 61, 156, 213, 224, 76, 3, 4, 1,
+ 1, 1, 9, 16, 119, 4, 4, 0, 13, 76, 247, 247, 251, 135, 33,
+247, 251, 247, 247, 251, 254, 33, 0, 4, 1, 0, 3, 4, 1, 7,
+ 0, 3, 251, 3, 247, 0, 15, 251, 247, 251, 247, 247, 251, 247, 247,
+251, 7, 4, 4, 1, 5, 83, 0, 25, 119, 1, 6, 1, 4, 3,
+ 1, 1, 203, 3, 251, 0, 15, 247, 1, 247, 241, 239, 224, 213, 206,
+ 33, 1, 4, 4, 1, 77, 119, 0, 0, 0, 167, 119, 0, 3, 26,
+ 4, 1, 0, 5, 4, 0, 7, 1, 4, 1, 4, 1, 4, 4, 0,
+ 3, 1, 0, 5, 4, 4, 1, 4, 107, 0, 16, 119, 0, 5, 11,
+ 4, 4, 1, 51, 0, 3, 251, 0, 16, 247, 1, 247, 247, 251, 251,
+247, 251, 58, 1, 4, 4, 1, 1, 4, 7, 4, 247, 4, 251, 7,
+247, 3, 4, 0, 3, 1, 31, 98, 0, 25, 119, 0, 11, 52, 4,
+ 4, 1, 4, 1, 74, 95, 58, 33, 4, 0, 5, 1, 0, 8, 4,
+ 4, 1, 4, 1, 6, 119, 119, 0, 0, 168, 119, 0, 3, 73, 11,
+ 6, 0, 4, 4, 0, 4, 1, 4, 4, 1, 3, 4, 1, 1, 1,
+ 4, 4, 1, 1, 26, 17, 119, 1, 17, 3, 4, 0, 8, 33, 255,
+247, 251, 247, 1, 251, 247, 3, 251, 0, 5, 247, 106, 1, 4, 1,
+ 0, 4, 4, 0, 4, 251, 247, 247, 251, 4, 247, 3, 251, 0, 4,
+247, 247, 251, 156, 3, 1, 0, 3, 4, 45, 114, 0, 26, 119, 0,
+ 3, 16, 4, 1, 0, 4, 4, 0, 7, 1, 1, 4, 4, 1, 4,
+ 1, 0, 4, 4, 0, 5, 1, 4, 50, 119, 119, 0, 0, 0, 172,
+119, 0, 5, 87, 41, 6, 7, 2, 0, 3, 4, 3, 1, 1, 4,
+ 1, 1, 3, 4, 18, 119, 1, 26, 3, 1, 0, 17, 12, 255, 251,
+251, 247, 47, 58, 247, 251, 247, 251, 251, 167, 1, 4, 1, 1, 0,
+ 3, 4, 0, 3, 247, 251, 251, 0, 3, 247, 1, 251, 4, 247, 0,
+ 5, 251, 247, 247, 33, 4, 0, 3, 1, 1, 63, 27, 119, 1, 88,
+ 4, 4, 4, 1, 0, 4, 4, 4, 1, 1, 3, 4, 0, 4, 1,
+ 4, 4, 31, 3, 119, 0, 0, 177, 119, 0, 11, 77, 37, 7, 2,
+ 1, 1, 4, 4, 1, 1, 98, 0, 18, 119, 1, 41, 3, 4, 0,
+ 40, 1, 254, 251, 247, 251, 251, 4, 246, 247, 251, 251, 247, 230, 1,
+ 1, 4, 4, 1, 4, 4, 167, 247, 251, 251, 247, 247, 251, 251, 247,
+251, 247, 254, 247, 247, 4, 1, 1, 4, 11, 107, 28, 119, 0, 8,
+ 88, 4, 4, 1, 1, 4, 1, 4, 3, 1, 0, 7, 4, 1, 4,
+ 4, 2, 4, 73, 0, 4, 119, 0, 0, 182, 119, 0, 4, 77, 37,
+ 31, 60, 20, 119, 0, 7, 60, 1, 1, 4, 1, 110, 251, 0, 3,
+247, 0, 16, 1, 246, 251, 251, 247, 247, 255, 1, 4, 4, 1, 1,
+ 4, 1, 86, 247, 3, 251, 1, 247, 4, 251, 0, 4, 254, 241, 181,
+ 12, 4, 1, 1, 50, 31, 119, 0, 13, 52, 4, 4, 1, 1, 4,
+ 13, 27, 41, 56, 77, 107, 114, 0, 7, 119, 0, 0, 206, 119, 0,
+ 43, 88, 4, 1, 4, 1, 4, 19, 82, 192, 254, 1, 247, 251, 247,
+251, 247, 255, 33, 4, 4, 1, 1, 4, 1, 4, 156, 167, 117, 64,
+ 33, 12, 12, 7, 4, 4, 1, 1, 4, 4, 1, 4, 4, 98, 0,
+ 33, 119, 1, 114, 1, 114, 16, 119, 0, 0, 207, 119, 0, 24, 4,
+ 4, 1, 1, 4, 4, 1, 1, 4, 4, 19, 76, 192, 255, 254, 255,
+ 58, 1, 1, 4, 4, 1, 4, 4, 7, 1, 1, 4, 1, 1, 6,
+ 4, 1, 1, 1, 52, 52, 119, 0, 0, 207, 119, 1, 41, 3, 4,
+ 0, 3, 1, 4, 4, 0, 3, 1, 1, 4, 3, 1, 0, 7, 19,
+ 30, 4, 1, 4, 1, 4, 0, 3, 1, 1, 4, 3, 1, 0, 7,
+ 4, 4, 1, 1, 4, 1, 1, 0, 4, 4, 1, 45, 53, 119, 0,
+ 0, 208, 119, 1, 37, 4, 4, 0, 5, 1, 4, 1, 4, 1, 0,
+ 4, 4, 1, 1, 4, 4, 0, 10, 5, 4, 4, 1, 1, 4, 1,
+ 4, 1, 1, 3, 4, 0, 6, 1, 1, 4, 1, 17, 83, 54, 119,
+ 0, 0, 209, 119, 0, 5, 88, 56, 31, 4, 4, 0, 3, 1, 1,
+ 4, 1, 1, 4, 4, 0, 8, 1, 4, 1, 1, 27, 98, 27, 1,
+ 4, 4, 0, 9, 5, 17, 31, 41, 56, 73, 77, 88, 107, 0, 56,
+119, 0, 0, 213, 119, 0, 4, 107, 77, 52, 31, 6, 4, 0, 4,
+ 1, 1, 4, 5, 3, 119, 0, 4, 114, 88, 88, 107, 66, 119, 0,
+ 0, 218, 119, 0, 8, 107, 77, 50, 34, 13, 1, 11, 41, 74, 119,
+ 0, 1
+};
diff --git a/engines/lure/detection.cpp b/engines/lure/detection.cpp
index a87fcf6945..690a358bc3 100644
--- a/engines/lure/detection.cpp
+++ b/engines/lure/detection.cpp
@@ -46,6 +46,7 @@ LureLanguage LureEngine::getLureLanguage() const {
case Common::FR_FRA: return LANG_FR_FRA;
case Common::DE_DEU: return LANG_DE_DEU;
case Common::ES_ESP: return LANG_ES_ESP;
+ case Common::RU_RUS: return LANG_RU_RUS;
case Common::EN_ANY: return LANG_EN_ANY;
case Common::UNK_LANG: return LANG_UNKNOWN;
default:
@@ -168,6 +169,21 @@ static const LureGameDescription gameDescriptions[] = {
GF_FLOPPY,
},
+ // Russian OG Edition
+ {
+ {
+ "lure",
+ "",
+ AD_ENTRY1("disk1.vga", "04cdcaa9f0cadca492f7aff0c8adfe06"),
+ Common::RU_RUS,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO0()
+ },
+ GF_FLOPPY,
+ },
+
+
{ AD_TABLE_END_MARKER, 0 }
};
@@ -177,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 {
@@ -226,10 +242,9 @@ SaveStateList LureMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Common::StringArray filenames;
Common::String saveDesc;
- Common::String pattern = "lure.???";
+ Common::String pattern = "lure.###";
filenames = saveFileMan->listSavefiles(pattern);
- sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
SaveStateList saveList;
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
@@ -246,6 +261,8 @@ SaveStateList LureMetaEngine::listSaves(const char *target) const {
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
diff --git a/engines/lure/game.cpp b/engines/lure/game.cpp
index efd33b6176..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;
@@ -1000,6 +1000,7 @@ bool Game::getYN() {
if (l == Common::FR_FRA) y = Common::KEYCODE_o;
else if ((l == Common::DE_DEU) || (l == Common::NL_NLD)) y = Common::KEYCODE_j;
else if ((l == Common::ES_ESP) || (l == Common::IT_ITA)) y = Common::KEYCODE_s;
+ else if (l == Common::RU_RUS) y = Common::KEYCODE_l;
bool vKbdFlag = g_system->hasFeature(OSystem::kFeatureVirtualKeyboard);
if (!vKbdFlag)
@@ -1018,7 +1019,12 @@ bool Game::getYN() {
while (events.pollEvent()) {
if (events.event().type == Common::EVENT_KEYDOWN) {
Common::KeyCode key = events.event().kbd.keycode;
- if ((key == y) || (key == Common::KEYCODE_n) ||
+ if (l == Common::RU_RUS) {
+ if ((key == y) || (key == Common::KEYCODE_y) || (key == Common::KEYCODE_ESCAPE)) {
+ breakFlag = true;
+ result = key == y;
+ }
+ } else if ((key == y) || (key == Common::KEYCODE_n) ||
(key == Common::KEYCODE_ESCAPE)) {
breakFlag = true;
result = key == y;
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 8a8299381e..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"
@@ -58,6 +57,7 @@ enum LureLanguage {
LANG_DE_DEU = 7,
LANG_ES_ESP = 17,
LANG_EN_ANY = 3,
+ LANG_RU_RUS = 3, // English data has been overridden
LANG_UNKNOWN = -1
};
diff --git a/engines/lure/menu.cpp b/engines/lure/menu.cpp
index 8867e8a626..8672f5fa87 100644
--- a/engines/lure/menu.cpp
+++ b/engines/lure/menu.cpp
@@ -75,6 +75,7 @@ const MenuRecordLanguage menuList[] = {
{Common::FR_FRA, {{40, 90, 3, 7}, {120, 195, 13, 11}, {232, 273, 23, 13}}},
{Common::DE_DEU, {{44, 95, 1, 11}, {135, 178, 8, 23}, {232, 273, 22, 15}}},
{Common::ES_ESP, {{40, 90, 3, 8}, {120, 195, 11, 13}, {208, 281, 17, 18}}},
+ {Common::RU_RUS, {{40, 87, 3, 7}, {127, 179, 13, 12}, {224, 281, 27, 10}}},
{Common::UNK_LANG, {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}}
};
@@ -378,9 +379,13 @@ uint16 PopupMenu::ShowItems(Action contextAction, uint16 roomNumber) {
++numItems;
}
- if (numItems == 0)
+ if (numItems == 0) {
// No items, so add a 'nothing' to the statusLine
- strcat(room.statusLine(), "(nothing)");
+ if (LureEngine::getReference().getLanguage() == Common::RU_RUS)
+ strcat(room.statusLine(), "(ybxtuj ytn)");
+ else
+ strcat(room.statusLine(), "(nothing)");
+ }
room.update();
screen.update();
diff --git a/engines/lure/res.cpp b/engines/lure/res.cpp
index 6b2705463d..7a79f48b87 100644
--- a/engines/lure/res.cpp
+++ b/engines/lure/res.cpp
@@ -44,6 +44,10 @@ Resources::Resources() : _rnd(LureEngine::getReference().rnd()) {
MemoryBlock *mb = Disk::getReference().getEntry(STRING_LIST_RESOURCE_ID);
_stringList.load(mb);
delete mb;
+
+ // WORKAROUND: In Spanish the look "Obsevar" should be "Observar"
+ if (!Common::String(_stringList.getString(LOOK)).compareTo("Obsevar"))
+ _stringList.setString(LOOK, "Observar");
}
Resources::~Resources() {
diff --git a/engines/lure/res_struct.cpp b/engines/lure/res_struct.cpp
index 5a4761c87b..ec1a546d05 100644
--- a/engines/lure/res_struct.cpp
+++ b/engines/lure/res_struct.cpp
@@ -1217,26 +1217,19 @@ void BarmanLists::loadFromStream(Common::ReadStream *stream) {
// String list resource class
void StringList::load(MemoryBlock *data) {
- _data = Memory::allocate(data->size());
- _data->copyFrom(data);
+ // Get the number of entries
+ uint numEntries = READ_LE_UINT16(data->data());
- _numEntries = READ_LE_UINT16(_data->data());
- char *p = (char *) _data->data() + sizeof(uint16);
-
- _entries = (char **) Memory::alloc(_numEntries * sizeof(char *));
-
- for (int index = 0; index < _numEntries; ++index) {
- _entries[index] = p;
+ // Iterate through loading the strings one at a time
+ const char *p = (const char *)data->data() + sizeof(uint16);
+ for (uint index = 0; index < numEntries; ++index) {
+ _entries.push_back(p);
p += strlen(p) + 1;
}
}
void StringList::clear() {
- if (_numEntries != 0) {
- Memory::dealloc(_entries);
- delete _data;
- _numEntries = 0;
- }
+ _entries.clear();
}
// Field list and miscellaneous variables
diff --git a/engines/lure/res_struct.h b/engines/lure/res_struct.h
index 9190912f5b..685c55ab13 100644
--- a/engines/lure/res_struct.h
+++ b/engines/lure/res_struct.h
@@ -28,6 +28,7 @@
#include "common/list.h"
#include "common/file.h"
#include "common/ptr.h"
+#include "common/str-array.h"
#include "common/textconsole.h"
namespace Lure {
@@ -850,22 +851,19 @@ enum StringEnum {S_CREDITS = 25, S_RESTART_GAME = 26, S_SAVE_GAME = 27, S_RESTOR
class StringList {
private:
- MemoryBlock *_data;
- int _numEntries;
- char **_entries;
+ Common::StringArray _entries;
public:
- StringList() { _numEntries = 0; }
- ~StringList() { clear(); }
+ StringList() {}
void load(MemoryBlock *data);
void clear();
- int count() { return _numEntries; }
+ int count() { return _entries.size(); }
const char *getString(int index) {
- if ((index < 0) || (index >= _numEntries)) error("Invalid index specified to String List");
- return _entries[index];
+ return _entries[index].c_str();
}
const char *getString(Action action) { return getString((int) action - 1); }
const char *getString(StringEnum sEnum) { return getString((int) sEnum); }
+ void setString(Action action, const Common::String &s) { _entries[(int)action - 1] = s; }
};
// The following class holds the field list used by the script engine as
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/lure/surface.cpp b/engines/lure/surface.cpp
index 17ac17814f..7cbef0fe85 100644
--- a/engines/lure/surface.cpp
+++ b/engines/lure/surface.cpp
@@ -1262,6 +1262,7 @@ static const ItemDesc copyProtectElements[] = {
{Common::NL_NLD, 57, 40, 208, 40, WORDING_HEADER, 32},
{Common::ES_ESP, 57, 40, 208, 40, WORDING_HEADER, 32},
{Common::IT_ITA, 57, 40, 208, 40, WORDING_HEADER, 32},
+ {Common::RU_RUS, 57, 40, 208, 40, WORDING_HEADER, 32},
{Common::UNK_LANG, 138, 168, 16, 8, NUMBER_HEADER, 32},
{Common::UNK_LANG, 145, 168, 16, 8, NUMBER_HEADER, 32},
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/action.h b/engines/mads/action.h
index 3ea10cd964..042fd971c9 100644
--- a/engines/mads/action.h
+++ b/engines/mads/action.h
@@ -30,6 +30,7 @@
namespace MADS {
enum TriggerMode {
+ SEQUENCE_TRIGGER_NONE = -1,
SEQUENCE_TRIGGER_PARSER = 0, // Triggers parser
SEQUENCE_TRIGGER_DAEMON = 1, // Triggers step/daemon code
SEQUENCE_TRIGGER_PREPARE = 2 // Triggers preparser
diff --git a/engines/mads/animation.cpp b/engines/mads/animation.cpp
index e4f44fc308..605c63e91d 100644
--- a/engines/mads/animation.cpp
+++ b/engines/mads/animation.cpp
@@ -162,6 +162,7 @@ Animation::Animation(MADSEngine *vm, Scene *scene) : _vm(vm), _scene(scene) {
_flags = 0;
_font = nullptr;
_resetFlag = false;
+ _canChangeView = false;
_messageCtr = 0;
_skipLoad = false;
_freeFlag = false;
@@ -177,6 +178,7 @@ Animation::Animation(MADSEngine *vm, Scene *scene) : _vm(vm), _scene(scene) {
_oldFrameEntry = 0;
_rgbResult = -1;
_palIndex1 = _palIndex2 = -1;
+ _dynamicHotspotIndex = -1;
}
Animation::~Animation() {
@@ -375,6 +377,7 @@ void Animation::loadFrame(int frameNumber) {
pt.x = _unkList[_unkIndex].x;
pt.y = _unkList[_unkIndex].y;
_unkIndex = 1 - _unkIndex;
+ warning("LoadFrame - Using unknown array");
}
if (drawFrame(spriteSet, pt, frameNumber))
@@ -463,21 +466,25 @@ void Animation::update() {
scene._spriteSlots.fullRefresh();
}
- // Handle any offset adjustment for sprites as of this frame
- bool paChanged = false;
- if (scene._posAdjust.x != misc._posAdjust.x) {
- scene._posAdjust.x = misc._posAdjust.x;
- paChanged = true;
- }
- if (scene._posAdjust.y != misc._posAdjust.y) {
- scene._posAdjust.y = misc._posAdjust.y;
- paChanged = true;
- }
+ bool isV2 = (_vm->getGameID() != GType_RexNebular);
+ if (isV2 && _canChangeView) {
+ // Handle any offset adjustment for sprites as of this frame
+ bool paChanged = false;
+ if (getFramePosAdjust(_currentFrame).x != scene._posAdjust.x) {
+ scene._posAdjust.x = getFramePosAdjust(_currentFrame).x;
+ paChanged = true;
+ }
+
+ if (getFramePosAdjust(_currentFrame).y != scene._posAdjust.y) {
+ scene._posAdjust.y = getFramePosAdjust(_currentFrame).y;
+ paChanged = true;
+ }
- if (paChanged) {
- int newIndex = scene._spriteSlots.add();
- scene._spriteSlots[newIndex]._seqIndex = -1;
- scene._spriteSlots[newIndex]._flags = IMG_REFRESH;
+ if (paChanged) {
+ int newIndex = scene._spriteSlots.add();
+ scene._spriteSlots[newIndex]._seqIndex = -1;
+ scene._spriteSlots[newIndex]._flags = IMG_REFRESH;
+ }
}
// Main frame animation loop - frames get animated by being placed, as necessary, into the
@@ -598,8 +605,8 @@ void Animation::setCurrentFrame(int frameNumber) {
_freeFlag = false;
}
-void Animation::setNextFrameTimer(int frameNumber) {
- _nextFrameTimer = frameNumber;
+void Animation::setNextFrameTimer(uint32 newTimer) {
+ _nextFrameTimer = newTimer;
}
void Animation::eraseSprites() {
@@ -611,4 +618,9 @@ void Animation::eraseSprites() {
}
}
+Common::Point Animation::getFramePosAdjust(int idx) {
+ warning("TODO: Implement getFramePosAdjust");
+
+ return Common::Point(0, 0);
+}
} // End of namespace MADS
diff --git a/engines/mads/animation.h b/engines/mads/animation.h
index 46ef85c5eb..a6a4cfbc8b 100644
--- a/engines/mads/animation.h
+++ b/engines/mads/animation.h
@@ -34,11 +34,12 @@
namespace MADS {
enum AnimFlag {
- ANIMFLAG_DITHER = 0x1000, // Dither to 16 colors
- ANIMFLAG_CUSTOM_FONT = 0x2000, // Load ccustom font
- ANIMFLAG_LOAD_BACKGROUND = 0x0100, // Load background
+ ANIMFLAG_LOAD_BACKGROUND = 0x0100, // Load background
ANIMFLAG_LOAD_BACKGROUND_ONLY = 0x0200, // Load background only
- ANIMFLAG_ANIMVIEW = 0x4000 // Cutscene animation
+
+ ANIMFLAG_DITHER = 0x0001, // Dither to 16 colors
+ ANIMFLAG_CUSTOM_FONT = 0x2000, // Load custom fonts
+ ANIMFLAG_ANIMVIEW = 0x4000 // Cutscene animation
};
enum AnimBgType {
@@ -189,8 +190,10 @@ public:
Common::Array<AnimUIEntry> _uiEntries;
Common::Array<AnimMessage> _messages;
bool _resetFlag;
+ bool _canChangeView;
int _currentFrame;
int _oldFrameEntry;
+ int _dynamicHotspotIndex;
static Animation *init(MADSEngine *vm, Scene *scene);
/*
@@ -224,8 +227,8 @@ public:
*/
void eraseSprites();
- void setNextFrameTimer(int frameNumber);
- int getNextFrameTimer() const { return _nextFrameTimer; }
+ void setNextFrameTimer(uint32 newTimer);
+ uint32 getNextFrameTimer() const { return _nextFrameTimer; }
void setCurrentFrame(int frameNumber);
int getCurrentFrame() const { return _currentFrame; }
@@ -235,6 +238,8 @@ public:
void resetSpriteSetsCount() { _header._spriteSetsCount = 0; } // CHECKME: See if it doesn't leak the memory when the destructor is called
SpriteAsset *getSpriteSet(int idx) { return _spriteSets[idx]; }
+
+ Common::Point getFramePosAdjust(int idx);
};
} // End of namespace MADS
diff --git a/engines/mads/assets.h b/engines/mads/assets.h
index 8a0dc2cd44..0aae534498 100644
--- a/engines/mads/assets.h
+++ b/engines/mads/assets.h
@@ -99,8 +99,9 @@ public:
int getCount() { return _frameCount; }
int getFrameRate() const { return _frameRate; }
int getPixelSpeed() const { return _pixelSpeed; }
- int getFrameWidth(int index);
- int getFrameHeight(int index);
+ Common::Point getFramePos(int index) { assert (index < _frameCount); return Common::Point(_frames[index]._bounds.left, _frames[index]._bounds.top); }
+ int getFrameWidth(int index) { assert (index < _frameCount); return _frames[index]._bounds.width(); }
+ int getFrameHeight(int index) { assert (index < _frameCount); return _frames[index]._bounds.height(); }
int getMaxFrameWidth() const { return _maxWidth; }
int getMaxFrameHeight() const { return _maxHeight; }
MSprite *getFrame(int frameIndex);
diff --git a/engines/mads/camera.cpp b/engines/mads/camera.cpp
new file mode 100644
index 0000000000..c9b2f1429e
--- /dev/null
+++ b/engines/mads/camera.cpp
@@ -0,0 +1,192 @@
+/* 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 "mads/mads.h"
+#include "mads/camera.h"
+
+namespace MADS {
+
+Camera::Camera(MADSEngine *vm) : _vm(vm) {
+ _panAllowedFl = false;
+ _activeFl = false;
+ _currentFrameFl = false;
+ _manualFl = false;
+ _speed = -1;
+ _rate = -1;
+ _target = -1;
+ _distOffCenter = -1;
+ _startTolerance = -1;
+ _endTolerance = -1;
+ _direction = -1;
+ _timer = 0;
+}
+
+void Camera::setDefaultPanX() {
+ _activeFl = false;
+ Scene &scene = _vm->_game->_scene;
+ _panAllowedFl = (scene._sceneInfo->_width > MADS_SCREEN_WIDTH);
+
+ if (_panAllowedFl) {
+ _manualFl = false;
+ _rate = 4;
+ _speed = 4;
+ _target = 0;
+ _distOffCenter = 80;
+ _startTolerance = 80;
+ _endTolerance = 4;
+ _timer = scene._frameStartTime;
+ }
+}
+
+void Camera::setDefaultPanY() {
+ _activeFl = false;
+ Scene &scene = _vm->_game->_scene;
+ _panAllowedFl = (scene._sceneInfo->_height > MADS_SCENE_HEIGHT);
+
+ if (_panAllowedFl) {
+ _manualFl = true;
+ _rate = 4;
+ _speed = 2;
+ _target = 0;
+ _distOffCenter = 80;
+ _startTolerance = 60;
+ _endTolerance = 4;
+ _timer = scene._frameStartTime;
+ }
+}
+
+void Camera::camPanTo(int target) {
+ if (_panAllowedFl) {
+ _activeFl = true;
+ _manualFl = true;
+ _target = target;
+ _timer = _vm->_game->_scene._frameStartTime;
+ }
+}
+
+bool Camera::camPan(int16 *picture_view, int16 *player_loc, int display_size, int picture_size) {
+ bool panningFl = false;
+ if (_panAllowedFl) {
+ Scene &scene = _vm->_game->_scene;
+ Player &player = _vm->_game->_player;
+
+ _currentFrameFl = false;
+
+ uint32 timer;
+ if ((abs((int32) (_timer - player._priorTimer)) < _rate) && (player._ticksAmount == _rate))
+ timer = player._priorTimer;
+ else
+ timer = _timer;
+
+ if (_activeFl && (scene._frameStartTime < timer))
+ return (panningFl);
+
+ _timer = scene._frameStartTime + _rate;
+
+ if (_manualFl) {
+ if (_activeFl) {
+ int diff = _target - *picture_view;
+ int direction = 0;
+ if (diff < 0)
+ direction = -1;
+ else if (diff > 0)
+ direction = 1;
+
+ int magnitude = MIN(abs(diff), _speed);
+
+ if (magnitude == 0)
+ _activeFl = false;
+ else {
+ int panAmount;
+ if (direction < 0)
+ panAmount = -magnitude;
+ else
+ panAmount = magnitude;
+
+ *picture_view += panAmount;
+
+ panningFl = true;
+ _currentFrameFl = true;
+ }
+ }
+ } else {
+ if (!_activeFl) {
+ int lowEdge = *picture_view + _startTolerance;
+ int highEdge = *picture_view - _startTolerance + display_size - 1;
+
+ if ((*player_loc < lowEdge) && (*picture_view > 0)) {
+ _activeFl = true;
+ _direction = -1;
+ }
+
+ if ((*player_loc > highEdge) && (*picture_view < (picture_size - display_size))) {
+ _activeFl = true;
+ _direction = 1;
+ }
+ }
+
+ int newTarget = *player_loc - (display_size >> 1);
+
+ if (_direction < 0)
+ newTarget -= _distOffCenter;
+ else
+ newTarget += _distOffCenter;
+
+ newTarget = MAX(0, newTarget);
+ newTarget = MIN(newTarget, (picture_size - display_size));
+
+ _target = newTarget;
+
+ int diff = newTarget - *picture_view;
+ int magnitude = abs(diff);
+
+ int direction = 0;
+ if (diff < 0)
+ direction = -1;
+ else if (diff > 0)
+ direction = 1;
+
+ if (_activeFl && (magnitude <= _endTolerance))
+ _activeFl = false;
+
+ if (_activeFl) {
+ magnitude = MIN(magnitude, _speed);
+
+ int panAmount;
+ if (direction < 0)
+ panAmount = -magnitude;
+ else
+ panAmount = magnitude;
+
+ if (panAmount) {
+ *picture_view += panAmount;
+ panningFl = true;
+ _currentFrameFl = true;
+ }
+ }
+ }
+ }
+
+ return (panningFl);
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/camera.h b/engines/mads/camera.h
new file mode 100644
index 0000000000..63f1f9f7ff
--- /dev/null
+++ b/engines/mads/camera.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 MADS_CAMERA_H
+#define MADS_CAMERA_H
+
+#include "mads/scene.h"
+#include "mads/player.h"
+#include "mads/camera.h"
+
+namespace MADS {
+
+class MADSEngine;
+
+class Camera {
+private:
+ MADSEngine *_vm;
+
+public:
+ bool _panAllowedFl;
+ bool _activeFl;
+ bool _currentFrameFl;
+ bool _manualFl;
+
+ int _speed;
+ int _rate;
+ int _target;
+ int _distOffCenter;
+ int _startTolerance;
+ int _endTolerance;
+ int _direction;
+ uint32 _timer;
+
+ Camera(MADSEngine *vm);
+
+ void camPanTo(int target);
+ bool camPan(int16 *picture_view, int16 *player_loc, int display_size, int picture_size);
+ void setDefaultPanX();
+ void setDefaultPanY();
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_CAMERA_H */
diff --git a/engines/mads/configure.engine b/engines/mads/configure.engine
index 60d833e9e8..21f2642c3f 100644
--- a/engines/mads/configure.engine
+++ b/engines/mads/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 mads "Rex Nebular and the Cosmic Gender Bender" no
+add_engine mads "MADS" yes
diff --git a/engines/mads/conversations.cpp b/engines/mads/conversations.cpp
new file mode 100644
index 0000000000..469aaedb81
--- /dev/null
+++ b/engines/mads/conversations.cpp
@@ -0,0 +1,1018 @@
+/* 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 "mads/conversations.h"
+#include "mads/mads.h"
+#include "mads/compression.h"
+#include "common/file.h"
+#include "common/util.h" // for Common::hexdump
+
+namespace MADS {
+
+GameConversations::GameConversations(MADSEngine *vm) : _vm(vm) {
+ _runningConv = nullptr;
+ _restoreRunning = 0;
+ _playerEnabled = false;
+ _inputMode = kInputBuildingSentences;
+ _startFrameNumber = 0;
+ _speakerVal = 0;
+ _currentMode = CONVMODE_NONE;
+ _priorMode = CONVMODE_NONE;
+ _popupVisible = false;
+ _verbId = 0;
+ _vars = _nextStartNode = nullptr;
+ _heroTrigger = 0;
+ _heroTriggerMode = SEQUENCE_TRIGGER_PARSER;
+ _interlocutorTrigger = 0;
+ _interlocutorTriggerMode = SEQUENCE_TRIGGER_PARSER;
+ _currentNode = 0;
+ _dialogNodeOffset = _dialogNodeSize = 0;
+ _dialog = nullptr;
+ _dialogAltFlag = false;
+ _personSpeaking = 0;
+
+ // Mark all conversation slots as empty
+ for (int idx = 0; idx < MAX_CONVERSATIONS; ++idx)
+ _conversations[idx]._convId = -1;
+}
+
+GameConversations::~GameConversations() {
+}
+
+void GameConversations::load(int id) {
+ // Scan through the conversation list for a free slot
+ int slotIndex = -1;
+ for (int idx = 0; idx < MAX_CONVERSATIONS && slotIndex == -1; ++idx) {
+ if (_conversations[idx]._convId == -1)
+ slotIndex = idx;
+ }
+ if (slotIndex == -1)
+ error("Too many conversations loaded");
+
+ // Set the conversation the slot will contain
+ _conversations[slotIndex]._convId = id;
+
+ // Load the conversation data
+ Common::String cnvFilename = Common::String::format("CONV%03d.CNV", id);
+ _conversations[slotIndex]._data.load(cnvFilename);
+
+ // Load the conversation's CND data
+ Common::String cndFilename = Common::String::format("CONV%03d.CND", id);
+ _conversations[slotIndex]._cnd.load(cndFilename);
+}
+
+ConversationEntry *GameConversations::getConv(int convId) {
+ for (uint idx = 0; idx < MAX_CONVERSATIONS; ++idx) {
+ if (_conversations[idx]._convId == convId)
+ return &_conversations[idx];
+ }
+
+ return nullptr;
+}
+
+void GameConversations::run(int id) {
+ // If another conversation is running, then stop it first
+ if (_runningConv)
+ stop();
+
+ // Get the next conversation to run
+ _runningConv = getConv(id);
+ if (!_runningConv)
+ error("Specified conversation %d not loaded", id);
+
+ // Initialize needed fields
+ _startFrameNumber = _vm->_events->getFrameCounter();
+ _playerEnabled = _vm->_game->_player._stepEnabled;
+ _inputMode = _vm->_game->_screenObjects._inputMode;
+ _heroTrigger = 0;
+ _interlocutorTrigger = 0;
+ _popupVisible = false;
+ _currentMode = CONVMODE_0;
+ _verbId = -1;
+ _speakerVal = 1;
+ _personSpeaking = 1;
+
+ // Initialize speaker arrays
+ Common::fill(&_speakerActive[0], &_speakerActive[MAX_SPEAKERS], false);
+ Common::fill(&_speakerSeries[0], &_speakerSeries[MAX_SPEAKERS], -1);
+ Common::fill(&_speakerFrame[0], &_speakerFrame[MAX_SPEAKERS], 1);
+ Common::fill(&_popupX[0], &_popupX[MAX_SPEAKERS], POPUP_CENTER);
+ Common::fill(&_popupY[0], &_popupY[MAX_SPEAKERS], POPUP_CENTER);
+ Common::fill(&_popupMaxLen[0], &_popupMaxLen[MAX_SPEAKERS], 30);
+
+ // Start the conversation
+ start();
+
+ // Setup variables to point to data in the speaker arrays
+ setVariable(2, &_speakerVal);
+ for (int idx = 0; idx < MAX_SPEAKERS; ++idx) {
+ setVariable(3 + idx, &_speakerFrame[idx]);
+ setVariable(8 + idx, &_popupX[idx]);
+ setVariable(13 + idx, &_popupY[idx]);
+ setVariable(18 + idx, &_popupMaxLen[idx]);
+ }
+
+ // Load sprite data for speaker portraits
+ for (uint idx = 0; idx < _runningConv->_data._speakerCount; ++idx) {
+ const Common::String &portraitName = _runningConv->_data._portraits[idx];
+ _speakerSeries[idx] = _vm->_game->_scene._sprites.addSprites(portraitName, PALFLAG_RESERVED);
+
+ if (_speakerSeries[idx] > 0) {
+ _speakerActive[idx] = true;
+ _speakerFrame[idx] = _runningConv->_data._speakerFrame[idx];
+ }
+ }
+
+ // Refresh colors if needed
+ if (_vm->_game->_kernelMode == KERNEL_ACTIVE_CODE)
+ _vm->_palette->refreshSceneColors();
+}
+
+void GameConversations::start() {
+ assert(_runningConv->_cnd._vars.size() >= 2);
+ _vars = &_runningConv->_cnd._vars[0];
+ _nextStartNode = &_runningConv->_cnd._vars[1];
+
+ _runningConv->_cnd._currentNode = -1;
+ _runningConv->_cnd._numImports = 0;
+ _runningConv->_cnd._vars[0].setValue(_nextStartNode->_val);
+
+ // Store a reference to the variables list in the script handler for later reference
+ ScriptEntry::Conditional::_vars = &_runningConv->_cnd._vars;
+}
+
+void GameConversations::setVariable(uint idx, int val) {
+ if (active())
+ _runningConv->_cnd._vars[idx].setValue(val);
+}
+
+void GameConversations::setVariable(uint idx, int *val) {
+ if (active())
+ _runningConv->_cnd._vars[idx].setValue(val);
+}
+
+void GameConversations::setStartNode(uint nodeIndex) {
+ assert(_nextStartNode && _nextStartNode->_isPtr == false);
+ _nextStartNode->_val = nodeIndex;
+}
+
+void GameConversations::stop() {
+ // Only need to proceed if there is an active conversation
+ if (!active())
+ return;
+
+ // Reset player enabled state if needed
+ if (_vm->_game->_kernelMode == KERNEL_ACTIVE_CODE)
+ _vm->_game->_player._stepEnabled = _playerEnabled;
+
+ // Remove any visible dialog window
+ removeActiveWindow();
+
+ // Release any sprites used for character portraits
+ for (int idx = 0; idx < _runningConv->_data._speakerCount; ++idx) {
+ if (_speakerActive[idx])
+ _vm->_game->_scene._sprites.remove(_speakerSeries[idx]);
+ }
+
+ // Flag conversation as no longer running
+ _runningConv = nullptr;
+
+ if (_inputMode == kInputConversation)
+ _vm->_game->_scene._userInterface.emptyConversationList();
+
+ _vm->_game->_scene._userInterface.setup(_inputMode);
+}
+
+void GameConversations::exportPointer(int *ptr) {
+ // Only need to proceed if there is an active conversation
+ if (!active())
+ return;
+
+ // Also don't proceed if the number of allowed imports has already been reached
+ if (_runningConv->_cnd._numImports >= _runningConv->_data._maxImports)
+ return;
+
+ // Get the variable to use for this next import and set it's value
+ int variableIndex = _runningConv->_cnd._importVariables[
+ _runningConv->_cnd._numImports++];
+ setVariable(variableIndex, ptr);
+}
+
+void GameConversations::exportValue(int val) {
+ // Only need to proceed if there is an active conversation
+ if (!active())
+ return;
+
+ // Also don't proceed if the number of allowed imports has already been reached
+ if (_runningConv->_cnd._numImports >= _runningConv->_data._maxImports)
+ return;
+
+ // Get the variable to use for this next import and set it's value
+ int variableIndex = _runningConv->_cnd._importVariables[
+ _runningConv->_cnd._numImports++];
+ setVariable(variableIndex, val);
+}
+
+void GameConversations::setHeroTrigger(int val) {
+ _heroTrigger = val;
+ _heroTriggerMode = _vm->_game->_triggerSetupMode;
+}
+
+void GameConversations::setInterlocutorTrigger(int val) {
+ _interlocutorTrigger = val;
+ _interlocutorTriggerMode = _vm->_game->_triggerSetupMode;
+}
+
+int *GameConversations::getVariable(int idx) {
+ assert(idx >= 0); // TODO: Some negative values are allowed? Investigate
+ return _vars[idx].getValue();
+}
+
+void GameConversations::hold() {
+ if (_currentMode != CONVMODE_NONE) {
+ _priorMode = _currentMode;
+ _currentMode = CONVMODE_NONE;
+ }
+}
+
+void GameConversations::release() {
+ if (_currentMode == CONVMODE_NONE) {
+ _currentMode = _priorMode;
+ if (_currentMode == 1 || _currentMode == 2)
+ update(true);
+ }
+}
+
+void GameConversations::flagEntry(DialogCommand mode, int entryIndex) {
+ assert(_runningConv);
+ uint &flags = _runningConv->_cnd._entryFlags[entryIndex];
+
+ switch (mode) {
+ case CMD_1:
+ flags |= ENTRYFLAG_4000;
+ flags &= ~ENTRYFLAG_8000;
+ break;
+
+ case CMD_HIDE:
+ flags &= ~ENTRYFLAG_8000;
+ break;
+
+ case CMD_UNHIDE:
+ if (!(flags & ENTRYFLAG_4000))
+ flags |= ENTRYFLAG_8000;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void GameConversations::reset(int id) {
+ warning("TODO: GameConversations::reset");
+}
+
+void GameConversations::update(bool flag) {
+ // Only need to proceed if there is an active conversation
+ if (!active())
+ return;
+
+ ConversationVar &var0 = _runningConv->_cnd._vars[0];
+
+ switch (_currentMode) {
+ case CONVMODE_0:
+ assert(var0.isNumeric());
+ if (var0._val < 0) {
+ if (_vm->_game->_scene._frameStartTime >= _startFrameNumber) {
+ removeActiveWindow();
+ if (_heroTrigger) {
+ _vm->_game->_scene._action._activeAction._verbId = _verbId;
+ _vm->_game->_trigger = _heroTrigger;
+ _vm->_game->_triggerMode = _heroTriggerMode;
+ _heroTrigger = 0;
+ }
+
+ _currentMode = CONVMODE_STOP;
+ }
+ } else {
+ bool isActive = nextNode();
+ _currentNode = var0._val;
+
+ if (isActive) {
+ _verbId = _runningConv->_data._nodes[_currentNode]._index;
+ _vm->_game->_scene._action._activeAction._verbId = _verbId;
+ _vm->_game->_scene._action._inProgress = true;
+ _vm->_game->_scene._action._savedFields._commandError = false;
+ _currentMode = CONVMODE_1;
+ } else {
+ _currentMode = generateMenu();
+ }
+ }
+ break;
+
+ case CONVMODE_1:
+ if (flag)
+ _currentMode = CONVMODE_3;
+ break;
+
+ case CONVMODE_2:
+ if (flag) {
+ _vm->_game->_player._stepEnabled = false;
+ _verbId = _vm->_game->_scene._action._activeAction._verbId;
+
+ if (!(_runningConv->_cnd._entryFlags[_verbId] & ENTRYFLAG_2))
+ flagEntry(CMD_HIDE, _verbId);
+
+ removeActiveWindow();
+ _vm->_game->_scene._userInterface.emptyConversationList();
+ _vm->_game->_scene._userInterface.setup(kInputConversation);
+ _personSpeaking = 0;
+ executeEntry(_verbId);
+
+ ConvDialog &dialog = _runningConv->_data._dialogs[_verbId];
+ if (dialog._speechIndex) {
+ _runningConv->_cnd._messageList3.clear();
+ _runningConv->_cnd._messageList3.push_back(dialog._speechIndex);
+ }
+
+ generateText(dialog._textLineIndex, _runningConv->_cnd._messageList3);
+ _currentMode = CONVMODE_0;
+
+ if (_heroTrigger) {
+ _vm->_game->_scene._action._activeAction._verbId = _verbId;
+ _vm->_game->_trigger = _heroTrigger;
+ _vm->_game->_triggerMode = _heroTriggerMode;
+ _heroTrigger = 0;
+ }
+ }
+ break;
+
+ case CONVMODE_3:
+ if (_vm->_game->_scene._frameStartTime >= _startFrameNumber) {
+ removeActiveWindow();
+ _personSpeaking = 0;
+ executeEntry(_verbId);
+ generateMessage(_runningConv->_cnd._messageList1, _runningConv->_cnd._messageList3);
+
+ if (_heroTrigger && _popupVisible) {
+ _vm->_game->_scene._action._activeAction._verbId = _verbId;
+ _vm->_game->_trigger = _heroTrigger;
+ _vm->_game->_triggerMode = _heroTriggerMode;
+ _heroTrigger = 0;
+ }
+
+ _currentMode = CONVMODE_4;
+ }
+ break;
+
+ case CONVMODE_4:
+ if (_vm->_game->_scene._frameStartTime >= _startFrameNumber) {
+ removeActiveWindow();
+ _personSpeaking = _speakerVal;
+
+ generateMessage(_runningConv->_cnd._messageList2, _runningConv->_cnd._messageList4);
+
+ if (_interlocutorTrigger && _popupVisible) {
+ _vm->_game->_scene._action._activeAction._verbId = _verbId;
+ _vm->_game->_trigger = _interlocutorTrigger;
+ _vm->_game->_triggerMode = _interlocutorTriggerMode;
+ _interlocutorTrigger = 0;
+ }
+ }
+ break;
+
+ case CONVMODE_STOP:
+ stop();
+ break;
+
+ default:
+ break;
+ }
+
+ warning("TODO: GameConversations::update");
+}
+
+void GameConversations::removeActiveWindow() {
+ warning("TODO: GameConversations::removeActiveWindow");
+}
+
+ConversationMode GameConversations::generateMenu() {
+ error("TODO: GameConversations::generateMenu");
+}
+
+void GameConversations::generateText(int textLineIndex, Common::Array<int> &messages) {
+ _dialogAltFlag = true;
+
+ error("TODO: GameConversations::generateText");
+}
+
+void GameConversations::generateMessage(Common::Array<int> &messageList, Common::Array<int> &voiceList) {
+ _dialogAltFlag = false;
+ if (messageList.size() == 0)
+ return;
+
+ if (_dialog)
+ delete _dialog;
+
+ // Get the speaker portrait
+ SpriteAsset &sprites = *_vm->_game->_scene._sprites[_speakerSeries[_personSpeaking]];
+ MSprite *portrait = sprites.getFrame(_speakerFrame[_personSpeaking]);
+
+ // Create the new text dialog
+ _dialog = new TextDialog(_vm, FONT_INTERFACE,
+ Common::Point(_popupX[_personSpeaking], _popupY[_personSpeaking]),
+ portrait, _popupMaxLen[_personSpeaking]);
+
+ // Add in the lines
+ for (uint msgNum = 0; msgNum < messageList.size(); ++msgNum) {
+ ConvMessage &msg = _runningConv->_data._messages[messageList[msgNum]];
+ uint stringIndex = msg._stringIndex;
+
+ for (uint strNum = 0; strNum < msg._count; ++strNum, ++stringIndex) {
+ Common::String textLine = _runningConv->_data._textLines[stringIndex];
+ textLine.trim();
+ _dialog->addLine(textLine);
+ }
+ }
+
+ // Show the dialog
+ _popupVisible = true;
+ _dialog->show();
+
+ // Play the speech if one was provided
+ if (voiceList.size() > 0) {
+ _vm->_audio->setSoundGroup(_runningConv->_data._speechFile);
+ _vm->_audio->playSound(voiceList[0] - 1);
+ }
+}
+
+bool GameConversations::nextNode() {
+ ConversationVar &var0 = _runningConv->_cnd._vars[0];
+ _runningConv->_cnd._currentNode = var0._val;
+ return _runningConv->_data._nodes[var0._val]._active;
+}
+
+int GameConversations::executeEntry(int index) {
+ ConvDialog &dlg = _runningConv->_data._dialogs[index];
+ ConversationVar &var0 = _runningConv->_cnd._vars[0];
+
+ _runningConv->_cnd._messageList1.clear();
+ _runningConv->_cnd._messageList2.clear();
+ _runningConv->_cnd._messageList3.clear();
+ _runningConv->_cnd._messageList4.clear();
+ _nextStartNode->_val = var0._val;
+
+ bool flag = true;
+ for (uint scriptIdx = 0; scriptIdx < dlg._script.size() && flag; ) {
+ ScriptEntry &scrEntry = dlg._script[scriptIdx];
+ if (scrEntry._command == CMD_END)
+ break;
+
+ switch (scrEntry._command) {
+ case CMD_1:
+ case CMD_HIDE:
+ case CMD_UNHIDE:
+ for (uint idx = 0; scrEntry._entries.size(); ++idx)
+ flagEntry(scrEntry._command, scrEntry._entries[idx]);
+ break;
+
+ case CMD_MESSAGE1:
+ case CMD_MESSAGE2:
+ scriptMessage(scrEntry);
+ break;
+
+ case CMD_ERROR:
+ error("Conversation script generated error");
+ break;
+
+ case CMD_NODE:
+ flag = !scriptNode(scrEntry);
+ break;
+
+ case CMD_GOTO: {
+ bool gotoFlag = scrEntry._conditionals[0].evaluate();
+ if (gotoFlag) {
+ scriptIdx = scrEntry._index;
+ continue;
+ }
+ break;
+ }
+
+ case CMD_ASSIGN: {
+ bool setFlag = scrEntry._conditionals[0].evaluate();
+ if (setFlag) {
+ int *ptr = _runningConv->_cnd._vars[scrEntry._index].getValue();
+ *ptr = scrEntry._conditionals[1].evaluate();
+ }
+ break;
+ }
+
+ default:
+ error("Unknown script opcode");
+ }
+
+ ++scriptIdx;
+ }
+
+ if (flag) {
+ var0._val = -1;
+ }
+
+ return var0._val;
+}
+
+void GameConversations::scriptMessage(ScriptEntry &scrEntry) {
+ // Check whether this operation should be done
+ bool doFlag = scrEntry._conditionals[0].evaluate();
+ if (!doFlag)
+ return;
+
+ // Figure out the entire range that messages can be selected from
+ int total = 0;
+ for (uint idx = 0; idx < scrEntry._entries2.size(); ++idx)
+ total += scrEntry._entries2[idx]._size;
+
+ // Choose a random entry from the list of possible values
+ int randomVal = _vm->getRandomNumber(1, total);
+ int randomIndex = -1;
+ while (randomVal > 0 && randomIndex < (int)scrEntry._entries2.size()) {
+ ++randomIndex;
+ randomVal -= scrEntry._entries2[randomIndex]._size;
+ }
+ if (randomIndex == (int)scrEntry._entries2.size())
+ randomIndex = 0;
+ int entryVal = scrEntry._entries2[randomIndex]._v2;
+
+ if (scrEntry._command == CMD_MESSAGE1) {
+ _runningConv->_cnd._messageList2.push_back(entryVal);
+
+ if (scrEntry._entries2.size() <= 1) {
+ for (uint idx = 0; idx < scrEntry._entries.size(); ++idx)
+ _runningConv->_cnd._messageList4.push_back(scrEntry._entries[idx]);
+ }
+ else if (scrEntry._entries.size() > 0 && randomIndex < (int)scrEntry._entries.size()) {
+ _runningConv->_cnd._messageList4.push_back(entryVal);
+ }
+ } else {
+ _runningConv->_cnd._messageList1.push_back(entryVal);
+
+ if (scrEntry._entries2.size() <= 1) {
+ for (uint idx = 0; idx < scrEntry._entries.size(); ++idx)
+ _runningConv->_cnd._messageList3.push_back(scrEntry._entries[idx]);
+ } else if (scrEntry._entries.size() > 0 && randomIndex < (int)scrEntry._entries.size()) {
+ _runningConv->_cnd._messageList3.push_back(entryVal);
+ }
+ }
+}
+
+bool GameConversations::scriptNode(ScriptEntry &scrEntry) {
+ bool doFlag = scrEntry._conditionals[0].evaluate();
+ if (!doFlag)
+ return false;
+
+ ConversationVar &var0 = _runningConv->_cnd._vars[0];
+ int val1 = scrEntry._conditionals[1].evaluate();
+ int val2 = scrEntry._conditionals[2].evaluate();
+
+ var0._val = val1;
+ if (val1 >= 0)
+ _nextStartNode->_val = val1;
+ else if (val2 >= 0)
+ _nextStartNode->_val = val2;
+
+ return true;
+}
+
+/*------------------------------------------------------------------------*/
+
+void ConversationData::load(const Common::String &filename) {
+ Common::File inFile;
+ char buffer[16];
+
+ inFile.open(filename);
+ MadsPack convFileUnpacked(&inFile);
+
+ // **** Section 0: Header *************************************************
+ Common::SeekableReadStream *convFile = convFileUnpacked.getItemStream(0);
+
+ _nodeCount = convFile->readUint16LE();
+ _dialogCount = convFile->readUint16LE();
+ _messageCount = convFile->readUint16LE();
+ _textLineCount = convFile->readUint16LE();
+ _unk2 = convFile->readUint16LE();
+ _maxImports = convFile->readUint16LE();
+ _speakerCount = convFile->readUint16LE();
+
+ for (uint idx = 0; idx < MAX_SPEAKERS; ++idx) {
+ convFile->read(buffer, 16);
+ _portraits[idx] = buffer;
+ }
+
+ for (uint idx = 0; idx < MAX_SPEAKERS; ++idx) {
+ _speakerFrame[idx] = convFile->readUint16LE();
+ }
+
+ convFile->read(buffer, 14);
+ _speechFile = Common::String(buffer);
+
+ // Total text length in section 5
+ _textSize = convFile->readUint32LE();
+ _commandsSize = convFile->readUint32LE();
+
+ // The rest of the section 0 is padding to allow room for a set of pointers
+ // to the contents of the remaining sections loaded into memory as a
+ // continuous data block containing both the header and the sections
+ delete convFile;
+
+ // **** Section 1: Nodes **************************************************
+ convFile = convFileUnpacked.getItemStream(1);
+
+ _nodes.clear();
+ for (uint i = 0; i < _nodeCount; i++) {
+ ConvNode node;
+ node._index = convFile->readUint16LE();
+ node._dialogCount = convFile->readUint16LE();
+ node._unk1 = convFile->readSint16LE(); // TODO
+ node._active = convFile->readSint16LE() != 0;
+ node._unk3 = convFile->readSint16LE(); // TODO
+ _nodes.push_back(node);
+ }
+
+ delete convFile;
+
+ // **** Section 2: Dialogs ************************************************
+ convFile = convFileUnpacked.getItemStream(2);
+ assert(convFile->size() == _dialogCount * 8);
+
+ _dialogs.resize(_dialogCount);
+ for (uint idx = 0; idx < _dialogCount; ++idx) {
+ _dialogs[idx]._textLineIndex = convFile->readSint16LE();
+ _dialogs[idx]._speechIndex = convFile->readSint16LE();
+ _dialogs[idx]._scriptOffset = convFile->readUint16LE();
+ _dialogs[idx]._scriptSize = convFile->readUint16LE();
+ }
+
+ delete convFile;
+
+ // **** Section 3: Messages ***********************************************
+ convFile = convFileUnpacked.getItemStream(3);
+ assert(convFile->size() == _messageCount * 4);
+
+ _messages.resize(_messageCount);
+ for (uint idx = 0; idx < _messageCount; ++idx) {
+ _messages[idx]._stringIndex = convFile->readUint16LE();
+ _messages[idx]._count = convFile->readUint16LE();
+ }
+
+ delete convFile;
+
+ // **** Section 4: Text line offsets **************************************
+ convFile = convFileUnpacked.getItemStream(4);
+ assert(convFile->size() == _textLineCount * 2);
+
+ uint16 *textLineOffsets = new uint16[_textLineCount]; // deleted below in section 5
+ for (uint16 i = 0; i < _textLineCount; i++)
+ textLineOffsets[i] = convFile->readUint16LE();
+
+ delete convFile;
+
+ // **** Section 5: Text lines *********************************************
+ convFile = convFileUnpacked.getItemStream(5);
+ assert(convFile->size() == _textSize);
+
+ Common::String textLine;
+ _textLines.resize(_textLineCount);
+ char textLineBuffer[256];
+ uint16 nextOffset;
+ for (uint16 i = 0; i < _textLineCount; i++) {
+ nextOffset = (i != _textLineCount - 1) ? textLineOffsets[i + 1] : convFile->size();
+ convFile->read(textLineBuffer, nextOffset - textLineOffsets[i]);
+ _textLines[i] = Common::String(textLineBuffer);
+ }
+
+ delete[] textLineOffsets;
+ delete convFile;
+
+ // **** Section 6: Scripts ************************************************
+ convFile = convFileUnpacked.getItemStream(6);
+ assert(convFile->size() == _commandsSize);
+
+ for (uint idx = 0; idx < _dialogs.size(); ++idx) {
+ // Move to the correct position for the dialog's script, and create
+ // a memory stream to represent the data for just that script
+ convFile->seek(_dialogs[idx]._scriptOffset);
+ Common::SeekableReadStream *scriptStream = convFile->readStream(_dialogs[idx]._scriptSize);
+
+ // Pass it to the dialog's script set class to parse into commands
+ _dialogs[idx]._script.load(*scriptStream, _dialogs[idx]._scriptOffset);
+ delete scriptStream;
+ }
+
+ delete convFile;
+ inFile.close();
+}
+
+/*------------------------------------------------------------------------*/
+
+ConversationConditionals::ConversationConditionals() : _numImports(0) {
+ _currentNode = -1;
+}
+
+void ConversationConditionals::load(const Common::String &filename) {
+ Common::File inFile;
+ Common::SeekableReadStream *convFile;
+
+ // Open up the file for access
+ inFile.open(filename);
+ MadsPack convFileUnpacked(&inFile);
+
+ // **** Section 0: Header *************************************************
+ convFile = convFileUnpacked.getItemStream(0);
+
+ _currentNode = convFile->readUint16LE();
+ int entryFlagsCount = convFile->readUint16LE();
+ int varsCount = convFile->readUint16LE();
+ int importsCount = convFile->readUint16LE();
+
+ convFile->skip(4);
+
+ _messageList1.resize(convFile->readUint16LE());
+ _messageList2.resize(convFile->readUint16LE());
+ _messageList3.resize(convFile->readUint16LE());
+ _messageList4.resize(convFile->readUint16LE());
+ convFile->skip(20);
+
+ for (uint idx = 0; idx < 10; ++idx) {
+ int v = convFile->readUint16LE();
+ if (idx < _messageList1.size())
+ _messageList1[idx] = v;
+ }
+ for (uint idx = 0; idx < 10; ++idx) {
+ int v = convFile->readUint16LE();
+ if (idx < _messageList2.size())
+ _messageList2[idx] = v;
+ }
+ for (uint idx = 0; idx < 10; ++idx) {
+ int v = convFile->readUint16LE();
+ if (idx < _messageList3.size())
+ _messageList3[idx] = v;
+ }
+ for (uint idx = 0; idx < 10; ++idx) {
+ int v = convFile->readUint16LE();
+ if (idx < _messageList4.size())
+ _messageList4[idx] = v;
+ }
+
+ delete convFile;
+
+ // **** Section: Imports *************************************************
+ int streamNum = 1;
+
+ _importVariables.resize(importsCount);
+ if (importsCount > 0) {
+ convFile = convFileUnpacked.getItemStream(streamNum++);
+
+ // Read in the variable indexes that each import value will be stored in
+ for (int idx = 0; idx < importsCount; ++idx)
+ _importVariables[idx] = convFile->readUint16LE();
+
+ delete convFile;
+ }
+
+ // **** Section: Entry Flags *********************************************
+ convFile = convFileUnpacked.getItemStream(streamNum++);
+ assert(convFile->size() == (entryFlagsCount * 2));
+
+ _entryFlags.resize(entryFlagsCount);
+ for (int idx = 0; idx < entryFlagsCount; ++idx)
+ _entryFlags[idx] = convFile->readUint16LE();
+
+ delete convFile;
+
+ // **** Section: Variables ***********************************************
+ convFile = convFileUnpacked.getItemStream(streamNum);
+ assert(convFile->size() == (varsCount * 6));
+
+ _vars.resize(varsCount);
+ for (int idx = 0; idx < varsCount; ++idx) {
+ convFile->skip(2); // Loaded values are never pointers, so don't need this
+ _vars[idx]._isPtr = false;
+ _vars[idx]._val = convFile->readSint16LE();
+ convFile->skip(2); // Unused segment selector for pointer values
+ }
+
+ delete convFile;
+}
+
+/*------------------------------------------------------------------------*/
+
+void ConversationVar::setValue(int val) {
+ _isPtr = false;
+ _valPtr = nullptr;
+ _val = val;
+}
+
+void ConversationVar::setValue(int *val) {
+ _isPtr = true;
+ _valPtr = val;
+ _val = 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+void DialogScript::load(Common::SeekableReadStream &s, uint startingOffset) {
+ clear();
+ Common::HashMap<uint, uint> instructionOffsets;
+
+ // Iterate getting each instruction in turn
+ while (s.pos() < s.size()) {
+ // Create a new entry for the next script command
+ instructionOffsets[startingOffset + s.pos()] = size();
+ push_back(ScriptEntry());
+ ScriptEntry &se = (*this)[size() - 1];
+
+ // Load the instruction
+ se.load(s);
+ }
+
+ // Do a final iteration over the loaded instructions to convert
+ // any GOTO instructions from original offsets to instruction indexes
+ for (uint idx = 0; idx < size(); ++idx) {
+ ScriptEntry &se = (*this)[idx];
+
+ if (se._command == CMD_GOTO)
+ se._index = instructionOffsets[se._index];
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+void ScriptEntry::load(Common::SeekableReadStream &s) {
+ // Get the command byte
+ _command = (DialogCommand)s.readByte();
+
+ if (!(_command == CMD_DIALOG_END || (_command >= CMD_END && _command <= CMD_ASSIGN))) {
+ warning("unknown opcode - %d", _command);
+ s.seek(0, SEEK_END);
+ return;
+ }
+
+ // Get in the conditional values
+ int numConditionals = 1;
+ if (_command == CMD_NODE)
+ numConditionals = 3;
+ else if (_command == CMD_ASSIGN)
+ numConditionals = 2;
+ else if (_command == CMD_ERROR)
+ numConditionals = 0;
+
+ for (int idx = 0; idx < numConditionals; ++idx)
+ _conditionals[idx].load(s);
+
+ // Get further parameters
+ switch (_command) {
+ case CMD_1:
+ case CMD_HIDE:
+ case CMD_UNHIDE: {
+ // Read in the list of entries whose flags are to be updated
+ int count = s.readByte();
+ for (int idx = 0; idx < count; ++idx)
+ _entries.push_back(s.readSint16LE());
+ break;
+ }
+
+ case CMD_MESSAGE1:
+ case CMD_MESSAGE2: {
+ int count2 = s.readByte();
+ int count1 = s.readByte();
+ _entries2.resize(count2);
+ _entries.resize(count1);
+
+ for (uint idx = 0; idx < _entries2.size(); ++idx) {
+ int v = s.readByte();
+ if (idx < 10)
+ _entries2[idx]._size = v;
+ }
+ for (uint idx = 0; idx < _entries2.size(); ++idx) {
+ int v = s.readUint16LE();
+ if (idx < 10)
+ _entries2[idx]._v2 = v;
+ }
+ for (uint idx = 0; idx < _entries.size(); ++idx) {
+ int v = s.readUint16LE();
+ if (idx < 10)
+ _entries[idx] = v;
+ }
+ break;
+ }
+
+ case CMD_ERROR:
+ case CMD_NODE:
+ // These opcodes have no extra parameters
+ break;
+
+ case CMD_GOTO:
+ case CMD_ASSIGN:
+ // Goto has a single extra parameter for the destination
+ // Assign has a single extra parameter for the variable index
+ // that the value resulting from the condition will be set to
+ _index = s.readUint16LE();
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Common::Array<ConversationVar> *ScriptEntry::Conditional::_vars = nullptr;
+
+void ScriptEntry::Conditional::load(Common::SeekableReadStream &s) {
+ _operation = (ConditionalOperation)s.readUint16LE();
+
+ if (_operation == CONDOP_ABORT) {
+ _param1._isVariable = false;
+ _param1._val = 0;
+ } else {
+ _param1._isVariable = s.readByte() != 0;
+ _param1._val = s.readSint16LE();
+ }
+
+ if (_operation == CONDOP_ABORT || _operation == CONDOP_VALUE) {
+ _param2._isVariable = false;
+ _param2._val = 0;
+ } else {
+ _param2._isVariable = s.readByte() != 0;
+ _param2._val = s.readSint16LE();
+ }
+}
+
+int ScriptEntry::Conditional::evaluate() const {
+ if (_operation == CONDOP_NONE)
+ return -1;
+
+ int param1 = get(1);
+ if (_operation == CONDOP_VALUE)
+ return param1;
+ int param2 = get(2);
+
+ switch (_operation) {
+ case CONDOP_ADD:
+ return param1 + param2;
+ case CONDOP_SUBTRACT:
+ return param1 - param2;
+ case CONDOP_MULTIPLY:
+ return param1 * param2;
+ case CONDOP_DIVIDE:
+ return param1 / param2;
+ case CONDOP_MODULUS:
+ return param1 % param2;
+ case CONDOP_LTEQ:
+ return (param1 <= param2) ? 1 : 0;
+ case CONDOP_GTEQ:
+ return (param1 < param2) ? 1 : 0;
+ case CONDOP_LT:
+ return (param1 < param2) ? 1 : 0;
+ case CONDOP_GT:
+ return (param1 > param2) ? 1 : 0;
+ case CONDOP_NEQ:
+ return (param1 != param2) ? 1 : 0;
+ case CONDOP_EQ:
+ return (param1 == param2) ? 1 : 0;
+ case CONDOP_AND:
+ return (param1 || param2) ? 1 : 0;
+ case CONDOP_OR:
+ return (param1 && param2) ? 1 : 0;
+ default:
+ error("Unknown conditional operation");
+ }
+}
+
+int ScriptEntry::Conditional::get(int paramNum) const {
+ const CondtionalParamEntry &p = (paramNum == 1) ? _param1 : _param2;
+ return p._isVariable ? *(*_vars)[p._val].getValue() : p._val;
+}
+
+/*------------------------------------------------------------------------*/
+
+
+} // End of namespace MADS
diff --git a/engines/mads/conversations.h b/engines/mads/conversations.h
new file mode 100644
index 0000000000..7b7d3485ef
--- /dev/null
+++ b/engines/mads/conversations.h
@@ -0,0 +1,505 @@
+/* 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 MADS_CONVERSATIONS_H
+#define MADS_CONVERSATIONS_H
+
+#include "common/scummsys.h"
+#include "common/array.h"
+#include "common/str-array.h"
+#include "mads/screen.h"
+#include "mads/dialogs.h"
+
+namespace MADS {
+
+#define MAX_CONVERSATIONS 5
+#define MAX_SPEAKERS 5
+
+enum ConversationMode {
+ CONVMODE_NONE = -1,
+ CONVMODE_0 = 0,
+ CONVMODE_1 = 1,
+ CONVMODE_2 = 2,
+ CONVMODE_3 = 3,
+ CONVMODE_4 = 4,
+ CONVMODE_5 = 5,
+ CONVMODE_6 = 6,
+ CONVMODE_7 = 7,
+ CONVMODE_8 = 8,
+ CONVMODE_9 = 9,
+ CONVMODE_STOP = 10
+};
+
+enum DialogCommand {
+ CMD_END = 0,
+ CMD_1 = 1,
+ CMD_HIDE = 2,
+ CMD_UNHIDE = 3,
+ CMD_MESSAGE1 = 4,
+ CMD_MESSAGE2 = 5,
+ CMD_ERROR = 6,
+ CMD_NODE = 7,
+ CMD_GOTO = 8,
+ CMD_ASSIGN = 9,
+ CMD_DIALOG_END = 255
+};
+
+enum ConvEntryFlag {
+ ENTRYFLAG_2 = 2,
+ ENTRYFLAG_4000 = 0x4000,
+ ENTRYFLAG_8000 = 0x8000
+};
+
+enum ConditionalOperation {
+ CONDOP_NONE = 0xff,
+ CONDOP_VALUE = 0,
+ CONDOP_ADD = 1,
+ CONDOP_SUBTRACT = 2,
+ CONDOP_MULTIPLY = 3,
+ CONDOP_DIVIDE = 4,
+ CONDOP_MODULUS = 5,
+ CONDOP_LTEQ = 6,
+ CONDOP_GTEQ = 7,
+ CONDOP_LT = 8,
+ CONDOP_GT = 9,
+ CONDOP_NEQ = 10,
+ CONDOP_EQ = 11,
+ CONDOP_AND = 12,
+ CONDOP_OR = 13,
+ CONDOP_ABORT = 0xff
+};
+
+
+struct ConversationVar {
+ bool _isPtr;
+ int _val;
+ int *_valPtr;
+
+ /**
+ * Constructor
+ */
+ ConversationVar() : _isPtr(false), _val(0), _valPtr(nullptr) {}
+
+ /**
+ * Sets a numeric value
+ */
+ void setValue(int val);
+
+ /**
+ * Sets a pointer value
+ */
+ void setValue(int *val);
+
+ /**
+ * Return either the variable's pointer, or a pointer to it's direct value
+ */
+ int *getValue() { return _isPtr ? _valPtr : &_val; }
+
+ /**
+ * Returns true if variable is a pointer
+ */
+ bool isPtr() const { return _isPtr; }
+
+ /**
+ * Returns true if variable is numeric
+ */
+ bool isNumeric() const { return !_isPtr; }
+};
+
+struct ScriptEntry {
+ struct Conditional {
+ struct CondtionalParamEntry {
+ bool _isVariable;
+ int _val;
+
+ /**
+ * Constructor
+ */
+ CondtionalParamEntry() : _isVariable(false), _val(0) {}
+ };
+
+ static Common::Array<ConversationVar> *_vars;
+ ConditionalOperation _operation;
+ CondtionalParamEntry _param1;
+ CondtionalParamEntry _param2;
+
+ /**
+ * Constructor
+ */
+ Conditional() : _operation(CONDOP_NONE) {}
+
+ /**
+ * Loads data from a passed stream into the parameters structure
+ */
+ void load(Common::SeekableReadStream &s);
+
+ /**
+ * Gets the value
+ */
+ int get(int paramNum) const;
+
+ /**
+ * Evaluates the conditional
+ */
+ int evaluate() const;
+ };
+
+ struct MessageEntry {
+ int _size;
+ int _v2;
+
+ MessageEntry() : _size(0), _v2(0) {}
+ };
+
+ DialogCommand _command;
+ Conditional _conditionals[3];
+
+ // Extra parameters for different opcodes
+ int _index;
+ Common::Array<int> _entries;
+ Common::Array<MessageEntry> _entries2;
+
+ /**
+ * Constructor
+ */
+ ScriptEntry() : _command(CMD_END), _index(0) {}
+
+ /**
+ * Loads data from a passed stream into the parameters structure
+ */
+ void load(Common::SeekableReadStream &s);
+};
+
+/**
+ * Representation of scripts associated with a dialog
+ */
+class DialogScript : public Common::Array<ScriptEntry> {
+public:
+ /**
+ * Loads a script from the passed stream
+ */
+ void load(Common::SeekableReadStream &s, uint startingOffset);
+};
+
+/**
+ * Reperesents the data for a dialog to be displayed in a conversation
+ */
+struct ConvDialog {
+ struct ScriptEntry {
+ DialogCommand _command;
+ };
+
+ int16 _textLineIndex; // 0-based
+ int16 _speechIndex; // 1-based
+ uint16 _scriptOffset; // offset of script entry
+ uint16 _scriptSize; // size of script entry
+
+ DialogScript _script;
+};
+
+/**
+ * Represents a node within the conversation control logic
+ */
+struct ConvNode {
+ uint16 _index;
+ uint16 _dialogCount;
+ int16 _unk1;
+ bool _active;
+ int16 _unk3;
+
+ Common::Array<ConvDialog> _dialogs;
+};
+
+/**
+ * Represents a message entry
+ */
+struct ConvMessage {
+ uint _stringIndex;
+ uint _count;
+
+ ConvMessage() : _stringIndex(0), _count(0) {}
+};
+
+/**
+ * Represents the static, non-changing data for a conversation
+ */
+struct ConversationData {
+ uint16 _nodeCount; // conversation nodes, each one containing several dialog options and messages
+ uint16 _dialogCount; // messages (non-selectable) + texts (selectable)
+ uint16 _messageCount; // messages (non-selectable)
+ uint16 _textLineCount;
+ uint16 _unk2;
+ uint16 _maxImports;
+ uint16 _speakerCount;
+ int _textSize;
+ int _commandsSize;
+
+ Common::String _portraits[MAX_SPEAKERS];
+ int _speakerFrame[MAX_SPEAKERS];
+ Common::String _speechFile;
+ Common::Array<ConvMessage> _messages;
+ Common::StringArray _textLines;
+ Common::Array<ConvNode> _nodes;
+ Common::Array<ConvDialog> _dialogs;
+
+ /**
+ * Load the specified conversation resource file
+ */
+ void load(const Common::String &filename);
+};
+
+/**
+ * Conditional (i.e. changeable) data for the conversation
+ */
+struct ConversationConditionals {
+ Common::Array<uint> _importVariables;
+ Common::Array<uint> _entryFlags;
+ Common::Array<ConversationVar> _vars;
+ int _numImports;
+
+ int _currentNode;
+ Common::Array<int> _messageList1;
+ Common::Array<int> _messageList2;
+ Common::Array<int> _messageList3;
+ Common::Array<int> _messageList4;
+
+ /**
+ * Constructor
+ */
+ ConversationConditionals();
+
+ /**
+ * Load the specified conversation conditionals resource file
+ */
+ void load(const Common::String &filename);
+};
+
+/**
+ * Represents all the data needed for a particular loaded conversation
+ */
+struct ConversationEntry {
+ int _convId;
+ ConversationData _data;
+ ConversationConditionals _cnd;
+};
+
+class MADSEngine;
+
+/**
+ * Manager for loading and running conversations
+ */
+class GameConversations {
+private:
+ MADSEngine *_vm;
+ ConversationEntry _conversations[MAX_CONVERSATIONS];
+ bool _speakerActive[MAX_SPEAKERS];
+ int _speakerSeries[MAX_SPEAKERS];
+ int _speakerFrame[MAX_SPEAKERS];
+ int _popupX[MAX_SPEAKERS];
+ int _popupY[MAX_SPEAKERS];
+ int _popupMaxLen[MAX_SPEAKERS];
+ InputMode _inputMode;
+ bool _popupVisible;
+ ConversationMode _currentMode;
+ ConversationMode _priorMode;
+ int _verbId;
+ int _speakerVal;
+ int _heroTrigger;
+ TriggerMode _heroTriggerMode;
+ int _interlocutorTrigger;
+ TriggerMode _interlocutorTriggerMode;
+ ConversationEntry *_runningConv;
+ int _restoreRunning;
+ bool _playerEnabled;
+ uint32 _startFrameNumber;
+ ConversationVar *_vars;
+ ConversationVar *_nextStartNode;
+ int _currentNode;
+ int _dialogNodeOffset, _dialogNodeSize;
+ int _personSpeaking;
+ TextDialog *_dialog;
+ bool _dialogAltFlag;
+
+ /**
+ * Returns the record for the specified conversation, if it's loaded
+ */
+ ConversationEntry *getConv(int convId);
+
+ /**
+ * Start a specified conversation slot
+ */
+ void start();
+
+ /**
+ * Remove any currently active dialog window
+ */
+ void removeActiveWindow();
+
+ /**
+ * Flags a conversation option/entry
+ */
+ void flagEntry(DialogCommand mode, int entryIndex);
+
+ /**
+ * Generate a menu
+ */
+ ConversationMode generateMenu();
+
+ /**
+ * Generate text
+ */
+ void generateText(int textLineIndex, Common::Array<int> &messages);
+
+ /**
+ * Generate message
+ */
+ void generateMessage(Common::Array<int> &messageList, Common::Array<int> &voiecList);
+
+ /**
+ * Gets the next node
+ */
+ bool nextNode();
+
+ /**
+ * Executes a conversation entry
+ */
+ int executeEntry(int index);
+
+ /**
+ * Handle messages
+ */
+ void scriptMessage(ScriptEntry &scrEntry);
+
+ /**
+ * Handle node changes
+ */
+ bool scriptNode(ScriptEntry &scrEntry);
+public:
+ /**
+ * Constructor
+ */
+ GameConversations(MADSEngine *vm);
+
+ /**
+ * Destructor
+ */
+ virtual ~GameConversations();
+
+ /**
+ * Gets the specified conversation and loads into into a free slot
+ * in the conversation list
+ */
+ void load(int id);
+
+ /**
+ * Run a specified conversation number. The conversation must have
+ * previously been loaded by calling the load method
+ */
+ void run(int id);
+
+ /**
+ * Sets a variable to a numeric value
+ */
+ void setVariable(uint idx, int val);
+
+ /**
+ * Sets a variable to a pointer value
+ */
+ void setVariable(uint idx, int *val);
+
+ /**
+ * Sets the starting node index
+ */
+ void setStartNode(uint nodeIndex);
+
+ /**
+ * Set the hero trigger
+ */
+ void setHeroTrigger(int val);
+
+ /**
+ * Set the interlocutor trigger
+ */
+ void setInterlocutorTrigger(int val);
+
+ /**
+ * Returns either the pointer value of a variable, or if the variable
+ * contains a numeric value directly, returns a pointer to it
+ */
+ int *getVariable(int idx);
+
+ /**
+ * Hold the current mode value
+ */
+ void hold();
+
+ /**
+ * Release the prevoiusly held mode value
+ */
+ void release();
+
+ /**
+ * Stop any currently running conversation
+ */
+ void stop();
+
+ /**
+ * Adds the passed pointer into the list of import variables for the given conversation
+ */
+ void exportPointer(int *ptr);
+
+ /**
+ * Adds the passed value into the list of import variables for the given conversation
+ */
+ void exportValue(int val);
+
+ void reset(int id);
+
+ /**
+ * Handles updating the conversation display
+ */
+ void update(bool flag);
+
+ /**
+ * Returns true if any conversation is currently atcive
+ */
+ bool active() const { return _runningConv != nullptr; }
+
+ /**
+ * Returns the currently active conversation Id
+ */
+ int activeConvId() const { return !active() ? -1 : _runningConv->_convId; }
+
+ /**
+ * Returns _restoreRunning value
+ */
+ int restoreRunning() const { return _restoreRunning; }
+
+ /**
+ * Returns the current conversation mode
+ */
+ ConversationMode currentMode() const { return _currentMode; }
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_CONVERSATIONS_H */
diff --git a/engines/mads/debugger.cpp b/engines/mads/debugger.cpp
index a6a4d3edbc..b9731b1d31 100644
--- a/engines/mads/debugger.cpp
+++ b/engines/mads/debugger.cpp
@@ -49,6 +49,7 @@ Debugger::Debugger(MADSEngine *vm) : GUI::Debugger(), _vm(vm) {
registerCmd("item", WRAP_METHOD(Debugger, Cmd_Item));
registerCmd("play_anim", WRAP_METHOD(Debugger, Cmd_PlayAnim));
registerCmd("play_text", WRAP_METHOD(Debugger, Cmd_PlayText));
+ registerCmd("set_camera", WRAP_METHOD(Debugger, Cmd_SetCamera));
}
static int strToInt(const char *s) {
@@ -157,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
@@ -391,4 +392,17 @@ bool Debugger::Cmd_PlayText(int argc, const char **argv) {
}
}
+bool Debugger::Cmd_SetCamera(int argc, const char **argv) {
+ if (argc != 3) {
+ debugPrintf("Usage: %s <x> <y>\n", argv[0]);
+ return true;
+ } else {
+ int x = strToInt(argv[1]);
+ int y = strToInt(argv[2]);
+ _vm->_game->_scene.setCamera(Common::Point(x, y));
+ _vm->_game->_scene.resetScene();
+ _vm->_game->_scene.drawElements(kTransitionNone, false);
+ return false;
+ }
+}
} // End of namespace MADS
diff --git a/engines/mads/debugger.h b/engines/mads/debugger.h
index 70b2cadc65..f6b58ac0de 100644
--- a/engines/mads/debugger.h
+++ b/engines/mads/debugger.h
@@ -51,6 +51,7 @@ protected:
bool Cmd_Item(int argc, const char **argv);
bool Cmd_PlayAnim(int argc, const char **argv);
bool Cmd_PlayText(int argc, const char **argv);
+ bool Cmd_SetCamera(int argc, const char **argv);
public:
bool _showMousePos;
public:
diff --git a/engines/mads/detection.cpp b/engines/mads/detection.cpp
index 57f4776e82..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;
@@ -188,11 +188,10 @@ SaveStateList MADSMetaEngine::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);
+ Common::String pattern = Common::String::format("%s.0##", target);
MADS::MADSSavegameHeader header;
filenames = saveFileMan->listSavefiles(pattern);
- sort(filenames.begin(), filenames.end()); // Sort to get the files in numerical order
SaveStateList saveList;
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
@@ -213,6 +212,8 @@ SaveStateList MADSMetaEngine::listSaves(const char *target) const {
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
diff --git a/engines/mads/detection_tables.h b/engines/mads/detection_tables.h
index 56df09577c..f0eb21f5d9 100644
--- a/engines/mads/detection_tables.h
+++ b/engines/mads/detection_tables.h
@@ -55,7 +55,7 @@ static const MADSGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformDOS,
- ADGF_TESTING,
+ ADGF_NO_FLAGS,
GUIO5(GUIO_NOSPEECH, GAMEOPTION_EASY_MOUSE, GAMEOPTION_ANIMATED_INVENTORY, GAMEOPTION_ANIMATED_INTERFACE, GAMEOPTION_NAUGHTY_MODE)
},
GType_RexNebular,
@@ -73,7 +73,7 @@ static const MADSGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformDOS,
- ADGF_TESTING,
+ ADGF_NO_FLAGS,
GUIO5(GUIO_NOSPEECH, GAMEOPTION_EASY_MOUSE, GAMEOPTION_ANIMATED_INVENTORY, GAMEOPTION_ANIMATED_INTERFACE, GAMEOPTION_NAUGHTY_MODE)
},
GType_RexNebular,
diff --git a/engines/mads/dialogs.cpp b/engines/mads/dialogs.cpp
index d9b27ce926..fa656a90c1 100644
--- a/engines/mads/dialogs.cpp
+++ b/engines/mads/dialogs.cpp
@@ -29,6 +29,12 @@
namespace MADS {
+enum PopupEdge {
+ EDGE_UPPER_LEFT = 0, EDGE_UPPER_RIGHT = 1, EDGE_LOWER_LEFT = 2,
+ EDGE_LOWER_RIGHT = 3, EDGE_LEFT = 4, EDGE_RIGHT = 5, EDGE_TOP = 6,
+ EDGE_BOTTOM = 7, EDGE_UPPER_CENTER = 8
+};
+
Dialog::Dialog(MADSEngine *vm)
: _vm(vm), _savedSurface(nullptr), _position(Common::Point(-1, -1)),
_width(0), _height(0) {
@@ -48,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);
@@ -81,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
@@ -119,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;
@@ -140,15 +145,36 @@ void Dialog::drawContent(const Common::Rect &r, int seed, byte color1, byte colo
TextDialog::TextDialog(MADSEngine *vm, const Common::String &fontName,
const Common::Point &pos, int maxChars)
: Dialog(vm) {
- _vm = vm;
_font = _vm->_font->getFont(fontName);
_position = pos;
+ _icon = nullptr;
+ _edgeSeries = nullptr;
+ _piecesPerCenter = 0;
+ _fontSpacing = 0;
+ _vm->_font->setColors(TEXTDIALOG_BLACK, TEXTDIALOG_BLACK, TEXTDIALOG_BLACK, TEXTDIALOG_BLACK);
+ _piecesPerCenter = 0;
+ init(maxChars);
+}
+
+TextDialog::TextDialog(MADSEngine *vm, const Common::String &fontName,
+ const Common::Point &pos, MSurface *icon, int maxTextChars): Dialog(vm) {
+ _font = _vm->_font->getFont(fontName);
+ _position = pos;
+ _icon = icon;
+ _edgeSeries = new SpriteAsset(_vm, "box.ss", PALFLAG_RESERVED);
_vm->_font->setColors(TEXTDIALOG_BLACK, TEXTDIALOG_BLACK, TEXTDIALOG_BLACK, TEXTDIALOG_BLACK);
+ _piecesPerCenter = _edgeSeries->getFrame(EDGE_UPPER_CENTER)->w / _edgeSeries->getFrame(EDGE_BOTTOM)->w;
+ _fontSpacing = 0;
+
+ int maxLen = estimatePieces(maxTextChars);
+ init(maxLen);
+}
- _innerWidth = (_font->maxWidth() + 1) * maxChars;
+void TextDialog::init(int maxTextChars) {
+ _innerWidth = (_font->maxWidth() + 1) * maxTextChars;
_width = _innerWidth + 10;
- _lineSize = maxChars * 2;
+ _lineSize = maxTextChars * 2;
_lineWidth = 0;
_currentX = 0;
_numLines = 0;
@@ -157,7 +183,16 @@ TextDialog::TextDialog(MADSEngine *vm, const Common::String &fontName,
_askXp = 0;
}
+int TextDialog::estimatePieces(int maxLen) {
+ int fontLen = (_font->maxWidth() + _fontSpacing) * maxLen;
+ int pieces = ((fontLen - 1) / _edgeSeries->getFrame(EDGE_TOP)->w) + 1;
+ int estimate = (pieces - _piecesPerCenter) / 2;
+
+ return estimate;
+}
+
TextDialog::~TextDialog() {
+ delete _edgeSeries;
}
void TextDialog::addLine(const Common::String &line, bool underline) {
@@ -290,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 {
@@ -300,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() {
@@ -324,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() {
@@ -416,7 +449,7 @@ FullScreenDialog::FullScreenDialog(MADSEngine *vm) : _vm(vm) {
}
FullScreenDialog::~FullScreenDialog() {
- _vm->_screen.resetClipBounds();
+ _vm->_screen->resetClipBounds();
_vm->_game->_scene.restrictScene();
}
@@ -455,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/dialogs.h b/engines/mads/dialogs.h
index efd2871d89..7642b76a3c 100644
--- a/engines/mads/dialogs.h
+++ b/engines/mads/dialogs.h
@@ -31,6 +31,7 @@
namespace MADS {
#define DIALOG_TOP 22
+#define POPUP_CENTER 0x8000
class Dialog {
private:
@@ -109,6 +110,11 @@ private:
* Clean up after finishing displaying the dialog
*/
void restorePalette();
+
+ /**
+ * Used by the constructors to initialize the dialog fields
+ */
+ void init(int maxTextChars);
protected:
Font *_font;
int _innerWidth;
@@ -120,6 +126,10 @@ protected:
int _askLineNum;
Common::String _lines[TEXT_DIALOG_MAX_LINES];
int _lineXp[TEXT_DIALOG_MAX_LINES];
+ SpriteAsset *_edgeSeries;
+ MSurface *_icon;
+ int _piecesPerCenter;
+ int _fontSpacing;
/**
* Calculate the bounds for the dialog
@@ -137,6 +147,17 @@ public:
int maxChars);
/**
+ * Constructor
+ * @param vm Engine reference
+ * @param fontName Font to use for display
+ * @param pos Position for window top-left
+ * @param icon Speaker portrait to show in dialog
+ * @param maxTextChars Horizontal width of text portion of window in characters
+ */
+ TextDialog(MADSEngine *vm, const Common::String &fontName, const Common::Point &pos,
+ MSurface *icon, int maxTextChars);
+
+ /**
* Destructor
*/
virtual ~TextDialog();
@@ -189,8 +210,13 @@ public:
void setLineXp(int xp);
/**
- * Show the dialog, and wait until a key or mouse press.
- */
+ * Estimates the maximum dialog length for text dialogs with icons
+ */
+ int estimatePieces(int maxLen);
+
+ /**
+ * Show the dialog, and wait until a key or mouse press.
+ */
virtual void show();
};
@@ -226,6 +252,11 @@ public:
virtual void showItem(int objectId, int messageId, int speech = 0) = 0;
virtual Common::String getVocab(int vocabId) = 0;
virtual bool show(int messageId, int objectId = -1) = 0;
+
+ /**
+ * Show a spinning picture of an object, used in V2+ games
+ */
+ virtual void spinObject(int idx) { warning("TODO: spinObject"); }
};
class FullScreenDialog: public EventTarget {
diff --git a/engines/mads/dragonsphere/dragonsphere_scenes.cpp b/engines/mads/dragonsphere/dragonsphere_scenes.cpp
index 6f5a28bff9..c20eeb72fa 100644
--- a/engines/mads/dragonsphere/dragonsphere_scenes.cpp
+++ b/engines/mads/dragonsphere/dragonsphere_scenes.cpp
@@ -28,6 +28,7 @@
#include "mads/scene.h"
#include "mads/dragonsphere/game_dragonsphere.h"
#include "mads/dragonsphere/dragonsphere_scenes.h"
+#include "mads/dragonsphere/dragonsphere_scenes1.h"
namespace MADS {
@@ -42,15 +43,15 @@ SceneLogic *SceneFactory::createScene(MADSEngine *vm) {
switch (scene._nextSceneId) {
// Scene group #1 (Castle, river and caves)
case 101: // king's bedroom
- return new DummyScene(vm); // TODO
+ return new Scene101(vm);
case 102: // queen's bedroom
- return new DummyScene(vm); // TODO
+ return new Scene102(vm);
case 103: // outside king's bedroom
- return new DummyScene(vm); // TODO
+ return new Scene103(vm);
case 104: // fireplace / bookshelf
- return new DummyScene(vm); // TODO
+ return new Scene104(vm);
case 105: // dining room
- return new DummyScene(vm); // TODO
+ return new Scene105(vm);
case 106: // throne room
return new DummyScene(vm); // TODO
case 107: // council chamber
@@ -200,13 +201,13 @@ Common::String DragonsphereScene::formAnimName(char sepChar, int suffixNum) {
/*------------------------------------------------------------------------*/
-void SceneInfoDragonsphere::loadCodes(MSurface &depthSurface, int variant) {
- // The intro scenes do not have any codes
- if (_sceneId >= 900)
+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))
return;
- Common::String ext = Common::String::format(".WW%d", variant);
- File f(Resources::formatName(RESPREFIX_RM, _sceneId, ext));
+ File f(fileName);
MadsPack codesPack(&f);
Common::SeekableReadStream *stream = codesPack.getItemStream(0);
@@ -216,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 173cc667ce..22d894b9d9 100644
--- a/engines/mads/dragonsphere/dragonsphere_scenes.h
+++ b/engines/mads/dragonsphere/dragonsphere_scenes.h
@@ -29,29 +29,49 @@
#include "mads/dragonsphere/game_dragonsphere.h"
//#include "mads/dragonsphere/globals_dragonsphere.h"
-
namespace MADS {
namespace Dragonsphere {
+enum Verb {
+ VERB_LOOK = 0x3,
+ VERB_TAKE = 0x4,
+ VERB_PUSH = 0x5,
+ VERB_OPEN = 0x6,
+ VERB_PUT = 0x7,
+ VERB_TALK_TO = 0x8,
+ VERB_GIVE = 0x9,
+ VERB_PULL = 0xA,
+ VERB_CLOSE = 0xB,
+ VERB_THROW = 0xC,
+ VERB_WALK_TO = 0xD,
+ VERB_WALK_ACROSS = 0x11,
+ VERB_WALK_BEHIND = 0x1C,
+ VERB_LOOK_AT = 0x1E,
+ VERB_WALK_THROUGH = 0x25,
+ VERB_WALK_INTO = 0x27,
+ VERB_INVOKE = 0x2F,
+ VERB_ATTACK = 0x39,
+ VERB_CARVE_UP = 0x3A,
+ VERB_THRUST = 0x57,
+ VERB_POUR = 0x62,
+ VERB_POUR_CONTENTS_OF = 0x63,
+ VERB_DRINK = 0x64,
+ VERB_SHIFT_SELF = 0x73,
+ VERB_SHIFT_INTO_BEAR = 0x74,
+ VERB_SHIFT_INTO_SEAL = 0x75,
+ VERB_SHIFT_INTO_SNAKE = 0x76,
+ VERB_WALK_DOWN = 0xA9,
+ VERB_WALK = 0x1CB,
+ VERB_WALK_AROUND = 0x221
+};
+
enum Noun {
NOUN_GAME = 0x1,
NOUN_QSAVE = 0x2,
- NOUN_LOOK = 0x3,
- NOUN_TAKE = 0x4,
- NOUN_PUSH = 0x5,
- NOUN_OPEN = 0x6,
- NOUN_PUT = 0x7,
- NOUN_TALK_TO = 0x8,
- NOUN_GIVE = 0x9,
- NOUN_PULL = 0xA,
- NOUN_CLOSE = 0xB,
- NOUN_THROW = 0xC,
- NOUN_WALK_TO = 0xD,
NOUN_NOTHING = 0xE,
NOUN_ = 0xF,
NOUN_FLOOR = 0x10,
- NOUN_WALK_ACROSS = 0x11,
NOUN_RUG = 0x12,
NOUN_CARPET = 0x13,
NOUN_WALL = 0x14,
@@ -62,18 +82,14 @@ enum Noun {
NOUN_NIGHTSTAND = 0x19,
NOUN_TAPESTRY = 0x1A,
NOUN_DRESSING_SCREEN = 0x1B,
- NOUN_WALK_BEHIND = 0x1C,
NOUN_ROYAL_CREST = 0x1D,
- NOUN_LOOK_AT = 0x1E,
NOUN_WASHBASIN = 0x1F,
NOUN_WASH_AT = 0x20,
NOUN_BOOK = 0x21,
NOUN_FIREPLACE = 0x22,
NOUN_FIREPLACE_SCREEN = 0x23,
NOUN_DOOR_TO_QUEENS_ROOM = 0x24,
- NOUN_WALK_THROUGH = 0x25,
NOUN_HALL_TO_SOUTH = 0x26,
- NOUN_WALK_INTO = 0x27,
NOUN_WALL_PLAQUE = 0x28,
NOUN_DECORATION = 0x29,
NOUN_SWORDS = 0x2A,
@@ -81,7 +97,6 @@ enum Noun {
NOUN_BUST_ON_WALL = 0x2C,
NOUN_WALL_ARCH = 0x2D,
NOUN_SIGNET_RING = 0x2E,
- NOUN_INVOKE = 0x2F,
NOUN_POLISH = 0x30,
NOUN_GANGBANG = 0x31,
NOUN_BIRD_FIGURINE = 0x32,
@@ -91,8 +106,6 @@ enum Noun {
NOUN_MAKE_NOISE = 0x36,
NOUN_SHIELDSTONE = 0x37,
NOUN_SWORD = 0x38,
- NOUN_ATTACK = 0x39,
- NOUN_CARVE_UP = 0x3A,
NOUN_GOBLET = 0x3B,
NOUN_FILL = 0x3C,
NOUN_DRINK_FROM = 0x3D,
@@ -121,7 +134,6 @@ enum Noun {
NOUN_MAGIC_BELT = 0x54,
NOUN_ADJUST = 0x55,
NOUN_AMULET = 0x56,
- NOUN_THRUST = 0x57,
NOUN_MUD = 0x58,
NOUN_FEEL = 0x59,
NOUN_TASTE = 0x5A,
@@ -132,9 +144,6 @@ enum Noun {
NOUN_FLASK = 0x5F,
NOUN_FLASK_FULL_OF_ACID = 0x60,
NOUN_POUR_CONTENTS = 0x61,
- NOUN_POUR = 0x62,
- NOUN_POUR_CONTENTS_OF = 0x63,
- NOUN_DRINK = 0x64,
NOUN_ROPE = 0x65,
NOUN_TIE = 0x66,
NOUN_POWER_VACUUM_STONE = 0x67,
@@ -149,10 +158,6 @@ enum Noun {
NOUN_BLACK_SPHERE = 0x70,
NOUN_SOPTUS_SOPORIFIC = 0x71,
NOUN_SHIFTER_RING = 0x72,
- NOUN_SHIFT_SELF = 0x73,
- NOUN_SHIFT_INTO_BEAR = 0x74,
- NOUN_SHIFT_INTO_SEAL = 0x75,
- NOUN_SHIFT_INTO_SNAKE = 0x76,
NOUN_REVERT = 0x77,
NOUN_MEDICINE_BUNDLE = 0x78,
NOUN_SHAKE = 0x79,
@@ -203,7 +208,6 @@ enum Noun {
NOUN_DOOR = 0xA6,
NOUN_WALL_SWITCH = 0xA7,
NOUN_STAIRS = 0xA8,
- NOUN_WALK_DOWN = 0xA9,
NOUN_EDGE_OF_ABYSS = 0xAA,
NOUN_COURTYARD = 0xAB,
NOUN_ROCK = 0xAC,
@@ -493,7 +497,6 @@ enum Noun {
NOUN_PATH_TO_HIGHTOWER = 0x1C8,
NOUN_SPIRIT_PLANE = 0x1C9,
NOUN_SPIRIT_TREE = 0x1CA,
- NOUN_WALK = 0x1CB,
NOUN_REMAINS = 0x1CC,
NOUN_DOORWAY_TO_ELEVATOR = 0x1CD,
NOUN_DRAGON_DOOR = 0x1CE,
@@ -579,7 +582,6 @@ enum Noun {
NOUN_SHIFTER_VILLAGE = 0x21E,
NOUN_SLATHAN_SKY = 0x21F,
NOUN_SHIFTER = 0x220,
- NOUN_WALK_AROUND = 0x221,
NOUN_WRECKED_BRIDGE = 0x222,
NOUN_SHACK = 0x223,
NOUN_WRECKED_SHACK = 0x224,
@@ -645,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
@@ -656,27 +658,6 @@ protected:
};
// TODO: Temporary, remove once implemented properly
-class Scene1xx : public DragonsphereScene {
-protected:
- /**
- * Plays an appropriate sound when entering a scene
- */
- void sceneEntrySound() {}
-
- /**
- *Sets the AA file to use for the scene
- */
- void setAAName() {}
-
- /**
- * Updates the prefix used for getting player sprites for the scene
- */
- void setPlayerSpritesPrefix() {}
-public:
- Scene1xx(MADSEngine *vm) : DragonsphereScene(vm) {}
-};
-
-// TODO: Temporary, remove once implemented properly
class DummyScene : public DragonsphereScene {
public:
DummyScene(MADSEngine *vm) : DragonsphereScene(vm) {
diff --git a/engines/mads/dragonsphere/dragonsphere_scenes1.cpp b/engines/mads/dragonsphere/dragonsphere_scenes1.cpp
new file mode 100644
index 0000000000..bb7cafec41
--- /dev/null
+++ b/engines/mads/dragonsphere/dragonsphere_scenes1.cpp
@@ -0,0 +1,3684 @@
+/* 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 "mads/mads.h"
+#include "mads/conversations.h"
+#include "mads/scene.h"
+#include "mads/dragonsphere/dragonsphere_scenes.h"
+#include "mads/dragonsphere/dragonsphere_scenes1.h"
+
+namespace MADS {
+
+namespace Dragonsphere {
+
+void Scene1xx::setAAName() {
+ int idx;
+
+ switch (_scene->_nextSceneId) {
+ case 108:
+ case 109:
+ idx = 3;
+ break;
+ case 110:
+ idx = 5;
+ break;
+ case 113:
+ case 114:
+ case 115:
+ case 117:
+ case 119:
+ idx = 1;
+ break;
+ case 116:
+ idx = 2;
+ break;
+ case 120:
+ idx = 8;
+ break;
+ default:
+ idx = 0;
+ break;
+ }
+
+ _game._aaName = Resources::formatAAName(idx);
+ _vm->_palette->setEntry(254, 56, 47, 32);
+
+}
+
+void Scene1xx::sceneEntrySound() {
+ if (!_vm->_musicFlag)
+ return;
+
+ switch (_scene->_nextSceneId) {
+ case 104:
+ if (_globals[kPlayerPersona] == 1)
+ _vm->_sound->command(44);
+ else
+ _vm->_sound->command(16);
+ break;
+
+ case 106:
+ if (_globals[kEndOfGame])
+ _vm->_sound->command(47);
+ else
+ _vm->_sound->command(16);
+ break;
+
+ case 108:
+ if (_game._visitedScenes.exists(109))
+ _vm->_sound->command(32);
+ else
+ _vm->_sound->command(33);
+ break;
+
+ case 109:
+ _vm->_sound->command(32);
+ break;
+
+ case 110:
+ _vm->_sound->command(37);
+ break;
+
+ case 111:
+ _vm->_sound->command(34);
+ break;
+
+ case 112:
+ _vm->_sound->command(38);
+ break;
+
+ case 113:
+ _vm->_sound->command(5);
+ if (_globals[kPlayerIsSeal])
+ _vm->_sound->command(35);
+ else
+ _vm->_sound->command(36);
+ break;
+
+ case 114:
+ _vm->_sound->command(36);
+ break;
+
+ case 115:
+ _vm->_sound->command(39);
+ break;
+
+ case 116:
+ _vm->_sound->command(40);
+ break;
+
+ case 117:
+ _vm->_sound->command(35);
+ break;
+
+ case 119:
+ _vm->_sound->command(41);
+ break;
+
+ case 120:
+ _vm->_sound->command(46);
+ break;
+
+ default:
+ _vm->_sound->command(16);
+ break;
+ }
+}
+
+void Scene1xx::setPlayerSpritesPrefix() {
+ int darkSceneFl = false;
+ int noPlayerFl = false;
+
+ _vm->_sound->command(5);
+ Common::String oldName = _game._player._spritesPrefix;
+
+ _globals[kPerformDisplacements] = true;
+
+ switch (_scene->_nextSceneId) {
+ case 106:
+ if (_scene->_currentSceneId == 120)
+ noPlayerFl = true;
+ break;
+
+ case 108:
+ case 109:
+ case 114:
+ case 115:
+ darkSceneFl = true;
+ break;
+
+ case 111:
+ case 112:
+ case 117:
+ case 120:
+ case 119:
+ noPlayerFl = true;
+ break;
+
+ case 113:
+ if (!_globals[kPlayerPersona])
+ noPlayerFl = true;
+ darkSceneFl = true;
+ break;
+ }
+
+ if (noPlayerFl || _globals[kNoLoadWalker]) {
+ _game._player._spritesPrefix = "";
+ } else if (!_game._player._forcePrefix) {
+ if (!_globals[kPlayerPersona] || _scene->_nextSceneId == 108 || _scene->_nextSceneId == 109) {
+ if (_scene->_nextSceneId == 113 || _scene->_nextSceneId == 114 || _scene->_nextSceneId == 115 || _scene->_nextSceneId == 116)
+ _game._player._spritesPrefix = "PD";
+ else
+ _game._player._spritesPrefix = "KG";
+ } else
+ _game._player._spritesPrefix = "PD";
+
+ if (darkSceneFl)
+ _game._player._spritesPrefix += "D";
+ }
+
+ if (oldName != _game._player._spritesPrefix)
+ _game._player._spritesChanged = true;
+
+ _game._player._scalingVelocity = true;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene101::Scene101(MADSEngine *vm) : Scene1xx(vm) {
+}
+
+void Scene101::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+}
+
+void Scene101::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene101::enter() {
+ sceneEntrySound();
+}
+
+void Scene101::step() {
+}
+
+void Scene101::actions() {
+ if (_action.isObject(NOUN_BED)) {
+ int sprIdx = _scene->_sprites.addSprites("*ob001i");
+ int seqIdx = _scene->_sequences.addStampCycle(sprIdx, false, 1);
+ _scene->_sequences.setDepth(seqIdx, 0);
+ _scene->_sequences.setPosition(seqIdx, Common::Point(10, 50));
+ _action._inProgress = false;
+ }
+}
+
+void Scene101::preActions() {
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene102::Scene102(MADSEngine *vm) : Scene1xx(vm) {
+ _diaryHotspotIdx1 = -1;
+ _diaryHotspotIdx2 = -1;
+ _diaryFrame = -1;
+ _animRunning = -1;
+}
+
+void Scene102::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+
+ s.syncAsSint16LE(_diaryHotspotIdx1);
+ s.syncAsSint16LE(_diaryHotspotIdx2);
+ s.syncAsSint16LE(_diaryFrame);
+ s.syncAsSint16LE(_animRunning);
+}
+
+void Scene102::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ _scene->addActiveVocab(NOUN_DIARIES);
+ _scene->addActiveVocab(VERB_WALK_TO);
+}
+
+void Scene102::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('p', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('p', 1));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('y', 0));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('y', 1));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('x', -1));
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites("*KGRD_6");
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('y', 2));
+
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 7, 0);
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 7, 0);
+ _globals._sequenceIndexes[8] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[8], false, 7, 0);
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 12);
+ _diaryHotspotIdx1 = _scene->_dynamicHotspots.add(NOUN_DIARIES, VERB_WALK_TO, SYNTAX_PLURAL, _globals._sequenceIndexes[1], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(_diaryHotspotIdx1, Common::Point(47, 123), FACING_NORTHWEST);
+
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 12);
+ _diaryHotspotIdx2 = _scene->_dynamicHotspots.add(NOUN_DIARIES, VERB_WALK_TO, SYNTAX_PLURAL, _globals._sequenceIndexes[2], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(_diaryHotspotIdx2, Common::Point(47, 123), FACING_NORTHWEST);
+
+ if (_scene->_priorSceneId == 103) {
+ _game._player._playerPos = Common::Point(170, 152);
+ _game._player._facing = FACING_NORTHWEST;
+ _globals._sequenceIndexes[6] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[6], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 5);
+ } else if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ _globals._sequenceIndexes[6] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[6], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 5);
+ _game._player.firstWalk(Common::Point(-10, 130), FACING_EAST, Common::Point(35, 144), FACING_EAST, false);
+ _game._player.setWalkTrigger(70);
+ } else {
+ _globals._sequenceIndexes[6] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[6], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 5);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene102::step() {
+ if ((_animRunning == 1) && _scene->_animation[_globals._animationIndexes[0]]) {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() != _diaryFrame) {
+ _diaryFrame = _scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame();
+
+ switch (_diaryFrame) {
+ case 6:
+ _scene->deleteSequence(_globals._sequenceIndexes[1]);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[1], SYNC_ANIM, _globals._animationIndexes[0]);
+ break;
+
+ case 10:
+ _vm->_sound->command(65);
+ break;
+
+ case 26:
+ _vm->_dialogs->show(10210);
+ _vm->_dialogs->show(10211);
+ _vm->_dialogs->show(10212);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ if ((_animRunning == 2) && _scene->_animation[_globals._animationIndexes[0]]) {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() != _diaryFrame) {
+ _diaryFrame = _scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame();
+
+ switch (_diaryFrame) {
+ case 6:
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[2], SYNC_ANIM, _globals._animationIndexes[0]);
+ break;
+
+ case 26:
+ _vm->_dialogs->show(10213);
+ _vm->_dialogs->show(10214);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ if (_game._trigger >= 70) {
+ switch (_game._trigger) {
+ case 70:
+ _scene->deleteSequence(_globals._sequenceIndexes[6]);
+ _vm->_sound->command(25);
+ _globals._sequenceIndexes[6] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[6], false, 9, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 5);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[6], 1, 4);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ break;
+
+ case 71: {
+ int idx = _globals._sequenceIndexes[6];
+ _globals._sequenceIndexes[6] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[6], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], -2);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[6], SYNC_SEQ, idx);
+ _game._player._stepEnabled = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void Scene102::actions() {
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(10201);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR_TO_KINGS_ROOM) || _action.isAction(VERB_OPEN, NOUN_DOOR_TO_KINGS_ROOM) || _action.isAction(VERB_PULL, NOUN_DOOR_TO_KINGS_ROOM)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[7] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[7], true, 8, 2);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[7], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_SPRITE, 2, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 1:
+ _scene->deleteSequence(_globals._sequenceIndexes[6]);
+ _vm->_sound->command(24);
+ _globals._sequenceIndexes[6] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[6], false, 9, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 5);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 2: {
+ int idx = _globals._sequenceIndexes[6];
+ _globals._sequenceIndexes[6] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[6], false, 5);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 5);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[6], SYNC_SEQ, idx);
+ }
+ break;
+
+ case 3:
+ _game._player._visible = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[7]);
+ _game._player.walk(Common::Point(0, 130), FACING_WEST);
+ _game._player._walkOffScreenSceneId = 101;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR_TO_HALLWAY) || _action.isAction(VERB_OPEN, NOUN_DOOR_TO_HALLWAY) || _action.isAction(VERB_PULL, NOUN_DOOR_TO_HALLWAY)) {
+ _scene->_nextSceneId = 103;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_DIARIES) || _action.isAction(VERB_OPEN, NOUN_DIARIES)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _animRunning = 1;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('B',-1), 1);
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[0], SYNC_PLAYER, 0);
+ break;
+
+ case 1:
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 12);
+ _diaryHotspotIdx1 = _scene->_dynamicHotspots.add(NOUN_DIARIES, VERB_WALK_TO, SYNTAX_PLURAL, _globals._sequenceIndexes[1], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(_diaryHotspotIdx1, Common::Point(47, 123), FACING_NORTHWEST);
+ _game._player._visible = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[0]);
+ _scene->_sequences.addTimer(6, 2);
+ break;
+
+ case 2:
+ _game._player.walk(Common::Point(51, 121), FACING_NORTHWEST);
+ _game._player.setWalkTrigger(3);
+ break;
+
+ case 3:
+ _game._player._visible = false;
+ _animRunning = 2;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('A',-1), 4);
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[0], SYNC_PLAYER, 0);
+ break;
+
+ case 4:
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 12);
+ _diaryHotspotIdx2 = _scene->_dynamicHotspots.add(NOUN_DIARIES, VERB_WALK_TO, SYNTAX_PLURAL, _globals._sequenceIndexes[2], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(_diaryHotspotIdx2, Common::Point(47, 123), FACING_NORTHWEST);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[0]);
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_FIREPLACE)) {
+ _vm->_dialogs->show(10202);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BED)) {
+ _vm->_dialogs->show(10203);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SHUTTERS)) {
+ _vm->_dialogs->show(10204);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RUG)) {
+ _vm->_dialogs->show(10206);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BOOKCASE)) {
+ _vm->_dialogs->show(10208);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DIARIES)) {
+ _vm->_dialogs->show(10209);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DOOR_TO_KINGS_ROOM)) {
+ _vm->_dialogs->show(10215);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FLOWERS)) {
+ _vm->_dialogs->show(10216);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WINDOW)) {
+ _vm->_dialogs->show(10217);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WOOD_BASKET)) {
+ _vm->_dialogs->show(10219);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FIREPLACE_SCREEN)) {
+ _vm->_dialogs->show(10220);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_NIGHTSTAND)) {
+ _vm->_dialogs->show(10222);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DOOR_TO_HALLWAY)) {
+ _vm->_dialogs->show(10223);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CHEST)) {
+ _vm->_dialogs->show(10224);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_TAPESTRY)) {
+ _vm->_dialogs->show(10226);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SCONCE)) {
+ _vm->_dialogs->show(10227);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(10228);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(10229);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DECORATION)) {
+ _vm->_dialogs->show(10230);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CEILING)) {
+ _vm->_dialogs->show(10231);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_CHEST)) {
+ _vm->_dialogs->show(10224);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_FLOWERS)) {
+ _vm->_dialogs->show(10225);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_WINDOW)) {
+ _vm->_dialogs->show(10218);
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isAction(VERB_PUSH) || _action.isAction(VERB_PULL)) && _action.isObject(NOUN_FIREPLACE_SCREEN)) {
+ _vm->_dialogs->show(10221);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLOSE, NOUN_SHUTTERS)) {
+ _vm->_dialogs->show(10205);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_PULL, NOUN_RUG)) {
+ _vm->_dialogs->show(10207);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene102::preActions() {
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene103::Scene103(MADSEngine *vm) : Scene1xx(vm) {
+}
+
+void Scene103::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+}
+
+void Scene103::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene103::enter() {
+ _vm->_disableFastwalk = true;
+
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('y', 1));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('y', 2));
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('y', 7));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('y', 0));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('y', 3));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('y', 4));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('y', 5));
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('y', 6));
+ _globals._spriteIndexes[9] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[10] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[11] = _scene->_sprites.addSprites("*KGRD_9");
+
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 7, 0, 0);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 7, 0, 4);
+ _globals._sequenceIndexes[8] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[8], false, 7, 0, 0);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 7, 0, 0);
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 7, 0, 3);
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 7, 0, 2);
+ _globals._sequenceIndexes[6] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[6], false, 7, 0, 0);
+ _globals._sequenceIndexes[7] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[7], false, 7, 0, 5);
+
+ if ((_scene->_priorSceneId == 104) || (_scene->_priorSceneId == 105)) {
+ _globals._sequenceIndexes[9] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[9], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 8);
+ _globals._sequenceIndexes[10] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[10], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 8);
+ }
+
+ if (_scene->_priorSceneId == 102) {
+ _globals._sequenceIndexes[9] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[9], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 6);
+ _globals._sequenceIndexes[10] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[10], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 14);
+ _scene->setCamera(Common::Point(320, 0));
+ _game._player.walk(Common::Point(482, 128), FACING_SOUTH);
+ _game._player.firstWalk(Common::Point(471, 108), FACING_SOUTH, Common::Point(482, 128), FACING_SOUTH, false);
+ _game._player.setWalkTrigger(72);
+ } else if (_scene->_priorSceneId == 104) {
+ _game._player._playerPos = Common::Point(130, 152);
+ _game._player._facing = FACING_NORTHEAST;
+ } else if (_scene->_priorSceneId == 105) {
+ _game._player._playerPos = Common::Point(517, 152);
+ _game._player._facing = FACING_NORTHWEST;
+ _scene->setCamera(Common::Point(320, 0));
+ } else if ((_scene->_priorSceneId == 101) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
+ _globals._sequenceIndexes[10] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[10], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 6);
+ _globals._sequenceIndexes[9] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[9], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 14);
+ _game._player.firstWalk(Common::Point(173, 108), FACING_SOUTH, Common::Point(162, 127), FACING_SOUTH, false);
+ _game._player.setWalkTrigger(70);
+ } else {
+ _globals._sequenceIndexes[10] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[10], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 6);
+ _globals._sequenceIndexes[9] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[9], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 6);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene103::step() {
+ switch (_game._trigger) {
+ case 70:
+ _scene->deleteSequence(_globals._sequenceIndexes[9]);
+ _vm->_sound->command(25);
+ _globals._sequenceIndexes[9] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[9], false, 6, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 6);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[9], 1, 3);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[9], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ break;
+
+ case 71: {
+ int tmpIdx = _globals._sequenceIndexes[9];
+ _globals._sequenceIndexes[9] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[9], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 6);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[9], SYNC_SEQ, tmpIdx);
+ _game._player._stepEnabled = true;
+ }
+ break;
+
+ case 72:
+ _scene->deleteSequence(_globals._sequenceIndexes[10]);
+ _vm->_sound->command(25);
+ _globals._sequenceIndexes[10] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[10], false, 6, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 6);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[10], 1, 3);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[10], SEQUENCE_TRIGGER_EXPIRE, 0, 73);
+ break;
+
+ case 73: {
+ int tmpIdx = _globals._sequenceIndexes[10];
+ _globals._sequenceIndexes[10] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[10], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 6);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[10], SYNC_SEQ, tmpIdx);
+ _game._player._stepEnabled = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene103::actions() {
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(10301);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR_TO_KINGS_ROOM) || _action.isAction(VERB_OPEN, NOUN_DOOR_TO_KINGS_ROOM) || _action.isAction(VERB_PULL, NOUN_DOOR_TO_KINGS_ROOM)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[11] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[11], false, 7, 2);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[11], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[11], SEQUENCE_TRIGGER_SPRITE, 2, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[11], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 1:
+ _scene->deleteSequence(_globals._sequenceIndexes[9]);
+ _vm->_sound->command(24);
+ _globals._sequenceIndexes[9] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[9], false, 7, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[9], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 2: {
+ int tmpIdx = _globals._sequenceIndexes[9];
+ _globals._sequenceIndexes[9] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[9], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 14);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[9], SYNC_SEQ, tmpIdx);
+ }
+ break;
+
+ case 3:
+ _game._player._visible = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[11]);
+ _scene->_sequences.addTimer(1, 4);
+ break;
+
+ case 4:
+ _game._player.walk(Common::Point(173, 108), FACING_NORTH);
+ _game._player.setWalkTrigger(5);
+ break;
+
+ case 5:
+ _scene->deleteSequence(_globals._sequenceIndexes[9]);
+ _vm->_sound->command(25);
+ _globals._sequenceIndexes[9] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[9], false, 7, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[9], SEQUENCE_TRIGGER_EXPIRE, 0, 6);
+ break;
+
+ case 6: {
+ int tmpIdx = _globals._sequenceIndexes[9];
+ _globals._sequenceIndexes[9] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[9], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 1);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[9], SYNC_SEQ, tmpIdx);
+ _scene->_sequences.addTimer(6, 7);
+ }
+ break;
+
+ case 7:
+ _scene->_nextSceneId = 101;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR_TO_QUEENS_ROOM) || _action.isAction(VERB_OPEN, NOUN_DOOR_TO_QUEENS_ROOM) || _action.isAction(VERB_PULL, NOUN_DOOR_TO_QUEENS_ROOM)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[11] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[11], true, 7, 2);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[11], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[11], SEQUENCE_TRIGGER_SPRITE, 2, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[11], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 1:
+ _scene->deleteSequence(_globals._sequenceIndexes[10]);
+ _vm->_sound->command(24);
+ _globals._sequenceIndexes[10] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[10], false, 7, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[10], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 2: {
+ int tmpIdx = _globals._sequenceIndexes[10];
+ _globals._sequenceIndexes[10] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[10], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 14);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[10], SYNC_SEQ, tmpIdx);
+ }
+ break;
+
+ case 3:
+ _game._player._visible = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[11]);
+ _scene->_sequences.addTimer(1, 4);
+ break;
+
+ case 4:
+ _game._player.walk(Common::Point(471, 108), FACING_NORTH);
+ _game._player.setWalkTrigger(5);
+ break;
+
+ case 5:
+ _scene->deleteSequence(_globals._sequenceIndexes[10]);
+ _vm->_sound->command(25);
+ _globals._sequenceIndexes[10] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[10], false, 7, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[10], SEQUENCE_TRIGGER_EXPIRE, 0, 6);
+ break;
+
+ case 6: {
+ int tmpIdx = _globals._sequenceIndexes[10];
+ _globals._sequenceIndexes[10] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[10], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 1);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[10], SYNC_SEQ, tmpIdx);
+ _scene->_sequences.addTimer(6, 7);
+ }
+ break;
+
+ case 7:
+ _scene->_nextSceneId = 102;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR_TO_MEETING_ROOM) || _action.isAction(VERB_OPEN, NOUN_DOOR_TO_MEETING_ROOM) || _action.isAction(VERB_PULL, NOUN_DOOR_TO_MEETING_ROOM)) {
+ _scene->_nextSceneId = 104;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR_TO_BALLROOM) || _action.isAction(VERB_OPEN, NOUN_DOOR_TO_BALLROOM) || _action.isAction(VERB_PULL, NOUN_DOOR_TO_BALLROOM)) {
+ _scene->_nextSceneId = 105;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_TAPESTRY)) {
+ if ((_scene->_customDest.x <= 75) && (_scene->_customDest.y <= 130))
+ _vm->_dialogs->show(10302);
+ else
+ _vm->_dialogs->show(10303);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_COAT_OF_ARMS)) {
+ _vm->_dialogs->show(10305);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DOOR_TO_QUEENS_ROOM)) {
+ _vm->_dialogs->show(10307);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DOOR_TO_KINGS_ROOM)) {
+ _vm->_dialogs->show(10308);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CEDAR_CHEST)) {
+ _vm->_dialogs->show(10309);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_TABLE)) {
+ _vm->_dialogs->show(10311);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SMALL_WINDOW)) {
+ _vm->_dialogs->show(10312);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LARGE_WINDOW)) {
+ _vm->_dialogs->show(10314);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BATTLE_AXES)) {
+ _vm->_dialogs->show(10315);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BUST_ON_WALL)) {
+ _vm->_dialogs->show(10317);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DECORATION)) {
+ _vm->_dialogs->show(10320);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WALL_PLAQUE)) {
+ _vm->_dialogs->show(10322);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DOOR_TO_BALLROOM)) {
+ _vm->_dialogs->show(10323);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DOOR_TO_MEETING_ROOM)) {
+ _vm->_dialogs->show(10324);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if ((_action.isAction(VERB_TAKE) || _action.isAction(VERB_PULL)) && _action.isObject(NOUN_BATTLE_AXES)) {
+ _vm->_dialogs->show(10316);
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isAction(VERB_PUSH) || _action.isAction(VERB_PULL)) && _action.isObject(NOUN_TAPESTRY)) {
+ _vm->_dialogs->show(10304);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_PULL, NOUN_COAT_OF_ARMS)) {
+ _vm->_dialogs->show(10306);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_CEDAR_CHEST)) {
+ _vm->_dialogs->show(10310);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_SMALL_WINDOW) || _action.isAction(VERB_OPEN, NOUN_LARGE_WINDOW)) {
+ _vm->_dialogs->show(10313);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene103::preActions() {
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene104::Scene104(MADSEngine *vm) : Scene1xx(vm) {
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _anim2ActvFl = false;
+ _anim3ActvFl = false;
+ _anim4ActvFl = false;
+ _anim5ActvFl = false;
+ _activateTimerFl = false;
+ _wasBearFl = false;
+ _amuletWorksFl = false;
+ _pidDrawnSword = false;
+ _anim6ActvFl = false;
+
+ _animationRunning = -1;
+ _deathTimer = -1;
+ _deathFrame = -1;
+ _doorwayHotspotId = -1;
+
+ _kingStatus = -1;
+ _kingFrame = -1;
+ _kingCount = -1;
+ _macCount = -1;
+ _macFrame = -1;
+ _macStatus = -1;
+ _queenStatus = -1;
+ _queenFrame = -1;
+ _queenCount = -1;
+ _pidStatus = -1;
+ _pidFrame = -1;
+ _pidCount = -1;
+ _twinklesFrame = -1;
+ _twinklesStatus = -1;
+ _twinklesCount = -1;
+
+ _tapestryFrame = -1;
+ _clock = -1;
+}
+
+void Scene104::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+
+ s.syncAsByte(_anim0ActvFl);
+ s.syncAsByte(_anim1ActvFl);
+ s.syncAsByte(_anim2ActvFl);
+ s.syncAsByte(_anim3ActvFl);
+ s.syncAsByte(_anim4ActvFl);
+ s.syncAsByte(_anim5ActvFl);
+ s.syncAsByte(_activateTimerFl);
+ s.syncAsByte(_wasBearFl);
+ s.syncAsByte(_amuletWorksFl);
+ s.syncAsByte(_pidDrawnSword);
+ s.syncAsByte(_anim6ActvFl);
+
+ s.syncAsSint16LE(_animationRunning);
+ s.syncAsSint16LE(_deathTimer);
+ s.syncAsSint16LE(_deathFrame);
+ s.syncAsSint16LE(_doorwayHotspotId);
+
+ s.syncAsSint16LE(_kingStatus);
+ s.syncAsSint16LE(_kingFrame);
+ s.syncAsSint16LE(_kingCount);
+ s.syncAsSint16LE(_queenStatus);
+ s.syncAsSint16LE(_queenFrame);
+ s.syncAsSint16LE(_queenCount);
+ s.syncAsSint16LE(_macStatus);
+ s.syncAsSint16LE(_macFrame);
+ s.syncAsSint16LE(_macCount);
+ s.syncAsSint16LE(_pidStatus);
+ s.syncAsSint16LE(_pidFrame);
+ s.syncAsSint16LE(_pidCount);
+ s.syncAsSint16LE(_twinklesStatus);
+ s.syncAsSint16LE(_twinklesFrame);
+ s.syncAsSint16LE(_twinklesCount);
+
+ s.syncAsSint16LE(_tapestryFrame);
+ s.syncAsSint32LE(_clock);
+}
+
+void Scene104::setup() {
+ if (_scene->_currentSceneId == 119)
+ _globals[kNoLoadWalker] = true;
+
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ _scene->addActiveVocab(NOUN_DOORWAY);
+ _scene->addActiveVocab(NOUN_QUEEN_MOTHER);
+ _scene->addActiveVocab(NOUN_KING);
+}
+
+void Scene104::enter() {
+ _vm->_gameConv->load(1);
+
+ if (_globals[kPlayerPersona] == 1) {
+ _scene->_sprites.addSprites(formAnimName('e', 8));
+ _scene->_sprites.addSprites(formAnimName('b', 5));
+ }
+
+ _scene->_hotspots.activate(NOUN_MACMORN, false);
+
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ _animationRunning = 0;
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _anim2ActvFl = false;
+ _anim3ActvFl = false;
+ _anim4ActvFl = false;
+ _anim5ActvFl = false;
+ _kingCount = 0;
+ _macCount = 0;
+ _queenCount = 0;
+ _twinklesCount = 0;
+ _deathTimer = 0;
+ _clock = 0;
+ _activateTimerFl = false;
+ _wasBearFl = false;
+ _amuletWorksFl = false;
+ _pidDrawnSword = false;
+ }
+
+ _anim6ActvFl = false;
+
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('x', 2));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('x', 3));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('x', 5));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('x', 4));
+
+ if (_globals[kNoLoadWalker]) {
+ _scene->drawToBackground(_globals._spriteIndexes[6], 5, Common::Point(-32000, -32000), 0, 100);
+ _scene->_sprites.remove(_globals._spriteIndexes[6]);
+ }
+
+ if (_globals[kPlayerPersona] == 0) {
+ _scene->_hotspots.activateAtPos(NOUN_TABLE, false, Common::Point(139, 132));
+
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites("*KGRD_8");
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites("*KGRM1_8");
+ _globals._spriteIndexes[11] = _scene->_sprites.addSprites(formAnimName('y', 5));
+ _globals._spriteIndexes[10] = _scene->_sprites.addSprites(formAnimName('y', 4));
+ _globals._spriteIndexes[12] = _scene->_sprites.addSprites(formAnimName('y', 1));
+
+ if (_globals[kTapestryStatus] == 0 || _globals[kTapestryStatus] == 2) {
+ _scene->_hotspots.activate(NOUN_WALL_PANEL, false);
+ _scene->_hotspots.activate(NOUN_SECRET_DOOR, false);
+ _globals._sequenceIndexes[11] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[11], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[11], 6);
+ } else {
+ _globals._sequenceIndexes[10] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[10], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 6);
+ _scene->_hotspots.activateAtPos(NOUN_TAPESTRY, false, Common::Point(310, 70));
+ }
+
+ if (_globals[kBooksStatus] == 1 || _globals[kBooksStatus] == 3) {
+ if (_globals[kTapestryStatus] == 1 || _globals[kTapestryStatus] == 3)
+ _scene->_hotspots.activate(NOUN_SECRET_DOOR, false);
+ } else if (_globals[kBooksStatus] == 2 || _globals[kBooksStatus] == 4) {
+ _globals._sequenceIndexes[12] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[12], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[12], 8);
+
+ if (_globals[kTapestryStatus] == 1 || _globals[kTapestryStatus] == 3) {
+ _scene->_hotspots.activate(NOUN_WALL_PANEL, false);
+ _scene->_hotspots.activate(NOUN_SECRET_DOOR, true);
+ }
+ }
+ } else {
+ _globals._spriteIndexes[14] = _scene->_sprites.addSprites(formAnimName('e', 5));
+ _scene->_sprites.addSprites(formAnimName('b', 0));
+ _globals._spriteIndexes[13] = _scene->_sprites.addSprites(formAnimName('b', 3));
+ _scene->_hotspots.activateAtPos(NOUN_TABLE, false, Common::Point(140, 107));
+ _scene->_hotspots.activateAtPos(NOUN_TABLE, true, Common::Point(139, 132));
+ _globals._spriteIndexes[10] = _scene->_sprites.addSprites(formAnimName('y', 4));
+
+ if (_globals[kNoLoadWalker]) {
+ _scene->drawToBackground(_globals._spriteIndexes[10], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_sprites.remove(_globals._spriteIndexes[10]);
+ }
+
+ _globals._spriteIndexes[9] = _scene->_sprites.addSprites(formAnimName('y', 3));
+ _globals._sequenceIndexes[9] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[9], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 8);
+ _doorwayHotspotId = _scene->_dynamicHotspots.add(NOUN_DOORWAY, VERB_WALK_THROUGH, SYNTAX_SINGULAR, _globals._sequenceIndexes[9], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(_doorwayHotspotId, Common::Point(295, 145), FACING_NORTHEAST);
+
+ _globals[kBooksStatus] = 0;
+ _scene->_hotspots.activateAtPos(NOUN_TAPESTRY, false, Common::Point(310, 70));
+ }
+
+ if (_globals[kBooksStatus] == 0)
+ _scene->_hotspots.activate(NOUN_BOOKS, false);
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 7, 0, 5);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 7, 0);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 7, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 3);
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 7, 0);
+
+
+ if (_globals[kPlayerPersona] == 0) {
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 4);
+ }
+
+ if (_scene->_priorSceneId == 106) {
+ _game._player._playerPos = Common::Point(201, 152);
+ _game._player._facing = FACING_NORTHWEST;
+ _globals._sequenceIndexes[6] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[6], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 14);
+ } else if ((_scene->_priorSceneId == 119) || (_scene->_priorSceneId == 104)) {
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 4);
+ _scene->_sequences.addTimer(60, 77);
+
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('k', 1), 0);
+ _anim0ActvFl = true;
+ _kingStatus = 2;
+ _scene->setAnimFrame(_globals._animationIndexes[0], 22);
+
+ _globals._animationIndexes[2] = _scene->loadAnimation(formAnimName('q', 1), 0);
+ _anim2ActvFl = true;
+ _queenStatus = 0;
+
+ _globals._sequenceIndexes[14] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[14], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[14], 6);
+
+ _globals._animationIndexes[4] = _scene->loadAnimation(formAnimName('p', 1), 79);
+
+ int idx = _scene->_dynamicHotspots.add(NOUN_QUEEN_MOTHER, VERB_WALK_TO, SYNTAX_FEM_NOT_PROPER, EXT_NONE, Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots[idx]._articleNumber = PREP_ON;
+ _scene->setDynamicAnim(idx, _globals._animationIndexes[2], 0);
+
+ _scene->_hotspots.activate(NOUN_MACMORN, true);
+
+ idx = _scene->_dynamicHotspots.add(NOUN_KING, VERB_WALK_TO, SYNTAX_MASC_NOT_PROPER, EXT_NONE, Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots[idx]._articleNumber = PREP_ON;
+ _scene->setDynamicAnim(idx, _globals._animationIndexes[0], 0);
+ } else if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ _globals._sequenceIndexes[6] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[6], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 14);
+ _game._player.firstWalk(Common::Point(77, 93), FACING_SOUTH, Common::Point(74, 107), FACING_SOUTH, false);
+ _game._player.setWalkTrigger(70);
+ } else if (_globals[kNoLoadWalker]) {
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 1);
+
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('k', 1), 0);
+ _anim0ActvFl = true;
+ _kingStatus = 0;
+ _scene->setAnimFrame(_globals._animationIndexes[0], 14);
+
+ _globals._animationIndexes[2] = _scene->loadAnimation(formAnimName('q', 1), 0);
+ _anim2ActvFl = true;
+ _queenStatus = 0;
+
+ _globals._animationIndexes[4] = _scene->loadAnimation(formAnimName('p', 2), 0);
+ _anim4ActvFl = true;
+ _pidStatus = 0;
+ if (_amuletWorksFl)
+ _scene->setAnimFrame(_globals._animationIndexes[4], 89);
+
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('m', 1), 0);
+ _anim1ActvFl = true;
+ _macStatus = 0;
+ _scene->setAnimFrame(_globals._animationIndexes[1], 25);
+
+ int idx = _scene->_dynamicHotspots.add(NOUN_QUEEN_MOTHER, VERB_WALK_TO, SYNTAX_FEM_NOT_PROPER, EXT_NONE, Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots[idx]._articleNumber = PREP_ON;
+ _scene->setDynamicAnim(idx, _globals._animationIndexes[2], 0);
+
+ _scene->_hotspots.activate(NOUN_MACMORN, true);
+
+ idx = _scene->_dynamicHotspots.add(NOUN_KING, VERB_WALK_TO, SYNTAX_MASC_NOT_PROPER, EXT_NONE, Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots[idx]._articleNumber = PREP_ON;
+ _scene->setDynamicAnim(idx, _globals._animationIndexes[0], 0);
+
+ if (_vm->_gameConv->restoreRunning() == 1) {
+ _game._player._stepEnabled = false;
+ _vm->_gameConv->run(1);
+ _vm->_gameConv->exportValue(0);
+ _vm->_gameConv->exportValue(0);
+ _vm->_gameConv->exportValue(0);
+ if (_globals[kLlanieStatus] != 2)
+ _vm->_gameConv->exportValue(1);
+ else
+ _vm->_gameConv->exportValue(0);
+ } else {
+ _activateTimerFl = true;
+ _deathTimer = 0;
+ _clock = 0;
+ _game._player._stepEnabled = true;
+ }
+ } else {
+ _globals._sequenceIndexes[6] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[6], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 12);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene104::step() {
+ if (_anim0ActvFl)
+ handleKingAnimation();
+
+ if (_anim1ActvFl)
+ handleMacAnimation1();
+
+ if (_anim2ActvFl)
+ handleQueenAnimation();
+
+ if (_anim3ActvFl)
+ handleTwinklesAnimation();
+
+ if (_anim4ActvFl)
+ handlePidAnimation();
+
+ if (_anim5ActvFl)
+ handleMacAnimation2();
+
+ if (_anim6ActvFl)
+ handleDeathAnimation();
+
+ if ((_animationRunning == 1) && _scene->_animation[_globals._animationIndexes[0]]) {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() != _tapestryFrame) {
+ _tapestryFrame = _scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame();
+
+ if (_tapestryFrame == 13) {
+ _game._player._visible = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[0]);
+ }
+ }
+ }
+
+ switch (_game._trigger) {
+ case 70:
+ _scene->deleteSequence(_globals._sequenceIndexes[6]);
+ _vm->_sound->command(25);
+ _globals._sequenceIndexes[6] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[6], false, 6, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[6], 1, 4);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ break;
+
+ case 71: {
+ int idx = _globals._sequenceIndexes[6];
+ _globals._sequenceIndexes[6] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[6], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 14);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[6], SYNC_SEQ, idx);
+ _game._player._stepEnabled = true;
+ }
+ break;
+ }
+
+ if (_game._trigger == 77)
+ _kingStatus = 0;
+
+ if (_game._trigger == 79) {
+ _scene->freeAnimation(_globals._animationIndexes[4]);
+
+ _globals._animationIndexes[4] = _scene->loadAnimation(formAnimName('p', 2), 0);
+ _anim4ActvFl = true;
+ _pidStatus = 0;
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[4], SYNC_CLOCK, 0);
+
+ _scene->deleteSequence(_globals._sequenceIndexes[14]);
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('m', 1), 0);
+ _anim1ActvFl = true;
+ _macStatus = 0;
+
+ _game._player._stepEnabled = false;
+ _vm->_gameConv->run(1);
+ _vm->_gameConv->exportValue(0);
+ _vm->_gameConv->exportValue(0);
+ _vm->_gameConv->exportValue(0);
+
+ if (_globals[kLlanieStatus] != 2)
+ _vm->_gameConv->exportValue(1);
+ else
+ _vm->_gameConv->exportValue(0);
+ }
+
+ if (_game._trigger == 85) {
+ _vm->_sound->command(100);
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 1);
+ }
+
+ if (_activateTimerFl) {
+ long clockDiff = _scene->_frameStartTime - _clock;
+ if ((clockDiff >= 0) && (clockDiff <= 4))
+ _deathTimer += clockDiff;
+ else
+ _deathTimer += 1;
+
+ _clock = _scene->_frameStartTime;
+
+ if (_deathTimer >= 1300) {
+ _activateTimerFl = false;
+ if (_pidDrawnSword) {
+ _pidStatus = 6;
+ _vm->_gameConv->run(1);
+ _vm->_gameConv->exportValue(0);
+ _vm->_gameConv->exportValue(1);
+ _vm->_gameConv->exportValue(0);
+ if (_globals[kLlanieStatus] != 2)
+ _vm->_gameConv->exportValue(1);
+ else
+ _vm->_gameConv->exportValue(0);
+ _vm->_gameConv->hold();
+ } else
+ _pidStatus = 8;
+
+ _game._player._stepEnabled = false;
+ }
+ }
+
+
+ if ((_globals[kTapestryStatus] == 1 || _globals[kTapestryStatus] == 3)
+ && (_globals[kBooksStatus] == 2 || _globals[kBooksStatus] == 4))
+ _globals[kCanViewCrownHole] = true;
+
+ if (_game._trigger == 95) {
+ _vm->_gameConv->reset(1);
+ _vm->_dialogs->show(10466);
+ _globals[kNoLoadWalker] = false;
+ _scene->_nextSceneId = 119;
+ }
+}
+
+void Scene104::actions() {
+ if (_vm->_gameConv->activeConvId() == 1) {
+ handleFinalConversation();
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ if (_globals[kPlayerPersona] == 0)
+ _vm->_dialogs->show(10401);
+ else
+ _vm->_dialogs->show(10437);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR_TO_THRONE_ROOM) || _action.isAction(VERB_OPEN, NOUN_DOOR_TO_THRONE_ROOM) || _action.isAction(VERB_PULL, NOUN_DOOR_TO_THRONE_ROOM)) {
+ if (_globals[kPlayerPersona] == 0)
+ _scene->_nextSceneId = 106;
+ else
+ _vm->_dialogs->show(10434);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR_TO_HALLWAY) || _action.isAction(VERB_OPEN, NOUN_DOOR_TO_HALLWAY) || _action.isAction(VERB_PULL, NOUN_DOOR_TO_HALLWAY)) {
+ if (_globals[kPlayerPersona] == 0) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[7] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[7], false, 8, 2);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[7], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_SPRITE, 2, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 1:
+ _scene->deleteSequence(_globals._sequenceIndexes[6]);
+ _vm->_sound->command(24);
+ _globals._sequenceIndexes[6] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[6], false, 6, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 14);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 2: {
+ int tmpIdx = _globals._sequenceIndexes[6];
+ _globals._sequenceIndexes[6] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[6], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 14);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[6], SYNC_SEQ, tmpIdx);
+ }
+ break;
+
+ case 3:
+ _game._player._visible = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[7]);
+ _scene->_sequences.addTimer(1, 4);
+ break;
+
+ case 4:
+ _game._player.walk(Common::Point(77, 93), FACING_NORTH);
+ _game._player.setWalkTrigger(5);
+ break;
+
+ case 5:
+ _scene->deleteSequence(_globals._sequenceIndexes[6]);
+ _vm->_sound->command(25);
+ _globals._sequenceIndexes[6] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[6], false, 7, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 6);
+ break;
+
+ case 6: {
+ int tmpIdx = _globals._sequenceIndexes[6];
+ _globals._sequenceIndexes[6] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[6], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 1);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[6], SYNC_SEQ, tmpIdx);
+ _scene->_sequences.addTimer(6, 7);
+ }
+ break;
+
+ case 7:
+ _scene->_nextSceneId = 103;
+ break;
+
+ default:
+ break;
+ }
+ } else
+ _vm->_dialogs->show(10434);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isAction(VERB_PULL) || _action.isAction(VERB_TAKE) || _action.isAction(VERB_OPEN)) && _action.isObject(NOUN_BOOKS)) {
+ if ((_globals[kBooksStatus] == 1) || (_globals[kBooksStatus] == 3) || _game._trigger) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[8] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[8], false, 8, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[8], -1, 3);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[8], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_SPRITE, 3, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 1:
+ _globals._sequenceIndexes[12] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[12], false, 6, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[12], 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[12], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 2: {
+ int tmpIdx = _globals._sequenceIndexes[12];
+ _globals._sequenceIndexes[12] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[12], false, -2);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[12], SYNC_SEQ, tmpIdx);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[12], 8);
+ if ((_globals[kTapestryStatus] == 1) || (_globals[kTapestryStatus] == 3)) {
+ _scene->_hotspots.activate(NOUN_WALL_PANEL, false);
+ _scene->_hotspots.activate(NOUN_SECRET_DOOR, true);
+ }
+ }
+ break;
+
+ case 3:
+ _game._player._visible = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[8]);
+ _scene->_sequences.addTimer(5, 4);
+ break;
+
+ case 4:
+ if (_globals[kBooksStatus] == 1) {
+ _globals[kPlayerScore] += 2;
+ _globals[kBooksStatus] = 2;
+ if ((_globals[kTapestryStatus] == 1) || (_globals[kTapestryStatus] == 3))
+ _vm->_dialogs->show(10428);
+ else {
+ _vm->_sound->command(94);
+ _vm->_sound->command(67);
+ _vm->_dialogs->show(10427);
+ }
+ } else {
+ _vm->_sound->command(94);
+ _vm->_sound->command(67);
+ _globals[kBooksStatus] = 4;
+ }
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_PUSH, NOUN_BOOKS)) {
+ if ((_globals[kBooksStatus] == 2) || (_globals[kBooksStatus] == 4)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[8] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[8], false, 8, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[8], -1, 3);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[8], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_SPRITE, 3, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 1:
+ _vm->_sound->command(94);
+ _vm->_sound->command(67);
+ _scene->deleteSequence(_globals._sequenceIndexes[12]);
+ _globals._sequenceIndexes[12] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[12], false, 6, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[12], 8);
+ _scene->_sequences.addTimer(6, 2);
+ break;
+
+ case 2:
+ if ((_globals[kTapestryStatus] == 1) || (_globals[kTapestryStatus] == 3)) {
+ _scene->_hotspots.activate(NOUN_WALL_PANEL, true);
+ _scene->_hotspots.activate(NOUN_SECRET_DOOR, false);
+ }
+ break;
+
+ case 3:
+ _game._player._visible = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[8]);
+ _scene->_sequences.addTimer(5, 4);
+ break;
+
+ case 4:
+ if (_globals[kBooksStatus] == 2)
+ _vm->_dialogs->show(10429);
+ _globals[kBooksStatus] = 3;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if ((_action.isAction(VERB_PULL) || _action.isAction(VERB_OPEN) || _action.isAction(VERB_PUSH)) && _action.isObject(NOUN_TAPESTRY)) {
+ if (_globals[kPlayerPersona] == 0) {
+ if (_scene->_customDest.x >= 279) {
+ if ((_globals[kTapestryStatus] == 0) || (_globals[kTapestryStatus] == 2)) {
+ switch (_game._trigger) {
+ case 0:
+ _scene->deleteSequence(_globals._sequenceIndexes[11]);
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _animationRunning = 1;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('a', -1), 1);
+ break;
+
+ case 1:
+ _game._player._visible = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[0]);
+ _globals._sequenceIndexes[10] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[10], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 6);
+ _scene->_hotspots.activateAtPos(NOUN_TAPESTRY, true, Common::Point(290, 20));
+ _scene->_hotspots.activateAtPos(NOUN_TAPESTRY, false, Common::Point(310, 70));
+ if ((_globals[kBooksStatus] == 2) || (_globals[kBooksStatus] == 4)) {
+ _scene->_hotspots.activate(NOUN_WALL_PANEL, false);
+ _scene->_hotspots.activate(NOUN_SECRET_DOOR, true);
+ } else {
+ _scene->_hotspots.activate(NOUN_WALL_PANEL, true);
+ _scene->_hotspots.activate(NOUN_SECRET_DOOR, false);
+ }
+ _scene->_sequences.addTimer(6, 2);
+ break;
+
+ case 2:
+ if (_globals[kTapestryStatus] == 0) {
+ _globals[kTapestryStatus] = 1;
+ _globals[kPlayerScore] += 2;
+ if (_globals[kBooksStatus] == 0 || _globals[kBooksStatus] == 1 || _globals[kBooksStatus] == 3)
+ _vm->_dialogs->show(10424);
+ else if (_globals[kBooksStatus] == 2 || _globals[kBooksStatus] == 4)
+ _vm->_dialogs->show(10425);
+ } else
+ _globals[kTapestryStatus] = 3;
+
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ } else
+ _vm->_dialogs->show(10404);
+ } else
+ _vm->_dialogs->show(10445);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isAction(VERB_PULL) || _action.isAction(VERB_CLOSE) || _action.isAction(VERB_PUSH)) && _action.isObject(NOUN_TAPESTRY)) {
+ if (_globals[kPlayerPersona] == 0) {
+ if (_scene->_customDest.x >= 279) {
+ if (_globals[kTapestryStatus] == 1 || _globals[kTapestryStatus] == 3) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _scene->deleteSequence(_globals._sequenceIndexes[10]);
+ _animationRunning = 2;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('d', -1), 1);
+ break;
+
+ case 1:
+ _game._player._visible = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[0]);
+ _globals._sequenceIndexes[11] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[11], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[11], 6);
+ _scene->_hotspots.activateAtPos(NOUN_TAPESTRY, false, Common::Point(290, 20));
+ _scene->_hotspots.activateAtPos(NOUN_TAPESTRY, true, Common::Point(310, 70));
+ _scene->_hotspots.activate(NOUN_SECRET_DOOR, false);
+ _scene->_hotspots.activate(NOUN_WALL_PANEL, false);
+ _scene->_sequences.addTimer(6, 2);
+ break;
+
+ case 2:
+ _globals[kTapestryStatus] = 2;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+ }
+ } else {
+ _vm->_dialogs->show(10445);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_BOOKS) || _action.isObject(NOUN_BOOKSHELF)) {
+ if (_globals[kPlayerPersona] == 0) {
+ switch (_globals[kBooksStatus]) {
+ case 0:
+ _scene->_hotspots.activate(NOUN_BOOKS, true);
+ _globals[kBooksStatus] = 1;
+ _vm->_dialogs->show(10418);
+ _action._inProgress = false;
+ return;
+
+ case 1:
+ _vm->_dialogs->show(10418);
+ _action._inProgress = false;
+ return;
+
+ case 2:
+ case 4:
+ _vm->_dialogs->show(10419);
+ _action._inProgress = false;
+ return;
+
+ case 3:
+ _vm->_dialogs->show(10420);
+ _action._inProgress = false;
+ return;
+
+ default:
+ break;
+ }
+ } else {
+ _vm->_dialogs->show(10439);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isObject(NOUN_FIREPLACE)) {
+ if (_globals[kPlayerPersona] == 0)
+ _vm->_dialogs->show(10402);
+ else
+ _vm->_dialogs->show(10438);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_TAPESTRY)) {
+ if (_globals[kPlayerPersona] == 0) {
+ if (_scene->_customDest.x >= 209 && _scene->_customDest.x <= 278)
+ _vm->_dialogs->show(10403);
+ else if (_scene->_customDest.x >= 107 && _scene->_customDest.x <= 190)
+ _vm->_dialogs->show(10422);
+ else if (_globals[kTapestryStatus] == 1 || _globals[kTapestryStatus] == 3)
+ _vm->_dialogs->show(10460);
+ else
+ _vm->_dialogs->show(10423);
+ } else
+ _vm->_dialogs->show(10439);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RUG)) {
+ if (_globals[kPlayerPersona] == 0)
+ _vm->_dialogs->show(10405);
+ else
+ _vm->_dialogs->show(10439);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FIREPLACE_SCREEN)) {
+ if (_globals[kPlayerPersona] == 0)
+ _vm->_dialogs->show(10407);
+ else
+ _vm->_dialogs->show(10439);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DOOR_TO_THRONE_ROOM)) {
+ if (_globals[kPlayerPersona] == 0)
+ _vm->_dialogs->show(10409);
+ else
+ _vm->_dialogs->show(10434);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SCONCE)) {
+ if (_globals[kPlayerPersona] == 0)
+ _vm->_dialogs->show(10410);
+ else
+ _vm->_dialogs->show(10440);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WOOD_BASKET)) {
+ if (_globals[kPlayerPersona] == 0)
+ _vm->_dialogs->show(10411);
+ else
+ _vm->_dialogs->show(10439);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_TROPHY)) {
+ if (_globals[kPlayerPersona] == 0)
+ _vm->_dialogs->show(10412);
+ else
+ _vm->_dialogs->show(10441);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_READING_BENCH)) {
+ if (_globals[kPlayerPersona] == 0)
+ _vm->_dialogs->show(10414);
+ else
+ _vm->_dialogs->show(10439);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LOVESEAT)) {
+ if (_globals[kPlayerPersona] == 0)
+ _vm->_dialogs->show(10416);
+ else
+ _vm->_dialogs->show(10439);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DOOR_TO_HALLWAY)) {
+ if (_globals[kPlayerPersona] == 0)
+ _vm->_dialogs->show(10421);
+ else
+ _vm->_dialogs->show(10434);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SECRET_DOOR)) {
+ _vm->_dialogs->show(10430);
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isObject(NOUN_DOORWAY) || _action.isAction(VERB_WALK_THROUGH, NOUN_DOORWAY) || _action.isAction(VERB_OPEN, NOUN_DOORWAY)) && (_globals[kPlayerPersona] == 1)) {
+ _vm->_dialogs->show(10432);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_WALL_PANEL)) {
+ if ((_globals[kBooksStatus] == 0) || (_globals[kBooksStatus] == 1))
+ _vm->_dialogs->show(10435);
+ else
+ _vm->_dialogs->show(10436);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_KING) && _globals[kPlayerPersona] == 1) {
+ _vm->_dialogs->show(10443);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_MUSIC_BOX) && _globals[kNoLoadWalker]) {
+ _vm->_dialogs->showItem(OBJ_MAGIC_MUSIC_BOX, 843, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_MACMORN) && (_globals[kPlayerPersona] == 1)) {
+ _vm->_dialogs->show(10444);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_TABLE)) {
+ if (_globals[kPlayerPersona] == 1)
+ _vm->_dialogs->show(10455);
+ else if (_scene->_customDest.x < 174)
+ _vm->_dialogs->show(10451);
+ else
+ _vm->_dialogs->show(10448);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DECORATION)) {
+ if (_globals[kPlayerPersona] == 1)
+ _vm->_dialogs->show(10439);
+ else
+ _vm->_dialogs->show(10449);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SWORD)) {
+ if (_globals[kPlayerPersona] == 1)
+ _vm->_dialogs->show(10439);
+ else
+ _vm->_dialogs->show(10450);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FLOOR) && (_globals[kPlayerPersona] == 1)) {
+ _vm->_dialogs->show(10439);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WALL) && (_globals[kPlayerPersona] == 1)) {
+ _vm->_dialogs->show(10439);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CANDLESTICK)) {
+ if (_globals[kPlayerPersona] == 1)
+ _vm->_dialogs->show(10439);
+ else
+ _vm->_dialogs->show(10461);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_QUEEN_MOTHER)) {
+ _vm->_dialogs->show(10456);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_MACMORN)) {
+ _vm->_dialogs->show(10444);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if ((_action.isAction(VERB_PUSH) || _action.isAction(VERB_PULL)) && _action.isObject(NOUN_RUG)) {
+ if (_globals[kPlayerPersona] == 0)
+ _vm->_dialogs->show(10406);
+ else
+ _vm->_dialogs->show(10445);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isAction(VERB_PUSH) || _action.isAction(VERB_PULL)) && _action.isObject(NOUN_FIREPLACE_SCREEN)) {
+ if (_globals[kPlayerPersona] == 0)
+ _vm->_dialogs->show(10408);
+ else
+ _vm->_dialogs->show(10445);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isAction(VERB_PUSH) || _action.isAction(VERB_PULL)) && _action.isObject(NOUN_TROPHY)) {
+ if (_globals[kPlayerPersona] == 0)
+ _vm->_dialogs->show(10413);
+ else
+ _vm->_dialogs->show(10445);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_READING_BENCH)) {
+ if (_globals[kPlayerPersona] == 0)
+ _vm->_dialogs->show(10415);
+ else
+ _vm->_dialogs->show(10445);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isAction(VERB_PUSH) || _action.isAction(VERB_PULL)) && _action.isObject(NOUN_LOVESEAT)) {
+ if (_globals[kPlayerPersona] == 0)
+ _vm->_dialogs->show(10417);
+ else
+ _vm->_dialogs->show(10445);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isAction(VERB_OPEN) || _action.isAction(VERB_PUSH) || _action.isAction(VERB_PULL)) && (_action.isObject(NOUN_SECRET_DOOR) || _action.isObject(NOUN_WALL_PANEL))) {
+ _vm->_dialogs->show(10431);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_INVOKE, NOUN_SIGNET_RING) && (_globals[kPlayerPersona] == 1)) {
+ _vm->_dialogs->show(10433);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_PUT, NOUN_TENTACLE_PARTS, NOUN_WALL_PANEL) && (_globals[kPlayerPersona] == 0)) {
+ _vm->_dialogs->show(10446);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_SHIFT_INTO_BEAR) && _anim0ActvFl) {
+ if (_wasBearFl)
+ _vm->_dialogs->show(10457);
+ else if (_amuletWorksFl)
+ _vm->_dialogs->show(10459);
+ else {
+ _wasBearFl = true;
+ _globals[kPlayerScore] += 2;
+ _vm->_gameConv->run(1);
+ _vm->_gameConv->exportValue(1);
+ _vm->_gameConv->exportValue(0);
+ _vm->_gameConv->exportValue(0);
+ if (_globals[kLlanieStatus] != 2)
+ _vm->_gameConv->exportValue(1);
+ else
+ _vm->_gameConv->exportValue(0);
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isAction(VERB_ATTACK, NOUN_SWORD, NOUN_MACMORN) || _action.isAction(VERB_CARVE_UP, NOUN_SWORD, NOUN_MACMORN) || _action.isAction(VERB_THRUST, NOUN_SWORD, NOUN_MACMORN) || _action.isAction(VERB_TAKE, NOUN_SWORD)) && _anim0ActvFl) {
+ _activateTimerFl = false;
+ _pidStatus = 6;
+
+ if (!_amuletWorksFl) {
+ _globals[kPlayerScore] += 5;
+ _vm->_gameConv->run(1);
+ _vm->_gameConv->exportValue(0);
+ _vm->_gameConv->exportValue(1);
+ _vm->_gameConv->exportValue(0);
+ if (_globals[kLlanieStatus] != 2)
+ _vm->_gameConv->exportValue(1);
+ else
+ _vm->_gameConv->exportValue(0);
+
+ _vm->_gameConv->hold();
+ } else {
+ _macStatus = 6;
+ _game._player._stepEnabled = false;
+ }
+ _amuletWorksFl = true;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_INVOKE, NOUN_AMULET) && _anim0ActvFl) {
+ if (_amuletWorksFl) {
+ _activateTimerFl = false;
+ _pidStatus = 5;
+ _globals[kPlayerScore] += 15;
+ _globals[kAmuletStatus] = 2;
+ _game._player._stepEnabled = false;
+
+ _scene->freeAnimation(_globals._animationIndexes[1]);
+
+ _globals._sequenceIndexes[14] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[14], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[14], 6);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[14], SYNC_CLOCK, 0);
+
+ _globals._spriteIndexes[15] = _scene->_sprites.addSprites(formAnimName('e', 3), PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('m', 2), 0);
+ _anim1ActvFl = false;
+ _anim5ActvFl = true;
+ } else
+ _vm->_dialogs->showItem(OBJ_AMULET, 945, 0);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_ATTACK, NOUN_SWORD, NOUN_QUEEN_MOTHER) || _action.isAction(VERB_CARVE_UP, NOUN_SWORD, NOUN_QUEEN_MOTHER) || _action.isAction(VERB_THRUST, NOUN_SWORD, NOUN_QUEEN_MOTHER)) {
+ _vm->_dialogs->show(10458);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TALK_TO, NOUN_MACMORN)) {
+ _vm->_dialogs->show(10464);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TALK_TO, NOUN_QUEEN_MOTHER)) {
+ _vm->_dialogs->show(10463);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TALK_TO, NOUN_KING)) {
+ _vm->_dialogs->show(10465);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_POUR_CONTENTS_OF, NOUN_MACMORN)) {
+ _vm->_dialogs->show(10462);
+ _action._inProgress = false;
+ return;
+ }
+
+
+ if (_anim2ActvFl && (_action.isAction(VERB_WALK_ACROSS) || _action.isAction(VERB_WALK_TO))) {
+ _vm->_dialogs->show(10445);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_CANDLESTICK)) {
+ _vm->_dialogs->show(10468);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_MUSIC_BOX) && _globals[kNoLoadWalker]) {
+ _vm->_dialogs->show(10470);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene104::preActions() {
+ if ((_action.isAction(VERB_PULL) || _action.isAction(VERB_OPEN) || _action.isAction(VERB_CLOSE) || _action.isAction(VERB_PUSH))
+ && _action.isObject(NOUN_TAPESTRY) && (_scene->_customDest.x > 280))
+ _game._player.walk(Common::Point(295, 145), FACING_NORTHEAST);
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR_TO_THRONE_ROOM)
+ || _action.isAction(VERB_WALK_THROUGH, NOUN_DOOR_TO_HALLWAY)
+ || _action.isAction(VERB_WALK_THROUGH, NOUN_DOORWAY)
+ || ((_action.isAction(VERB_PULL) || _action.isAction(VERB_OPEN) || _action.isAction(VERB_PUSH)) && _action.isObject(NOUN_TAPESTRY))
+ || ((_action.isAction(VERB_PULL) || _action.isAction(VERB_CLOSE) || _action.isAction(VERB_PUSH)) && _action.isObject(NOUN_TAPESTRY))
+ || ((_action.isAction(VERB_PUSH) || _action.isAction(VERB_PULL))
+ && (_action.isObject(NOUN_RUG) || _action.isObject(NOUN_FIREPLACE_SCREEN) || _action.isObject(NOUN_TROPHY) || _action.isObject(NOUN_LOVESEAT)))
+ || _action.isAction(VERB_OPEN, NOUN_READING_BENCH)) {
+ if (_globals[kPlayerPersona] == 1)
+ _game._player.cancelWalk();
+ }
+
+ if (_globals[kNoLoadWalker])
+ _game._player._needToWalk = false;
+}
+
+void Scene104::handleFinalConversation() {
+ bool interlocutorFl = false;
+ bool heroFl = false;
+
+ switch (_action._activeAction._verbId) {
+ case 11:
+ _deathTimer = 0;
+ _clock = 0;
+ _activateTimerFl = true;
+ interlocutorFl = true;
+ heroFl = true;
+ break;
+
+ case 14:
+ if (!_game._trigger)
+ _macStatus = 3;
+
+ interlocutorFl = true;
+ heroFl = true;
+ break;
+
+ case 17:
+ _pidStatus = 3;
+ _vm->_gameConv->hold();
+ interlocutorFl = true;
+ heroFl = true;
+ break;
+
+ case 20:
+ if (!_game._trigger)
+ _macStatus = 2;
+ interlocutorFl = true;
+ heroFl = true;
+ break;
+
+ case 30:
+ _vm->_gameConv->setStartNode(31);
+ _vm->_gameConv->stop();
+
+ if (_globals[kLlanieStatus] == 2) {
+ _globals._animationIndexes[3] = _scene->loadAnimation(formAnimName('l', 1), 0);
+ _anim3ActvFl = true;
+ _twinklesStatus = 1;
+ }
+ break;
+
+ case 38:
+ _globals[kEndOfGame] = true;
+ _scene->_nextSceneId = 106;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 81:
+ switch (_action._activeAction._verbId) {
+ case 0:
+ case 2:
+ case 4:
+ case 5:
+ case 7:
+ case 8:
+ case 11:
+ case 17:
+ if (_macStatus == 0)
+ _macStatus = 1;
+
+ _pidStatus = 0;
+ if (_queenStatus != 2)
+ _queenStatus = 0;
+
+ _kingStatus = 0;
+ break;
+
+ case 1:
+ case 3:
+ case 6:
+ case 20:
+ case 22:
+ case 24:
+ case 26:
+ case 28:
+ case 32:
+ case 34:
+ case 39:
+ case 41:
+ case 43:
+ _kingStatus = 1;
+ _pidStatus = 0;
+ if (_queenStatus != 2)
+ _queenStatus = 0;
+
+ if (_macStatus == 1)
+ _macStatus = 0;
+
+ break;
+
+ case 21:
+ case 23:
+ case 25:
+ case 27:
+ case 35:
+ case 40:
+ case 42:
+ if (_queenStatus != 2)
+ _queenStatus = 1;
+
+ _pidStatus = 0;
+ if (_macStatus == 1)
+ _macStatus = 0;
+
+ _kingStatus = 0;
+ break;
+
+ case 31:
+ case 33:
+ _twinklesStatus = 1;
+ _pidStatus = 0;
+ if (_queenStatus != 2)
+ _queenStatus = 0;
+
+ if (_macStatus == 1)
+ _macStatus = 0;
+
+ _kingStatus = 0;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 83:
+ if ((_action._activeAction._verbId == 8) || (_action._activeAction._verbId == 11))
+ _pidStatus = 2;
+ else
+ _pidStatus = 1;
+
+ if (_macStatus == 1)
+ _macStatus = 0;
+
+ if (_queenStatus != 2)
+ _queenStatus = 0;
+
+ _kingStatus = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ if (!heroFl)
+ _vm->_gameConv->setHeroTrigger(83);
+
+ if (!interlocutorFl)
+ _vm->_gameConv->setInterlocutorTrigger(81);
+
+ _kingCount = 0;
+ _queenCount = 0;
+ _macCount = 0;
+ _twinklesCount = 0;
+ _pidCount = 0;
+}
+
+void Scene104::handleKingAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == _kingFrame)
+ return;
+
+ _kingFrame = _scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame();
+ int resetFrame = -1;
+
+ switch (_kingFrame) {
+ case 14:
+ case 21:
+ switch (_kingStatus) {
+ case 0:
+ if (_kingCount > _vm->getRandomNumber(40, 50)) {
+ _kingCount = 0;
+ if (_vm->getRandomNumber(1,2) == 1)
+ resetFrame = 13;
+ else
+ resetFrame = 14;
+ } else {
+ ++_kingCount;
+ resetFrame = 13;
+ }
+ break;
+
+ case 1:
+ resetFrame = 14;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 16:
+ case 17:
+ case 18:
+ case 19:
+ switch (_kingStatus) {
+ case 0:
+ if (_kingCount > _vm->getRandomNumber(40, 50)) {
+ _kingCount = 0;
+ if (_vm->getRandomNumber(1,2) == 1)
+ resetFrame = 15;
+ else
+ resetFrame = 19;
+ } else {
+ ++_kingCount;
+ resetFrame = 15;
+ }
+ break;
+
+ case 1:
+ resetFrame = _vm->getRandomNumber(16, 18);
+ ++_kingCount;
+ if (_kingCount > 15) {
+ _kingStatus = 0;
+ _kingCount = 0;
+ resetFrame = 15;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 22:
+ if (_kingStatus == 2)
+ resetFrame = 21;
+ else
+ resetFrame = 0;
+
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[0], resetFrame);
+ _kingFrame = resetFrame;
+ }
+}
+
+
+void Scene104::handleMacAnimation1() {
+ if (_scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame() == _macFrame)
+ return;
+
+ _macFrame = _scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame();
+ int resetFrame = -1;
+
+ switch (_macFrame) {
+ case 1:
+ case 2:
+ case 7:
+ switch (_macStatus) {
+ case 0:
+ resetFrame = 0;
+ break;
+
+ case 1:
+ if (_macCount == 0) {
+ if (_vm->getRandomNumber(1,2) == 1)
+ resetFrame = 2;
+ else
+ resetFrame = 1;
+
+ ++_macCount;
+ } else {
+ resetFrame = _vm->getRandomNumber(0, 1);
+ ++_macCount;
+ if (_macCount > 15) {
+ _macStatus = 0;
+ _macCount = 0;
+ resetFrame = 0;
+ }
+ }
+ break;
+
+ case 2:
+ resetFrame = 90;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 3:
+ case 4:
+ case 5:
+ switch (_macStatus) {
+ case 0:
+ case 2:
+ case 3:
+ case 4:
+ resetFrame = 5;
+ break;
+
+ case 1:
+ if (_macCount == 0) {
+ if (_vm->getRandomNumber(1,2) == 1)
+ resetFrame = 5;
+ else
+ resetFrame = 3;
+
+ ++_macCount;
+
+ } else {
+ resetFrame = _vm->getRandomNumber(3, 4);
+ ++_macCount;
+ if (_macCount > 15) {
+ _macStatus = 0;
+ _macCount = 0;
+ resetFrame = 5;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 25:
+ _game._player._stepEnabled = true;
+ break;
+
+ case 26:
+ case 90:
+ case 174:
+ switch (_macStatus) {
+ case 3:
+ resetFrame = 76;
+ _macStatus = 0;
+ _game._player._stepEnabled = false;
+ break;
+
+ case 4:
+ break;
+
+ case 5:
+ resetFrame = 147;
+ _macStatus = 0;
+ break;
+
+ case 6:
+ _pidFrame = 105;
+ resetFrame = 26;
+ _scene->setAnimFrame(_globals._animationIndexes[4], 105);
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[4], SYNC_ANIM, _globals._animationIndexes[1]);
+ break;
+
+ default:
+ resetFrame = 25;
+ break;
+ }
+ break;
+
+ case 36:
+ _globals._sequenceIndexes[13] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[13], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 13);
+ break;
+
+ case 37:
+ _scene->setAnimFrame(_globals._animationIndexes[4], 89);
+ _pidFrame = 89;
+ _pidStatus = 7;
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[4], SYNC_ANIM, _globals._animationIndexes[1]);
+ break;
+
+ case 76:
+ _vm->_gameConv->reset(1);
+ _vm->_dialogs->show(10467);
+ _globals[kNoLoadWalker] = false;
+ _scene->_nextSceneId = 119;
+ break;
+
+ case 82:
+ _pidStatus = 4;
+ break;
+
+ case 97:
+ _activateTimerFl = true;
+ _scene->deleteSequence(_globals._sequenceIndexes[5]);
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 10, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 85);
+ break;
+
+ case 112:
+ resetFrame = 8;
+ _macStatus = 0;
+ break;
+
+ case 162:
+ _vm->_gameConv->release();
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[1], resetFrame);
+ _macFrame = resetFrame;
+ }
+}
+
+
+void Scene104::handleMacAnimation2() {
+
+ if (_scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame() == _macFrame)
+ return;
+
+ _macFrame = _scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame();
+ int resetFrame = -1;
+
+ switch (_macFrame) {
+ case 1:
+ if (_macStatus != 4)
+ resetFrame = 0;
+ break;
+
+ case 2:
+ _scene->deleteSequence(_globals._sequenceIndexes[14]);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[14], SYNC_ANIM, _globals._animationIndexes[1]);
+ break;
+
+ case 37:
+ _scene->freeAnimation(_globals._animationIndexes[1]);
+ _scene->_sprites.remove(_globals._spriteIndexes[15]);
+ _anim5ActvFl = false;
+ resetFrame = -1;
+
+ _vm->_dialogs->show(10426);
+ _vm->_sound->command(45);
+ _vm->_gameConv->run(1);
+ _vm->_gameConv->exportValue(0);
+ _vm->_gameConv->exportValue(0);
+ _vm->_gameConv->exportValue(1);
+ if (_globals[kLlanieStatus] != 2)
+ _vm->_gameConv->exportValue(1);
+ else
+ _vm->_gameConv->exportValue(0);
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[1], resetFrame);
+ _macFrame = resetFrame;
+ }
+}
+
+void Scene104::handleQueenAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[2]]->getCurrentFrame() == _queenFrame)
+ return;
+
+ _queenFrame = _scene->_animation[_globals._animationIndexes[2]]->getCurrentFrame();
+ int resetFrame = -1;
+
+ switch (_queenFrame) {
+ case 1:
+ case 8:
+ case 15:
+ case 24:
+ switch (_queenStatus) {
+ case 0:
+ if (_queenCount > _vm->getRandomNumber(40, 50)) {
+ _queenCount = 0;
+ if (_vm->getRandomNumber(1,2) == 1)
+ resetFrame = 0;
+ else
+ resetFrame = 8;
+ } else {
+ ++_queenCount;
+ resetFrame = 0;
+ }
+ break;
+
+ case 1:
+ if (_vm->getRandomNumber(1,2) == 1)
+ resetFrame = 1;
+ else
+ resetFrame = 15;
+
+ _queenStatus = 0;
+ break;
+
+ case 2:
+ resetFrame = 8;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 12:
+ case 29:
+ switch (_queenStatus) {
+ case 0:
+ if (_queenCount > _vm->getRandomNumber(40, 50)) {
+ _queenCount = 0;
+ if (_vm->getRandomNumber(1,2) == 1)
+ resetFrame = 11;
+ else
+ resetFrame = 12;
+ } else {
+ ++_queenCount;
+ resetFrame = 11;
+ }
+ break;
+
+ case 1:
+ resetFrame = 12;
+ break;
+
+ case 2:
+ resetFrame = 24;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 27:
+ switch (_queenStatus) {
+ case 0:
+ case 1:
+ resetFrame = 27;
+ break;
+
+ case 2:
+ resetFrame = 26;
+ break;
+
+ case 3:
+ resetFrame = 27;
+ _queenStatus = 0;
+ break;
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[2], resetFrame);
+ _queenFrame = resetFrame;
+ }
+}
+
+void Scene104::handleTwinklesAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[3]]->getCurrentFrame() == _twinklesFrame)
+ return;
+
+ _twinklesFrame = _scene->_animation[_globals._animationIndexes[3]]->getCurrentFrame();
+ int resetFrame = -1;
+
+ switch (_twinklesFrame) {
+ case 1:
+ if (_twinklesStatus == 2)
+ resetFrame = 0;
+ break;
+
+ case 10:
+ _queenStatus = 2;
+ break;
+
+ case 28:
+ _vm->_gameConv->run(1);
+ _vm->_gameConv->exportValue(0);
+ _vm->_gameConv->exportValue(0);
+ _vm->_gameConv->exportValue(1);
+ if (_globals[kLlanieStatus] != 2)
+ _vm->_gameConv->exportValue(1);
+ else
+ _vm->_gameConv->exportValue(0);
+ break;
+
+ case 36:
+ _queenStatus = 3;
+ break;
+
+ case 37:
+ case 38:
+ case 47:
+ switch (_twinklesStatus) {
+ case 0:
+ if (_twinklesFrame != 37 && _twinklesFrame != 38)
+ _twinklesFrame = 38;
+
+ if (_twinklesCount > _vm->getRandomNumber(40, 50)) {
+ _twinklesCount = 0;
+ if (_vm->getRandomNumber(1, 2) == 1)
+ resetFrame = 36;
+ else
+ resetFrame = 37;
+ } else {
+ ++_twinklesCount;
+ resetFrame = _twinklesFrame - 1;
+ }
+ break;
+
+ case 1:
+ resetFrame = 38;
+ _twinklesStatus = 0;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[3], resetFrame);
+ _twinklesFrame = resetFrame;
+ }
+}
+
+void Scene104::handleDeathAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[4]]->getCurrentFrame() == _deathFrame)
+ return;
+
+ _deathFrame = _scene->_animation[_globals._animationIndexes[4]]->getCurrentFrame();
+
+ if (_deathFrame == 11)
+ _scene->playSpeech(7);
+ else if (_deathFrame == 17)
+ _scene->playSpeech(6);
+}
+
+void Scene104::handlePidAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[4]]->getCurrentFrame() == _pidFrame)
+ return;
+
+ _pidFrame = _scene->_animation[_globals._animationIndexes[4]]->getCurrentFrame();
+ int resetFrame = -1;
+
+ switch (_pidFrame) {
+ case 1:
+ case 2:
+ case 3:
+ case 9:
+ case 47:
+ case 81:
+ switch (_pidStatus) {
+ case 0:
+ resetFrame = 0;
+ break;
+
+ case 1:
+ resetFrame = _vm->getRandomNumber(0, 2);
+ ++_pidCount;
+ if (_pidCount > 20) {
+ _pidStatus = 0;
+ _pidCount = 0;
+ resetFrame = 0;
+ }
+ break;
+
+ case 2:
+ resetFrame = 3;
+ break;
+
+ case 3:
+ _activateTimerFl = false;
+ resetFrame = 10;
+ break;
+
+ case 5:
+ _game._player._stepEnabled = false;
+ _activateTimerFl = false;
+ resetFrame = 47;
+ _pidStatus = 0;
+ break;
+
+ case 6:
+ resetFrame = 81;
+ break;
+
+ case 8:
+ _scene->freeAnimation(_globals._animationIndexes[1]);
+ _scene->freeAnimation(_globals._animationIndexes[4]);
+ _anim1ActvFl = false;
+ _anim4ActvFl = false;
+ _globals._animationIndexes[4] = _scene->loadAnimation(formAnimName('d', 2), 95);
+ _anim6ActvFl = true;
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[4], SYNC_CLOCK, 0);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ if (_pidStatus == 2) {
+ resetFrame = _vm->getRandomNumber(4, 6);
+ ++_pidCount;
+ if (_pidCount > 20) {
+ _pidStatus = 0;
+ _pidCount = 0;
+ resetFrame = 7;
+ }
+ } else
+ resetFrame = 7;
+ break;
+
+ case 24:
+ _vm->_gameConv->release();
+ break;
+
+ case 25:
+ if (_pidStatus == 4) {
+ resetFrame = 25;
+ _pidStatus = 0;
+ } else
+ resetFrame = 24;
+ break;
+
+ case 46:
+ _activateTimerFl = true;
+ _clock = 0;
+ _deathTimer = 0;
+ _game._player._stepEnabled = true;
+ break;
+
+ case 60:
+ resetFrame = 107;
+ break;
+
+ case 62:
+ _macStatus = 4;
+ break;
+
+ case 88:
+ if (_deathTimer < 1300)
+ _macStatus = 5;
+ break;
+
+ case 89:
+ if (_pidStatus == 5) {
+ resetFrame = 55;
+ _pidStatus = 0;
+ } else if (_deathTimer >= 1300)
+ _macStatus = 6;
+ else {
+ _pidDrawnSword = true;
+ resetFrame = 88;
+ }
+ break;
+
+ case 91:
+ _scene->playSpeech(7);
+ break;
+
+ case 95:
+ _scene->playSpeech(6);
+ break;
+
+ case 105:
+ resetFrame = 104;
+ break;
+
+ case 106:
+ if (_pidStatus == 7)
+ resetFrame = 89;
+ else
+ resetFrame = 105;
+ break;
+
+ case 111:
+ resetFrame = 60;
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[4], resetFrame);
+ _pidFrame = resetFrame;
+ }
+}
+/*------------------------------------------------------------------------*/
+
+Scene105::Scene105(MADSEngine *vm) : Scene1xx(vm) {
+ _maidTalkingFl = false;
+ _sitUpFl = false;
+ _goodNumberFl = false;
+
+ _maidFrame = -1;
+ _newStatus = -1;
+ _previousStatus = -1;
+ _maidHotspotId1 = -1;
+ _maidHotspotId2 = -1;
+ _bucketHotspotId = -1;
+ _boneHotspotId = -1;
+ _gobletHotspotId = -1;
+}
+
+void Scene105::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+
+ s.syncAsByte(_maidTalkingFl);
+ s.syncAsByte(_sitUpFl);
+ s.syncAsByte(_goodNumberFl);
+
+ s.syncAsSint16LE(_maidFrame);
+ s.syncAsSint16LE(_newStatus);
+ s.syncAsSint16LE(_previousStatus);
+ s.syncAsSint16LE(_maidHotspotId1);
+ s.syncAsSint16LE(_maidHotspotId2);
+ s.syncAsSint16LE(_bucketHotspotId);
+ s.syncAsSint16LE(_boneHotspotId);
+ s.syncAsSint16LE(_gobletHotspotId);
+}
+
+void Scene105::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ _scene->addActiveVocab(NOUN_SCULLERY_MAID);
+ _scene->addActiveVocab(NOUN_BUCKET);
+ _scene->addActiveVocab(VERB_WALK_TO);
+ _scene->addActiveVocab(NOUN_BONE);
+ _scene->addActiveVocab(NOUN_GOBLET);
+}
+
+void Scene105::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('x', 2));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites("*KGRD_8");
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 7, 0);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 7, 0, 3);
+
+ _maidHotspotId1 = _scene->_dynamicHotspots.add(NOUN_SCULLERY_MAID, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(189, 123, 189 + 25, 123 + 11));
+ _scene->_dynamicHotspots.setPosition(_maidHotspotId1, Common::Point(174, 151), FACING_NORTHEAST);
+ _scene->_dynamicHotspots[_maidHotspotId1]._articleNumber = PREP_ON;
+
+ _maidHotspotId2 = _scene->_dynamicHotspots.add(NOUN_SCULLERY_MAID, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(189, 134, 189 + 38, 134 + 9));
+ _scene->_dynamicHotspots.setPosition(_maidHotspotId2, Common::Point(174, 151), FACING_NORTHEAST);
+ _scene->_dynamicHotspots[_maidHotspotId2]._articleNumber = PREP_ON;
+
+ _bucketHotspotId = _scene->_dynamicHotspots.add(NOUN_BUCKET, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(176, 137, 176 + 10, 137 + 8));
+ _scene->_dynamicHotspots.setPosition(_bucketHotspotId, Common::Point(174, 151), FACING_NORTHEAST);
+
+ if (_game._objects.isInRoom(OBJ_GOBLET)) {
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('p', 1));
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites("*KGRM_6");
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, -1);
+ _gobletHotspotId = _scene->_dynamicHotspots.add(NOUN_GOBLET, VERB_WALK_TO, SYNTAX_SINGULAR, _globals._sequenceIndexes[5], Common::Rect(0, 0, 0, 0));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 6);
+ _scene->_dynamicHotspots.setPosition(_gobletHotspotId, Common::Point(63, 142), FACING_WEST);
+ }
+
+ if (_game._objects.isInRoom(OBJ_BONE)) {
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('p', 0));
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites("*KGRL_6");
+ _globals._sequenceIndexes[6] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[6], false, -1);
+ _boneHotspotId = _scene->_dynamicHotspots.add(NOUN_BONE, VERB_WALK_TO, SYNTAX_SINGULAR, _globals._sequenceIndexes[6], Common::Rect(0, 0, 0, 0));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 6);
+ _scene->_dynamicHotspots.setPosition(_boneHotspotId, Common::Point(255, 145), FACING_EAST);
+ }
+
+ _vm->_gameConv->load(2);
+ _newStatus = 1;
+ _previousStatus = 0;
+ _maidTalkingFl = false;
+ _sitUpFl = false;
+ _goodNumberFl = false;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('A',-1), 1);
+
+
+ if (_scene->_priorSceneId == 106) {
+ _game._player._playerPos = Common::Point(104, 152);
+ _game._player._facing = FACING_NORTHEAST;
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 12);
+ } else if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 6);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 12);
+ _game._player.firstWalk(Common::Point(120, 96), FACING_SOUTH, Common::Point(117, 108), FACING_SOUTH, false);
+ _game._player.setWalkTrigger(70);
+ } else {
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 15);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene105::step() {
+ if (_scene->_animation[_globals._animationIndexes[0]]) {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() != _maidFrame) {
+ _maidFrame = _scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame();
+ int resetFrame = -1;
+
+ if (_sitUpFl && !_maidTalkingFl) {
+ _previousStatus = _newStatus;
+ _newStatus = 4;
+ }
+
+ if (_maidTalkingFl) {
+ _previousStatus = _newStatus;
+ _newStatus = 5;
+ }
+
+ switch (_maidFrame) {
+ case 16:
+ if (_newStatus == 1) {
+ _goodNumberFl = false;
+ while (!_goodNumberFl)
+ setRandomStatus();
+ }
+
+ if (_newStatus == 1)
+ resetFrame = 1;
+ else if ((_newStatus == 3 && !_sitUpFl) || _newStatus == 4)
+ resetFrame = 53;
+ else if ((_newStatus == 3) && (_sitUpFl))
+ resetFrame = 24;
+ break;
+
+ case 24:
+ if (_newStatus == 2) {
+ _goodNumberFl = false;
+ while (!_goodNumberFl)
+ setRandomStatus();
+ }
+
+ if ((_newStatus == 3) || (_newStatus == 5))
+ resetFrame = 53;
+ else if (_newStatus == 1)
+ resetFrame = 56;
+ else if (_newStatus == 4)
+ resetFrame = 53;
+
+ break;
+
+ case 32:
+ if (_newStatus == 3) {
+ _goodNumberFl = false;
+ while (!_goodNumberFl)
+ setRandomStatus();
+ }
+
+ if ((_newStatus == 1) || (_newStatus == 2))
+ resetFrame = 57;
+ else if (_newStatus == 4)
+ resetFrame = 55;
+ break;
+
+ case 53:
+ _maidTalkingFl = false;
+ _goodNumberFl = false;
+ while (!_goodNumberFl)
+ setRandomStatus();
+
+ if (_newStatus == 1)
+ resetFrame = 60;
+ else if (_newStatus == 2)
+ resetFrame = 57;
+ else if (_newStatus == 3)
+ resetFrame = 63;
+ else if (_newStatus == 4)
+ resetFrame = 55;
+ break;
+
+ case 56:
+ if (_newStatus == 4) {
+ _goodNumberFl = false;
+ while (!_goodNumberFl)
+ setRandomWipebrow();
+ }
+
+ if (_newStatus == 4)
+ resetFrame = 55;
+ else if (_newStatus == 5)
+ resetFrame = 32;
+ else if (_newStatus == 3)
+ resetFrame = 24;
+ break;
+
+ case 57:
+ if (_newStatus == 1)
+ resetFrame = 1;
+ break;
+
+ case 60:
+ if (_newStatus == 1)
+ resetFrame = 1;
+ else if (_newStatus == 2)
+ resetFrame = 16;
+ break;
+
+ case 63:
+ if (_newStatus == 1)
+ resetFrame = 1;
+ break;
+
+ case 64:
+ resetFrame = 24;
+ break;
+
+ default:
+ break;
+ }
+
+ if ((resetFrame >= 0) && (resetFrame != _scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame())) {
+ _scene->setAnimFrame(_globals._animationIndexes[0], resetFrame);
+ _maidFrame = resetFrame;
+ }
+ }
+ }
+
+ if (_game._trigger >= 70) {
+ switch (_game._trigger) {
+ case 70:
+ _scene->deleteSequence(_globals._sequenceIndexes[3]);
+ _vm->_sound->command(25);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[3], false, 6, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 12);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 5);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ break;
+
+ case 71: {
+ int seqIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 15);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[3], SYNC_SEQ, seqIdx);
+ _game._player._stepEnabled = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void Scene105::actions() {
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(10501);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_vm->_gameConv->activeConvId() == 2) {
+ handleConversation();
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR_TO_HALLWAY) || _action.isAction(VERB_OPEN, NOUN_DOOR_TO_HALLWAY) || _action.isAction(VERB_PULL, NOUN_DOOR_TO_HALLWAY)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[4] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[4], false, 8, 2);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[4],true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_SPRITE, 2, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 1:
+ _scene->deleteSequence(_globals._sequenceIndexes[3]);
+ _vm->_sound->command(24);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 6, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 12);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 2: {
+ int seqIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 12);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[3], SYNC_SEQ, seqIdx);
+ }
+ break;
+
+ case 3:
+ _game._player._visible = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[4]);
+ _scene->_sequences.addTimer(1,4);
+ break;
+
+ case 4:
+ _game._player.walk(Common::Point(120, 96), FACING_NORTH);
+ _game._player.setWalkTrigger(5);
+ break;
+
+ case 5:
+ _scene->deleteSequence(_globals._sequenceIndexes[3]);
+ _vm->_sound->command(25);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[3], false, 7, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 6);
+ break;
+
+ case 6: {
+ int seqIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 1);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[3], SYNC_SEQ, seqIdx);
+ _scene->_sequences.addTimer(6, 7);
+ }
+ break;
+
+ case 7:
+ _scene->_nextSceneId = 103;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR_TO_THRONE_ROOM) || _action.isAction(VERB_OPEN, NOUN_DOOR_TO_THRONE_ROOM) || _action.isAction(VERB_PULL, NOUN_DOOR_TO_THRONE_ROOM)) {
+ _scene->_nextSceneId = 106;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TALK_TO, NOUN_SCULLERY_MAID)) {
+ _vm->_gameConv->run(2);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_GOBLET)) {
+ if (_game._trigger || !_game._objects.isInInventory(OBJ_GOBLET)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[8] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[8], true, 6, 2);
+ _scene->_sequences.setAnimRange (_globals._sequenceIndexes[8], 1, 7);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[8], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_SPRITE, 7, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _scene->deleteSequence (_globals._sequenceIndexes[5]);
+ _scene->_dynamicHotspots.remove(_gobletHotspotId);
+ _vm->_sound->command(26);
+ _game._objects.addToInventory(OBJ_GOBLET);
+ _vm->_dialogs->showItem(OBJ_GOBLET, 10519, 0);
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[8]);
+ _globals[kPlayerScore] += 1;
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_BONE) && _action._mainObjectSource == CAT_HOTSPOT) {
+ if (_game._trigger || !_game._objects.isInInventory(OBJ_BONE)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[7] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[7], false, 6, 2);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[7], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_SPRITE, 6, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _scene->deleteSequence (_globals._sequenceIndexes[6]);
+ _vm->_sound->command(26);
+ _scene->_dynamicHotspots.remove(_boneHotspotId);
+ _game._objects.addToInventory(OBJ_BONE);
+ _vm->_dialogs->showItem(OBJ_BONE, 10520, 0);
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[7]);
+ if (!(_globals[kPlayerScoreFlags] & 2048)) {
+ _globals[kPlayerScoreFlags] |= 2048;
+ _globals[kPlayerScore] += 1;
+ }
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_BONE) && _game._objects.isInInventory(OBJ_BONE) && (_action._mainObjectSource == CAT_HOTSPOT)) {
+ _vm->_dialogs->show(40112);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(10502);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BRAZIER)) {
+ _vm->_dialogs->show(10503);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DINING_TABLE)) {
+ if (_scene->_customDest.x <= 98) {
+ if (_game._objects[OBJ_GOBLET]._roomNumber == _scene->_currentSceneId)
+ _vm->_dialogs->show(10505);
+ else
+ _vm->_dialogs->show(10522);
+ } else
+ _vm->_dialogs->show(10504);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CHAIR)) {
+ _vm->_dialogs->show(10507);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WINDOW)) {
+ _vm->_dialogs->show(10508);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_TAPESTRY)) {
+ _vm->_dialogs->show(10509);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DOOR_TO_THRONE_ROOM)) {
+ _vm->_dialogs->show(10511);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(10512);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DOOR_TO_HALLWAY)) {
+ _vm->_dialogs->show(10513);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DIVIDING_WALL)) {
+ _vm->_dialogs->show(10514);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CEILING)) {
+ _vm->_dialogs->show(10515);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SCULLERY_MAID)) {
+ _vm->_dialogs->show(10516);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_GOBLET) && _game._objects.isInRoom(OBJ_GOBLET)) {
+ _vm->_dialogs->show(10517);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BONE) && _game._objects.isInRoom(OBJ_BONE)) {
+ _vm->_dialogs->show(10518);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SCONCE)) {
+ _vm->_dialogs->show(10524);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BUCKET)) {
+ _vm->_dialogs->show(10521);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_SCULLERY_MAID)) {
+ _vm->_dialogs->show(30);
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isAction(VERB_PUSH) || _action.isAction(VERB_PULL)) && _action.isObject(NOUN_DINING_TABLE)) {
+ _vm->_dialogs->show(10506);
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isAction(VERB_PUSH) || _action.isAction(VERB_PULL)) && _action.isObject(NOUN_TAPESTRY)) {
+ _vm->_dialogs->show(10510);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene105::preActions() {
+ if (_action.isAction(VERB_TALK_TO, NOUN_SCULLERY_MAID))
+ _sitUpFl = true;
+}
+
+void Scene105::setRandomStatus() {
+ _previousStatus = _newStatus;
+ int rndVal = _vm->getRandomNumber(1, 30);
+ if (rndVal < 20) {
+ _newStatus = 1;
+ _goodNumberFl = true;
+ } else if ((rndVal > 19) && (rndVal < 27) && (_previousStatus != 2)) {
+ _newStatus = 2;
+ _goodNumberFl = true;
+ } else if (_previousStatus != 3) {
+ _newStatus = 3;
+ _goodNumberFl = true;
+ }
+}
+
+void Scene105::setRandomWipebrow() {
+ _previousStatus = _newStatus;
+
+ if (_vm->getRandomNumber(1, 100) < 100) {
+ _newStatus = 4;
+ _goodNumberFl = true;
+ } else if (_previousStatus != 3) {
+ _newStatus = 3;
+ _goodNumberFl = true;
+ }
+}
+
+void Scene105::handleConversation() {
+ if ((_action._activeAction._verbId == 0) && !_sitUpFl)
+ _sitUpFl = true;
+
+ if ((_action._activeAction._verbId == 1) || (_action._activeAction._verbId == 2)) {
+ switch (_game._trigger) {
+ case 0:
+ _vm->_gameConv->setInterlocutorTrigger(1);
+ break;
+
+ case 1:
+ _maidTalkingFl = true;
+ _sitUpFl = false;
+ _vm->_gameConv->setHeroTrigger(2);
+ break;
+
+ case 2:
+ _maidTalkingFl = false;
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+} // End of namespace Dragonsphere
+} // End of namespace MADS
diff --git a/engines/mads/dragonsphere/dragonsphere_scenes1.h b/engines/mads/dragonsphere/dragonsphere_scenes1.h
new file mode 100644
index 0000000000..fe51ed4135
--- /dev/null
+++ b/engines/mads/dragonsphere/dragonsphere_scenes1.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.
+ *
+ */
+
+#ifndef MADS_DRAGON_SCENES1_H
+#define MADS_DRAGON_SCENES1_H
+
+#include "common/scummsys.h"
+#include "common/serializer.h"
+#include "mads/game.h"
+#include "mads/scene.h"
+#include "mads/dragonsphere/dragonsphere_scenes.h"
+
+namespace MADS {
+
+namespace Dragonsphere {
+
+class Scene1xx : public DragonsphereScene {
+protected:
+ /**
+ * Plays an appropriate sound when entering a scene
+ */
+ void sceneEntrySound();
+
+ /**
+ *Sets the AA file to use for the scene
+ */
+ void setAAName();
+
+ /**
+ * Updates the prefix used for getting player sprites for the scene
+ */
+ void setPlayerSpritesPrefix();
+public:
+ Scene1xx(MADSEngine *vm) : DragonsphereScene(vm) {}
+};
+
+class Scene101 : public Scene1xx {
+public:
+ Scene101(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene102 : public Scene1xx {
+private:
+ int _diaryHotspotIdx1;
+ int _diaryHotspotIdx2;
+ int _diaryFrame;
+ int _animRunning;
+
+public:
+ Scene102(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene103 : public Scene1xx {
+public:
+ Scene103(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene104 : public Scene1xx {
+private:
+ bool _anim0ActvFl;
+ bool _anim1ActvFl;
+ bool _anim2ActvFl;
+ bool _anim3ActvFl;
+ bool _anim4ActvFl;
+ bool _anim5ActvFl;
+ bool _anim6ActvFl;
+ bool _activateTimerFl;
+ bool _wasBearFl;
+ bool _amuletWorksFl;
+ bool _pidDrawnSword;
+ int _animationRunning;
+ int _deathTimer;
+ int _deathFrame;
+ int _doorwayHotspotId;
+
+ int _kingStatus;
+ int _kingFrame;
+ int _kingCount;
+ int _queenStatus;
+ int _queenFrame;
+ int _queenCount;
+ int _pidStatus;
+ int _pidFrame;
+ int _pidCount;
+ int _macStatus;
+ int _macFrame;
+ int _macCount;
+ int _twinklesStatus;
+ int _twinklesFrame;
+ int _twinklesCount;
+ int _tapestryFrame;
+
+ int32 _clock;
+
+ void handleFinalConversation();
+ void handleKingAnimation();
+ void handleMacAnimation1();
+ void handleMacAnimation2();
+ void handleQueenAnimation();
+ void handleTwinklesAnimation();
+ void handleDeathAnimation();
+ void handlePidAnimation();
+
+public:
+ Scene104(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene105 : public Scene1xx {
+private:
+ bool _maidTalkingFl;
+ bool _sitUpFl;
+ bool _goodNumberFl;
+
+ int _maidFrame;
+ int _maidHotspotId1;
+ int _maidHotspotId2;
+ int _newStatus;
+ int _previousStatus;
+ int _bucketHotspotId;
+ int _boneHotspotId;
+ int _gobletHotspotId;
+
+ void setRandomStatus();
+ void setRandomWipebrow();
+ void handleConversation();
+
+public:
+ Scene105(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+} // End of namespace Dragonsphere
+} // End of namespace MADS
+
+#endif /* MADS_DRAGON_SCENES1_H */
diff --git a/engines/mads/dragonsphere/game_dragonsphere.cpp b/engines/mads/dragonsphere/game_dragonsphere.cpp
index b07eab9daa..f528056a54 100644
--- a/engines/mads/dragonsphere/game_dragonsphere.cpp
+++ b/engines/mads/dragonsphere/game_dragonsphere.cpp
@@ -28,7 +28,7 @@
#include "mads/msurface.h"
#include "mads/dragonsphere/game_dragonsphere.h"
//#include "mads/nebular/dialogs_nebular.h"
-//#include "mads/nebular/globals_nebular.h"
+#include "mads/dragonsphere/globals_dragonsphere.h"
#include "mads/dragonsphere/dragonsphere_scenes.h"
namespace MADS {
diff --git a/engines/mads/dragonsphere/game_dragonsphere.h b/engines/mads/dragonsphere/game_dragonsphere.h
index b57f8833c6..b9eb86af64 100644
--- a/engines/mads/dragonsphere/game_dragonsphere.h
+++ b/engines/mads/dragonsphere/game_dragonsphere.h
@@ -26,7 +26,7 @@
#include "common/scummsys.h"
#include "mads/game.h"
#include "mads/globals.h"
-//#include "mads/nebular/globals_nebular.h"
+#include "mads/dragonsphere/globals_dragonsphere.h"
namespace MADS {
@@ -80,7 +80,7 @@ enum InventoryObject {
OBJ_DIAMOND_DUST = 40,
OBJ_RUBY_RING = 41,
OBJ_GOLD_NUGGET = 42,
- OBJ_MUSIC_BOX = 43,
+ OBJ_MAGIC_MUSIC_BOX = 43,
OBJ_EMERALD = 44,
OBJ_PARCHMENT = 45,
OBJ_GAME = 46,
@@ -88,15 +88,6 @@ enum InventoryObject {
OBJ_NEW_BUNDLE = 48
};
-// HACK: A stub for now, remove from here once it's implemented properly
-class DragonsphereGlobals : public Globals {
-public:
- DragonsphereGlobals() {
- resize(210); // Rex has 210 globals
- }
- virtual ~DragonsphereGlobals() {}
-};
-
class GameDragonsphere : public Game {
friend class Game;
protected:
diff --git a/engines/mads/dragonsphere/globals_dragonsphere.cpp b/engines/mads/dragonsphere/globals_dragonsphere.cpp
new file mode 100644
index 0000000000..fa05ed97c2
--- /dev/null
+++ b/engines/mads/dragonsphere/globals_dragonsphere.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 "common/config-manager.h"
+#include "mads/dragonsphere/globals_dragonsphere.h"
+
+namespace MADS {
+
+namespace Dragonsphere {
+
+DragonsphereGlobals::DragonsphereGlobals()
+ : Globals() {
+ // Initialize lists
+ resize(140);
+ _spriteIndexes.resize(30);
+ _sequenceIndexes.resize(30);
+ _animationIndexes.resize(30);
+}
+
+void DragonsphereGlobals::synchronize(Common::Serializer &s) {
+ Globals::synchronize(s);
+
+ _spriteIndexes.synchronize(s);
+ _sequenceIndexes.synchronize(s);
+ _animationIndexes.synchronize(s);
+}
+
+
+} // End of namespace Dragonsphere
+
+} // End of namespace MADS
diff --git a/engines/mads/dragonsphere/globals_dragonsphere.h b/engines/mads/dragonsphere/globals_dragonsphere.h
new file mode 100644
index 0000000000..cc0e42eb43
--- /dev/null
+++ b/engines/mads/dragonsphere/globals_dragonsphere.h
@@ -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.
+ *
+ */
+
+#ifndef MADS_GLOBALS_DRAGONSPHERE_H
+#define MADS_GLOBALS_DRAGONSPHERE_H
+
+#include "common/scummsys.h"
+#include "common/array.h"
+#include "mads/game.h"
+#include "mads/resources.h"
+
+namespace MADS {
+
+namespace Dragonsphere {
+
+enum GlobalId {
+ // Global variables
+
+ kWalkerTiming = 0,
+ kWalkerTiming2 = 1,
+ kPlayerPersona = 10,
+ kPlayerScore = 11,
+ kDragonHighScene = 12,
+ kDragonMyScene = 13,
+ kNoLoadWalker = 14,
+ kPlayerScoreFlags = 15,
+ kSorcerorDefeated = 16,
+ kPreRoom = 17,
+ kPerformDisplacements = 18,
+
+ kKingStatus = 20,
+ kWardStatus = 21,
+ kTalkedToSoptus = 22,
+ kTalkedToShifter = 23,
+ kAmuletStatus = 24,
+ kBooksStatus = 25,
+ kTapestryStatus = 26,
+ kTalkedToMerchant = 27,
+ kCanViewCrownHole = 28,
+ kTalkedToStatus = 29,
+
+ kGuardPidStatus = 30,
+ kCrawledOutOfBed101 = 31,
+ kStatueIsOnStairway114 = 32,
+ kDogIsAsleep = 33,
+ kCrystalBallDead = 34,
+ kThrewBone = 35,
+ kWoodenDoorOpen = 36,
+ kKingIsInStairwell = 37,
+ kLlanieStatus = 38,
+ kNoTalkToGuard = 39,
+
+ kObjectGiven201 = 40,
+ kKingGotStabbed = 41,
+ kGivenObjectBefore = 42,
+ kGuardsAreAsleep = 43,
+ kDomeUp = 44,
+ kTalkedToWise = 45,
+ kDollGiven = 46,
+ kResetConv = 47,
+ kTalkedToGreta = 48,
+ kSlimeHealed = 49,
+
+ kDanceMusicOn = 50,
+ kPlayerIsSeal = 51,
+ kVinesHavePlayer = 52,
+ kEndOfGame = 53,
+ kResetConv2 = 54,
+ kInvokedFrom111 = 55,
+
+ kSaveWinsInDesert = 60,
+ kBubblesUpIn301 = 61,
+ kBubbleWontAttack = 62,
+ kPidLookedAtDoll = 63,
+
+ kOasis = 80,
+ kFireHoles = 81,
+ kDesertRoom = 82,
+ kFromDirection = 83,
+ kDesertCounter = 84,
+ kMoveDirection409 = 85,
+ kHealVerbsVisible = 86,
+ kGrapesHaveGrown = 87,
+ kPidTalkShamon = 88,
+ kPidJustDied = 89,
+
+ kGrapesAreDead = 90,
+ kRocIsChewingDates = 91,
+ kWinsInDesert = 92,
+ kWinsTillPrize = 93,
+ kPidHasBeenHealedSop = 94,
+ kGamePoints = 95,
+ kDancePoints = 96,
+ kCluePoints = 97,
+ kPrizesOwedToPlayer = 98,
+ kObjectFlags = 99,
+
+ kWaterfallDiverted = 100,
+ kShakStatus = 101,
+ kMaxGridValue = 102,
+ kMoveDirection510 = 103,
+ kShak506Angry = 104,
+ kMonsterIsDead = 105,
+ kDoneTalkingLani502 = 106,
+ kFoundLani504 = 107,
+ kSaidUseSwordShak = 108,
+ kGobletFilledSoporific = 109,
+
+ kBeenIn504AsPid = 110,
+ kSeenLaniDeadFirstTime = 111,
+ kSaidPoemIn504 = 112,
+ kTriedToHealLlanie504 = 113,
+ kPutBundleOnLlanie504 = 114,
+ kMake504Empty = 115,
+ kHasTakenMud = 116,
+ kPlatformClicked606 = 117,
+ kHadSpiritBundle = 118,
+
+ kMudIsInEye603 = 120,
+ kRopeIsAlive = 121,
+ kRatCageIsOpen = 122,
+ kFlaskOnPlate = 123,
+ kFluidIsDripping = 124,
+ kHoleIsIn607 = 125,
+ kRopeIsHangingIn607 = 126,
+ kObjectIsInFreezer605 = 127,
+ kObjectImitated = 128,
+ kHasRed = 129,
+
+ kHasYellow = 130,
+ kHasBlue = 131,
+ kWizardDead = 132,
+ kVineWillGrab = 133,
+ kFloorIsCool = 134,
+ kRatMelted = 135,
+ kDoorIsCool = 136,
+ kUsedElevator = 137,
+ kBeenOnTopFloor = 138,
+ kTorchIsIn609 = 139,
+
+ kGridPosition = 140
+ };
+
+class DragonsphereGlobals : public Globals {
+public:
+ SynchronizedList _spriteIndexes;
+ SynchronizedList _sequenceIndexes;
+ SynchronizedList _animationIndexes;
+public:
+ /**
+ * Constructor
+ */
+ DragonsphereGlobals();
+
+ /**
+ * Synchronize the globals data
+ */
+ virtual void synchronize(Common::Serializer &s);
+};
+
+} // End of namespace Dragonsphere
+
+} // End of namespace MADS
+
+#endif /* MADS_GLOBALS_DRAGONSPHERE_H */
diff --git a/engines/mads/events.cpp b/engines/mads/events.cpp
index 7ba9098935..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();
@@ -269,4 +269,9 @@ void EventsManager::initVars() {
_strokeGoing = 0;
}
+void EventsManager::clearEvents() {
+ _pendingKeys.clear();
+}
+
+
} // End of namespace MADS
diff --git a/engines/mads/events.h b/engines/mads/events.h
index 1a2579cae0..5750cb0f40 100644
--- a/engines/mads/events.h
+++ b/engines/mads/events.h
@@ -165,10 +165,18 @@ public:
void initVars();
/**
+ * Clears all currently pending keypresses
+ */
+ void clearEvents();
+
+ /**
* Returns true if there's any pending keys to be processed
*/
bool isKeyPressed() const { return !_pendingKeys.empty(); }
+ /**
+ * Gets the next pending keypress
+ */
Common::KeyState getKey() { return _pendingKeys.pop(); }
};
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 91f6cd5630..0a6741ba7a 100644
--- a/engines/mads/game.cpp
+++ b/engines/mads/game.cpp
@@ -57,8 +57,7 @@ Game *Game::init(MADSEngine *vm) {
}
Game::Game(MADSEngine *vm)
- : _vm(vm), _surface(nullptr), _objects(vm), _scene(vm),
- _screenObjects(vm), _player(vm) {
+ : _vm(vm), _surface(nullptr), _objects(vm), _scene(vm), _screenObjects(vm), _player(vm), _camX(vm), _camY(vm) {
_sectionNumber = 1;
_priorSectionNumber = 0;
_loadGameSlot = -1;
@@ -82,6 +81,7 @@ Game::Game(MADSEngine *vm)
_winStatus = 0;
_widepipeCtr = 0;
_fx = kTransitionNone;
+ _panningSpeed = 1; // Medium speed
// Load the inventory object list
_objects.load();
@@ -218,6 +218,10 @@ void Game::sectionLoop() {
}
_scene.loadScene(_scene._nextSceneId, _aaName, 0);
+ camInitDefault();
+ camSetSpeed();
+
+
_vm->_sound->pauseNewCommands();
if (!_player._spritesLoaded) {
@@ -297,8 +301,10 @@ void Game::sectionLoop() {
_vm->_events->waitCursor();
_kernelMode = KERNEL_ROOM_PRELOAD;
- delete _scene._activeAnimation;
- _scene._activeAnimation = nullptr;
+ for (int i = 0; i < 10; i++) {
+ delete _scene._animation[i];
+ _scene._animation[i] = nullptr;
+ }
_scene._reloadSceneFlag = false;
@@ -492,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;
@@ -594,7 +600,82 @@ 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) {
+ uint32 syncTime = 0;
+
+ switch (masterType) {
+ case SYNC_SEQ:
+ syncTime = _scene._sequences[masterId]._timeout;
+ break;
+
+ case SYNC_ANIM:
+ syncTime = _scene._animation[masterId]->getNextFrameTimer();
+ break;
+
+ case SYNC_CLOCK:
+ syncTime = _scene._frameStartTime + masterId;
+ break;
+
+ case SYNC_PLAYER:
+ syncTime = _player._priorTimer;
+ break;
+ }
+
+
+ switch (slaveType) {
+ case SYNC_SEQ:
+ _scene._sequences[slaveId]._timeout = syncTime;
+ break;
+
+ case SYNC_PLAYER:
+ _player._priorTimer = syncTime;
+ break;
+
+ case SYNC_ANIM:
+ _scene._animation[slaveId]->setNextFrameTimer(syncTime);
+ break;
+
+ case SYNC_CLOCK:
+ error("syncTimer is trying to force _frameStartTime");
+ }
+}
+
+void Game::camInitDefault() {
+ _camX.setDefaultPanX();
+ _camY.setDefaultPanY();
+}
+
+void Game::camSetSpeed() {
+ switch (_panningSpeed) {
+ case 1:
+ _camX._speed = 8;
+ _camY._speed = 4;
+ break;
+
+ case 2:
+ _camX._speed = 320;
+ _camY._speed = 160;
+ break;
+
+ default:
+ _camX._speed = 4;
+ _camY._speed = 2;
+ break;
+ }
+}
+
+void Game::camUpdate() {
+ bool any_pan = _camX.camPan(&_scene._posAdjust.x, &_player._playerPos.x, 320, _scene._sceneInfo->_width);
+ any_pan |= _camY.camPan(&_scene._posAdjust.y, &_player._playerPos.y, 156, _scene._sceneInfo->_height);
+
+ if (any_pan) {
+ _scene.setCamera(_scene._posAdjust);
+ _screenObjects._forceRescan = true;
+ }
}
} // End of namespace MADS
diff --git a/engines/mads/game.h b/engines/mads/game.h
index 95b54b0d1a..9defb58b1a 100644
--- a/engines/mads/game.h
+++ b/engines/mads/game.h
@@ -34,6 +34,7 @@
#include "mads/inventory.h"
#include "mads/player.h"
#include "mads/screen.h"
+#include "mads/camera.h"
namespace MADS {
@@ -44,6 +45,11 @@ enum KernelMode {
KERNEL_ROOM_PRELOAD = 3, KERNEL_ROOM_INIT = 4, KERNEL_ACTIVE_CODE = 5
};
+enum SyncType {
+ SYNC_SEQ = 1, SYNC_PLAYER = 2, SYNC_ANIM = 3, SYNC_CLOCK = 4
+};
+
+
#define MADS_SAVEGAME_VERSION 1
struct MADSSavegameHeader {
@@ -142,6 +148,8 @@ public:
int _winStatus;
int _widepipeCtr;
int _loadGameSlot;
+ int _panningSpeed;
+ Camera _camX, _camY;
public:
virtual ~Game();
@@ -235,6 +243,12 @@ public:
* Creates a temporary thumbnail for use in saving games
*/
void createThumbnail();
+
+ void syncTimers(SyncType slaveType, int slaveId, SyncType masterType, int masterId);
+
+ void camInitDefault();
+ void camSetSpeed();
+ void camUpdate();
};
} // End of namespace MADS
diff --git a/engines/mads/hotspots.cpp b/engines/mads/hotspots.cpp
index 8afef2e524..098313eca4 100644
--- a/engines/mads/hotspots.cpp
+++ b/engines/mads/hotspots.cpp
@@ -27,6 +27,7 @@ namespace MADS {
DynamicHotspot::DynamicHotspot() {
_seqIndex = 0;
+ _animIndex = -1;
_facing = FACING_NONE;
_descId = 0;
_verbId = 0;
@@ -52,6 +53,11 @@ DynamicHotspots::DynamicHotspots(MADSEngine *vm) : _vm(vm) {
_count = 0;
}
+int DynamicHotspots::add(int descId, int verbId, int syntax, int seqIndex, const Common::Rect &bounds) {
+ warning("TODO: DynamicHotspots::add(5 params))");
+ return add(descId, verbId, seqIndex, bounds);
+}
+
int DynamicHotspots::add(int descId, int verbId, int seqIndex, const Common::Rect &bounds) {
// Find a free slot
uint idx = 0;
@@ -69,6 +75,7 @@ int DynamicHotspots::add(int descId, int verbId, int seqIndex, const Common::Rec
_entries[idx]._verbId = verbId;
_entries[idx]._articleNumber = PREP_IN;
_entries[idx]._cursor = CURSOR_NONE;
+ _entries[idx]._animIndex = -1;
++_count;
_changed = true;
@@ -101,6 +108,8 @@ void DynamicHotspots::remove(int index) {
if (index >= 0 && _entries[index]._active) {
if (_entries[index]._seqIndex >= 0)
scene._sequences[_entries[index]._seqIndex]._dynamicHotspotIndex = -1;
+ if (_entries[index]._animIndex >= 0)
+ scene._animation[_entries[index]._animIndex]->_dynamicHotspotIndex = -1;
_entries[index]._active = false;
--_count;
@@ -212,4 +221,16 @@ void Hotspots::activate(int vocabId, bool active) {
}
}
+void Hotspots::activateAtPos(int vocabId, bool active, Common::Point pos) {
+ for (uint idx = 0; idx < size(); ++idx) {
+ Hotspot &hotspot = (*this)[idx];
+ if ((hotspot._vocabId == vocabId) && (pos.x >= hotspot._bounds.left) &&
+ (pos.x <= hotspot._bounds.right) && (pos.y >= hotspot._bounds.top) &&
+ (pos.y <= hotspot._bounds.bottom)) {
+ hotspot._active = active;
+ _vm->_game->_screenObjects.setActive(CAT_HOTSPOT, idx, active);
+ }
+ }
+}
+
} // End of namespace MADS
diff --git a/engines/mads/hotspots.h b/engines/mads/hotspots.h
index 902275bb21..ffd53e5a70 100644
--- a/engines/mads/hotspots.h
+++ b/engines/mads/hotspots.h
@@ -35,6 +35,7 @@ class DynamicHotspot {
public:
bool _active;
int _seqIndex;
+ int _animIndex;
Common::Rect _bounds;
Common::Point _feetPos;
Facing _facing;
@@ -54,7 +55,17 @@ public:
void synchronize(Common::Serializer &s);
};
-#define DYNAMIC_HOTSPOTS_SIZE 8
+#define DYNAMIC_HOTSPOTS_SIZE 16
+
+#define SYNTAX_SINGULAR 0
+#define SYNTAX_PLURAL 1
+#define SYNTAX_PARTITIVE 2
+#define SYNTAX_SINGULAR_MASC 3
+#define SYNTAX_SINGULAR_FEM 4
+#define SYNTAX_SINGULAR_LIVING 5
+#define SYNTAX_MASC_NOT_PROPER 6
+#define SYNTAX_FEM_NOT_PROPER 7
+#define MAX_SYNTAX 8
class DynamicHotspots {
private:
@@ -68,6 +79,7 @@ public:
Common::Array<MADS::DynamicHotspot>::size_type size() const { return _entries.size(); }
DynamicHotspot &operator[](uint idx) { return _entries[idx]; }
+ int add(int descId, int verbId, int syntax, int seqIndex, const Common::Rect &bounds);
int add(int descId, int verbId, int seqIndex, const Common::Rect &bounds);
int setPosition(int index, const Common::Point &pos, Facing facing);
int setCursor(int index, CursorType cursor);
@@ -113,6 +125,12 @@ public:
* Sets the active state of a given hotspot
*/
void activate(int vocabId, bool active);
+
+ /**
+ * Sets the active state of a given hotspot if it includes a given position
+ */
+ void activateAtPos(int vocabId, bool active, Common::Point pos);
+
};
} // End of namespace MADS
diff --git a/engines/mads/mads.cpp b/engines/mads/mads.cpp
index 8c7b6b1ce3..5776d813cf 100644
--- a/engines/mads/mads.cpp
+++ b/engines/mads/mads.cpp
@@ -46,16 +46,19 @@ MADSEngine::MADSEngine(OSystem *syst, const MADSGameDescription *gameDesc) :
_musicFlag = true;
_soundFlag = true;
_dithering = false;
+ _disableFastwalk = false;
_debugger = nullptr;
_dialogs = nullptr;
_events = nullptr;
_font = nullptr;
_game = nullptr;
+ _gameConv = nullptr;
_palette = nullptr;
_resources = nullptr;
_sound = nullptr;
_audio = nullptr;
+ _screen = nullptr;
}
MADSEngine::~MADSEngine() {
@@ -65,6 +68,7 @@ MADSEngine::~MADSEngine() {
delete _font;
Font::deinit();
delete _game;
+ delete _gameConv;
delete _palette;
delete _resources;
delete _sound;
@@ -91,14 +95,15 @@ 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);
+ _gameConv = new GameConversations(this);
loadOptions();
- _screen.empty();
+ _screen->clear();
}
void MADSEngine::loadOptions() {
diff --git a/engines/mads/mads.h b/engines/mads/mads.h
index 901035320a..52f71f7c79 100644
--- a/engines/mads/mads.h
+++ b/engines/mads/mads.h
@@ -30,6 +30,7 @@
#include "common/util.h"
#include "engines/engine.h"
#include "graphics/surface.h"
+#include "mads/conversations.h"
#include "mads/debugger.h"
#include "mads/dialogs.h"
#include "mads/events.h"
@@ -96,9 +97,10 @@ public:
EventsManager *_events;
Font *_font;
Game *_game;
+ GameConversations * _gameConv;
Palette *_palette;
Resources *_resources;
- ScreenSurface _screen;
+ Screen *_screen;
SoundManager *_sound;
AudioPlayer *_audio;
bool _easyMouse;
@@ -108,6 +110,7 @@ public:
bool _musicFlag;
bool _soundFlag;
bool _dithering;
+ bool _disableFastwalk;
public:
MADSEngine(OSystem *syst, const MADSGameDescription *gameDesc);
virtual ~MADSEngine();
diff --git a/engines/mads/menu_views.cpp b/engines/mads/menu_views.cpp
index cfc3b09461..9050ca6081 100644
--- a/engines/mads/menu_views.cpp
+++ b/engines/mads/menu_views.cpp
@@ -1,24 +1,24 @@
/* 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.
- *
- */
+*
+* 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 "mads/game.h"
@@ -253,7 +253,8 @@ 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]);
delete sceneInfo;
@@ -345,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) {
@@ -355,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
@@ -570,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;
@@ -586,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
@@ -795,4 +798,40 @@ int AnimationView::getParameter() {
return result;
}
+void AnimationView::checkResource(const Common::String &resourceName) {
+ //bool hasSuffix = false;
+
+}
+
+int AnimationView::scanResourceIndex(const Common::String &resourceName) {
+ int foundIndex = -1;
+
+ if (_v1) {
+ const char *chP = strchr(resourceName.c_str(), '\\');
+ if (!chP) {
+ chP = strchr(resourceName.c_str(), '*');
+ }
+
+ Common::String resName = chP ? Common::String(chP + 1) : resourceName;
+
+ if (_v2 != 3) {
+ assert(_resIndex.size() == 0);
+ }
+
+ // Scan for the resource name
+ for (uint resIndex = 0; resIndex < _resIndex.size(); ++resIndex) {
+ ResIndexEntry &resEntry = _resIndex[resIndex];
+ if (resEntry._resourceName.compareToIgnoreCase(resourceName)) {
+ foundIndex = resIndex;
+ break;
+ }
+ }
+ }
+
+ if (foundIndex >= 0) {
+ // TODO
+ }
+ return -1;
+}
+
} // End of namespace MADS
diff --git a/engines/mads/menu_views.h b/engines/mads/menu_views.h
index 6c8a2a8bdd..e22b6223a7 100644
--- a/engines/mads/menu_views.h
+++ b/engines/mads/menu_views.h
@@ -119,8 +119,8 @@ protected:
virtual void doFrame();
/**
- * Called when the script is finished
- */
+ * Called when the script is finished
+ */
virtual void scriptDone();
public:
/**
@@ -191,6 +191,11 @@ private:
int _manualFrame2;
int _animFrameNumber;
bool _nextCyclingActive;
+private:
+ void checkResource(const Common::String &resourceName);
+
+ int scanResourceIndex(const Common::String &resourceName);
+
uint _scrollFrameCtr;
private:
void load();
diff --git a/engines/mads/messages.cpp b/engines/mads/messages.cpp
index d88806150d..773ebd309c 100644
--- a/engines/mads/messages.cpp
+++ b/engines/mads/messages.cpp
@@ -193,6 +193,10 @@ void KernelMessages::processText(int msgIndex) {
msg._timeout = 0;
}
+ if (msg._flags & KMSG_ANIM) {
+ warning("TODO: Implement animated text");
+ }
+
if ((msg._timeout <= 0) && (_vm->_game->_trigger == 0)) {
msg._flags |= KMSG_EXPIRE;
if (msg._trigger != 0) {
@@ -465,6 +469,16 @@ void KernelMessages::initRandomMessages(int maxSimultaneousMessages,
va_end(va);
}
+void KernelMessages::setAnim(int msgId, int seqId, int val3 = 0) {
+ if (msgId < 0)
+ return;
+
+ _entries[msgId]._flags |= KMSG_ANIM;
+ _entries[msgId]._sequenceIndex = seqId;
+
+ warning("TODO: KernelMessages::setAnim, unused parameter");
+}
+
/*------------------------------------------------------------------------*/
@@ -544,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 764477a7fc..ced8c5bb6d 100644
--- a/engines/mads/messages.h
+++ b/engines/mads/messages.h
@@ -39,14 +39,14 @@ namespace MADS {
enum KernelMessageFlags {
KMSG_QUOTED = 1, KMSG_PLAYER_TIMEOUT = 2, KMSG_SEQ_ENTRY = 4, KMSG_SCROLL = 8,
KMSG_RIGHT_ALIGN = 0x10, KMSG_CENTER_ALIGN = 0x20, KMSG_EXPIRE = 0x40,
- KMSG_ACTIVE = 0x80
+ KMSG_ACTIVE = 0x80, KMSG_ANIM = 0x100
};
class MADSEngine;
class KernelMessage {
public:
- uint8 _flags;
+ uint16 _flags;
int _sequenceIndex;
int _color1;
int _color2;
@@ -104,6 +104,7 @@ public:
int addQuote(int quoteId, int endTrigger, uint32 timeout);
void scrollMessage(int msgIndex, int numTicks, bool quoted);
void setSeqIndex(int msgIndex, int seqIndex);
+ void setAnim(int msgId, int seqId, int val3);
void remove(int msgIndex);
void reset();
void update();
@@ -169,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/module.mk b/engines/mads/module.mk
index 7cb7a91e8c..8f154394bf 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -3,10 +3,16 @@ MODULE := engines/mads
MODULE_OBJS := \
dragonsphere/game_dragonsphere.o \
dragonsphere/dragonsphere_scenes.o \
+ dragonsphere/dragonsphere_scenes1.o \
+ dragonsphere/globals_dragonsphere.o \
phantom/game_phantom.o \
phantom/globals_phantom.o \
phantom/phantom_scenes.o \
phantom/phantom_scenes1.o \
+ phantom/phantom_scenes2.o \
+ phantom/phantom_scenes3.o \
+ phantom/phantom_scenes4.o \
+ phantom/phantom_scenes5.o \
nebular/dialogs_nebular.o \
nebular/game_nebular.o \
nebular/globals_nebular.o \
@@ -25,7 +31,9 @@ MODULE_OBJS := \
animation.o \
assets.o \
audio.o \
+ camera.o \
compression.o \
+ conversations.o \
debugger.o \
detection.o \
dialogs.o \
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 80891afb83..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,24 +48,25 @@ 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 refrence used all surfaces
+ * Sets the engine reference used all surfaces
*/
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 960a2cc2f4..2af80f517e 100644
--- a/engines/mads/nebular/dialogs_nebular.cpp
+++ b/engines/mads/nebular/dialogs_nebular.cpp
@@ -82,11 +82,14 @@ bool DialogsNebular::show(int messageId, int objectId) {
if (centerFlag) {
crFlag = true;
} else {
- if (objectId == -1) {
+ if (dialog)
+ delete dialog;
+
+ if (objectId == -1)
dialog = new TextDialog(_vm, FONT_INTERFACE, _defaultPosition, _dialogWidth);
- } else {
+ else
dialog = new PictureDialog(_vm, _defaultPosition, _dialogWidth, objectId);
- }
+
dialog->wordWrap(dialogText);
dialog->incNumLines();
}
@@ -146,11 +149,10 @@ bool DialogsNebular::show(int messageId, int objectId) {
}
if (!dialog) {
- if (objectId == -1) {
+ if (objectId == -1)
dialog = new TextDialog(_vm, FONT_INTERFACE, _defaultPosition, _dialogWidth);
- } else {
+ else
dialog = new PictureDialog(_vm, _defaultPosition, _dialogWidth, objectId);
- }
}
if (centerFlag) {
@@ -169,12 +171,12 @@ bool DialogsNebular::show(int messageId, int objectId) {
crFlag = false;
}
- if (!centerFlag)
- dialog->incNumLines();
-
if (!dialog)
error("DialogsNebular::show - Uninitialized dialog");
+ if (!centerFlag)
+ dialog->incNumLines();
+
// Show the dialog
_vm->_events->setCursor(CURSOR_ARROW);
dialog->show();
@@ -366,6 +368,8 @@ void DialogsNebular::showScummVMSaveDialog() {
// Flag for scene loading that we're returning from a dialog
scene._currentSceneId = RETURNING_FROM_DIALOG;
+
+ delete dialog;
}
void DialogsNebular::showScummVMRestoreDialog() {
@@ -382,6 +386,8 @@ void DialogsNebular::showScummVMRestoreDialog() {
// Flag for scene loading that we're returning from a dialog
scene._currentSceneId = RETURNING_FROM_DIALOG;
}
+
+ delete dialog;
}
/*------------------------------------------------------------------------*/
@@ -432,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;
@@ -464,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();
@@ -531,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]);
@@ -562,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);
@@ -572,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;
@@ -592,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]);
@@ -685,7 +686,6 @@ void GameDialog::display() {
}
GameDialog::~GameDialog() {
- _vm->_screen.resetClipBounds();
_vm->_game->_scene._currentSceneId = RETURNING_FROM_DIALOG;
}
diff --git a/engines/mads/nebular/game_nebular.cpp b/engines/mads/nebular/game_nebular.cpp
index e8e0a4f42c..1db5eaea00 100644
--- a/engines/mads/nebular/game_nebular.cpp
+++ b/engines/mads/nebular/game_nebular.cpp
@@ -118,6 +118,10 @@ void GameNebular::startGame() {
initializeGlobals();
+ if (_loadGameSlot >= 0)
+ // User selected to resume a savegame
+ return;
+
// Check copy protection
ProtectionResult protectionResult = checkCopyProtection();
@@ -350,7 +354,7 @@ void GameNebular::setSectionHandler() {
void GameNebular::checkShowDialog() {
// Loop for showing dialogs, if any need to be shown
- if (_vm->_dialogs->_pendingDialog && (_player._stepEnabled || _winStatus)
+ if (_vm->_dialogs->_pendingDialog && (_player._stepEnabled || _winStatus)
&& !_globals[kCopyProtectFailed]) {
_player.releasePlayerSprites();
@@ -689,8 +693,6 @@ void GameNebular::doObjectAction() {
_globals[kHandsetCellStatus] = _difficulty != DIFFICULTY_HARD || _globals[kHandsetCellStatus] ? 1 : 2;
dialogs.show(425);
}
- } else if (action.isAction(VERB_SET, NOUN_TIMEBOMB)) {
- dialogs.show(427);
} else if (action.isAction(VERB_PUT, NOUN_BOMB, NOUN_CHICKEN) || action.isAction(VERB_PUT, NOUN_BOMBS, NOUN_CHICKEN)) {
_objects.setRoom(OBJ_CHICKEN, NOWHERE);
if (_objects.isInInventory(OBJ_BOMBS)) {
@@ -824,8 +826,8 @@ void GameNebular::unhandledAction() {
void GameNebular::step() {
if (_player._visible && _player._stepEnabled && !_player._moving &&
(_player._facing == _player._turnToFacing)) {
- if (_scene._frameStartTime >= *((uint32 *)&_globals[kWalkerTiming])) {
- if (!_player._stopWalkerIndex) {
+ if (_scene._frameStartTime >= (uint32)_globals[kWalkerTiming]) {
+ if (_player._stopWalkers.empty()) {
int randomVal = _vm->getRandomNumber(29999);
if (_globals[kSexOfRex] == REX_MALE) {
switch (_player._facing) {
@@ -873,19 +875,19 @@ void GameNebular::step() {
}
}
- *((uint32 *)&_globals[kWalkerTiming]) += 6;
+ _globals[kWalkerTiming] += 6;
}
}
// Below is countdown to set the timebomb off in room 604
if (_globals[kTimebombStatus] == TIMEBOMB_ACTIVATED) {
- int diff = _scene._frameStartTime - *((uint32 *)&_globals[kTimebombClock]);
- if ((diff >= 0) && (diff <= 60)) {
- *((uint32 *)&_globals[kTimebombTimer]) += diff;
- } else {
- ++*((uint32 *)&_globals[kTimebombTimer]);
- }
- *((uint32 *)&_globals[kTimebombClock]) = _scene._frameStartTime;
+ int diff = _scene._frameStartTime - _globals[kTimebombClock];
+ if ((diff >= 0) && (diff <= 60))
+ _globals[kTimebombTimer] += diff;
+ else
+ ++_globals[kTimebombTimer];
+
+ _globals[kTimebombClock] = (int) _scene._frameStartTime;
}
}
diff --git a/engines/mads/nebular/menu_nebular.cpp b/engines/mads/nebular/menu_nebular.cpp
index 6fe17f3beb..cd81efe0f0 100644
--- a/engines/mads/nebular/menu_nebular.cpp
+++ b/engines/mads/nebular/menu_nebular.cpp
@@ -48,6 +48,7 @@ MainMenu::MainMenu(MADSEngine *vm): MenuView(vm) {
_highlightedIndex = -1;
_selectedIndex = -1;
_buttonDown = false;
+ _showEvolve = _showSets = false;
for (int i = 0; i < 7; ++i)
_menuItems[i] = nullptr;
@@ -137,12 +138,14 @@ void MainMenu::doFrame() {
}
_vm->_events->showCursor();
+ showBonusItems();
} else {
if ((_menuItemIndex == -1) || (_frameIndex == 0)) {
if (++_menuItemIndex == 6) {
// Reached end of display animation
_vm->_events->showCursor();
+ showBonusItems();
return;
} else if (_menuItemIndex == 4 && !shouldShowQuotes()) {
++_menuItemIndex;
@@ -180,6 +183,17 @@ void MainMenu::addSpriteSlot() {
_redrawFlag = true;
}
+void MainMenu::showBonusItems() {
+ Scene &scene = _vm->_game->_scene;
+ _showEvolve = Common::File::exists("SECTION0.HAG") && Common::File::exists("evolve.res");
+ _showSets = Common::File::exists("SECTION0.HAG") && Common::File::exists("sets.res");
+
+ if (_showSets)
+ scene._kernelMessages.add(Common::Point(290, 143), 0x4140, 0, 0, 0, "S");
+ if (_showEvolve)
+ scene._kernelMessages.add(Common::Point(305, 143), 0x4140, 0, 0, 0, "E");
+}
+
bool MainMenu::onEvent(Common::Event &event) {
Scene &scene = _vm->_game->_scene;
if (_selectedIndex != -1)
@@ -280,6 +294,10 @@ bool MainMenu::onEvent(Common::Event &event) {
_selectedIndex = _highlightedIndex;
unhighlightItem();
_frameIndex = 0;
+ } else if (_showSets && Common::Rect(290, 165, 300, 185).contains(event.mouse)) {
+ handleAction(SETS);
+ } else if (_showEvolve && Common::Rect(305, 165, 315, 185).contains(event.mouse)) {
+ handleAction(EVOLVE);
}
return true;
@@ -334,6 +352,14 @@ void MainMenu::handleAction(MADSGameAction action) {
TextView::execute(_vm, "quotes");
return;
+ case SETS:
+ AnimationView::execute(_vm, "sets");
+ break;
+
+ case EVOLVE:
+ AnimationView::execute(_vm, "evolve");
+ break;
+
case EXIT:
_vm->_dialogs->_pendingDialog = DIALOG_ADVERT;
break;
@@ -358,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/menu_nebular.h b/engines/mads/nebular/menu_nebular.h
index 35af0bb34f..8a0cc3575d 100644
--- a/engines/mads/nebular/menu_nebular.h
+++ b/engines/mads/nebular/menu_nebular.h
@@ -35,7 +35,10 @@ class MADSEngine;
namespace Nebular {
-enum MADSGameAction { START_GAME, RESUME_GAME, SHOW_INTRO, CREDITS, QUOTES, EXIT };
+enum MADSGameAction {
+ START_GAME, RESUME_GAME, SHOW_INTRO, CREDITS, QUOTES, EXIT,
+ SETS, EVOLVE
+};
class MainMenu: public MenuView {
private:
@@ -45,6 +48,7 @@ private:
int _frameIndex;
uint32 _delayTimeout;
bool _skipFlag;
+ bool _showEvolve, _showSets;
/**
* Currently highlighted menu item
@@ -81,7 +85,16 @@ private:
*/
void addSpriteSlot();
+ /**
+ * Returns true if the Quotes item should be shown.
+ * i.e. if the player has completed the game
+ */
bool shouldShowQuotes();
+
+ /**
+ * Show the bonus item icons, if available
+ */
+ void showBonusItems();
protected:
/**
* Display the menu
diff --git a/engines/mads/nebular/nebular_scenes.cpp b/engines/mads/nebular/nebular_scenes.cpp
index eb6f7a5610..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) {
@@ -485,7 +485,7 @@ void SceneTeleporter::teleporterHandleKey() {
if (_scene->_currentSceneId != 711) {
if (_curMessageId >= 0)
_scene->_kernelMessages.remove(_curMessageId);
- _curMessageId = _scene->_kernelMessages.add(Common::Point(143, 61), 0xFDFC, 16, 0, 9999999, _msgText);
+ _curMessageId = _scene->_kernelMessages.add(Common::Point(143, 61), 0xFDFC, 16, 0, INDEFINITE_TIMEOUT, _msgText);
}
break;
@@ -563,8 +563,8 @@ void SceneTeleporter::teleporterEnter() {
Common::String msgText2 = Common::String::format("#%.4d", codeVal);
if (_scene->_currentSceneId != 711) {
- _scene->_kernelMessages.add(Common::Point(133, 34), 0, 32, 0, 9999999, msgText2);
- _scene->_kernelMessages.add(Common::Point(143, 61), 0xFDFC, 16, 0, 9999999, _msgText);
+ _scene->_kernelMessages.add(Common::Point(133, 34), 0, 32, 0, INDEFINITE_TIMEOUT, msgText2);
+ _scene->_kernelMessages.add(Common::Point(143, 61), 0xFDFC, 16, 0, INDEFINITE_TIMEOUT, _msgText);
}
_meteorologistCurPlace = 0;
@@ -577,9 +577,9 @@ void SceneTeleporter::teleporterEnter() {
bool SceneTeleporter::teleporterActions() {
bool retVal = false;
- static int _buttonList[12] = { NOUN_0_KEY, NOUN_1_KEY, NOUN_2_KEY, NOUN_3_KEY, NOUN_4_KEY, NOUN_5_KEY, NOUN_6_KEY, NOUN_7_KEY, NOUN_8_KEY, NOUN_9_KEY, NOUN_SMILE_KEY, NOUN_FROWN_KEY };
if (_action.isAction(VERB_PRESS) || _action.isAction(VERB_PUSH)) {
+ static int _buttonList[12] = { NOUN_0_KEY, NOUN_1_KEY, NOUN_2_KEY, NOUN_3_KEY, NOUN_4_KEY, NOUN_5_KEY, NOUN_6_KEY, NOUN_7_KEY, NOUN_8_KEY, NOUN_9_KEY, NOUN_SMILE_KEY, NOUN_FROWN_KEY };
for (int i = 0; i < 12; i++) {
if (_action._activeAction._objectNameId == _buttonList[i])
_buttonTyped = i;
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_scenes1.cpp b/engines/mads/nebular/nebular_scenes1.cpp
index 0cb1b11ee9..9207d87be7 100644
--- a/engines/mads/nebular/nebular_scenes1.cpp
+++ b/engines/mads/nebular/nebular_scenes1.cpp
@@ -258,32 +258,32 @@ void Scene101::step() {
break;
}
- if (_scene->_activeAnimation != nullptr) {
- if ((_scene->_activeAnimation->getCurrentFrame() >= 6) && (_messageNum == 0)) {
+ if (_scene->_animation[0] != nullptr) {
+ if ((_scene->_animation[0]->getCurrentFrame() >= 6) && (_messageNum == 0)) {
_messageNum++;
_scene->_kernelMessages.add(Common::Point(63, _posY), 0x1110, 0, 0, 240, _game.getQuote(49));
_posY += 14;
}
- if ((_scene->_activeAnimation->getCurrentFrame() >= 7) && (_messageNum == 1)) {
+ if ((_scene->_animation[0]->getCurrentFrame() >= 7) && (_messageNum == 1)) {
_messageNum++;
_scene->_kernelMessages.add(Common::Point(63, _posY), 0x1110, 0, 0, 240, _game.getQuote(54));
_posY += 14;
}
- if ((_scene->_activeAnimation->getCurrentFrame() >= 10) && (_messageNum == 2)) {
+ if ((_scene->_animation[0]->getCurrentFrame() >= 10) && (_messageNum == 2)) {
_messageNum++;
_scene->_kernelMessages.add(Common::Point(63, _posY), 0x1110, 0, 0, 240, _game.getQuote(55));
_posY += 14;
}
- if ((_scene->_activeAnimation->getCurrentFrame() >= 17) && (_messageNum == 3)) {
+ if ((_scene->_animation[0]->getCurrentFrame() >= 17) && (_messageNum == 3)) {
_messageNum++;
_scene->_kernelMessages.add(Common::Point(63, _posY), 0x1110, 0, 0, 240, _game.getQuote(56));
_posY += 14;
}
- if ((_scene->_activeAnimation->getCurrentFrame() >= 20) && (_messageNum == 4)) {
+ if ((_scene->_animation[0]->getCurrentFrame() >= 20) && (_messageNum == 4)) {
_messageNum++;
_scene->_kernelMessages.add(Common::Point(63, _posY), 0x1110, 0, 0, 240, _game.getQuote(50));
_posY += 14;
@@ -1263,7 +1263,7 @@ void Scene102::actions() {
return;
}
- if (_action.isAction(VERB_LOOK, NOUN_BURGER) && (_action._mainObjectSource == 4)) {
+ if (_action.isAction(VERB_LOOK, NOUN_BURGER) && (_action._mainObjectSource == CAT_HOTSPOT)) {
_vm->_dialogs->show(801);
_action._inProgress = false;
}
@@ -1782,7 +1782,7 @@ void Scene104::step() {
if ((_game._player._special > 0) && _game._player._stepEnabled)
_game._player._stepEnabled = false;
- if (_kargShootingFl && (_scene->_activeAnimation->getCurrentFrame() >= 19)) {
+ if (_kargShootingFl && (_scene->_animation[0]->getCurrentFrame() >= 19)) {
_scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(52));
_kargShootingFl = false;
}
@@ -2079,7 +2079,7 @@ void Scene106::step() {
}
}
- if (_firstEmergingFl && (_scene->_activeAnimation->getCurrentFrame() >= 19)) {
+ if (_firstEmergingFl && (_scene->_animation[0]->getCurrentFrame() >= 19)) {
_firstEmergingFl = false;
_scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(52));
}
@@ -2263,7 +2263,7 @@ void Scene107::enter() {
}
void Scene107::step() {
- if (_shootingFl && (_scene->_activeAnimation->getCurrentFrame() >= 19)) {
+ if (_shootingFl && (_scene->_animation[0]->getCurrentFrame() >= 19)) {
_scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(52));
_shootingFl = false;
}
@@ -2295,7 +2295,7 @@ void Scene107::actions() {
_scene->_nextSceneId = 105;
else if (_action.isAction(VERB_LOOK, NOUN_NORTHERN_SEA_CLIFF))
_vm->_dialogs->show(10701);
- else if (_action.isAction(VERB_LOOK, NOUN_DEAD_FISH) && (_action._mainObjectSource == 4))
+ else if (_action.isAction(VERB_LOOK, NOUN_DEAD_FISH) && (_action._mainObjectSource == CAT_HOTSPOT))
_vm->_dialogs->show(10702);
else if (_action.isAction(VERB_LOOK, NOUN_BUSH_LIKE_FORMATION))
_vm->_dialogs->show(10703);
@@ -2919,7 +2919,7 @@ void Scene110::actions() {
switch (_game._trigger) {
case 0:
_scene->loadAnimation(Resources::formatName(110, 'T', 0, EXT_AA, ""), 1);
- _scene->_activeAnimation->setNextFrameTimer(_game._player._ticksAmount + _game._player._priorTimer);
+ _scene->_animation[0]->setNextFrameTimer(_game._player._ticksAmount + _game._player._priorTimer);
_game._player._stepEnabled = false;
_game._player._visible = false;
break;
@@ -3066,7 +3066,7 @@ void Scene111::step() {
if (_game._trigger == 73)
_vm->_sound->command(37);
- if (_rexDivingFl && (_scene->_activeAnimation->getCurrentFrame() >= 9)) {
+ if (_rexDivingFl && (_scene->_animation[0]->getCurrentFrame() >= 9)) {
_vm->_sound->command(36);
_rexDivingFl = false;
}
@@ -3138,8 +3138,8 @@ void Scene112::enter() {
}
void Scene112::step() {
- if ((_scene->_activeAnimation != nullptr) && (_game._storyMode == STORYMODE_NICE)) {
- if (_scene->_activeAnimation->getCurrentFrame() >= 54) {
+ if ((_scene->_animation[0] != nullptr) && (_game._storyMode == STORYMODE_NICE)) {
+ if (_scene->_animation[0]->getCurrentFrame() >= 54) {
_scene->freeAnimation();
_game._trigger = 70;
}
diff --git a/engines/mads/nebular/nebular_scenes2.cpp b/engines/mads/nebular/nebular_scenes2.cpp
index 1cbd6f56ef..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;
@@ -484,7 +484,7 @@ void Scene202::enter() {
}
_scene->loadAnimation(formAnimName('M', -1), 71);
- _scene->_activeAnimation->setCurrentFrame(200);
+ _scene->_animation[0]->setCurrentFrame(200);
} else {
if (_ladderTopFl) {
_game._player._visible = false;
@@ -596,7 +596,7 @@ void Scene202::step() {
break;
}
- if (!_scene->_activeAnimation && (_globals[kMeteorologistStatus] != METEOROLOGIST_GONE) && (_meteoClock2 <= _scene->_frameStartTime) && (_meteoClock1 <= _scene->_frameStartTime)) {
+ if (!_scene->_animation[0] && (_globals[kMeteorologistStatus] != METEOROLOGIST_GONE) && (_meteoClock2 <= _scene->_frameStartTime) && (_meteoClock1 <= _scene->_frameStartTime)) {
int randVal = _vm->getRandomNumber(1, 500);
int threshold = 1;
if (_ladderTopFl)
@@ -615,11 +615,11 @@ void Scene202::step() {
}
}
- if (!_scene->_activeAnimation)
+ if (!_scene->_animation[0])
return;
if (_waitingMeteoFl) {
- if (_scene->_activeAnimation->getCurrentFrame() >= 200) {
+ if (_scene->_animation[0]->getCurrentFrame() >= 200) {
if ((_globals[kMeteorologistWatch] == METEOROLOGIST_TOWER) || _globals[kLadderBroken]) {
_scene->_nextSceneId = 213;
} else {
@@ -628,7 +628,7 @@ void Scene202::step() {
}
}
- if ((_scene->_activeAnimation->getCurrentFrame() == 160) && (_meteoFrame != _scene->_activeAnimation->getCurrentFrame())) {
+ if ((_scene->_animation[0]->getCurrentFrame() == 160) && (_meteoFrame != _scene->_animation[0]->getCurrentFrame())) {
Common::Point msgPos;
int msgFlag;
if (!_ladderTopFl) {
@@ -647,15 +647,15 @@ void Scene202::step() {
_toTeleportFl = true;
}
- if (_scene->_activeAnimation->getCurrentFrame() == _meteoFrame) {
+ if (_scene->_animation[0]->getCurrentFrame() == _meteoFrame) {
return;
}
- _meteoFrame = _scene->_activeAnimation->getCurrentFrame();
+ _meteoFrame = _scene->_animation[0]->getCurrentFrame();
int randVal = _vm->getRandomNumber(1, 1000);
int frameStep = -1;
- switch (_scene->_activeAnimation->getCurrentFrame()) {
+ switch (_scene->_animation[0]->getCurrentFrame()) {
case 42:
case 77:
case 96:
@@ -693,8 +693,8 @@ void Scene202::step() {
break;
}
- if (frameStep >= 0 && frameStep != _scene->_activeAnimation->getCurrentFrame() + 1) {
- _scene->_activeAnimation->setCurrentFrame(frameStep);
+ if (frameStep >= 0 && frameStep != _scene->_animation[0]->getCurrentFrame() + 1) {
+ _scene->_animation[0]->setCurrentFrame(frameStep);
_meteoFrame = frameStep;
}
}
@@ -797,7 +797,7 @@ void Scene202::actions() {
_scene->_nextSceneId = 203;
} else if (_action.isAction(VERB_WALK_TOWARDS, NOUN_FIELD_TO_NORTH)) {
if (_globals[kMeteorologistStatus] != METEOROLOGIST_GONE) {
- if (_scene->_activeAnimation)
+ if (_scene->_animation[0])
_globals[kMeteorologistStatus] = METEOROLOGIST_PRESENT;
else
_globals[kMeteorologistStatus] = METEOROLOGIST_ABSENT;
@@ -890,7 +890,7 @@ void Scene202::actions() {
_globals._sequenceIndexes[10] = _scene->_sequences.startCycle(_globals._spriteIndexes[9], false, 6);
_scene->_sequences.setDepth(_globals._sequenceIndexes[10], 1);
_scene->_sequences.setPosition(_globals._sequenceIndexes[10], Common::Point(172, 123));
- if (_scene->_activeAnimation) {
+ if (_scene->_animation[0]) {
_waitingMeteoFl = true;
_globals[kMeteorologistWatch] = METEOROLOGIST_GROUND;
} else {
@@ -898,7 +898,7 @@ void Scene202::actions() {
}
break;
case 2:
- if (!_scene->_activeAnimation && !_meteorologistSpecial) {
+ if (!_scene->_animation[0] && !_meteorologistSpecial) {
_vm->_dialogs->show(20222);
}
_scene->_sequences.remove(_globals._sequenceIndexes[10]);
@@ -932,13 +932,13 @@ void Scene202::actions() {
_globals._sequenceIndexes[10] = _scene->_sequences.startCycle(_globals._spriteIndexes[9], true, -2);
_scene->_sequences.setPosition(_globals._sequenceIndexes[10], Common::Point(247, 82));
_scene->_sequences.setDepth(_globals._sequenceIndexes[10], 1);
- if (_scene->_activeAnimation) {
- if (_scene->_activeAnimation->getCurrentFrame() > 200) {
+ if (_scene->_animation[0]) {
+ if (_scene->_animation[0]->getCurrentFrame() > 200) {
_scene->_sequences.addTimer(120, 2);
} else {
_waitingMeteoFl = true;
_globals[kMeteorologistWatch] = METEOROLOGIST_GONE;
- if ((_scene->_activeAnimation->getCurrentFrame() >= 44) && (_scene->_activeAnimation->getCurrentFrame() <= 75)) {
+ if ((_scene->_animation[0]->getCurrentFrame() >= 44) && (_scene->_animation[0]->getCurrentFrame() <= 75)) {
_scene->_kernelMessages.reset();
int msgIndex = _scene->_kernelMessages.add(Common::Point(248, 15), 0x1110, 32, 0, 60, _game.getQuote(100));
_scene->_kernelMessages.setQuoted(msgIndex, 4, false);
@@ -952,7 +952,7 @@ void Scene202::actions() {
}
break;
case 2:
- if (!_scene->_activeAnimation)
+ if (!_scene->_animation[0])
_vm->_dialogs->show(20222);
_meteorologistSpecial = false;
_scene->_sequences.remove(_globals._sequenceIndexes[10]);
@@ -1227,7 +1227,7 @@ void Scene205::enter() {
if (_globals[kSexOfRex] != SEX_MALE) {
_scene->loadAnimation(formAnimName('a', -1));
- _scene->_activeAnimation->_resetFlag = true;
+ _scene->_animation[0]->_resetFlag = true;
} else {
_beingKicked = true;
_globals._sequenceIndexes[8] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[8], false, 8, 1, 0, 0);
@@ -1284,7 +1284,7 @@ void Scene205::step() {
}
void Scene205::handleWomanSpeech(int quote) {
- _kernelMessage = _scene->_kernelMessages.add(Common::Point(186, 27), 0xFBFA, 0, 0, 9999999, _game.getQuote(quote));
+ _kernelMessage = _scene->_kernelMessages.add(Common::Point(186, 27), 0xFBFA, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(quote));
}
void Scene205::actions() {
@@ -1379,8 +1379,8 @@ void Scene205::actions() {
_scene->_sequences.updateTimeout(_globals._sequenceIndexes[9], -1);
_vm->_sound->command(27);
} else if (_game._trigger == 1) {
- if (_scene->_activeAnimation != nullptr)
- _scene->_activeAnimation->resetSpriteSetsCount();
+ if (_scene->_animation[0] != nullptr)
+ _scene->_animation[0]->resetSpriteSetsCount();
_vm->_dialogs->show(20516);
_scene->_reloadSceneFlag = true;
@@ -1405,9 +1405,9 @@ void Scene205::actions() {
_vm->_dialogs->show(20503);
else if (_action.isAction(VERB_LOOK, NOUN_HUT))
_vm->_dialogs->show(20504);
- else if (_action.isAction(VERB_LOOK, NOUN_CHICKEN) && (_action._mainObjectSource == 4))
+ else if (_action.isAction(VERB_LOOK, NOUN_CHICKEN) && (_action._mainObjectSource == CAT_HOTSPOT))
_vm->_dialogs->show(20505);
- else if (_action.isAction(VERB_TAKE, NOUN_CHICKEN) && (_action._mainObjectSource == 4))
+ else if (_action.isAction(VERB_TAKE, NOUN_CHICKEN) && (_action._mainObjectSource == CAT_HOTSPOT))
_vm->_dialogs->show(20506);
else if (_action.isAction(VERB_LOOK, NOUN_CHICKEN_ON_SPIT))
_vm->_dialogs->show(20507);
@@ -1746,9 +1746,9 @@ void Scene208::enter() {
}
void Scene208::step() {
- if (_boundingFl && _scene->_activeAnimation &&
- (_rhotundaTime <= _scene->_activeAnimation->getCurrentFrame())) {
- _rhotundaTime = _scene->_activeAnimation->getCurrentFrame();
+ if (_boundingFl && _scene->_animation[0] &&
+ (_rhotundaTime <= _scene->_animation[0]->getCurrentFrame())) {
+ _rhotundaTime = _scene->_animation[0]->getCurrentFrame();
if (_rhotundaTime == 125)
_scene->_sequences.remove(_globals._sequenceIndexes[4]);
@@ -4064,7 +4064,7 @@ void Scene210::setDialogNode(int node) {
_vm->_palette->lock();
_scene->_kernelMessages.reset();
_scene->freeAnimation();
- _scene->_activeAnimation = nullptr;
+ _scene->_animation[0] = nullptr;
_scene->resetScene();
_globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('c', -1));
@@ -4109,7 +4109,7 @@ void Scene210::setDialogNode(int node) {
}
void Scene210::handleTwinklesSpeech(int quoteId, int shiftX, uint32 delay) {
- _scene->_kernelMessages.add(Common::Point(10, 70 + (shiftX * 14)), 0xFDFC, 0, 0, (delay == 0) ? 9999999 : delay, _game.getQuote(quoteId));
+ _scene->_kernelMessages.add(Common::Point(10, 70 + (shiftX * 14)), 0xFDFC, 0, 0, (delay == 0) ? INDEFINITE_TIMEOUT : delay, _game.getQuote(quoteId));
}
void Scene210::newNode(int node) {
@@ -4263,8 +4263,8 @@ void Scene210::enter() {
}
restoreDialogNode(_curDialogNode, quote, number);
- if (_scene->_activeAnimation)
- _scene->_activeAnimation->setCurrentFrame(131);
+ if (_scene->_animation[0])
+ _scene->_animation[0]->setCurrentFrame(131);
}
_vm->_palette->setEntry(252, 63, 63, 10);
@@ -4274,9 +4274,9 @@ void Scene210::enter() {
}
void Scene210::step() {
- if ((_twinkleAnimationType == 1) && _scene->_activeAnimation) {
- if (_twinklesCurrentFrame != _scene->_activeAnimation->getCurrentFrame()) {
- _twinklesCurrentFrame = _scene->_activeAnimation->getCurrentFrame();
+ if ((_twinkleAnimationType == 1) && _scene->_animation[0]) {
+ if (_twinklesCurrentFrame != _scene->_animation[0]->getCurrentFrame()) {
+ _twinklesCurrentFrame = _scene->_animation[0]->getCurrentFrame();
int reset_frame = -1;
int random = _vm->getRandomNumber(1, 1000);
@@ -4396,8 +4396,8 @@ void Scene210::step() {
}
if (reset_frame >= 0) {
- if (reset_frame != _scene->_activeAnimation->getCurrentFrame()) {
- _scene->_activeAnimation->setCurrentFrame(reset_frame);
+ if (reset_frame != _scene->_animation[0]->getCurrentFrame()) {
+ _scene->_animation[0]->setCurrentFrame(reset_frame);
_twinklesCurrentFrame = reset_frame;
}
@@ -4411,9 +4411,9 @@ void Scene210::step() {
}
}
- if ((_twinkleAnimationType == 2) && _scene->_activeAnimation) {
- if (_twinklesCurrentFrame != _scene->_activeAnimation->getCurrentFrame()) {
- _twinklesCurrentFrame = _scene->_activeAnimation->getCurrentFrame();
+ if ((_twinkleAnimationType == 2) && _scene->_animation[0]) {
+ if (_twinklesCurrentFrame != _scene->_animation[0]->getCurrentFrame()) {
+ _twinklesCurrentFrame = _scene->_animation[0]->getCurrentFrame();
int reset_frame = -1;
if (_twinklesCurrentFrame == 53) {
@@ -4422,8 +4422,8 @@ void Scene210::step() {
} else if ((_twinklesCurrentFrame == 75) && _shouldTalk)
reset_frame = 60;
- if ((reset_frame >= 0) && (reset_frame != _scene->_activeAnimation->getCurrentFrame())) {
- _scene->_activeAnimation->setCurrentFrame(reset_frame);
+ if ((reset_frame >= 0) && (reset_frame != _scene->_animation[0]->getCurrentFrame())) {
+ _scene->_animation[0]->setCurrentFrame(reset_frame);
_twinklesCurrentFrame = reset_frame;
}
}
@@ -4646,7 +4646,7 @@ void Scene211::enter() {
_game._player._stepEnabled = false;
_game._player._visible = false;
_scene->loadAnimation(formAnimName('A', -1), 100);
- _scene->_activeAnimation->setCurrentFrame(169);
+ _scene->_animation[0]->setCurrentFrame(169);
} else if (_scene->_priorSceneId != RETURNING_FROM_DIALOG) {
_game._player._playerPos = Common::Point(310, 31);
_game._player._facing = FACING_SOUTHWEST;
@@ -4725,8 +4725,8 @@ void Scene211::step() {
}
}
- if (_ambushFl && (_scene->_activeAnimation->getCurrentFrame() > _monkeyFrame)) {
- _monkeyFrame = _scene->_activeAnimation->getCurrentFrame();
+ if (_ambushFl && (_scene->_animation[0]->getCurrentFrame() > _monkeyFrame)) {
+ _monkeyFrame = _scene->_animation[0]->getCurrentFrame();
switch (_monkeyFrame) {
case 2: {
int msgIndex = _scene->_kernelMessages.add(Common::Point(12, 4), 0xFDFC, 0, 0, 60, _game.getQuote(157));
@@ -4798,9 +4798,9 @@ void Scene211::step() {
_wakeFl = false;
}
- if (_scene->_activeAnimation->getCurrentFrame() > _monkeyFrame) {
- _monkeyFrame = _scene->_activeAnimation->getCurrentFrame();
- switch (_scene->_activeAnimation->getCurrentFrame()) {
+ if (_scene->_animation[0]->getCurrentFrame() > _monkeyFrame) {
+ _monkeyFrame = _scene->_animation[0]->getCurrentFrame();
+ switch (_scene->_animation[0]->getCurrentFrame()) {
case 177: {
int msgIndex = _scene->_kernelMessages.add(Common::Point(63, _scrollY), 0x1110, 0, 0, 180, _game.getQuote(165));
_scene->_kernelMessages.setQuoted(msgIndex, 4, true);
diff --git a/engines/mads/nebular/nebular_scenes3.cpp b/engines/mads/nebular/nebular_scenes3.cpp
index 5a6edbf995..7323ee893d 100644
--- a/engines/mads/nebular/nebular_scenes3.cpp
+++ b/engines/mads/nebular/nebular_scenes3.cpp
@@ -293,8 +293,8 @@ void Scene302::step() {
if (_game._trigger == 71)
_scene->_nextSceneId = 303;
- if ((_scene->_activeAnimation != nullptr) && (_scene->_activeAnimation->getCurrentFrame() != _oldFrame)) {
- _oldFrame = _scene->_activeAnimation->getCurrentFrame();
+ if ((_scene->_animation[0] != nullptr) && (_scene->_animation[0]->getCurrentFrame() != _oldFrame)) {
+ _oldFrame = _scene->_animation[0]->getCurrentFrame();
if (_oldFrame == 147) {
_game._objects.setRoom(OBJ_POISON_DARTS, 1);
_game._objects.setRoom(OBJ_BLOWGUN, 1);
@@ -551,7 +551,7 @@ void Scene307::handlePrisonerEncounter() {
}
}
-void Scene307::handlePrisonerSpeech(int firstQuoteId, int number, long timeout) {
+void Scene307::handlePrisonerSpeech(int firstQuoteId, int number, uint32 timeout) {
int height = number * 14;
int posY;
@@ -581,13 +581,13 @@ void Scene307::setDialogNode(int node) {
case 1:
_globals[kMetBuddyBeast] = true;
- handlePrisonerSpeech(0x10F, 2, 9999999);
+ handlePrisonerSpeech(0x10F, 2, INDEFINITE_TIMEOUT);
_dialog1.start();
break;
case 2:
_globals[kMetBuddyBeast] = true;
- handlePrisonerSpeech(0x111, 2, 9999999);
+ handlePrisonerSpeech(0x111, 2, INDEFINITE_TIMEOUT);
_dialog1.start();
break;
@@ -598,7 +598,7 @@ void Scene307::setDialogNode(int node) {
case 5:
_globals[kKnowsBuddyBeast] = true;
- handlePrisonerSpeech(0x117, 2, 9999999);
+ handlePrisonerSpeech(0x117, 2, INDEFINITE_TIMEOUT);
_dialog2.start();
break;
@@ -609,7 +609,7 @@ void Scene307::setDialogNode(int node) {
case 7:
_globals[kKnowsBuddyBeast] = true;
- handlePrisonerSpeech(0x124, 10, 9999999);
+ handlePrisonerSpeech(0x124, 10, INDEFINITE_TIMEOUT);
_dialog2.write(0x11A, false);
_dialog2.write(0x11B, true);
_dialog2.write(0x120, true);
@@ -617,7 +617,7 @@ void Scene307::setDialogNode(int node) {
break;
case 8:
- handlePrisonerSpeech(0x12E, 6, 9999999);
+ handlePrisonerSpeech(0x12E, 6, INDEFINITE_TIMEOUT);
_dialog2.write(0x11A, false);
_dialog2.write(0x11B, false);
_dialog2.write(0x11C, true);
@@ -627,38 +627,38 @@ void Scene307::setDialogNode(int node) {
break;
case 9:
- handlePrisonerSpeech(0x134, 4, 9999999);
+ handlePrisonerSpeech(0x134, 4, INDEFINITE_TIMEOUT);
_dialog2.write(0x11D, false);
_dialog2.start();
break;
case 10:
- handlePrisonerSpeech(0x138, 6, 9999999);
+ handlePrisonerSpeech(0x138, 6, INDEFINITE_TIMEOUT);
_dialog2.write(0x11E, false);
_dialog2.start();
break;
case 11:
- handlePrisonerSpeech(0x13E, 6, 9999999);
+ handlePrisonerSpeech(0x13E, 6, INDEFINITE_TIMEOUT);
_dialog2.write(0x11F, false);
_dialog2.write(0x121, true);
_dialog2.start();
break;
case 12:
- handlePrisonerSpeech(0x144, 4, 9999999);
+ handlePrisonerSpeech(0x144, 4, INDEFINITE_TIMEOUT);
_dialog2.write(0x11C, false);
_dialog2.start();
break;
case 13:
- handlePrisonerSpeech(0x148, 7, 9999999);
+ handlePrisonerSpeech(0x148, 7, INDEFINITE_TIMEOUT);
_dialog2.write(0x120, false);
_dialog2.start();
break;
case 14:
- handlePrisonerSpeech(0x14F, 3, 9999999);
+ handlePrisonerSpeech(0x14F, 3, INDEFINITE_TIMEOUT);
_dialog2.write(0x121, false);
_dialog2.start();
break;
@@ -670,7 +670,7 @@ void Scene307::setDialogNode(int node) {
case 16:
_globals[kKnowsBuddyBeast] = true;
- handlePrisonerSpeech(0x10C, 1, 9999999);
+ handlePrisonerSpeech(0x10C, 1, INDEFINITE_TIMEOUT);
_dialog2.start();
break;
@@ -828,23 +828,23 @@ void Scene307::enter() {
void Scene307::step() {
handleForceField(&_forceField, &_globals._spriteIndexes[0]);
- if ((_animationMode == 1) && (_scene->_activeAnimation != nullptr)) {
- if (_scene->_activeAnimation->getCurrentFrame() == 126) {
+ if ((_animationMode == 1) && (_scene->_animation[0] != nullptr)) {
+ if (_scene->_animation[0]->getCurrentFrame() == 126) {
_forceField._flag = false;
_vm->_sound->command(5);
}
- if (_scene->_activeAnimation->getCurrentFrame() == 194) {
+ if (_scene->_animation[0]->getCurrentFrame() == 194) {
_forceField._flag = true;
_vm->_sound->command(24);
}
}
- if ((_animationMode == 2) && (_scene->_activeAnimation != nullptr)) {
- if (_scene->_activeAnimation->getCurrentFrame() == 54)
+ if ((_animationMode == 2) && (_scene->_animation[0] != nullptr)) {
+ if (_scene->_animation[0]->getCurrentFrame() == 54)
_forceField._flag = false;
- if (_scene->_activeAnimation->getCurrentFrame() == 150) {
+ if (_scene->_animation[0]->getCurrentFrame() == 150) {
_game._player._visible = false;
_game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
}
@@ -869,7 +869,7 @@ void Scene307::step() {
}
_lastFrameTime = _scene->_frameStartTime;
- if ((_guardTime > 3000) && !_duringPeeingFl && (_scene->_activeAnimation == nullptr)
+ if ((_guardTime > 3000) && !_duringPeeingFl && (_scene->_animation[0] == nullptr)
&& (_game._screenObjects._inputMode != kInputConversation) && _globals[kMetBuddyBeast] && !_activePrisonerFl) {
if (!_game._objects.isInInventory(OBJ_SCALPEL) && !_grateOpenedFl) {
_game._player._stepEnabled = false;
@@ -879,7 +879,7 @@ void Scene307::step() {
_scene->loadAnimation(formAnimName('b', -1), 70);
}
_guardTime = 0;
- } else if ((_prisonerTimer > 300) && (_game._screenObjects._inputMode != kInputConversation) && (_scene->_activeAnimation == nullptr) && !_activePrisonerFl) {
+ } else if ((_prisonerTimer > 300) && (_game._screenObjects._inputMode != kInputConversation) && (_scene->_animation[0] == nullptr) && !_activePrisonerFl) {
if (!_globals[kMetBuddyBeast]) {
int idx = _scene->_kernelMessages.add(Common::Point(5, 51), 0xFDFC, 0, 81, 120, _game.getQuote(_prisonerMessageId));
_scene->_kernelMessages.setQuoted(idx, 4, true);
@@ -1380,9 +1380,9 @@ void Scene309::enter() {
_game._player._stepEnabled = false;
_scene->loadAnimation(formAnimName('a', -1), 60);
- _characterSpriteIndexes[0] = _scene->_activeAnimation->_spriteListIndexes[2];
- _characterSpriteIndexes[1] = _scene->_activeAnimation->_spriteListIndexes[2];
- _characterSpriteIndexes[2] = _scene->_activeAnimation->_spriteListIndexes[1];
+ _characterSpriteIndexes[0] = _scene->_animation[0]->_spriteListIndexes[2];
+ _characterSpriteIndexes[1] = _scene->_animation[0]->_spriteListIndexes[2];
+ _characterSpriteIndexes[2] = _scene->_animation[0]->_spriteListIndexes[1];
_messagesIndexes[0] = -1;
_messagesIndexes[1] = -1;
@@ -1404,9 +1404,9 @@ void Scene309::step() {
if (_game._trigger == 62)
_messagesIndexes[2] = -1;
- if (_scene->_activeAnimation != nullptr) {
- if (_lastFrame != _scene->_activeAnimation->getCurrentFrame()) {
- _lastFrame = _scene->_activeAnimation->getCurrentFrame();
+ if (_scene->_animation[0] != nullptr) {
+ if (_lastFrame != _scene->_animation[0]->getCurrentFrame()) {
+ _lastFrame = _scene->_animation[0]->getCurrentFrame();
if (_lastFrame == 39) {
_messagesIndexes[0] = _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 32, 61, 210, _game.getQuote(348));
_messagesIndexes[1] = _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 32, 0, 210, _game.getQuote(349));
@@ -1419,15 +1419,15 @@ void Scene309::step() {
if (_messagesIndexes[charIdx] >= 0) {
bool match = false;
int j = -1;
- for (j = _scene->_activeAnimation->_oldFrameEntry; j < _scene->_activeAnimation->_header._frameEntriesCount; j++) {
- if (_scene->_activeAnimation->_frameEntries[j]._spriteSlot._spritesIndex == _characterSpriteIndexes[charIdx]) {
+ for (j = _scene->_animation[0]->_oldFrameEntry; j < _scene->_animation[0]->_header._frameEntriesCount; j++) {
+ if (_scene->_animation[0]->_frameEntries[j]._spriteSlot._spritesIndex == _characterSpriteIndexes[charIdx]) {
match = true;
break;
}
}
if (match) {
- SpriteSlotSubset *curSpriteSlot = &_scene->_activeAnimation->_frameEntries[j]._spriteSlot;
+ SpriteSlotSubset *curSpriteSlot = &_scene->_animation[0]->_frameEntries[j]._spriteSlot;
_scene->_kernelMessages._entries[_messagesIndexes[charIdx]]._position.x = curSpriteSlot->_position.x;
_scene->_kernelMessages._entries[_messagesIndexes[charIdx]]._position.y = curSpriteSlot->_position.y - (50 + (14 * ((charIdx == 0) ? 2 : 1)));
}
@@ -2465,59 +2465,59 @@ void Scene318::handleDialog() {
switch (_action._activeAction._verbId) {
case 0x191:
- handleInternDialog(0x19E, 2, 9999999);
+ handleInternDialog(0x19E, 2, INDEFINITE_TIMEOUT);
_dialog1.write(0x192, true);
break;
case 0x192:
- handleInternDialog(0x1A0, 5, 9999999);
+ handleInternDialog(0x1A0, 5, INDEFINITE_TIMEOUT);
_dialog1.write(0x193, true);
break;
case 0x193:
- handleInternDialog(0x1A5, 4, 9999999);
+ handleInternDialog(0x1A5, 4, INDEFINITE_TIMEOUT);
_dialog1.write(0x194, true);
break;
case 0x194:
- handleInternDialog(0x1A9, 6, 9999999);
+ handleInternDialog(0x1A9, 6, INDEFINITE_TIMEOUT);
_dialog1.write(0x195, true);
_dialog1.write(0x196, true);
_dialog1.write(0x19D, false);
break;
case 0x195:
- handleInternDialog(0x1AF, 7, 9999999);
+ handleInternDialog(0x1AF, 7, INDEFINITE_TIMEOUT);
if (!_dialog1.read(0x196))
_dialog1.write(0x197, true);
break;
case 0x196:
- handleInternDialog(0x1B6, 5, 9999999);
+ handleInternDialog(0x1B6, 5, INDEFINITE_TIMEOUT);
if (!_dialog1.read(0x195))
_dialog1.write(0x197, true);
break;
case 0x197:
- handleInternDialog(0x1BB, 5, 9999999);
+ handleInternDialog(0x1BB, 5, INDEFINITE_TIMEOUT);
break;
case 0x198:
- handleInternDialog(0x1C0, 5, 9999999);
+ handleInternDialog(0x1C0, 5, INDEFINITE_TIMEOUT);
_dialog1.write(0x19A, true);
break;
case 0x199:
- handleInternDialog(0x1C5, 3, 9999999);
+ handleInternDialog(0x1C5, 3, INDEFINITE_TIMEOUT);
break;
case 0x19A:
- handleInternDialog(0x1C8, 5, 9999999);
+ handleInternDialog(0x1C8, 5, INDEFINITE_TIMEOUT);
_dialog1.write(0x19B, true);
break;
case 0x19B:
- handleInternDialog(0x1CD, 3, 9999999);
+ handleInternDialog(0x1CD, 3, INDEFINITE_TIMEOUT);
break;
case 0x19C:
@@ -2602,7 +2602,7 @@ void Scene318::enter() {
if (_globals[kAfterHavoc]) {
_scene->loadAnimation(formAnimName('f', -1));
- _scene->_activeAnimation->_resetFlag = true;
+ _scene->_animation[0]->_resetFlag = true;
} else if (!_globals[kHasSeenProfPyro]) {
_scene->_hotspots.activate(NOUN_PROFESSORS_GURNEY, false);
_scene->_hotspots.activate(NOUN_PROFESSOR, false);
@@ -2655,7 +2655,7 @@ void Scene318::enter() {
0x1C8, 0x1C9, 0x1CA, 0x1CB, 0x1CC, 0x1CD, 0x1CE, 0x1CF, 0x1D0, 0x1D1, 0x1D2, 0x1D3,
0x190, 0x19D, 0);
- if ((_scene->_priorSceneId == RETURNING_FROM_DIALOG) || (((_scene->_priorSceneId == 318) ||
+ if ((_scene->_priorSceneId == RETURNING_FROM_DIALOG) || (((_scene->_priorSceneId == 318) ||
(_scene->_priorSceneId == RETURNING_FROM_LOADING)) && (!_globals[kAfterHavoc]))) {
if (!_globals[kAfterHavoc]) {
_game._player._visible = false;
@@ -2705,9 +2705,9 @@ void Scene318::enter() {
}
void Scene318::step() {
- if ((_scene->_activeAnimation != nullptr) && (_animMode == 2)) {
- if (_lastFrame != _scene->_activeAnimation->getCurrentFrame()) {
- _lastFrame = _scene->_activeAnimation->getCurrentFrame();
+ if ((_scene->_animation[0] != nullptr) && (_animMode == 2)) {
+ if (_lastFrame != _scene->_animation[0]->getCurrentFrame()) {
+ _lastFrame = _scene->_animation[0]->getCurrentFrame();
int nextFrame = -1;
switch (_lastFrame) {
@@ -2759,8 +2759,8 @@ void Scene318::step() {
break;
}
- if ((nextFrame >= 0) && (nextFrame != _scene->_activeAnimation->getCurrentFrame())) {
- _scene->_activeAnimation->setCurrentFrame(nextFrame);
+ if ((nextFrame >= 0) && (nextFrame != _scene->_animation[0]->getCurrentFrame())) {
+ _scene->_animation[0]->setCurrentFrame(nextFrame);
_lastFrame = nextFrame;
}
}
@@ -2818,7 +2818,7 @@ void Scene318::step() {
if (_internCounter >= 3600) {
_vm->_sound->command(59);
- _vm->_screen._shakeCountdown = 20;
+ _vm->_screen->_shakeCountdown = 20;
_internWalkingFl = true;
}
}
@@ -2865,7 +2865,7 @@ void Scene318::actions() {
case 1:
_game._player._stepEnabled = true;
- handleInternDialog(0x18F, 1, 9999999);
+ handleInternDialog(0x18F, 1, INDEFINITE_TIMEOUT);
_dialog1.start();
break;
@@ -3152,27 +3152,27 @@ void Scene319::enter() {
_slacheInitFl = true;
if (_globals[kRexHasMetSlache]) {
- handleSlacheDialogs(VERB_WALK_OUTSIDE, 2, 9999999);
+ handleSlacheDialogs(VERB_WALK_OUTSIDE, 2, INDEFINITE_TIMEOUT);
_slachePosY = 3;
} else {
- handleSlacheDialogs(0x186, 4, 9999999);
+ handleSlacheDialogs(0x186, 4, INDEFINITE_TIMEOUT);
_slachePosY = 5;
}
}
switch (_slacheTopic) {
case 1:
- handleSlacheDialogs(0x15F, 2, 9999999);
+ handleSlacheDialogs(0x15F, 2, INDEFINITE_TIMEOUT);
_dialog1.start();
break;
case 2:
- handleSlacheDialogs(0x16B, 2, 9999999);
+ handleSlacheDialogs(0x16B, 2, INDEFINITE_TIMEOUT);
_dialog2.start();
break;
case 3:
- handleSlacheDialogs(0x177, 2, 9999999);
+ handleSlacheDialogs(0x177, 2, INDEFINITE_TIMEOUT);
_dialog3.start();
break;
@@ -3185,11 +3185,11 @@ void Scene319::enter() {
}
void Scene319::step() {
- if (_scene->_activeAnimation == nullptr)
+ if (_scene->_animation[0] == nullptr)
return;
- if (_animFrame != _scene->_activeAnimation->getCurrentFrame()) {
- _animFrame = _scene->_activeAnimation->getCurrentFrame();
+ if (_animFrame != _scene->_animation[0]->getCurrentFrame()) {
+ _animFrame = _scene->_animation[0]->getCurrentFrame();
int nextFrame = -1;
if (_animMode == 1) {
switch (_animFrame) {
@@ -3288,25 +3288,25 @@ 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->_activeAnimation->getCurrentFrame())) {
- _scene->_activeAnimation->setCurrentFrame(nextFrame);
+ if ((nextFrame >= 0) && (nextFrame != _scene->_animation[0]->getCurrentFrame())) {
+ _scene->_animation[0]->setCurrentFrame(nextFrame);
_animFrame = nextFrame;
}
}
@@ -3320,13 +3320,13 @@ void Scene319::step() {
_scene->freeAnimation();
_scene->loadAnimation(formAnimName('b', 0));
if (_nextAction1 == 3)
- _scene->_activeAnimation->setCurrentFrame(85);
+ _scene->_animation[0]->setCurrentFrame(85);
else if (_nextAction1 == 1)
- _scene->_activeAnimation->setCurrentFrame(40);
+ _scene->_animation[0]->setCurrentFrame(40);
- _animFrame = _scene->_activeAnimation->getCurrentFrame();
+ _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;
@@ -3394,7 +3394,7 @@ void Scene319::actions() {
if (!_slacheTalkingFl) {
_scene->_sequences.addTimer(4, 2);
} else {
- handleSlacheDialogs(0x16B, 2, 9999999);
+ handleSlacheDialogs(0x16B, 2, INDEFINITE_TIMEOUT);
_dialog2.start();
_game._player._stepEnabled = true;
}
@@ -3411,7 +3411,7 @@ void Scene319::actions() {
if (!_slacheTalkingFl) {
_scene->_sequences.addTimer(4, 2);
} else {
- handleSlacheDialogs(0x177, 2, 9999999);
+ handleSlacheDialogs(0x177, 2, INDEFINITE_TIMEOUT);
_dialog3.start();
_game._player._stepEnabled = true;
}
@@ -3480,7 +3480,7 @@ void Scene319::actions() {
curDialog = &_dialog3;
}
- handleSlacheDialogs(nextDocQuote, 2, 9999999);
+ handleSlacheDialogs(nextDocQuote, 2, INDEFINITE_TIMEOUT);
if (addDialogLine) {
curDialog->write(_action._activeAction._verbId, false);
curDialog->write(addVerbId, true);
@@ -3512,7 +3512,7 @@ void Scene319::actions() {
curDialog = &_dialog3;
}
- handleSlacheDialogs(nextDocQuote, 2, 9999999);
+ handleSlacheDialogs(nextDocQuote, 2, INDEFINITE_TIMEOUT);
if (addDialogLine) {
curDialog->write(_action._activeAction._verbId, false);
curDialog->write(addVerbId, true);
@@ -3710,9 +3710,9 @@ void Scene320::enter() {
}
void Scene320::step() {
- if (_scene->_activeAnimation != nullptr) {
- if (_lastFrame != _scene->_activeAnimation->getCurrentFrame()) {
- _lastFrame = _scene->_activeAnimation->getCurrentFrame();
+ if (_scene->_animation[0] != nullptr) {
+ if (_lastFrame != _scene->_animation[0]->getCurrentFrame()) {
+ _lastFrame = _scene->_animation[0]->getCurrentFrame();
switch (_lastFrame) {
case 95:
_blinkFl = true;
@@ -3731,7 +3731,7 @@ void Scene320::step() {
case 417:
case 457:
- _vm->_screen._shakeCountdown = 40;
+ _vm->_screen->_shakeCountdown = 40;
_vm->_sound->command(59);
break;
@@ -3892,8 +3892,8 @@ void Scene321::enter() {
}
void Scene321::step() {
- if (_scene->_activeAnimation != nullptr) {
- if ((_scene->_activeAnimation->getCurrentFrame() >= 260) && (_globals[kSexOfRex] == REX_MALE) && (_game._storyMode >= STORYMODE_NICE))
+ if (_scene->_animation[0] != nullptr) {
+ if ((_scene->_animation[0]->getCurrentFrame() >= 260) && (_globals[kSexOfRex] == REX_MALE) && (_game._storyMode >= STORYMODE_NICE))
_scene->_nextSceneId = 316;
}
@@ -5045,7 +5045,7 @@ void Scene359::actions() {
_vm->_dialogs->show(35918);
else if (_action.isAction(VERB_TAKE, NOUN_LIMB))
_vm->_dialogs->show(35919);
- else if (_action.isAction(VERB_LOOK, NOUN_SECURITY_CARD) && (_action._mainObjectSource == 4))
+ else if (_action.isAction(VERB_LOOK, NOUN_SECURITY_CARD) && (_action._mainObjectSource == CAT_HOTSPOT))
_vm->_dialogs->show(35921);
else if (_action.isAction(VERB_LOOK, NOUN_BLOOD_STAIN)) {
if ((_game._difficulty != DIFFICULTY_HARD) && (_game._objects[OBJ_SECURITY_CARD]._roomNumber == 359))
diff --git a/engines/mads/nebular/nebular_scenes3.h b/engines/mads/nebular/nebular_scenes3.h
index cf925b3867..af75b14193 100644
--- a/engines/mads/nebular/nebular_scenes3.h
+++ b/engines/mads/nebular/nebular_scenes3.h
@@ -158,7 +158,7 @@ private:
void handlePrisonerDialog();
void handlePrisonerEncounter();
void setDialogNode(int node);
- void handlePrisonerSpeech(int firstQuoteId, int number, long timeout);
+ void handlePrisonerSpeech(int firstQuoteId, int number, uint32 timeout);
public:
Scene307(MADSEngine *vm);
diff --git a/engines/mads/nebular/nebular_scenes4.cpp b/engines/mads/nebular/nebular_scenes4.cpp
index c981f6a6e4..d71fd9f8c9 100644
--- a/engines/mads/nebular/nebular_scenes4.cpp
+++ b/engines/mads/nebular/nebular_scenes4.cpp
@@ -396,7 +396,7 @@ void Scene402::handleConversation1() {
break;
}
_scene->_kernelMessages.reset();
- _scene->_kernelMessages.add(Common::Point(quotePosX, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(quoteId));
+ _scene->_kernelMessages.add(Common::Point(quotePosX, 41), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(quoteId));
_game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
_scene->_sequences.addTimer(1, 100);
_talkTimer = 120;
@@ -406,7 +406,7 @@ void Scene402::handleConversation1() {
case 0x215:
_scene->_kernelMessages.reset();
- _scene->_kernelMessages.add(Common::Point(260, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1EC));
+ _scene->_kernelMessages.add(Common::Point(260, 41), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x1EC));
_game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
_scene->_sequences.addTimer(1, 100);
_talkTimer = 120;
@@ -502,8 +502,8 @@ void Scene402::handleConversation2() {
_scene->_sequences.addTimer(1, 100);
_talkTimer = 180;
_scene->_kernelMessages.reset();
- _scene->_kernelMessages.add(Common::Point(198, 27), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1E7));
- _scene->_kernelMessages.add(Common::Point(201, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1E8));
+ _scene->_kernelMessages.add(Common::Point(198, 27), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x1E7));
+ _scene->_kernelMessages.add(Common::Point(201, 41), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x1E8));
_bartenderCurrentQuestion = 7;
break;
@@ -512,8 +512,8 @@ void Scene402::handleConversation2() {
_scene->_sequences.addTimer(1, 100);
_talkTimer = 180;
_scene->_kernelMessages.reset();
- _scene->_kernelMessages.add(Common::Point(220, 27), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1E9));
- _scene->_kernelMessages.add(Common::Point(190, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1EA));
+ _scene->_kernelMessages.add(Common::Point(220, 27), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x1E9));
+ _scene->_kernelMessages.add(Common::Point(190, 41), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x1EA));
_bartenderCurrentQuestion = 8;
break;
@@ -522,7 +522,7 @@ void Scene402::handleConversation2() {
_scene->_sequences.addTimer(1, 100);
_talkTimer = 150;
_scene->_kernelMessages.reset();
- _scene->_kernelMessages.add(Common::Point(196, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1EB));
+ _scene->_kernelMessages.add(Common::Point(196, 41), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x1EB));
_bartenderCurrentQuestion = 9;
break;
@@ -548,8 +548,8 @@ void Scene402::handleConversation3() {
_game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
_scene->_sequences.addTimer(1, 86);
_scene->_kernelMessages.reset();
- _scene->_kernelMessages.add(Common::Point(188, 27), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1ED));
- _scene->_kernelMessages.add(Common::Point(199, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1EE));
+ _scene->_kernelMessages.add(Common::Point(188, 27), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x1ED));
+ _scene->_kernelMessages.add(Common::Point(199, 41), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x1EE));
setDialogNode(4);
_bartenderCurrentQuestion = 2;
break;
@@ -799,47 +799,47 @@ void Scene402::enter() {
switch (_bartenderCurrentQuestion) {
case 1:
- _scene->_kernelMessages.add(Common::Point(260, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1EC));
+ _scene->_kernelMessages.add(Common::Point(260, 41), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x1EC));
break;
case 2:
- _scene->_kernelMessages.add(Common::Point(188, 27), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1ED));
- _scene->_kernelMessages.add(Common::Point(199, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1EE));
+ _scene->_kernelMessages.add(Common::Point(188, 27), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x1ED));
+ _scene->_kernelMessages.add(Common::Point(199, 41), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x1EE));
break;
case 3:
- _scene->_kernelMessages.add(Common::Point(177, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1EF));
+ _scene->_kernelMessages.add(Common::Point(177, 41), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x1EF));
break;
case 4:
- _scene->_kernelMessages.add(Common::Point(205, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1E4));
+ _scene->_kernelMessages.add(Common::Point(205, 41), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x1E4));
break;
case 5:
- _scene->_kernelMessages.add(Common::Point(203, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1E5));
+ _scene->_kernelMessages.add(Common::Point(203, 41), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x1E5));
break;
case 6:
- _scene->_kernelMessages.add(Common::Point(260, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1E6));
+ _scene->_kernelMessages.add(Common::Point(260, 41), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x1E6));
break;
case 7:
- _scene->_kernelMessages.add(Common::Point(198, 27), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1E7));
- _scene->_kernelMessages.add(Common::Point(201, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1E8));
+ _scene->_kernelMessages.add(Common::Point(198, 27), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x1E7));
+ _scene->_kernelMessages.add(Common::Point(201, 41), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x1E8));
break;
case 8:
- _scene->_kernelMessages.add(Common::Point(220, 27), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1E9));
- _scene->_kernelMessages.add(Common::Point(190, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1EA));
+ _scene->_kernelMessages.add(Common::Point(220, 27), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x1E9));
+ _scene->_kernelMessages.add(Common::Point(190, 41), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x1EA));
break;
case 9:
- _scene->_kernelMessages.add(Common::Point(196, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1EB));
+ _scene->_kernelMessages.add(Common::Point(196, 41), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x1EB));
break;
case 10:
- _scene->_kernelMessages.add(Common::Point(198, 27), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1E2));
- _scene->_kernelMessages.add(Common::Point(199, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1E3));
+ _scene->_kernelMessages.add(Common::Point(198, 27), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x1E2));
+ _scene->_kernelMessages.add(Common::Point(199, 41), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x1E3));
break;
default:
@@ -876,7 +876,7 @@ void Scene402::enter() {
_refuseAlienLiquor = false;
_scene->loadAnimation(Resources::formatName(402, 'd', 1, EXT_AA, ""));
- _scene->_activeAnimation->_resetFlag = true;
+ _scene->_animation[0]->_resetFlag = true;
_globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, 1);
_scene->_sequences.setDepth(_globals._sequenceIndexes[5], 1);
@@ -1536,43 +1536,43 @@ void Scene402::step() {
if (_game._trigger == 32)
_rightWomanMoving = false;
- if (_scene->_activeAnimation->getCurrentFrame() == 1) {
+ if (_scene->_animation[0]->getCurrentFrame() == 1) {
switch (_vm->getRandomNumber(1, 50)) {
case 1:
- _scene->_activeAnimation->setCurrentFrame(2);
+ _scene->_animation[0]->setCurrentFrame(2);
break;
case 2:
- _scene->_activeAnimation->setCurrentFrame(7);
+ _scene->_animation[0]->setCurrentFrame(7);
break;
case 3:
- _scene->_activeAnimation->setCurrentFrame(11);
+ _scene->_animation[0]->setCurrentFrame(11);
break;
default:
- _scene->_activeAnimation->setCurrentFrame(0);
+ _scene->_animation[0]->setCurrentFrame(0);
break;
}
}
- if ((_scene->_activeAnimation->getCurrentFrame() == 4) && (_drinkTimer < 10)) {
+ if ((_scene->_animation[0]->getCurrentFrame() == 4) && (_drinkTimer < 10)) {
++ _drinkTimer;
- _scene->_activeAnimation->setCurrentFrame(3);
+ _scene->_animation[0]->setCurrentFrame(3);
}
if (_drinkTimer == 10) {
_drinkTimer = 0;
- _scene->_activeAnimation->setCurrentFrame(4);
- _scene->_activeAnimation->_currentFrame = 5;
+ _scene->_animation[0]->setCurrentFrame(4);
+ _scene->_animation[0]->_currentFrame = 5;
}
- switch (_scene->_activeAnimation->getCurrentFrame()) {
+ switch (_scene->_animation[0]->getCurrentFrame()) {
case 6:
case 10:
case 14:
- _scene->_activeAnimation->setCurrentFrame(0);
+ _scene->_animation[0]->setCurrentFrame(0);
break;
default:
@@ -2268,8 +2268,8 @@ void Scene402::actions() {
if (_game._objects.isInRoom(OBJ_ALIEN_LIQUOR)) {
if (!_refuseAlienLiquor) {
_scene->_kernelMessages.reset();
- _scene->_kernelMessages.add(Common::Point(198, 27), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1E2));
- _scene->_kernelMessages.add(Common::Point(199, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1E3));
+ _scene->_kernelMessages.add(Common::Point(198, 27), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x1E2));
+ _scene->_kernelMessages.add(Common::Point(199, 41), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x1E3));
_bartenderCurrentQuestion = 10;
_game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
_scene->_sequences.addTimer(1, 100);
@@ -2281,7 +2281,7 @@ void Scene402::actions() {
_dialog1.start();
} else {
- _scene->_kernelMessages.add(Common::Point(177, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1EF));
+ _scene->_kernelMessages.add(Common::Point(177, 41), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x1EF));
_game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
_scene->_sequences.addTimer(1, 100);
_talkTimer = 120;
@@ -3126,36 +3126,36 @@ void Scene410::enter() {
sceneEntrySound();
_scene->loadAnimation(Resources::formatName(410, 'r', -1, EXT_AA, ""));
- _scene->_activeAnimation->_resetFlag = true;
+ _scene->_animation[0]->_resetFlag = true;
}
void Scene410::step() {
- if (_scene->_activeAnimation->getCurrentFrame() == 1) {
+ if (_scene->_animation[0]->getCurrentFrame() == 1) {
if (_vm->getRandomNumber(1, 30) == 1)
- _scene->_activeAnimation->setCurrentFrame(2);
+ _scene->_animation[0]->setCurrentFrame(2);
else
- _scene->_activeAnimation->setCurrentFrame(0);
+ _scene->_animation[0]->setCurrentFrame(0);
}
- if (_scene->_activeAnimation->getCurrentFrame() == 9) {
+ if (_scene->_animation[0]->getCurrentFrame() == 9) {
if (_vm->getRandomNumber(1, 30) == 1)
- _scene->_activeAnimation->setCurrentFrame(10);
+ _scene->_animation[0]->setCurrentFrame(10);
else
- _scene->_activeAnimation->setCurrentFrame(8);
+ _scene->_animation[0]->setCurrentFrame(8);
}
- if (_scene->_activeAnimation->getCurrentFrame() == 5) {
+ if (_scene->_animation[0]->getCurrentFrame() == 5) {
if (_vm->getRandomNumber(1, 30) == 1)
- _scene->_activeAnimation->setCurrentFrame(6);
+ _scene->_animation[0]->setCurrentFrame(6);
else
- _scene->_activeAnimation->setCurrentFrame(4);
+ _scene->_animation[0]->setCurrentFrame(4);
}
- if (_scene->_activeAnimation->getCurrentFrame() == 3) {
+ if (_scene->_animation[0]->getCurrentFrame() == 3) {
if (_vm->getRandomNumber(1, 2) == 1)
- _scene->_activeAnimation->setCurrentFrame(4);
+ _scene->_animation[0]->setCurrentFrame(4);
else // == 2
- _scene->_activeAnimation->setCurrentFrame(8);
+ _scene->_animation[0]->setCurrentFrame(8);
}
}
@@ -3491,7 +3491,7 @@ void Scene411::handleDialog() {
_game._player._priorTimer = _scene->_frameStartTime + _game._player._ticksAmount;
_game._player._visible = false;
_game._player._stepEnabled = false;
- _scene->_activeAnimation->setCurrentFrame(_resetFrame);
+ _scene->_animation[0]->setCurrentFrame(_resetFrame);
}
_scene->_kernelMessages.reset();
_newQuantity = computeQuoteAndQuantity();
@@ -3661,16 +3661,16 @@ void Scene411::enter() {
}
_scene->loadAnimation(formAnimName('a', -1));
- _scene->_activeAnimation->setCurrentFrame(128);
+ _scene->_animation[0]->setCurrentFrame(128);
_makeMushroomCloud = false;
_killRox = false;
}
void Scene411::step() {
- if (_scene->_activeAnimation != nullptr) {
- if (_curAnimationFrame != _scene->_activeAnimation->getCurrentFrame()) {
- _curAnimationFrame = _scene->_activeAnimation->getCurrentFrame();
+ if (_scene->_animation[0] != nullptr) {
+ if (_curAnimationFrame != _scene->_animation[0]->getCurrentFrame()) {
+ _curAnimationFrame = _scene->_animation[0]->getCurrentFrame();
_resetFrame = -1;
switch (_curAnimationFrame) {
@@ -3738,14 +3738,14 @@ void Scene411::step() {
break;
}
- if ((_resetFrame >= 0) && (_resetFrame != _scene->_activeAnimation->getCurrentFrame())) {
- _scene->_activeAnimation->setCurrentFrame(_resetFrame);
+ if ((_resetFrame >= 0) && (_resetFrame != _scene->_animation[0]->getCurrentFrame())) {
+ _scene->_animation[0]->setCurrentFrame(_resetFrame);
_curAnimationFrame = _resetFrame;
}
}
}
- if (_scene->_activeAnimation->getCurrentFrame() == 86)
+ if (_scene->_animation[0]->getCurrentFrame() == 86)
_vm->_sound->command(59);
}
@@ -4113,10 +4113,10 @@ void Scene413::enter() {
}
void Scene413::step() {
- if (_scene->_activeAnimation && _scene->_activeAnimation->getCurrentFrame() == 38)
- _scene->_activeAnimation->setCurrentFrame(37);
+ if (_scene->_animation[0] && _scene->_animation[0]->getCurrentFrame() == 38)
+ _scene->_animation[0]->setCurrentFrame(37);
- if (_scene->_activeAnimation && _scene->_activeAnimation->getCurrentFrame() == 21 && _canMove) {
+ if (_scene->_animation[0] && _scene->_animation[0]->getCurrentFrame() == 21 && _canMove) {
_vm->_sound->command(27);
_canMove = false;
}
diff --git a/engines/mads/nebular/nebular_scenes5.cpp b/engines/mads/nebular/nebular_scenes5.cpp
index 95eb429193..ea3574b0d1 100644
--- a/engines/mads/nebular/nebular_scenes5.cpp
+++ b/engines/mads/nebular/nebular_scenes5.cpp
@@ -722,9 +722,9 @@ void Scene504::enter() {
}
void Scene504::step() {
- if ((_carAnimationMode == 1) && (_scene->_activeAnimation != nullptr)) {
- if (_scene->_activeAnimation->getCurrentFrame() != _carFrame) {
- _carFrame = _scene->_activeAnimation->getCurrentFrame();
+ if ((_carAnimationMode == 1) && (_scene->_animation[0] != nullptr)) {
+ if (_scene->_animation[0]->getCurrentFrame() != _carFrame) {
+ _carFrame = _scene->_animation[0]->getCurrentFrame();
int nextFrame;
if (_carFrame == 1)
@@ -732,8 +732,8 @@ void Scene504::step() {
else
nextFrame = -1;
- if ((nextFrame >= 0) && (nextFrame != _scene->_activeAnimation->getCurrentFrame())) {
- _scene->_activeAnimation->setCurrentFrame(nextFrame);
+ if ((nextFrame >= 0) && (nextFrame != _scene->_animation[0]->getCurrentFrame())) {
+ _scene->_animation[0]->setCurrentFrame(nextFrame);
_carFrame = nextFrame;
}
}
@@ -943,15 +943,15 @@ void Scene505::enter() {
_game._player._stepEnabled = false;
_frame = -1;
_scene->loadAnimation(formAnimName('a', -1));
- _scene->_activeAnimation->setCurrentFrame(86);
+ _scene->_animation[0]->setCurrentFrame(86);
sceneEntrySound();
_vm->_sound->command(16);
}
void Scene505::step() {
- if (_frame != _scene->_activeAnimation->getCurrentFrame()) {
- _frame = _scene->_activeAnimation->getCurrentFrame();
+ if (_frame != _scene->_animation[0]->getCurrentFrame()) {
+ _frame = _scene->_animation[0]->getCurrentFrame();
int resetFrame = -1;
switch (_frame) {
@@ -1088,8 +1088,8 @@ void Scene505::step() {
break;
}
- if ((resetFrame >= 0) && (resetFrame != _scene->_activeAnimation->getCurrentFrame())) {
- _scene->_activeAnimation->setCurrentFrame(resetFrame);
+ if ((resetFrame >= 0) && (resetFrame != _scene->_animation[0]->getCurrentFrame())) {
+ _scene->_animation[0]->setCurrentFrame(resetFrame);
_frame = resetFrame;
}
}
@@ -1254,7 +1254,7 @@ void Scene506::step() {
switch (_game._trigger) {
case 70:
_game._player._visible = true;
- _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ _game._player._priorTimer = _scene->_animation[0]->getNextFrameTimer() - _game._player._ticksAmount;
_scene->_sequences.addTimer(6, 71);
break;
@@ -1603,7 +1603,7 @@ void Scene508::enter() {
_globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, -2);
_scene->_sequences.setDepth(_globals._sequenceIndexes[3], 8);
_globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, -2);
- int idx = _scene->_dynamicHotspots.add(NOUN_LASER_BEAM, VERB_WALKTO, _globals._sequenceIndexes[5], Common::Rect(0, 0, 0, 0));
+ int idx = _scene->_dynamicHotspots.add(NOUN_SPINACH_PATCH_DOLL, VERB_WALKTO, _globals._sequenceIndexes[5], Common::Rect(0, 0, 0, 0));
_scene->_dynamicHotspots.setPosition(idx, Common::Point(57, 116), FACING_NORTHEAST);
_scene->_hotspots.activate(NOUN_HOLE, false);
_scene->_hotspots.activate(NOUN_LASER_BEAM, false);
@@ -1943,9 +1943,9 @@ void Scene511::enter() {
}
void Scene511::step() {
- if ((_lineAnimationMode == 1) && _scene->_activeAnimation) {
- if (_lineFrame != _scene->_activeAnimation->getCurrentFrame()) {
- _lineFrame = _scene->_activeAnimation->getCurrentFrame();
+ if ((_lineAnimationMode == 1) && _scene->_animation[0]) {
+ if (_lineFrame != _scene->_animation[0]->getCurrentFrame()) {
+ _lineFrame = _scene->_animation[0]->getCurrentFrame();
int resetFrame = -1;
if ((_lineAnimationPosition == 2) && (_lineFrame == 14))
@@ -1961,8 +1961,8 @@ void Scene511::step() {
resetFrame = 2;
}
- if ((resetFrame >= 0) && (resetFrame != _scene->_activeAnimation->getCurrentFrame())) {
- _scene->_activeAnimation->setCurrentFrame(resetFrame);
+ if ((resetFrame >= 0) && (resetFrame != _scene->_animation[0]->getCurrentFrame())) {
+ _scene->_animation[0]->setCurrentFrame(resetFrame);
_lineFrame = resetFrame;
}
}
@@ -1971,7 +1971,7 @@ void Scene511::step() {
switch (_game._trigger) {
case 70:
_game._player._visible = true;
- _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ _game._player._priorTimer = _scene->_animation[0]->getNextFrameTimer() - _game._player._ticksAmount;
_scene->_sequences.addTimer(6, 71);
break;
@@ -2009,7 +2009,7 @@ void Scene511::preActions() {
_scene->loadAnimation(formAnimName('R',2), 1);
} else if (_game._trigger == 1) {
_game._player._visible = true;
- _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ _game._player._priorTimer = _scene->_animation[0]->getNextFrameTimer() - _game._player._ticksAmount;
_game._objects.setRoom(OBJ_FISHING_LINE, 1);
_handingLine = false;
_game._player._stepEnabled = true;
@@ -2089,7 +2089,7 @@ void Scene511::actions() {
} else {
_vm->_dialogs->show(51130);
}
- } else if (_action.isAction(VERB_TIE, NOUN_FISHING_LINE, NOUN_BOAT) ||
+ } else if (_action.isAction(VERB_TIE, NOUN_FISHING_LINE, NOUN_BOAT) ||
_action.isAction(VERB_ATTACH, NOUN_FISHING_LINE, NOUN_BOAT)) {
if (_globals[kBoatRaised])
_vm->_dialogs->show(51131);
@@ -2118,8 +2118,8 @@ void Scene511::actions() {
_globals[kLineStatus] = 3;
_game._player._stepEnabled = true;
- if (_scene->_activeAnimation)
- _scene->_activeAnimation->eraseSprites();
+ if (_scene->_animation[0])
+ _scene->_animation[0]->eraseSprites();
_game._player.update();
}
}
@@ -2159,9 +2159,9 @@ void Scene511::actions() {
_vm->_dialogs->show(51128);
} else if (_action.isAction(VERB_LOOK, NOUN_PORTHOLE))
_vm->_dialogs->show(51122);
- else if (_action.isAction(VERB_LOOK, NOUN_FISHING_LINE) && (_action._mainObjectSource == 4) && (_globals[kLineStatus] == 2))
+ else if (_action.isAction(VERB_LOOK, NOUN_FISHING_LINE) && (_action._mainObjectSource == CAT_HOTSPOT) && (_globals[kLineStatus] == 2))
_vm->_dialogs->show(51126);
- else if (_action.isAction(VERB_LOOK, NOUN_FISHING_LINE) && (_action._mainObjectSource == 4) && (_globals[kLineStatus] == 3))
+ else if (_action.isAction(VERB_LOOK, NOUN_FISHING_LINE) && (_action._mainObjectSource == CAT_HOTSPOT) && (_globals[kLineStatus] == 3))
_vm->_dialogs->show(51133);
else if (_action.isAction(VERB_LOOK, NOUN_STATUE))
_vm->_dialogs->show(51127);
@@ -2434,8 +2434,8 @@ void Scene512::actions() {
_vm->_dialogs->show(51225);
else if (_action.isAction(VERB_LOOK, NOUN_PADLOCK_KEY) && _game._objects.isInRoom(OBJ_PADLOCK_KEY))
_vm->_dialogs->show(51215);
- else if (_action.isAction(VERB_LOOK, NOUN_FISHING_ROD) && (!_scene->_activeAnimation ||
- _scene->_activeAnimation->getCurrentFrame() == 4))
+ else if (_action.isAction(VERB_LOOK, NOUN_FISHING_ROD) && (!_scene->_animation[0] ||
+ _scene->_animation[0]->getCurrentFrame() == 4))
_vm->_dialogs->show(51216);
else if (_action.isAction(VERB_LOOK, NOUN_SHIPS_WHEEL))
_vm->_dialogs->show(51218);
@@ -2570,7 +2570,7 @@ void Scene513::step() {
switch (_game._trigger) {
case 70:
_game._player._visible = true;
- _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ _game._player._priorTimer = _scene->_animation[0]->getNextFrameTimer() - _game._player._ticksAmount;
_scene->_sequences.addTimer(6, 71);
break;
diff --git a/engines/mads/nebular/nebular_scenes6.cpp b/engines/mads/nebular/nebular_scenes6.cpp
index d97e37ea0b..e6e286392c 100644
--- a/engines/mads/nebular/nebular_scenes6.cpp
+++ b/engines/mads/nebular/nebular_scenes6.cpp
@@ -124,7 +124,7 @@ void Scene601::step() {
switch (_game._trigger) {
case 70:
_game._player._visible = true;
- _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ _game._player._priorTimer = _scene->_animation[0]->getNextFrameTimer() - _game._player._ticksAmount;
_scene->_sequences.addTimer(30, 71);
break;
@@ -431,7 +431,7 @@ void Scene602::actions() {
case 1: {
_game._player._visible = true;
- _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ _game._player._priorTimer = _scene->_animation[0]->getNextFrameTimer() - _game._player._ticksAmount;
_lastSpriteIdx = _globals._spriteIndexes[3];
_lastSequenceIdx = _scene->_sequences.startCycle(_lastSpriteIdx, false, -1);
_scene->_sequences.setDepth(_lastSequenceIdx, 14);
@@ -684,7 +684,7 @@ void Scene603::actions() {
_vm->_dialogs->show(60327);
else
_vm->_dialogs->show(60328);
- } else if (_action.isAction(VERB_LOOK, NOUN_COMPACT_CASE) && (_action._mainObjectSource == 4))
+ } else if (_action.isAction(VERB_LOOK, NOUN_COMPACT_CASE) && (_action._mainObjectSource == CAT_HOTSPOT))
_vm->_dialogs->show(60329);
// For the next two checks, the second part of the check wasn't surrounded par parenthesis, which was obviously wrong
else if (_action.isAction(VERB_LOOK) && (_action.isObject(NOUN_BRA) || _action.isObject(NOUN_BOA) || _action.isObject(NOUN_SLIP)))
@@ -775,7 +775,7 @@ void Scene604::step() {
switch (_game._trigger) {
case 70:
_game._player._visible = true;
- _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ _game._player._priorTimer = _scene->_animation[0]->getNextFrameTimer() - _game._player._ticksAmount;
_scene->_sequences.addTimer(30, 71);
break;
@@ -797,9 +797,9 @@ void Scene604::step() {
break;
}
- if (_monsterActive && (_scene->_activeAnimation != nullptr)) {
- if (_scene->_activeAnimation->getCurrentFrame() != _monsterFrame) {
- _monsterFrame = _scene->_activeAnimation->getCurrentFrame();
+ if (_monsterActive && (_scene->_animation[0] != nullptr)) {
+ if (_scene->_animation[0]->getCurrentFrame() != _monsterFrame) {
+ _monsterFrame = _scene->_animation[0]->getCurrentFrame();
int nextMonsterFrame = -1;
switch (_monsterFrame) {
@@ -837,7 +837,7 @@ void Scene604::step() {
}
if ((nextMonsterFrame >= 0) && (nextMonsterFrame != _monsterFrame)) {
- _scene->_activeAnimation->setCurrentFrame(nextMonsterFrame);
+ _scene->_animation[0]->setCurrentFrame(nextMonsterFrame);
_monsterFrame = nextMonsterFrame;
}
}
@@ -1297,7 +1297,7 @@ void Scene607::step() {
switch (_game._trigger) {
case 80:
_game._player._visible = true;
- _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ _game._player._priorTimer = _scene->_animation[0]->getNextFrameTimer() - _game._player._ticksAmount;
_scene->_sequences.addTimer(6, 81);
break;
@@ -1331,7 +1331,7 @@ void Scene607::handleThrowingBone() {
case 1:
_game._player._visible = true;
- _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ _game._player._priorTimer = _scene->_animation[0]->getNextFrameTimer() - _game._player._ticksAmount;
if (_animationMode != 1)
_scene->_hotspots.activate(NOUN_OBNOXIOUS_DOG, false);
@@ -1605,7 +1605,7 @@ void Scene608::restoreAnimations() {
_scene->_sequences.remove(_globals._sequenceIndexes[6]);
_scene->_sequences.remove(_globals._sequenceIndexes[7]);
_scene->loadAnimation(formAnimName('A', -1));
- _scene->_activeAnimation->setCurrentFrame(6);
+ _scene->_animation[0]->setCurrentFrame(6);
}
}
@@ -1757,7 +1757,7 @@ void Scene608::enter() {
int idx = _scene->_dynamicHotspots.add(NOUN_CAR, VERB_WALKTO, -1, Common::Rect(100, 100, 100 + 82, 100 + 25));
_carHotspotId = _scene->_dynamicHotspots.setPosition(idx, Common::Point(96, 132), FACING_NORTHEAST);
_scene->loadAnimation(formAnimName('A', -1));
- _scene->_activeAnimation->setCurrentFrame(6);
+ _scene->_animation[0]->setCurrentFrame(6);
} else if (_globals[kCarStatus] == CAR_SQUASHES_DOG) {
_carMode = 2;
_dogDeathMode = 0;
@@ -1927,13 +1927,13 @@ void Scene608::step() {
_animationMode = 0;
}
- if ((_carMode == 4) && (_scene->_activeAnimation != nullptr)) {
- if (_scene->_activeAnimation->getCurrentFrame() != _carFrame) {
- _carFrame = _scene->_activeAnimation->getCurrentFrame();
+ if ((_carMode == 4) && (_scene->_animation[0] != nullptr)) {
+ if (_scene->_animation[0]->getCurrentFrame() != _carFrame) {
+ _carFrame = _scene->_animation[0]->getCurrentFrame();
if (_carFrame == 10) {
_game._player._visible = true;
- _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ _game._player._priorTimer = _scene->_animation[0]->getNextFrameTimer() - _game._player._ticksAmount;
} else if (_carFrame == 56) {
resetDogVariables();
_animationMode = 0;
@@ -1942,12 +1942,12 @@ void Scene608::step() {
}
}
- if ((_carMode == 5) && (_scene->_activeAnimation != nullptr)) {
- if (_scene->_activeAnimation->getCurrentFrame() != _carFrame) {
- _carFrame = _scene->_activeAnimation->getCurrentFrame();
+ if ((_carMode == 5) && (_scene->_animation[0] != nullptr)) {
+ if (_scene->_animation[0]->getCurrentFrame() != _carFrame) {
+ _carFrame = _scene->_animation[0]->getCurrentFrame();
if (_carFrame == 10) {
_game._player._visible = true;
- _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ _game._player._priorTimer = _scene->_animation[0]->getNextFrameTimer() - _game._player._ticksAmount;
} else if (_carFrame == 52) {
resetDogVariables();
_animationMode = 0;
@@ -1956,13 +1956,13 @@ void Scene608::step() {
}
}
- if ((_carMode == 6) && (_scene->_activeAnimation != nullptr)) {
- if (_scene->_activeAnimation->getCurrentFrame() != _carFrame) {
- _carFrame = _scene->_activeAnimation->getCurrentFrame();
+ if ((_carMode == 6) && (_scene->_animation[0] != nullptr)) {
+ if (_scene->_animation[0]->getCurrentFrame() != _carFrame) {
+ _carFrame = _scene->_animation[0]->getCurrentFrame();
if (_carFrame == 11) {
_game._player._visible = true;
- _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ _game._player._priorTimer = _scene->_animation[0]->getNextFrameTimer() - _game._player._ticksAmount;
} else if (_carFrame == 41) {
_globals._sequenceIndexes[10] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[10], false, 9, 0, 0, 0);
_scene->_sequences.setAnimRange(_globals._sequenceIndexes[10], 10, 11);
@@ -2000,9 +2000,9 @@ void Scene608::step() {
if (_game._trigger == 112)
_dogYelping = false;
- if ((_carMode == 0) && (_scene->_activeAnimation != nullptr)) {
- if (_scene->_activeAnimation->getCurrentFrame() != _carFrame) {
- _carFrame = _scene->_activeAnimation->getCurrentFrame();
+ if ((_carMode == 0) && (_scene->_animation[0] != nullptr)) {
+ if (_scene->_animation[0]->getCurrentFrame() != _carFrame) {
+ _carFrame = _scene->_animation[0]->getCurrentFrame();
int nextFrame = -1;
if ((_globals[kCarStatus] == CAR_UP) || (_globals[kCarStatus] == CAR_DOWN)) {
@@ -2015,7 +2015,7 @@ void Scene608::step() {
break;
case 1:
- if (_scene->_activeAnimation->getCurrentFrame() >= 12) {
+ if (_scene->_animation[0]->getCurrentFrame() >= 12) {
nextFrame = 0;
_carMoveMode = 0;
_globals[kCarStatus] = CAR_UP;
@@ -2023,7 +2023,7 @@ void Scene608::step() {
break;
case 2:
- if (_scene->_activeAnimation->getCurrentFrame() >= 6) {
+ if (_scene->_animation[0]->getCurrentFrame() >= 6) {
nextFrame = 6;
_carMoveMode = 0;
_globals[kCarStatus] = CAR_DOWN;
@@ -2035,35 +2035,35 @@ void Scene608::step() {
}
}
- if ((nextFrame >= 0) && (nextFrame != _scene->_activeAnimation->getCurrentFrame())) {
- _scene->_activeAnimation->setCurrentFrame(nextFrame);
+ if ((nextFrame >= 0) && (nextFrame != _scene->_animation[0]->getCurrentFrame())) {
+ _scene->_animation[0]->setCurrentFrame(nextFrame);
_carFrame = nextFrame;
}
}
}
- if ((_carMode == 2) && (_scene->_activeAnimation != nullptr)) {
- if (_scene->_activeAnimation->getCurrentFrame() != _carFrame) {
- _carFrame = _scene->_activeAnimation->getCurrentFrame();
+ if ((_carMode == 2) && (_scene->_animation[0] != nullptr)) {
+ if (_scene->_animation[0]->getCurrentFrame() != _carFrame) {
+ _carFrame = _scene->_animation[0]->getCurrentFrame();
int nextFrame = -1;
if (_carMoveMode == 0)
nextFrame = 28;
- else if (_scene->_activeAnimation->getCurrentFrame() >= 28) {
+ else if (_scene->_animation[0]->getCurrentFrame() >= 28) {
nextFrame = 28;
_carMoveMode = 0;
}
- if ((nextFrame >= 0) && (nextFrame != _scene->_activeAnimation->getCurrentFrame())) {
- _scene->_activeAnimation->setCurrentFrame(nextFrame);
+ if ((nextFrame >= 0) && (nextFrame != _scene->_animation[0]->getCurrentFrame())) {
+ _scene->_animation[0]->setCurrentFrame(nextFrame);
_carFrame = nextFrame;
}
}
}
- if ((_carMode == 3) && (_scene->_activeAnimation != nullptr)) {
- if (_scene->_activeAnimation->getCurrentFrame() != _carFrame) {
- _carFrame = _scene->_activeAnimation->getCurrentFrame();
+ if ((_carMode == 3) && (_scene->_animation[0] != nullptr)) {
+ if (_scene->_animation[0]->getCurrentFrame() != _carFrame) {
+ _carFrame = _scene->_animation[0]->getCurrentFrame();
int nextFrame = -1;
if (_resetPositionsFl) {
@@ -2071,22 +2071,22 @@ void Scene608::step() {
_carMoveMode = 0;
} else if (_carMoveMode == 0)
nextFrame = 6;
- else if (_scene->_activeAnimation->getCurrentFrame() >= 6) {
+ else if (_scene->_animation[0]->getCurrentFrame() >= 6) {
nextFrame = 6;
_carMoveMode = 0;
}
- if ((nextFrame >= 0) && (nextFrame != _scene->_activeAnimation->getCurrentFrame())) {
- _scene->_activeAnimation->setCurrentFrame(nextFrame);
+ if ((nextFrame >= 0) && (nextFrame != _scene->_animation[0]->getCurrentFrame())) {
+ _scene->_animation[0]->setCurrentFrame(nextFrame);
_carFrame = nextFrame;
}
}
}
- if ((_carMode == 1) && (_scene->_activeAnimation != nullptr)) {
- if (_scene->_activeAnimation->getCurrentFrame() != _carFrame) {
- _carFrame = _scene->_activeAnimation->getCurrentFrame();
+ if ((_carMode == 1) && (_scene->_animation[0] != nullptr)) {
+ if (_scene->_animation[0]->getCurrentFrame() != _carFrame) {
+ _carFrame = _scene->_animation[0]->getCurrentFrame();
int nextFrame = -1;
if (_resetPositionsFl) {
@@ -2094,13 +2094,13 @@ void Scene608::step() {
_carMoveMode = 0;
} else if (_carMoveMode == 0)
nextFrame = 6;
- else if (_scene->_activeAnimation->getCurrentFrame() >= 6) {
+ else if (_scene->_animation[0]->getCurrentFrame() >= 6) {
nextFrame = 6;
_carMoveMode = 0;
}
- if ((nextFrame >= 0) && (nextFrame != _scene->_activeAnimation->getCurrentFrame())) {
- _scene->_activeAnimation->setCurrentFrame(nextFrame);
+ if ((nextFrame >= 0) && (nextFrame != _scene->_animation[0]->getCurrentFrame())) {
+ _scene->_animation[0]->setCurrentFrame(nextFrame);
_carFrame = nextFrame;
}
}
@@ -2476,7 +2476,7 @@ void Scene608::actions() {
_vm->_dialogs->show(60824);
} else if (_action.isAction(VERB_OPEN, NOUN_STORAGE_BOX))
_vm->_dialogs->show(60826);
- else if (_action.isAction(VERB_LOOK, NOUN_REARVIEW_MIRROR) && (_action._mainObjectSource == 4))
+ else if (_action.isAction(VERB_LOOK, NOUN_REARVIEW_MIRROR) && (_action._mainObjectSource == CAT_HOTSPOT))
_vm->_dialogs->show(60828);
else if (_action.isAction(VERB_LOOK, NOUN_TOOL_BOX)) {
if (_game._objects[OBJ_POLYCEMENT]._roomNumber == _scene->_currentSceneId)
@@ -2605,7 +2605,7 @@ void Scene609::step() {
switch (_game._trigger) {
case 70:
_game._player._visible = true;
- _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ _game._player._priorTimer = _scene->_animation[0]->getNextFrameTimer() - _game._player._ticksAmount;
_scene->_sequences.addTimer(6, 71);
break;
@@ -3014,7 +3014,7 @@ void Scene610::actions() {
_vm->_dialogs->show(61024);
else if (_action.isAction(VERB_LOOK, NOUN_SPOTLIGHT))
_vm->_dialogs->show(61025);
- else if (_action.isAction(VERB_LOOK, NOUN_PHONE_HANDSET) && (_action._mainObjectSource == 4))
+ else if (_action.isAction(VERB_LOOK, NOUN_PHONE_HANDSET) && (_action._mainObjectSource == CAT_HOTSPOT))
_vm->_dialogs->show(61026);
else if (_action.isAction(VERB_LOOK, NOUN_PHONE_CRADLE))
_vm->_dialogs->show(61027);
@@ -3466,12 +3466,12 @@ void Scene611::displayHermitQuestions(int question) {
Common::String curQuote = _game.getQuote(0x281);
int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
int quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x282);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 14), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 14), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
}
break;
@@ -3479,12 +3479,12 @@ void Scene611::displayHermitQuestions(int question) {
Common::String curQuote = _game.getQuote(0x283);
int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
int quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x284);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 14), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 14), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
}
break;
@@ -3492,7 +3492,7 @@ void Scene611::displayHermitQuestions(int question) {
Common::String curQuote = _game.getQuote(0x285);
int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
int quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 14), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 14), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
}
break;
@@ -3500,7 +3500,7 @@ void Scene611::displayHermitQuestions(int question) {
Common::String curQuote = _game.getQuote(0x286);
int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
int quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 14), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 14), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
}
break;
@@ -3508,17 +3508,17 @@ void Scene611::displayHermitQuestions(int question) {
Common::String curQuote = _game.getQuote(0x297);
int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
int quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y - 14), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y - 14), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x298);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x299);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 14), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 14), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
}
break;
@@ -3526,12 +3526,12 @@ void Scene611::displayHermitQuestions(int question) {
Common::String curQuote = _game.getQuote(0x29A);
int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
int quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x29B);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 14), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 14), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
}
break;
@@ -3539,12 +3539,12 @@ void Scene611::displayHermitQuestions(int question) {
Common::String curQuote = _game.getQuote(0x2A0);
int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
int quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2A1);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
}
break;
@@ -3552,17 +3552,17 @@ void Scene611::displayHermitQuestions(int question) {
Common::String curQuote = _game.getQuote(0x2A2);
int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
int quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2A3);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2A4);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
}
break;
@@ -3570,12 +3570,12 @@ void Scene611::displayHermitQuestions(int question) {
Common::String curQuote = _game.getQuote(0x2A5);
int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
int quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2A6);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
}
break;
@@ -3583,17 +3583,17 @@ void Scene611::displayHermitQuestions(int question) {
Common::String curQuote = _game.getQuote(0x2A8);
int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
int quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2A9);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2AA);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
}
break;
@@ -3601,22 +3601,22 @@ void Scene611::displayHermitQuestions(int question) {
Common::String curQuote = _game.getQuote(0x2AB);
int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
int quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 17), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 17), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2AC);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2AD);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2AE);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
}
break;
@@ -3624,22 +3624,22 @@ void Scene611::displayHermitQuestions(int question) {
Common::String curQuote = _game.getQuote(0x2AF);
int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
int quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 17), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 17), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2B0);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2B1);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2B2);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
}
break;
@@ -3647,26 +3647,26 @@ void Scene611::displayHermitQuestions(int question) {
Common::String curQuote = _game.getQuote(0x2B3);
int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
int quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 3), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 3), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2B4);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 17), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 17), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2B5);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2B6);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
- _scene->_kernelMessages.add(Common::Point(11, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x2B7));
- _scene->_kernelMessages.add(Common::Point(11, _defaultDialogPos.y + 73), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x2B8));
- _scene->_kernelMessages.add(Common::Point(11, _defaultDialogPos.y + 87), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x2B9));
+ _scene->_kernelMessages.add(Common::Point(11, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x2B7));
+ _scene->_kernelMessages.add(Common::Point(11, _defaultDialogPos.y + 73), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x2B8));
+ _scene->_kernelMessages.add(Common::Point(11, _defaultDialogPos.y + 87), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, _game.getQuote(0x2B9));
}
break;
@@ -3674,22 +3674,22 @@ void Scene611::displayHermitQuestions(int question) {
Common::String curQuote = _game.getQuote(0x2BA);
int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
int quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 17), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 17), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2BB);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2BC);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2BD);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
}
break;
@@ -3697,22 +3697,22 @@ void Scene611::displayHermitQuestions(int question) {
Common::String curQuote = _game.getQuote(0x2BE);
int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
int quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 17), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 17), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2BF);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2C0);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2C1);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
}
break;
@@ -3720,27 +3720,27 @@ void Scene611::displayHermitQuestions(int question) {
Common::String curQuote = _game.getQuote(0x2C2);
int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
int quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 3), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 3), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2C3);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 17), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 17), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2C4);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2C5);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2C6);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
}
break;
@@ -3748,22 +3748,22 @@ void Scene611::displayHermitQuestions(int question) {
Common::String curQuote = _game.getQuote(0x2C7);
int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
int quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 17), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 17), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2C8);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2C0);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2CA);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
}
break;
@@ -3771,17 +3771,17 @@ void Scene611::displayHermitQuestions(int question) {
Common::String curQuote = _game.getQuote(0x2CB);
int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
int quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2CC);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2CD);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
}
break;
@@ -3789,17 +3789,17 @@ void Scene611::displayHermitQuestions(int question) {
Common::String curQuote = _game.getQuote(0x2CE);
int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
int quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2CF);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2D0);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
}
break;
@@ -3807,27 +3807,27 @@ void Scene611::displayHermitQuestions(int question) {
Common::String curQuote = _game.getQuote(0x2E1);
int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
int quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 3), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 3), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2E2);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 17), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 17), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2E3);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2E4);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
curQuote = _game.getQuote(0x2E5);
width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
quotePosX = _defaultDialogPos.x - (width / 2);
- _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, curQuote);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, INDEFINITE_TIMEOUT, curQuote);
}
break;
@@ -3930,7 +3930,7 @@ void Scene611::enter() {
0x2D9, 0x2DA, 0x2DB, 0x2DC, 0x2DD, 0x2DE, 0x2DF, 0x2E0, 0x2E1, 0x2E2, 0x2E3, 0x2E4, 0x2E5, 0x2E6,
0x323, 0x324, 0);
- _dialog1.setup(kConvHermit1, 0x287, 0x288, 0x289, 0x28A, 0x28B, 0x28C, 0x28D, 0x28E, 0x28F, 0x290,
+ _dialog1.setup(kConvHermit1, 0x287, 0x288, 0x289, 0x28A, 0x28B, 0x28C, 0x28D, 0x28E, 0x28F, 0x290,
0x291, 0x292, 0x293, 0x294, 0x295, 0x296, 0);
_dialog2.setup(kConvHermit2, 0x29C, 0x29D, 0x29E, 0x29F, 0);
@@ -4145,13 +4145,13 @@ void Scene611::step() {
_hermitMovingFl = true;
}
- if (_stickFingerFl && (_scene->_activeAnimation->getCurrentFrame() == 47)) {
+ if (_stickFingerFl && (_scene->_animation[0]->getCurrentFrame() == 47)) {
_stickFingerFl = false;
_hermitMovingFl = true;
_hermitMode = 1;
}
- if (_scene->_activeAnimation != nullptr && (_scene->_activeAnimation->getCurrentFrame() == 240) && _check1Fl) {
+ if (_scene->_animation[0] != nullptr && (_scene->_animation[0]->getCurrentFrame() == 240) && _check1Fl) {
_check1Fl = false;
_scene->_kernelMessages.add(Common::Point(33, 88), 0xFDFC, 0, 0, 90, _game.getQuote(0x27E));
_scene->_sequences.addTimer(120, 120);
@@ -4240,7 +4240,7 @@ void Scene611::step() {
}
}
- if (_scene->_activeAnimation != nullptr && _scene->_activeAnimation->getCurrentFrame() == 254)
+ if (_scene->_animation[0] != nullptr && _scene->_animation[0]->getCurrentFrame() == 254)
_game._player._stepEnabled = true;
if (_game._trigger == 110) {
@@ -4266,7 +4266,7 @@ void Scene611::step() {
}
if (_hermitMode == 6) {
- if ((_scene->_activeAnimation->getCurrentFrame() == 9) && _check1Fl) {
+ if ((_scene->_animation[0]->getCurrentFrame() == 9) && _check1Fl) {
_scene->_sequences.remove(_globals._sequenceIndexes[3]);
_globals._sequenceIndexes[3] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[3], false, 7, 1, 0, 0);
_scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 2);
@@ -4275,7 +4275,7 @@ void Scene611::step() {
_check1Fl = false;
}
- if ((_scene->_activeAnimation->getCurrentFrame() == 17) && !_check1Fl) {
+ if ((_scene->_animation[0]->getCurrentFrame() == 17) && !_check1Fl) {
_nextFrame = 26;
_hermitMode = 4;
_check1Fl = true;
@@ -4283,13 +4283,13 @@ void Scene611::step() {
}
if (_hermitMode == 4) {
- if ((_scene->_activeAnimation->getCurrentFrame() == 33) && _check1Fl) {
+ if ((_scene->_animation[0]->getCurrentFrame() == 33) && _check1Fl) {
displayHermitQuestions(_hermitDisplayedQuestion);
_nextFrame = 1;
_check1Fl = false;
}
- if ((_scene->_activeAnimation->getCurrentFrame() == 9) && !_check1Fl) {
+ if ((_scene->_animation[0]->getCurrentFrame() == 9) && !_check1Fl) {
_nextFrame = 8;
_scene->_sequences.addTimer(1, 113);
_check1Fl = true;
@@ -4315,8 +4315,8 @@ void Scene611::step() {
_scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 115);
}
- if ((_nextFrame >= 0) && (_nextFrame != _scene->_activeAnimation->getCurrentFrame())) {
- _scene->_activeAnimation->setCurrentFrame(_nextFrame);
+ if ((_nextFrame >= 0) && (_nextFrame != _scene->_animation[0]->getCurrentFrame())) {
+ _scene->_animation[0]->setCurrentFrame(_nextFrame);
_nextFrame = -1;
}
@@ -4588,7 +4588,7 @@ void Scene612::step() {
switch (_game._trigger) {
case 70:
_game._player._visible = true;
- _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ _game._player._priorTimer = _scene->_animation[0]->getNextFrameTimer() - _game._player._ticksAmount;
_scene->_sequences.addTimer(6, 71);
break;
diff --git a/engines/mads/nebular/nebular_scenes7.cpp b/engines/mads/nebular/nebular_scenes7.cpp
index c2a249e5f8..6caebb7f79 100644
--- a/engines/mads/nebular/nebular_scenes7.cpp
+++ b/engines/mads/nebular/nebular_scenes7.cpp
@@ -361,7 +361,7 @@ void Scene701::actions() {
case 1: {
_game._player._visible = true;
- _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ _game._player._priorTimer = _scene->_animation[0]->getNextFrameTimer() - _game._player._ticksAmount;
_globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -1);
_scene->_sequences.setDepth (_globals._sequenceIndexes[2], 9);
int idx = _scene->_dynamicHotspots.add(NOUN_BOAT, VERB_CLIMB_INTO, _globals._sequenceIndexes[2], Common::Rect(0, 0, 0, 0));
@@ -498,7 +498,7 @@ void Scene702::actions() {
_game._player._stepEnabled = false;
_game._player._visible = false;
_scene->_nextSceneId = 711;
- } else if (_action.isAction(VERB_TAKE, NOUN_BONES) && (_action._mainObjectSource == 4) && (!_game._objects.isInInventory(OBJ_BONES) || _game._trigger)) {
+ } else if (_action.isAction(VERB_TAKE, NOUN_BONES) && (_action._mainObjectSource == CAT_HOTSPOT) && (!_game._objects.isInInventory(OBJ_BONES) || _game._trigger)) {
switch (_game._trigger) {
case 0:
_game._player._stepEnabled = false;
@@ -537,9 +537,9 @@ void Scene702::actions() {
_vm->_dialogs->show(70215);
else if (_action.isAction(VERB_LOOK, NOUN_TELEPORTER))
_vm->_dialogs->show(70216);
- else if (_action.isAction(VERB_LOOK, NOUN_BONES) && (_action._mainObjectSource == 4))
+ else if (_action.isAction(VERB_LOOK, NOUN_BONES) && (_action._mainObjectSource == CAT_HOTSPOT))
_vm->_dialogs->show(70217);
- else if (_action.isAction(VERB_TAKE, NOUN_BONES) && (_action._mainObjectSource == 4)) {
+ else if (_action.isAction(VERB_TAKE, NOUN_BONES) && (_action._mainObjectSource == CAT_HOTSPOT)) {
if (_game._objects.isInInventory(OBJ_BONES))
_vm->_dialogs->show(70219);
} else if (_action.isAction(VERB_LOOK, NOUN_SUBMERGED_CITY))
@@ -694,7 +694,7 @@ void Scene703::enter() {
_boatDir = 2;
_monsterMode = 0;
_scene->loadAnimation(formAnimName('A', -1));
- _scene->_activeAnimation->setCurrentFrame(34);
+ _scene->_animation[0]->setCurrentFrame(34);
} else if (_scene->_priorSceneId != RETURNING_FROM_DIALOG) {
_game._player._stepEnabled = false;
_boatDir = 1;
@@ -712,17 +712,17 @@ void Scene703::enter() {
_boatDir = 1;
_monsterMode = 1;
_scene->loadAnimation(formAnimName('B', -1));
- _scene->_activeAnimation->setCurrentFrame(39);
+ _scene->_animation[0]->setCurrentFrame(39);
} else if (_boatDir == 1) {
_curSequence = 0;
_monsterMode = 0;
_scene->loadAnimation(formAnimName('A', -1));
- _scene->_activeAnimation->setCurrentFrame(9);
+ _scene->_animation[0]->setCurrentFrame(9);
} else if (_boatDir == 2) {
_curSequence = 0;
_monsterMode = 0;
_scene->loadAnimation(formAnimName('A', -1));
- _scene->_activeAnimation->setCurrentFrame(56);
+ _scene->_animation[0]->setCurrentFrame(56);
}
if (_scene->_roomChanged) {
@@ -764,9 +764,9 @@ void Scene703::step() {
if (_game._trigger == 70)
_scene->_reloadSceneFlag = true;
- if ((_monsterMode == 3) && (_scene->_activeAnimation != nullptr)) {
- if (_scene->_activeAnimation->getCurrentFrame() != _boatFrame) {
- _boatFrame = _scene->_activeAnimation->getCurrentFrame();
+ if ((_monsterMode == 3) && (_scene->_animation[0] != nullptr)) {
+ if (_scene->_animation[0]->getCurrentFrame() != _boatFrame) {
+ _boatFrame = _scene->_animation[0]->getCurrentFrame();
int nextBoatFrame = -1;
if (_boatFrame == 62) {
@@ -777,8 +777,8 @@ void Scene703::step() {
}
}
- if ((nextBoatFrame >= 0) && (nextBoatFrame != _scene->_activeAnimation->getCurrentFrame())) {
- _scene->_activeAnimation->setCurrentFrame(nextBoatFrame);
+ if ((nextBoatFrame >= 0) && (nextBoatFrame != _scene->_animation[0]->getCurrentFrame())) {
+ _scene->_animation[0]->setCurrentFrame(nextBoatFrame);
_boatFrame = nextBoatFrame;
}
}
@@ -787,9 +787,9 @@ void Scene703::step() {
if (_game._trigger == 70)
_scene->_reloadSceneFlag = true;
- if ((_monsterMode == 0) && (_scene->_activeAnimation != nullptr)) {
- if (_scene->_activeAnimation->getCurrentFrame() != _boatFrame) {
- _boatFrame = _scene->_activeAnimation->getCurrentFrame();
+ if ((_monsterMode == 0) && (_scene->_animation[0] != nullptr)) {
+ if (_scene->_animation[0]->getCurrentFrame() != _boatFrame) {
+ _boatFrame = _scene->_animation[0]->getCurrentFrame();
int nextBoatFrame = -1;
switch (_boatFrame) {
@@ -860,8 +860,8 @@ void Scene703::step() {
break;
}
- if ((nextBoatFrame >= 0) && (nextBoatFrame != _scene->_activeAnimation->getCurrentFrame())) {
- _scene->_activeAnimation->setCurrentFrame(nextBoatFrame);
+ if ((nextBoatFrame >= 0) && (nextBoatFrame != _scene->_animation[0]->getCurrentFrame())) {
+ _scene->_animation[0]->setCurrentFrame(nextBoatFrame);
_boatFrame = nextBoatFrame;
}
}
@@ -895,9 +895,9 @@ void Scene703::step() {
}
- if ((_monsterMode == 1) && (_scene->_activeAnimation != nullptr)) {
- if (_scene->_activeAnimation->getCurrentFrame() != _boatFrame) {
- _boatFrame = _scene->_activeAnimation->getCurrentFrame();
+ if ((_monsterMode == 1) && (_scene->_animation[0] != nullptr)) {
+ if (_scene->_animation[0]->getCurrentFrame() != _boatFrame) {
+ _boatFrame = _scene->_animation[0]->getCurrentFrame();
int nextBoatFrame = -1;
switch (_boatFrame) {
@@ -934,16 +934,16 @@ void Scene703::step() {
break;
}
- if ((nextBoatFrame >= 0) && (nextBoatFrame != _scene->_activeAnimation->getCurrentFrame())) {
- _scene->_activeAnimation->setCurrentFrame(nextBoatFrame);
+ if ((nextBoatFrame >= 0) && (nextBoatFrame != _scene->_animation[0]->getCurrentFrame())) {
+ _scene->_animation[0]->setCurrentFrame(nextBoatFrame);
_boatFrame = nextBoatFrame;
}
}
}
- if ((_monsterMode == 2) && (_scene->_activeAnimation != nullptr)) {
- if (_scene->_activeAnimation->getCurrentFrame() != _boatFrame) {
- _boatFrame = _scene->_activeAnimation->getCurrentFrame();
+ if ((_monsterMode == 2) && (_scene->_animation[0] != nullptr)) {
+ if (_scene->_animation[0]->getCurrentFrame() != _boatFrame) {
+ _boatFrame = _scene->_animation[0]->getCurrentFrame();
int nextBoatFrame = -1;
switch (_boatFrame) {
@@ -983,7 +983,7 @@ void Scene703::step() {
_scene->freeAnimation();
_monsterMode = 1;
_scene->loadAnimation(formAnimName('B', -1));
- _scene->_activeAnimation->setCurrentFrame(39);
+ _scene->_animation[0]->setCurrentFrame(39);
_game._player._stepEnabled = true;
break;
@@ -992,7 +992,7 @@ void Scene703::step() {
_scene->freeAnimation();
_monsterMode = 1;
_scene->loadAnimation(formAnimName('B', -1));
- _scene->_activeAnimation->setCurrentFrame(39);
+ _scene->_animation[0]->setCurrentFrame(39);
_game._player._stepEnabled = true;
} else
_game._objects.setRoom(OBJ_CHICKEN_BOMB, 1);
@@ -1005,7 +1005,7 @@ void Scene703::step() {
_scene->freeAnimation();
_monsterMode = 0;
_scene->loadAnimation(formAnimName('A', -1));
- _scene->_activeAnimation->setCurrentFrame(9);
+ _scene->_animation[0]->setCurrentFrame(9);
_game._player._stepEnabled = true;
if (_game._storyMode == STORYMODE_NAUGHTY)
_vm->_dialogs->show(70321);
@@ -1018,8 +1018,8 @@ void Scene703::step() {
break;
}
- if ((nextBoatFrame >= 0) && (nextBoatFrame != _scene->_activeAnimation->getCurrentFrame())) {
- _scene->_activeAnimation->setCurrentFrame(nextBoatFrame);
+ if ((nextBoatFrame >= 0) && (nextBoatFrame != _scene->_animation[0]->getCurrentFrame())) {
+ _scene->_animation[0]->setCurrentFrame(nextBoatFrame);
_boatFrame = nextBoatFrame;
}
}
@@ -1055,7 +1055,7 @@ void Scene703::actions() {
_scene->freeAnimation();
_monsterMode = 2;
_scene->loadAnimation(formAnimName('C', -1));
- _scene->_activeAnimation->setCurrentFrame(19);
+ _scene->_animation[0]->setCurrentFrame(19);
} else if (_action.isAction(VERB_THROW, NOUN_CHICKEN, NOUN_SEA_MONSTER)) {
_game._player._stepEnabled = false;
_scene->freeAnimation();
@@ -1066,13 +1066,13 @@ void Scene703::actions() {
_scene->freeAnimation();
_monsterMode = 2;
_scene->loadAnimation(formAnimName('C', -1));
- _scene->_activeAnimation->setCurrentFrame(39);
+ _scene->_animation[0]->setCurrentFrame(39);
} else if (_action.isAction(VERB_THROW, NOUN_BOMB, NOUN_SEA_MONSTER)) {
_game._player._stepEnabled = false;
_scene->freeAnimation();
_monsterMode = 2;
_scene->loadAnimation(formAnimName('C', -1));
- _scene->_activeAnimation->setCurrentFrame(59);
+ _scene->_animation[0]->setCurrentFrame(59);
} else if (_action.isAction(VERB_THROW, NOUN_CHICKEN_BOMB, NOUN_SEA_MONSTER)) {
_useBomb = true;
_game._player._stepEnabled = false;
@@ -1241,21 +1241,21 @@ void Scene704::enter() {
_animationMode = 2;
_boatDirection = 2;
_scene->loadAnimation(formAnimName('A', -1));
- _scene->_activeAnimation->setCurrentFrame(36);
+ _scene->_animation[0]->setCurrentFrame(36);
} else if (_scene->_priorSceneId != RETURNING_FROM_DIALOG) {
_game._player._stepEnabled = false;
_boatDirection = 1;
_scene->loadAnimation(formAnimName('A', -1));
} else if (_boatDirection == 1) {
_scene->loadAnimation(formAnimName('A', -1));
- _scene->_activeAnimation->setCurrentFrame(8);
+ _scene->_animation[0]->setCurrentFrame(8);
} else if (_boatDirection == 2) {
if (_game._objects[OBJ_BOTTLE]._roomNumber == _scene->_currentSceneId) {
_scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(123, 125));
_scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
}
_scene->loadAnimation(formAnimName('A', -1));
- _scene->_activeAnimation->setCurrentFrame(57);
+ _scene->_animation[0]->setCurrentFrame(57);
}
if (_scene->_roomChanged)
@@ -1269,9 +1269,9 @@ void Scene704::enter() {
}
void Scene704::step() {
- if (_scene->_activeAnimation != nullptr) {
- if (_scene->_activeAnimation->getCurrentFrame() != _boatCurrentFrame) {
- _boatCurrentFrame = _scene->_activeAnimation->getCurrentFrame();
+ if (_scene->_animation[0] != nullptr) {
+ if (_scene->_animation[0]->getCurrentFrame() != _boatCurrentFrame) {
+ _boatCurrentFrame = _scene->_animation[0]->getCurrentFrame();
int nextFrame = -1;
switch (_boatCurrentFrame) {
@@ -1377,8 +1377,8 @@ void Scene704::step() {
break;
}
- if ((nextFrame >= 0) && (nextFrame != _scene->_activeAnimation->getCurrentFrame())) {
- _scene->_activeAnimation->setCurrentFrame(nextFrame);
+ if ((nextFrame >= 0) && (nextFrame != _scene->_animation[0]->getCurrentFrame())) {
+ _scene->_animation[0]->setCurrentFrame(nextFrame);
_boatCurrentFrame = nextFrame;
}
}
@@ -1455,7 +1455,7 @@ void Scene704::actions() {
_vm->_dialogs->show(70412);
} else if (_action.isAction(VERB_LOOK, NOUN_VOLCANO_RIM))
_vm->_dialogs->show(70413);
- else if (_action.isAction(VERB_LOOK, NOUN_BOTTLE) && (_action._mainObjectSource == 4))
+ else if (_action.isAction(VERB_LOOK, NOUN_BOTTLE) && (_action._mainObjectSource == CAT_HOTSPOT))
_vm->_dialogs->show(70414);
else if (_action.isAction(VERB_LOOK, NOUN_OPEN_WATER_TO_SOUTH))
_vm->_dialogs->show(70416);
@@ -1906,9 +1906,9 @@ void Scene706::step() {
_scene->_reloadSceneFlag = true;
}
- if (_scene->_activeAnimation != nullptr) {
- if ((_animationMode != 0) && (_scene->_activeAnimation->getCurrentFrame() != _animationFrame)) {
- _animationFrame = _scene->_activeAnimation->getCurrentFrame();
+ if (_scene->_animation[0] != nullptr) {
+ if ((_animationMode != 0) && (_scene->_animation[0]->getCurrentFrame() != _animationFrame)) {
+ _animationFrame = _scene->_animation[0]->getCurrentFrame();
if (_animationFrame == 6) {
_scene->_sequences.remove(_globals._sequenceIndexes[1]);
@@ -2017,7 +2017,7 @@ void Scene706::actions() {
_vm->_dialogs->show(70623);
else if (_action.isAction(VERB_LOOK, NOUN_VASE) && (_game._objects[OBJ_VASE]._roomNumber == _scene->_currentSceneId))
_vm->_dialogs->show(70624);
- else if (_action.isAction(VERB_LOOK, NOUN_BOTTLE) && (_action._mainObjectSource == 4))
+ else if (_action.isAction(VERB_LOOK, NOUN_BOTTLE) && (_action._mainObjectSource == CAT_HOTSPOT))
_vm->_dialogs->show(70632);
else
return;
diff --git a/engines/mads/nebular/nebular_scenes8.cpp b/engines/mads/nebular/nebular_scenes8.cpp
index a904569624..951b270a1c 100644
--- a/engines/mads/nebular/nebular_scenes8.cpp
+++ b/engines/mads/nebular/nebular_scenes8.cpp
@@ -930,7 +930,7 @@ void Scene804::enter() {
void Scene804::step() {
if (!_messWithThrottle) {
- if ((_throttleGone) && (_movingThrottle) && (_scene->_activeAnimation->getCurrentFrame() == 39)) {
+ if ((_throttleGone) && (_movingThrottle) && (_scene->_animation[0]->getCurrentFrame() == 39)) {
_globals._sequenceIndexes[1] = _scene->_sequences.startCycle
(_globals._spriteIndexes[1], false, 1);
_scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(133, 139));
@@ -938,7 +938,7 @@ void Scene804::step() {
_throttleGone = false;
}
- if ((_movingThrottle) && (_scene->_activeAnimation->getCurrentFrame() == 42)) {
+ if ((_movingThrottle) && (_scene->_animation[0]->getCurrentFrame() == 42)) {
_resetFrame = 0;
_movingThrottle = false;
}
@@ -947,12 +947,12 @@ void Scene804::step() {
_resetFrame = 42;
}
- if (_scene->_activeAnimation->getCurrentFrame() == 65)
+ if (_scene->_animation[0]->getCurrentFrame() == 65)
_scene->_sequences.remove(_globals._sequenceIndexes[7]);
switch (_game._storyMode) {
case STORYMODE_NAUGHTY:
- if (_scene->_activeAnimation->getCurrentFrame() == 81) {
+ if (_scene->_animation[0]->getCurrentFrame() == 81) {
_resetFrame = 80;
_globals[kInSpace] = false;
_globals[kBeamIsUp] = true;
@@ -964,7 +964,7 @@ void Scene804::step() {
break;
case STORYMODE_NICE:
- if (_scene->_activeAnimation->getCurrentFrame() == 68) {
+ if (_scene->_animation[0]->getCurrentFrame() == 68) {
_resetFrame = 66;
_globals[kInSpace] = false;
_globals[kBeamIsUp] = true;
@@ -975,12 +975,12 @@ void Scene804::step() {
}
}
- if (_scene->_activeAnimation->getCurrentFrame() == 34) {
+ if (_scene->_animation[0]->getCurrentFrame() == 34) {
_resetFrame = 36;
_scene->_sequences.remove(_globals._sequenceIndexes[1]);
}
- if (_scene->_activeAnimation->getCurrentFrame() == 37) {
+ if (_scene->_animation[0]->getCurrentFrame() == 37) {
_resetFrame = 36;
if (!_dontPullThrottleAgain) {
_dontPullThrottleAgain = true;
@@ -992,20 +992,20 @@ void Scene804::step() {
_scene->_nextSceneId = 803;
}
- if ((_scene->_activeAnimation->getCurrentFrame() == 7) && (!_globals[kWindowFixed])) {
+ if ((_scene->_animation[0]->getCurrentFrame() == 7) && (!_globals[kWindowFixed])) {
_globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 1);
_scene->_sequences.addTimer(20, 110);
_globals[kWindowFixed] = true;
}
- if (_scene->_activeAnimation->getCurrentFrame() == 10) {
+ if (_scene->_animation[0]->getCurrentFrame() == 10) {
_resetFrame = 0;
_game._player._stepEnabled = true;
_game._objects.setRoom(OBJ_POLYCEMENT, NOWHERE);
}
// FIXME: Original doesn't have resetFrame check. Check why this has been needed
- if (_resetFrame == -1 && _scene->_activeAnimation->getCurrentFrame() == 1) {
+ if (_resetFrame == -1 && _scene->_animation[0]->getCurrentFrame() == 1) {
int randomVal = _vm->getRandomNumber(29) + 1;
switch (randomVal) {
case 1:
@@ -1023,7 +1023,7 @@ void Scene804::step() {
}
}
- switch (_scene->_activeAnimation->getCurrentFrame()) {
+ switch (_scene->_animation[0]->getCurrentFrame()) {
case 26:
case 28:
case 31:
@@ -1031,12 +1031,12 @@ void Scene804::step() {
break;
}
} else {
- if ((_scene->_activeAnimation->getCurrentFrame() == 36) && (!_throttleGone)) {
+ if ((_scene->_animation[0]->getCurrentFrame() == 36) && (!_throttleGone)) {
_scene->_sequences.remove(_globals._sequenceIndexes[1]);
_throttleGone = true;
}
- if (_scene->_activeAnimation->getCurrentFrame() == 39) {
+ if (_scene->_animation[0]->getCurrentFrame() == 39) {
_movingThrottle = false;
switch (_throttleCounter) {
case 1:
@@ -1074,8 +1074,8 @@ void Scene804::step() {
}
if (_resetFrame >= 0) {
- if (_resetFrame != _scene->_activeAnimation->getCurrentFrame()) {
- _scene->_activeAnimation->setCurrentFrame(_resetFrame);
+ if (_resetFrame != _scene->_animation[0]->getCurrentFrame()) {
+ _scene->_animation[0]->setCurrentFrame(_resetFrame);
_resetFrame = -1;
}
}
@@ -1084,12 +1084,12 @@ void Scene804::step() {
_scene->_nextSceneId = 803;
}
- if ((_scene->_activeAnimation->getCurrentFrame() == 72) && !_alreadyPop) {
+ if ((_scene->_animation[0]->getCurrentFrame() == 72) && !_alreadyPop) {
_vm->_sound->command(21);
_alreadyPop = true;
}
- if ((_scene->_activeAnimation->getCurrentFrame() == 80) && !_alreadyOrgan) {
+ if ((_scene->_animation[0]->getCurrentFrame() == 80) && !_alreadyOrgan) {
_vm->_sound->command(22);
_alreadyOrgan = true;
}
@@ -1606,7 +1606,7 @@ void Scene810::enter() {
}
void Scene810::step() {
- if (_scene->_activeAnimation && (_scene->_activeAnimation->getCurrentFrame() == 200)
+ if (_scene->_animation[0] && (_scene->_animation[0]->getCurrentFrame() == 200)
&& _moveAllowed) {
_scene->_sequences.addTimer(100, 70);
_moveAllowed = false;
diff --git a/engines/mads/nebular/sound_nebular.cpp b/engines/mads/nebular/sound_nebular.cpp
index 711f82a05b..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 {
@@ -216,6 +215,8 @@ ASound::ASound(Audio::Mixer *mixer, OPL::OPL *opl, const Common::String &filenam
}
ASound::~ASound() {
+ _opl->stop();
+
Common::List<CachedDataEntry>::iterator i;
for (i = _dataCache.begin(); i != _dataCache.end(); ++i)
delete[] (*i)._data;
@@ -2025,8 +2026,8 @@ const ASound4::CommandPtr ASound4::_commandList[61] = {
&ASound4::nullCommand, &ASound4::nullCommand, &ASound4::nullCommand, &ASound4::command43,
&ASound4::nullCommand, &ASound4::nullCommand, &ASound4::nullCommand, &ASound4::nullCommand,
&ASound4::nullCommand, &ASound4::nullCommand, &ASound4::nullCommand, &ASound4::nullCommand,
- &ASound4::nullCommand, &ASound4::nullCommand, &ASound4::nullCommand, &ASound4::nullCommand,
- &ASound4::nullCommand, &ASound4::command57, &ASound4::nullCommand, &ASound4::command59,
+ &ASound4::command52, &ASound4::command53, &ASound4::command54, &ASound4::command55,
+ &ASound4::command56, &ASound4::command57, &ASound4::command58, &ASound4::command59,
&ASound4::command60
};
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/palette.h b/engines/mads/palette.h
index 6c98947384..1efe63b324 100644
--- a/engines/mads/palette.h
+++ b/engines/mads/palette.h
@@ -316,7 +316,7 @@ public:
void refreshSceneColors();
- static int closestColor(const byte *matchColor, const byte *refPalette,
+ static int closestColor(const byte *matchColor, const byte *refPalette,
int paletteInc, int count);
};
diff --git a/engines/mads/phantom/game_phantom.cpp b/engines/mads/phantom/game_phantom.cpp
index 592a108aea..af9769d529 100644
--- a/engines/mads/phantom/game_phantom.cpp
+++ b/engines/mads/phantom/game_phantom.cpp
@@ -35,10 +35,111 @@ namespace MADS {
namespace Phantom {
-GamePhantom::GamePhantom(MADSEngine *vm)
- : Game(vm) {
+ Catacombs _easyCatacombs[32] = {
+ { 401, { -1, 1, 2, 6 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
+ { 404, { 10, 11, 3, 0 }, { 2, 3, 0, 1 }, MAZE_EVENT_PUDDLE },
+ { 404, { 0, 3, 4, -2 }, { 2, 3, 0, 1 }, MAZE_EVENT_BLOCK },
+ { 401, { 1, 14, 5, 2 }, { 2, 3, 0, 1 }, MAZE_EVENT_POT },
+ { 453, { 2, 4, -1, 4 }, { 2, 3, 0, 1 }, MAZE_EVENT_DRAIN },
+ { 403, { 3, 6, -1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_PLANK },
+ { 406, { -1, 0, -1, 5 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
+ { 453, { -1, 8, -1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
+ { 406, { -1, 9, -1, 7 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
+ { 401, { 1, -1, 10, 8 }, { 2, 3, 0, 1 }, MAZE_EVENT_RAT_NEST | MAZE_EVENT_SKULL },
+ { 408, { 9, -1, 1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
+ { 453, { 12, -1, -1, 1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_STONE },
+ { 408, { 13, -1, 11, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
+ { 401, { 13, 20, 12, 13 }, { 3, 3, 0, 0 }, MAZE_EVENT_BRICK },
+ { 453, { 16, 15, -1, 3 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_RAT_NEST },
+ { 456, { -1, -1, -1, 14 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
+ { 404, { -1, 17, 14, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_WEB | MAZE_EVENT_POT },
+ { 401, { 18, -1, 19, 16 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
+ { 408, { -1, -1, 17, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
+ { 403, { 17, -1, -1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_HOLE | MAZE_EVENT_WEB },
+ { 403, { 21, 22, -1, 13 }, { 2, 3, 0, 1 }, MAZE_EVENT_WEB | MAZE_EVENT_SKULL },
+ { 404, { -1, -1, 20, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
+ { 406, { -1, 23, -1, 20 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
+ { 404, { 24, 23, 23, 22 }, { 2, 2, 1, 1 }, MAZE_EVENT_RAT_NEST | MAZE_EVENT_BRICK },
+ { 401, { -1, 1, 23, 25 }, { 2, 1, 0, 1 }, MAZE_EVENT_PUDDLE | MAZE_EVENT_POT | MAZE_EVENT_BRICK },
+ { 407, { 29, 24, 28, 26 }, { 3, 3, 1, 1 }, MAZE_EVENT_NONE },
+ { 401, { 27, 25, 23, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_SKULL },
+ { 404, { -1, 28, 26, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_WEB | MAZE_EVENT_FALLEN_BLOCK },
+ { 456, { -1, 25, -1, 27 }, { 2, 2, 0, 1 }, MAZE_EVENT_NONE },
+ { 406, { -1, 30, -1, 25 }, { 2, 3, 0, 0 }, MAZE_EVENT_NONE },
+ { 453, { -3, 30, -1, 29 }, { 2, 3, 0, 1 }, MAZE_EVENT_STONE | MAZE_EVENT_RAT_NEST | MAZE_EVENT_WEB },
+ { 408, { -5, -1, -4, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_WEB | MAZE_EVENT_BRICK }
+ };
+
+ Catacombs _hardCatacombs[62] = {
+ { 401, { -1, 1, 2, 6 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
+ { 404, { 10, 11, 3, 0 }, { 2, 3, 0, 1 }, MAZE_EVENT_PUDDLE },
+ { 404, { 0, 3, 4, -2 }, { 2, 3, 0, 1 }, MAZE_EVENT_BLOCK },
+ { 401, { 1, 20, 5, 2 }, { 2, 0, 0, 1 }, MAZE_EVENT_POT },
+ { 453, { 2, 4, -1, 4 }, { 2, 3, 0, 1 }, MAZE_EVENT_DRAIN },
+ { 403, { 3, 6, -1, 4 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_PLANK },
+ { 406, { -1, 0, -1, 5 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
+ { 453, { -1, 8, -1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
+ { 406, { -1, 9, -1, 7 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
+ { 401, { 1, -1, 10, 8 }, { 0, 3, 0, 1 }, MAZE_EVENT_RAT_NEST | MAZE_EVENT_SKULL },
+ { 408, { 9, -1, 1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
+ { 453, { 12, -1, -1, 1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_STONE },
+ { 408, { 13, -1, 11, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
+ { 401, { 13, 21, 12, 13 }, { 3, 3, 0, 0 }, MAZE_EVENT_BRICK },
+ { 453, { 16, 15, -1, 20 }, { 2, 3, 0, 2 }, MAZE_EVENT_RAT_NEST | MAZE_EVENT_BRICK },
+ { 456, { -1, -1, -1, 14 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
+ { 404, { -1, 17, 14, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_WEB | MAZE_EVENT_POT },
+ { 401, { 18, -1, 19, 16 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
+ { 408, { -1, -1, 17, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
+ { 403, { 17, -1, -1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_HOLE | MAZE_EVENT_WEB },
+ { 408, { 3, -1, 14, -1 }, { 1, 3, 3, 1 }, MAZE_EVENT_NONE },
+ { 404, { 9, 30, 22, 13 }, { 0, 3, 0, 1 }, MAZE_EVENT_RAT_NEST },
+ { 403, { 21, 23, -1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_HOLE | MAZE_EVENT_WEB },
+ { 401, { -1, -1, 24, 22 }, { 2, 3, 3, 1 }, MAZE_EVENT_BRICK },
+ { 406, { -1, 26, -1, 23 }, { 2, 0, 0, 2 }, MAZE_EVENT_NONE },
+ { 407, { 36, 33, 35, 34 }, { 3, 3, 1, 1 }, MAZE_EVENT_NONE },
+ { 453, { 24, 27, -1, -1 }, { 1, 0, 0, 1 }, MAZE_EVENT_BRICK },
+ { 403, { 26, -1, -1, 28 }, { 1, 3, 0, 0 }, MAZE_EVENT_BRICK | MAZE_EVENT_SKULL },
+ { 404, { 27, 28, 28, 29 }, { 3, 2, 1, 2 }, MAZE_EVENT_NONE },
+ { 408, { -1, -1, 28, -1 }, { 2, 3, 3, 1 }, MAZE_EVENT_BRICK },
+ { 406, { -1, 31, -1, 21 }, { 2, 0, 0, 1 }, MAZE_EVENT_NONE },
+ { 401, { 30, 33, 1, -1 }, { 1, 2, 1, 1 }, MAZE_EVENT_PUDDLE | MAZE_EVENT_POT },
+ { 456, { -1, 31, -1, 33 }, { 2, 1, 0, 0 }, MAZE_EVENT_NONE },
+ { 404, { 32, -1, 31, 25 }, { 3, 3, 1, 1 }, MAZE_EVENT_NONE },
+ { 401, { 46, 25, 31, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_SKULL },
+ { 401, { -1, 25, 41, -1 }, { 2, 2, 1, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_POT },
+ { 406, { -1, 37, -1, 25 }, { 2, 3, 0, 0 }, MAZE_EVENT_NONE },
+ { 453, { -3, 37, -1, 36 }, { 2, 3, 0, 1 }, MAZE_EVENT_STONE | MAZE_EVENT_RAT_NEST | MAZE_EVENT_WEB },
+ { 408, { 57, -1, 54, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
+ { 408, { 40, -1, -4, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_WEB },
+ { 404, { 40, 40, 39, 53 }, { 1, 0, 0, 1 }, MAZE_EVENT_BLOCK | MAZE_EVENT_FALLEN_BLOCK },
+ { 456, { -1, 35, -1, 42 }, { 2, 2, 0, 2 }, MAZE_EVENT_NONE },
+ { 408, { 43, -1, 41, -1 }, { 1, 3, 3, 1 }, MAZE_EVENT_BRICK },
+ { 406, { -1, 42, -1, 61 }, { 2, 0, 0, 1 }, MAZE_EVENT_NONE },
+ { 403, { 58, 45, -1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_RAT_NEST },
+ { 401, { 34, -1, 46, 44 }, { 0, 3, 0, 1 }, MAZE_EVENT_RAT_NEST | MAZE_EVENT_BRICK },
+ { 404, { 45, -1, 34, 47 }, { 2, 3, 0, 1 }, MAZE_EVENT_WEB | MAZE_EVENT_FALLEN_BLOCK },
+ { 406, { -1, 46, -1, 48 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
+ { 403, { 49, 47, -1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_SKULL | MAZE_EVENT_WEB },
+ { 408, { 50, -1, 48, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
+ { 408, { 51, -1, 49, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
+ { 408, { 52, -1, 50, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
+ { 408, { -1, -1, 51, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
+ { 406, { -1, 40, -1, 54 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
+ { 403, { 38, 53, -1, 55 }, { 2, 3, 0, 1 }, MAZE_EVENT_SKULL },
+ { 453, { 56, 54, -1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_WEB },
+ { 401, { 56, -5, 55, 56 }, { 3, 3, 0, 0 }, MAZE_EVENT_BRICK | MAZE_EVENT_SKULL },
+ { 404, { -1, 57, 38, 57 }, { 2, 3, 0, 1 }, MAZE_EVENT_POT | MAZE_EVENT_BLOCK },
+ { 404, { 59, 59, 44, 60 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
+ { 404, { 59, 60, 59, 58 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
+ { 404, { 61, 58, 59, 59 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
+ { 404, { 34, 43, 60, 44 }, { 0, 3, 0, 1 }, MAZE_EVENT_NONE }
+ };
+
+GamePhantom::GamePhantom(MADSEngine *vm) : Game(vm) {
_surface = new MSurface(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT);
- _storyMode = STORYMODE_NAUGHTY;
+ _difficulty = DIFFICULTY_HARD;
+ _catacombs = nullptr;
+ _catacombSize = -1;
}
void GamePhantom::startGame() {
@@ -51,8 +152,7 @@ void GamePhantom::startGame() {
void GamePhantom::initializeGlobals() {
_globals.reset();
-
- // TODO: Catacombs setup
+ setupCatacombs();
_player._facing = FACING_NORTH;
_player._turnToFacing = FACING_NORTH;
@@ -104,7 +204,7 @@ void GamePhantom::initializeGlobals() {
_globals[kChristineToldEnvelope] = false;
_globals[kLeaveAngelMusicOn] = false;
_globals[kDoorIn409IsOpen] = false;
- _globals[kUnknown] = false;
+ _globals[kPriestPistonPuke] = false;
_globals[kCobwebIsCut] = false;
_globals[kChristineIsInBoat] = false;
_globals[kRightDoorIsOpen504] = false;
@@ -161,27 +261,561 @@ void GamePhantom::checkShowDialog() {
}
}
+void GamePhantom::genericObjectExamine() {
+ MADSAction &action = _scene._action;
+ int id = _objects.getIdFromDesc(action._activeAction._objectNameId);
+
+ if (action.isAction(VERB_LOOK, NOUN_RED_FRAME))
+ _vm->_dialogs->showItem(id, (_globals[kCurrentYear] == 1993) ? 802 : 842, 0);
+ else if (action.isAction(VERB_LOOK, NOUN_YELLOW_FRAME))
+ _vm->_dialogs->showItem(id, (_globals[kCurrentYear] == 1993) ? 804 : 843, 0);
+ else if (action.isAction(VERB_LOOK, NOUN_BLUE_FRAME))
+ _vm->_dialogs->showItem(id, (_globals[kCurrentYear] == 1993) ? 817 : 844, 0);
+ else if (action.isAction(VERB_LOOK, NOUN_GREEN_FRAME))
+ _vm->_dialogs->showItem(id, (_globals[kCurrentYear] == 1993) ? 819 : 845, 0);
+ else if (action.isAction(VERB_LOOK, NOUN_LANTERN))
+ _vm->_dialogs->showItem(id, (_globals[kLanternStatus] == 1) ? 831 : 801, 0);
+ else if (action.isAction(VERB_LOOK, NOUN_SMALL_NOTE))
+ _vm->_dialogs->showItem(OBJ_SMALL_NOTE, 846, 2);
+ else if (action.isAction(VERB_LOOK, NOUN_PARCHMENT))
+ _vm->_dialogs->showItem(OBJ_PARCHMENT, 812, 3);
+ else if (action.isAction(VERB_LOOK, NOUN_LETTER))
+ _vm->_dialogs->showItem(OBJ_LETTER, 813, 4);
+ else if (action.isAction(VERB_LOOK, NOUN_NOTICE))
+ _vm->_dialogs->showItem(OBJ_NOTICE, 814, 5);
+ else if (action.isAction(VERB_LOOK, NOUN_CRUMPLED_NOTE))
+ _vm->_dialogs->showItem(OBJ_CRUMPLED_NOTE, 816, 6);
+ else if (action.isAction(VERB_LOOK, NOUN_LARGE_NOTE))
+ _vm->_dialogs->showItem(OBJ_LARGE_NOTE, 818, 7);
+ else
+ _vm->_dialogs->showItem(id, 800 + id, 0);
+}
+
void GamePhantom::doObjectAction() {
- // TODO: Copied from Nebular
- //Scene &scene = _scene;
MADSAction &action = _scene._action;
- //Dialogs &dialogs = *_vm->_dialogs;
- //int id;
- action._inProgress = false;
+ if ((_scene._currentSceneId >= 401) && (_scene._currentSceneId <= 456)
+ && (action.isObject(NOUN_RED_FRAME) || action.isObject(NOUN_YELLOW_FRAME) || action.isObject(NOUN_GREEN_FRAME) || action.isObject(NOUN_BLUE_FRAME))
+ && action.isAction(VERB_PUT)) {
+ if (action.isTarget(NOUN_UNLUCKY_ADVENTURER)) {
+ _vm->_dialogs->show(35);
+ action._inProgress = false;
+ return;
+ } else if (action.isTarget(NOUN_HOLE)) {
+ _vm->_dialogs->show(36);
+ action._inProgress = false;
+ return;
+ } else if (action.isTarget(NOUN_GRATE)) {
+ _vm->_dialogs->show(37);
+ action._inProgress = false;
+ return;
+ } else if (action.isTarget(NOUN_WALL)) {
+ _vm->_dialogs->show(38);
+ action._inProgress = false;
+ return;
+ }
+ }
+
+ if (action._lookFlag) {
+ _vm->_dialogs->show(810);
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_PUT, NOUN_RED_FRAME) || action.isAction(VERB_PUT, NOUN_BLUE_FRAME) || action.isAction(VERB_PUT, NOUN_YELLOW_FRAME) || action.isAction(VERB_PUT, NOUN_GREEN_FRAME)) {
+ _vm->_dialogs->show((action.isTarget(NOUN_PUDDLE)) ? 40124 : 40125);
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_WEAR, NOUN_WEDDING_RING)) {
+ if (_globals[kRingIsOnFinger])
+ _vm->_dialogs->show(849);
+ else {
+ _vm->_dialogs->show(835);
+ _globals[kRingIsOnFinger] = true;
+ }
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_REMOVE, NOUN_WEDDING_RING)) {
+ if (!_globals[kRingIsOnFinger])
+ _vm->_dialogs->show(848);
+ else {
+ _vm->_dialogs->show(836);
+ _globals[kRingIsOnFinger] = false;
+ }
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_LOOK, NOUN_ARCHWAY_TO_WEST) || action.isAction(VERB_LOOK, NOUN_ARCHWAY_TO_EAST) || action.isAction(VERB_LOOK, NOUN_ARCHWAY_TO_NORTH)) {
+ _vm->_dialogs->show(34);
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_ATTACK, NOUN_CHRISTINE)) {
+ _vm->_dialogs->show(33);
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_LOOK, NOUN_KEY)) {
+ _vm->_dialogs->showItem(OBJ_KEY, 800, 0);
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_LOOK, NOUN_SANDBAG)) {
+ _vm->_dialogs->showItem(OBJ_SANDBAG, 803, 0);
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_LOOK, NOUN_SMALL_NOTE) || action.isAction(VERB_READ, NOUN_SMALL_NOTE)) {
+ _vm->_dialogs->showItem(OBJ_SMALL_NOTE, 806, 2);
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_LOOK, NOUN_ROPE)) {
+ _vm->_dialogs->showItem(OBJ_ROPE, 807, 0);
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_LOOK, NOUN_SWORD)) {
+ _vm->_dialogs->showItem(OBJ_SWORD, 808, 0);
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_LOOK, NOUN_ENVELOPE) || action.isAction(VERB_READ, NOUN_ENVELOPE)) {
+ _vm->_dialogs->showItem(OBJ_ENVELOPE, 809, 0);
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_LOOK, NOUN_TICKET) || action.isAction(VERB_READ, NOUN_TICKET)) {
+ _vm->_dialogs->showItem(OBJ_TICKET, 810, 0);
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_LOOK, NOUN_PIECE_OF_PAPER) || action.isAction(VERB_READ, NOUN_PIECE_OF_PAPER)) {
+ _vm->_dialogs->showItem(OBJ_PIECE_OF_PAPER, 811, 1);
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_LOOK, NOUN_PARCHMENT) || action.isAction(VERB_READ, NOUN_PARCHMENT)) {
+ _vm->_dialogs->showItem(OBJ_PARCHMENT, 812, 3);
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_LOOK, NOUN_LETTER) || action.isAction(VERB_READ, NOUN_LETTER)) {
+ _vm->_dialogs->showItem(OBJ_LETTER, 813, 4);
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_LOOK, NOUN_NOTICE) || action.isAction(VERB_READ, NOUN_NOTICE)) {
+ _vm->_dialogs->showItem(OBJ_NOTICE, 814, 5);
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_LOOK, NOUN_BOOK) || action.isAction(VERB_READ, NOUN_BOOK)) {
+ _vm->_dialogs->showItem(OBJ_BOOK, 815, 0);
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_LOOK, NOUN_CRUMPLED_NOTE) || action.isAction(VERB_READ, NOUN_CRUMPLED_NOTE)) {
+ _vm->_dialogs->showItem(OBJ_CRUMPLED_NOTE, 816, 6);
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_LOOK, NOUN_LARGE_NOTE) || action.isAction(VERB_READ, NOUN_LARGE_NOTE)) {
+ _vm->_dialogs->showItem(OBJ_LARGE_NOTE, 818, 7);
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_LOOK, NOUN_MUSIC_SCORE) || action.isAction(VERB_READ, NOUN_MUSIC_SCORE)) {
+ _vm->_dialogs->showItem(OBJ_MUSIC_SCORE, 820, 0);
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_LOOK, NOUN_WEDDING_RING)) {
+ _vm->_dialogs->showItem(OBJ_WEDDING_RING, 821, 0);
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_LOOK, NOUN_CABLE_HOOK)) {
+ _vm->_dialogs->showItem(OBJ_CABLE_HOOK, 822, 0);
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_LOOK, NOUN_ROPE_WITH_HOOK)) {
+ _vm->_dialogs->showItem(OBJ_ROPE_WITH_HOOK, 823, 0);
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_LOOK, NOUN_OAR)) {
+ _vm->_dialogs->showItem(OBJ_OAR, 824, 0);
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_LOOK) && _objects.isInInventory(_objects.getIdFromDesc(action._activeAction._objectNameId))) {
+ genericObjectExamine();
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_TURN_ON, NOUN_LANTERN)) {
+ if ((_globals[kLanternStatus] == 1) && !_trigger)
+ _vm->_dialogs->show(828);
+ else {
+ switch (_trigger) {
+ case 0:
+ _scene._sequences.addTimer(4, 1);
+ _globals[kLanternStatus] = 1;
+ _vm->_dialogs->spinObject(OBJ_LANTERN);
+ break;
+
+ case 1:
+ _vm->_dialogs->show(825);
+ break;
+
+ default:
+ break;
+ }
+ }
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_TURN_OFF, NOUN_LANTERN)) {
+ if ((_globals[kLanternStatus] == 0) && !_trigger)
+ _vm->_dialogs->show(829);
+ else if ((_scene._currentSceneId / 100) == 4)
+ _vm->_dialogs->show(826);
+ else {
+ switch (_trigger) {
+ case 0:
+ _scene._sequences.addTimer(4, 1);
+ _globals[kLanternStatus] = 0;
+ _vm->_dialogs->spinObject(OBJ_LANTERN);
+ break;
+
+ case 1:
+ _vm->_dialogs->show(827);
+ break;
+
+ default:
+ break;
+ }
+ }
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_OPEN, NOUN_ENVELOPE)) {
+ _objects.setRoom(OBJ_ENVELOPE, NOWHERE);
+ _objects.addToInventory(OBJ_TICKET);
+ _objects.addToInventory(OBJ_PIECE_OF_PAPER);
+ _vm->_dialogs->show(833);
+ action._inProgress = false;
+ return;
+ }
+
+ if (action.isAction(VERB_ATTACH, NOUN_CABLE_HOOK, NOUN_ROPE)) {
+ if (!_objects.isInInventory(OBJ_ROPE))
+ _vm->_dialogs->show(11438);
+ else {
+ _objects.setRoom(OBJ_CABLE_HOOK, NOWHERE);
+ _objects.setRoom(OBJ_ROPE, NOWHERE);
+ _objects.addToInventory(OBJ_ROPE_WITH_HOOK);
+ _vm->_dialogs->showItem(OBJ_ROPE_WITH_HOOK, 823, 0);
+ }
+ action._inProgress = false;
+ }
}
void GamePhantom::unhandledAction() {
- // TODO
+ int messageId = 0;
+ int rndNum = _vm->getRandomNumber(1, 1000);
+ MADSAction &action = _scene._action;
+
+ if (action.isAction(VERB_PUT, NOUN_CHANDELIER, NOUN_SEATS))
+ _vm->_dialogs->show(10123);
+ else if (action.isAction(VERB_TAKE)) {
+ if (_objects.isInInventory(_objects.getIdFromDesc(action._activeAction._objectNameId)))
+ messageId = 25;
+ else {
+ if (rndNum <= 333)
+ messageId = 1;
+ else if (rndNum <= 666)
+ messageId = 2;
+ else
+ messageId = 3;
+ }
+ } else if (action.isAction(VERB_PUSH)) {
+ if (rndNum < 750)
+ messageId = 4;
+ else
+ messageId = 5;
+ } else if (action.isAction(VERB_PULL)) {
+ if (rndNum < 750)
+ messageId = 6;
+ else
+ messageId = 7;
+ } else if (action.isAction(VERB_OPEN)) {
+ if (rndNum <= 500)
+ messageId = 8;
+ else if (rndNum <= 750)
+ messageId = 9;
+ else
+ messageId = 10;
+ } else if (action.isAction(VERB_CLOSE)) {
+ if (rndNum <= 500)
+ messageId = 11;
+ else if (rndNum <= 750)
+ messageId = 12;
+ else
+ messageId = 13;
+ } else if (action.isAction(VERB_PUT)) {
+ if (_objects.isInInventory(_objects.getIdFromDesc(action._activeAction._objectNameId)))
+ messageId = 26;
+ else if (rndNum < 500)
+ messageId = 14;
+ else
+ messageId = 15;
+ } else if (action.isAction(VERB_TALK_TO)) {
+ if (rndNum <= 500)
+ messageId = 16;
+ else
+ messageId = 17;
+ } else if (action.isAction(VERB_GIVE)) {
+ if (_objects.isInInventory(_objects.getIdFromDesc(action._activeAction._objectNameId)))
+ messageId = 27;
+ else
+ messageId = 18;
+ } else if (action.isAction(VERB_THROW)) {
+ if (_objects.isInInventory(_objects.getIdFromDesc(action._activeAction._objectNameId)))
+ messageId = 19;
+ else
+ messageId = 28;
+ } else if (action.isAction(VERB_LOOK)) {
+ if (rndNum <= 333)
+ messageId = 20;
+ else if (rndNum <= 666)
+ messageId = 21;
+ else
+ messageId = 22;
+ } else if ((action.isAction(VERB_UNLOCK) || action.isAction(VERB_LOCK))
+ && (action.isObject(NOUN_DOOR) || action.isObject(NOUN_LEFT_DOOR) || action.isObject(NOUN_MIDDLE_DOOR) || action.isObject(NOUN_RIGHT_DOOR) || action.isObject(NOUN_TRAP_DOOR)))
+ messageId = 32;
+ else if (!action.isAction(VERB_WALK_TO) && !action.isAction(VERB_WALK_ACROSS) && !action.isAction(VERB_WALK_DOWN) && !action.isAction(VERB_WALK_UP)) {
+ if (rndNum < 500)
+ messageId = 23;
+ else
+ messageId = 24;
+ }
+
+ if (messageId)
+ _vm->_dialogs->show(messageId);
+}
+
+void GamePhantom::stopWalker() {
+ int state = _globals[kWalkerConverseState];
+ int command = _globals[kWalkerConverse];
+
+ _globals[kWalkerConverseNow] = state;
+
+ if ((_player._facing != FACING_NORTHEAST) && (_player._facing != FACING_NORTHWEST)) {
+ state = 0;
+ command = 0;
+ }
+
+ switch (state) {
+ case 1:
+ switch (command) {
+ case 1:
+ _player.addWalker(3, 0);
+ break;
+
+ case 2:
+ case 3:
+ _player.addWalker(6, 0);
+ _player.addWalker(5, 0);
+ _player.addWalker(4, 0);
+ state = 2;
+ break;
+
+ case 4:
+ _player.addWalker(8, 0);
+ _player.addWalker(4, 0);
+ state = 4;
+ break;
+
+ default:
+ _player.addWalker(-2, 0);
+ state = 0;
+ break;
+ }
+ break;
+
+ case 2:
+ case 3:
+ switch (command) {
+ case 2:
+ case 3:
+ if (state == 2) {
+ if (_vm->getRandomNumber(1, 30000) < 2000) {
+ _player.addWalker(10, 0);
+ _player.addWalker(7, 0);
+ state = 3;
+ } else
+ _player.addWalker(6, 0);
+ } else {
+ if (_vm->getRandomNumber(1, 30000) < 1000) {
+ _player.addWalker(6, 0);
+ _player.addWalker(7, 0);
+ state = 2;
+ } else
+ _player.addWalker(10, 0);
+ }
+ break;
+
+ default:
+ _player.addWalker(-4, 0);
+ _player.addWalker(-5, 0);
+ if (state == 3) {
+ _player.addWalker(6, 0);
+ _player.addWalker(7, 0);
+ }
+ state = 1;
+ break;
+ }
+ break;
+
+ case 4:
+ if (command == 4)
+ _player.addWalker(9, 0);
+ else {
+ _player.addWalker(-4, 0);
+ _player.addWalker(-8, 0);
+ state = 1;
+ }
+ break;
+
+ case 0:
+ default:
+ switch (command) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ _player.addWalker(2, 0);
+ state = 1;
+ break;
+
+ default:
+ stopWalkerBasic();
+ break;
+ }
+ break;
+ }
+
+ _globals[kWalkerConverse] = command;
+ _globals[kWalkerConverseState] = state;
}
void GamePhantom::step() {
- if (_player._visible && _player._stepEnabled && !_player._moving &&
- (_player._facing == _player._turnToFacing)) {
+ if (_player._visible && !_globals[kStopWalkerDisabled]
+ && (_player._stepEnabled || (_vm->_gameConv->activeConvId() >= 0))
+ && !_player._moving && (_player._facing == _player._turnToFacing)
+ && (_scene._frameStartTime >= (uint32)_globals[kWalkerTiming])) {
+ if (_player._stopWalkers.empty())
+ stopWalker();
- // TODO
+ _globals[kWalkerTiming] += 6;
}
+}
+
+void GamePhantom::stopWalkerBasic() {
+ int rndVal = _vm->getRandomNumber(1, 30000);
+
+ switch (_player._facing) {
+ case FACING_SOUTH:
+ if (rndVal < 500) {
+ int maxSteps = _vm->getRandomNumber(4, 10);
+ for (int i = 0; i < maxSteps; i++)
+ _player.addWalker((rndVal < 250) ? 1 : 2, 0);
+ } else if (rndVal < 750) {
+ for (int i = 0; i < 4; i++)
+ _player.addWalker(1, 0);
+ _player.addWalker(0, 0);
+
+ for (int i = 0; i < 4; i++)
+ _player.addWalker(2, 0);
+
+ _player.addWalker(0, 0);
+ }
+ break;
+
+ case FACING_SOUTHEAST:
+ case FACING_SOUTHWEST:
+ case FACING_NORTHEAST:
+ case FACING_NORTHWEST:
+ if (rndVal < 150) {
+ _player.addWalker(-1, 0);
+ _player.addWalker(1, 0);
+ for (int i = 0; i < 6; i++)
+ _player.addWalker(0, 0);
+ }
+ break;
+
+ case FACING_EAST:
+ case FACING_WEST:
+ if (rndVal < 250) {
+ _player.addWalker(-1, 0);
+ int maxSteps = _vm->getRandomNumber(2, 6);
+ for (int i = 0; i < maxSteps; i++)
+ _player.addWalker(2, 0);
+ _player.addWalker(1, 0);
+ _player.addWalker(0, 0);
+ _player.addWalker(0, 0);
+ } else if (rndVal < 500)
+ _globals[kWalkerTiming] = (int)_scene._frameStartTime;
+ break;
+
+ case FACING_NORTH:
+ if (rndVal < 250) {
+ _player.addWalker(-1, 0);
+ int maxSteps = _vm->getRandomNumber(3, 7);
+ for (int i = 0; i < maxSteps; i++)
+ _player.addWalker(2, 0);
+ _player.addWalker(1, 0);
+ _player.addWalker(0, 0);
+ }
+ break;
+
+ default:
+ break;
+ }
}
void GamePhantom::synchronize(Common::Serializer &s, bool phase1) {
@@ -193,6 +827,121 @@ void GamePhantom::synchronize(Common::Serializer &s, bool phase1) {
}
}
+void GamePhantom::enterCatacombs(bool val) {
+ setupCatacombs();
+
+ int var4, var2;
+ if (_scene._currentSceneId == 409) {
+ if (val) {
+ var4 = _globals[kCatacombs409b];
+ var2 = _globals[kCatacombs409bFrom];
+ } else {
+ var4 = _globals[kCatacombs409a];
+ var2 = _globals[kCatacombs409aFrom];
+ }
+ } else if (_scene._currentSceneId == 501) {
+ var4 = _globals[kCatacombs501];
+ var2 = _globals[kCatacombs501From];
+ } else {
+ var4 = _globals[kCatacombs309];
+ var2 = _globals[kCatacombs309From];
+ }
+
+ newCatacombRoom(var4, var2);
+}
+
+void GamePhantom::initCatacombs() {
+ _globals[kCatacombsRoom] = _globals[kCatacombsNextRoom];
+}
+
+void GamePhantom::setupCatacombs() {
+ switch (_difficulty) {
+ case DIFFICULTY_EASY:
+ _catacombs = _easyCatacombs;
+ _catacombSize = 32;
+
+ _globals[kCatacombs309] = 2;
+ _globals[kCatacombs309From] = 3;
+ _globals[kCatacombs409a] = 30;
+ _globals[kCatacombs409aFrom] = 0;
+ _globals[kCatacombs409b] = 31;
+ _globals[kCatacombs409bFrom] = 2;
+ _globals[kCatacombs501] = 31;
+ _globals[kCatacombs501From] = 0;
+ break;
+
+ case DIFFICULTY_MEDIUM:
+ // TODO: FIXME. Do we need to set something here?
+ break;
+
+ case DIFFICULTY_HARD:
+ _catacombs = _hardCatacombs;
+ _catacombSize = 62;
+
+ _globals[kCatacombs309] = 2;
+ _globals[kCatacombs309From] = 3;
+ _globals[kCatacombs409a] = 37;
+ _globals[kCatacombs409aFrom] = 0;
+ _globals[kCatacombs409b] = 39;
+ _globals[kCatacombs409bFrom] = 2;
+ _globals[kCatacombs501] = 56;
+ _globals[kCatacombs501From] = 1;
+ break;
+ }
+}
+
+int GamePhantom::exitCatacombs(int dir) {
+ assert(_globals[kCatacombsRoom] == CLIP(_globals[kCatacombsRoom], 0, _catacombSize - 1));
+ assert(dir == CLIP(dir, 0, 3));
+
+ return (_catacombs[_globals[kCatacombsRoom]]._exit[dir]);
+}
+
+void GamePhantom::moveCatacombs(int dir) {
+ assert(_globals[kCatacombsRoom] == CLIP(_globals[kCatacombsRoom], 0, _catacombSize - 1));
+ assert(dir == CLIP(dir, 0, 3));
+
+ newCatacombRoom(_catacombs[_globals[kCatacombsRoom]]._fromDirection[dir], _catacombs[_globals[kCatacombsRoom]]._exit[dir]);
+}
+
+void GamePhantom::newCatacombRoom(int toRoom, int fromExit) {
+ _globals[kCatacombsNextRoom] = toRoom;
+ _globals[kCatacombsFrom] = fromExit & 0x03;
+ _globals[kCatacombsFlag] = fromExit & 0xFC;
+
+ int newSceneNum = -1;
+
+ if (toRoom < 0) {
+ switch (toRoom) {
+ case -5:
+ newSceneNum = 501;
+ break;
+
+ case -4:
+ case -3:
+ newSceneNum = 409;
+ break;
+
+ case -2:
+ newSceneNum = 309;
+ break;
+
+ default:
+ error("Unexpected room in newCatacombRoom");
+ }
+ } else {
+ newSceneNum = _catacombs[toRoom]._sceneNum;
+ _globals[81] = _catacombs[toRoom]._flags;
+ }
+
+ if (_triggerSetupMode == SEQUENCE_TRIGGER_PREPARE) {
+ _player._walkOffScreenSceneId = newSceneNum;
+ } else {
+ _scene._reloadSceneFlag = true;
+ _scene._nextSceneId = newSceneNum;
+ }
+}
+
} // End of namespace Phantom
} // End of namespace MADS
diff --git a/engines/mads/phantom/game_phantom.h b/engines/mads/phantom/game_phantom.h
index 44b2321f42..2f0204f331 100644
--- a/engines/mads/phantom/game_phantom.h
+++ b/engines/mads/phantom/game_phantom.h
@@ -32,8 +32,9 @@ namespace MADS {
namespace Phantom {
-// TODO: Adapt for Phantom's difficulty setting
-enum StoryMode { STORYMODE_NAUGHTY = 1, STORYMODE_NICE = 2 };
+enum Difficulty {
+ DIFFICULTY_HARD = 1, DIFFICULTY_MEDIUM = 2, DIFFICULTY_EASY = 3
+};
enum InventoryObject {
OBJ_NONE = -1,
@@ -64,8 +65,40 @@ enum InventoryObject {
OBJ_OAR = 24
};
+enum MazeEvent {
+ MAZE_EVENT_NONE = 0,
+ MAZE_EVENT_PUDDLE = 0x0001,
+ MAZE_EVENT_RAT_NEST = 0x0002,
+ MAZE_EVENT_SKULL = 0x0004,
+ MAZE_EVENT_POT = 0x0008,
+ MAZE_EVENT_BRICK = 0x0010,
+ MAZE_EVENT_HOLE = 0x0020,
+ MAZE_EVENT_WEB = 0x0040,
+ MAZE_EVENT_PLANK = 0x0080,
+ MAZE_EVENT_DRAIN = 0x0100,
+ MAZE_EVENT_STONE = 0x0200,
+ MAZE_EVENT_BLOCK = 0x0400,
+ MAZE_EVENT_FALLEN_BLOCK = 0x0800
+};
+
+struct Catacombs {
+ int _sceneNum;
+ int _exit[4];
+ int _fromDirection[4];
+ int _flags;
+};
+
class GamePhantom : public Game {
friend class Game;
+
+private:
+ void genericObjectExamine();
+ void stopWalker();
+ void stopWalkerBasic();
+
+ Catacombs *_catacombs;
+ int _catacombSize;
+
protected:
GamePhantom(MADSEngine *vm);
@@ -78,7 +111,8 @@ protected:
virtual void checkShowDialog();
public:
PhantomGlobals _globals;
- StoryMode _storyMode;
+ Difficulty _difficulty;
+
virtual Globals &globals() { return _globals; }
@@ -89,20 +123,25 @@ public:
virtual void step();
virtual void synchronize(Common::Serializer &s, bool phase1);
-};
+ void setupCatacombs();
+ void enterCatacombs(bool val);
+ void initCatacombs();
+ void moveCatacombs(int dir);
+ int exitCatacombs(int dir);
+ void newCatacombRoom(int fromRoom, int fromExit);
+};
+// Section handlers aren't needed in ScummVM implementation
class Section1Handler : public SectionHandler {
public:
Section1Handler(MADSEngine *vm) : SectionHandler(vm) {}
- // TODO: Properly implement handler methods
virtual void preLoadSection() {}
virtual void sectionPtr2() {}
virtual void postLoadSection() {}
};
-// TODO: Properly implement handler classes
typedef Section1Handler Section2Handler;
typedef Section1Handler Section3Handler;
typedef Section1Handler Section4Handler;
diff --git a/engines/mads/phantom/globals_phantom.cpp b/engines/mads/phantom/globals_phantom.cpp
index e0db0a1bb0..eea84762fe 100644
--- a/engines/mads/phantom/globals_phantom.cpp
+++ b/engines/mads/phantom/globals_phantom.cpp
@@ -28,12 +28,12 @@ namespace MADS {
namespace Phantom {
-PhantomGlobals::PhantomGlobals()
- : Globals() {
+PhantomGlobals::PhantomGlobals() : Globals() {
// Initialize lists
resize(210);
_spriteIndexes.resize(30);
_sequenceIndexes.resize(30);
+ _animationIndexes.resize(30);
}
void PhantomGlobals::synchronize(Common::Serializer &s) {
@@ -41,6 +41,7 @@ void PhantomGlobals::synchronize(Common::Serializer &s) {
_spriteIndexes.synchronize(s);
_sequenceIndexes.synchronize(s);
+ _animationIndexes.synchronize(s);
}
diff --git a/engines/mads/phantom/globals_phantom.h b/engines/mads/phantom/globals_phantom.h
index c23b53cdf5..f120df3c47 100644
--- a/engines/mads/phantom/globals_phantom.h
+++ b/engines/mads/phantom/globals_phantom.h
@@ -99,9 +99,20 @@ enum GlobalId {
// Section #4 Variables
kCatacombsRoom = 80,
- // TODO
+ kCatacombsMisc = 81,
+ kCatacombsFlag = 82,
+ kCatacombsFrom = 83,
+ kCatacombs309 = 84,
+ kCatacombs409a = 85,
+ kCatacombs409b = 86,
+ kCatacombs501 = 87,
+ kCatacombs309From = 88,
+ kCatacombs409aFrom = 89,
+ kCatacombs409bFrom = 90,
+ kCatacombs501From = 91,
+ kCatacombsNextRoom = 92,
kDoorIn409IsOpen = 93,
- kUnknown = 94, // TODO
+ kPriestPistonPuke = 94,
kCobwebIsCut = 95,
// Section #5 Variables
@@ -124,6 +135,7 @@ class PhantomGlobals : public Globals {
public:
SynchronizedList _spriteIndexes;
SynchronizedList _sequenceIndexes;
+ SynchronizedList _animationIndexes;
public:
/**
* Constructor
diff --git a/engines/mads/phantom/phantom_scenes.cpp b/engines/mads/phantom/phantom_scenes.cpp
index f7f4d154df..bfb521e369 100644
--- a/engines/mads/phantom/phantom_scenes.cpp
+++ b/engines/mads/phantom/phantom_scenes.cpp
@@ -29,6 +29,10 @@
#include "mads/phantom/game_phantom.h"
#include "mads/phantom/phantom_scenes.h"
#include "mads/phantom/phantom_scenes1.h"
+#include "mads/phantom/phantom_scenes2.h"
+#include "mads/phantom/phantom_scenes3.h"
+#include "mads/phantom/phantom_scenes4.h"
+#include "mads/phantom/phantom_scenes5.h"
namespace MADS {
@@ -37,8 +41,9 @@ namespace Phantom {
SceneLogic *SceneFactory::createScene(MADSEngine *vm) {
Scene &scene = vm->_game->_scene;
- // TODO
- //scene.addActiveVocab(NOUN_DROP);
+ // When changing from one section to the other, set the scaling velocity
+ if ((scene._nextSceneId / 100) != (scene._priorSceneId / 100))
+ vm->_game->_player._scalingVelocity = true;
switch (scene._nextSceneId) {
// Scene group #1 (theater, stage and dressing rooms)
@@ -47,107 +52,107 @@ SceneLogic *SceneFactory::createScene(MADSEngine *vm) {
case 102: // music stands
return new Scene102(vm);
case 103: // below stage
- return new DummyScene(vm); // TODO
+ return new Scene103(vm);
case 104: // stage
- return new DummyScene(vm); // TODO
+ return new Scene104(vm);
case 105: // ground floor, storage room
- return new DummyScene(vm); // TODO
+ return new Scene105(vm);
case 106: // behind stage
- return new DummyScene(vm); // TODO
+ return new Scene106(vm);
case 107: // stage right wing
- return new DummyScene(vm); // TODO
+ return new Scene107(vm);
case 108: // stage left wing
- return new DummyScene(vm); // TODO
+ return new Scene108(vm);
case 109: // upper floor, staircase
- return new DummyScene(vm); // TODO
+ return new Scene109(vm);
case 110: // outside dressing rooms 1
- return new DummyScene(vm); // TODO
+ return new Scene110(vm);
case 111: // outside dressing rooms 2
- return new DummyScene(vm); // TODO
+ return new Scene111(vm);
case 112: // inside dressing room 1
- return new DummyScene(vm); // TODO
+ return new Scene112(vm);
case 113: // inside dressing room 2
- return new DummyScene(vm); // TODO
+ return new Scene113(vm);
case 114: // lower floor, storage room
- return new DummyScene(vm); // TODO
+ return new Scene114(vm);
case 150: // cutscene
- return new DummyScene(vm); // TODO
+ return new Scene150(vm);
// Scene group #2 (theater entrance, offices, balcony)
case 201: // entrance / ticket office
- return new DummyScene(vm); // TODO
+ return new Scene201(vm);
case 202: // outside offices / paintings room
- return new DummyScene(vm); // TODO
+ return new Scene202(vm);
case 203: // office
- return new DummyScene(vm); // TODO
+ return new Scene203(vm);
case 204: // library
- return new DummyScene(vm); // TODO
+ return new Scene204(vm);
case 205: // upper floor, outside balcony boxes
- return new DummyScene(vm); // TODO
+ return new Scene205(vm);
case 206: // balcony box #1
- return new DummyScene(vm); // TODO
+ return new Scene206(vm);
case 207: // balcony box #2
- return new DummyScene(vm); // TODO
+ return new Scene207(vm);
case 208: // stage and balcony view
- return new DummyScene(vm); // TODO
+ return new Scene208(vm);
case 250: // cutscene
- return new DummyScene(vm); // TODO
+ return new Scene250(vm);
// Scene group #3 (catwalks, chandelier, lake / catacombs entrance)
case 301: // catwalk #1 above stage
- return new DummyScene(vm); // TODO
+ return new Scene301(vm);
case 302: // catwalk #2 above stage
- return new DummyScene(vm); // TODO
+ return new Scene302(vm);
case 303: // above chandelier
- return new DummyScene(vm); // TODO
+ return new Scene303(vm);
case 304: // chandelier
- return new DummyScene(vm); // TODO
+ return new Scene304(vm);
case 305: // chandelier fight, phantom closeup
- return new DummyScene(vm); // TODO
+ return new Scene305(vm);
case 306: // chandelier #2
- return new DummyScene(vm); // TODO
+ return new Scene306(vm);
case 307: // catwalk #3 above stage
- return new DummyScene(vm); // TODO
+ return new Scene307(vm);
case 308: // hidden staircase behind balcony box
- return new DummyScene(vm); // TODO
+ return new Scene308(vm);
case 309: // lake and archway
- return new DummyScene(vm); // TODO
+ return new Scene309(vm);
case 310: // lake
- return new DummyScene(vm); // TODO
+ return new Scene310(vm);
// Scene group #4 (labyrinth)
case 401: // labyrinth room, 3 exits
- return new DummyScene(vm); // TODO
+ return new Scene401(vm);
case 403: // labyrinth room (big), 4 exits + 1 bricked door, left
- return new DummyScene(vm); // TODO
+ return new Scene403(vm);
case 404: // labyrinth room, 3 exits
- return new DummyScene(vm); // TODO
+ return new Scene404(vm);
case 406: // labyrinth room, 2 exits
- return new DummyScene(vm); // TODO
+ return new Scene406(vm);
case 407: // catacomb room / lake
- return new DummyScene(vm); // TODO
+ return new Scene407(vm);
case 408: // catacomb corridor
- return new DummyScene(vm); // TODO
+ return new Scene408(vm);
case 409: // catacomb room, door with switch panel
- return new DummyScene(vm); // TODO
+ return new Scene409(vm);
case 410: // skull switch panel
- return new DummyScene(vm); // TODO
+ return new Scene410(vm);
case 453: // Labyrinth room (big), 4 exits + 1 bricked door, right
- return new DummyScene(vm); // TODO
+ return new Scene453(vm);
case 456: // Labyrinth room, 2 exits
- return new DummyScene(vm); // TODO
+ return new Scene456(vm);
// Scene group #5 (Phantom's hideout)
case 501: // catacombs, outside phantom's hideout, lake and boat
- return new DummyScene(vm); // TODO
+ return new Scene501(vm);
case 502: // push panel trap
- return new DummyScene(vm); // TODO
+ return new Scene502(vm);
case 504: // Phantom's hideout, church organ
- return new DummyScene(vm); // TODO
+ return new Scene504(vm);
case 505: // Phantom's hideout, sarcophagus
- return new DummyScene(vm); // TODO
+ return new Scene505(vm);
case 506: // catacomb room with ramp
- return new DummyScene(vm); // TODO
+ return new Scene506(vm);
default:
error("Invalid scene %d called", scene._nextSceneId);
@@ -169,13 +174,13 @@ Common::String PhantomScene::formAnimName(char sepChar, int suffixNum) {
/*------------------------------------------------------------------------*/
-void SceneInfoPhantom::loadCodes(MSurface &depthSurface, int variant) {
- // The intro scenes do not have any codes
- if (_sceneId >= 900)
+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))
return;
- Common::String ext = Common::String::format(".WW%d", variant);
- File f(Resources::formatName(RESPREFIX_RM, _sceneId, ext));
+ File f(fileName);
MadsPack codesPack(&f);
Common::SeekableReadStream *stream = codesPack.getItemStream(0);
@@ -185,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 c0a823ae06..6b7ab697f3 100644
--- a/engines/mads/phantom/phantom_scenes.h
+++ b/engines/mads/phantom/phantom_scenes.h
@@ -46,13 +46,19 @@ enum Verb {
VERB_CLOSE = 0xB,
VERB_THROW = 0xC,
VERB_WALK_TO = 0xD,
+ VERB_ATTACK = 0x14,
VERB_CLIMB_DOWN = 0x21,
VERB_CLIMB_INTO = 0x22,
VERB_CLIMB_THROUGH = 0x23,
+ VERB_EXIT = 0x34,
VERB_EXIT_TO = 0x37,
VERB_JUMP_INTO = 0x53,
+ VERB_LASSO = 0x59,
+ VERB_LOCK = 0x5D,
VERB_LOOK_AT = 0x60,
VERB_LOOK_THROUGH = 0x61,
+ VERB_READ = 0x7A,
+ VERB_REMOVE = 0x7C,
VERB_TURN_OFF = 0x95,
VERB_TURN_ON = 0x96,
VERB_UNLOCK = 0x97,
@@ -60,9 +66,18 @@ enum Verb {
VERB_WALK_DOWN = 0x9A,
VERB_WALK_THROUGH = 0x9B,
VERB_WALK_UP = 0x9C,
+ VERB_WEAR = 0xA1,
VERB_CLIMB_UP = 0xA5,
VERB_WALK_ONTO = 0xA6,
- VERB_WALK = 0xA7
+ VERB_WALK = 0xA7,
+ VERB_ENTER = 0xEC,
+ VERB_WALK_BEHIND = 0xF3,
+ VERB_CLIMB = 0x120,
+ VERB_ATTACH = 0x131,
+ VERB_GRAPPLE = 0x133,
+ VERB_SIT_ON = 0x138,
+ VERB_SIT_IN = 0x13A,
+ VERB_WALK_DOWN_STAIRS_TO = 0x153
};
enum Noun {
@@ -74,7 +89,6 @@ enum Noun {
NOUN_ACT_CURTAIN = 0x11,
NOUN_AISLE = 0x12,
NOUN_APRON = 0x13,
- NOUN_ATTACK = 0x14,
NOUN_BACKSTAGE = 0x15,
NOUN_BEAR_PROP = 0x16,
NOUN_BLUE_FRAME = 0x17,
@@ -103,7 +117,6 @@ enum Noun {
NOUN_DRESSING_TABLE = 0x31,
NOUN_ELEPHANT_PROP = 0x32,
NOUN_ENVELOPE = 0x33,
- NOUN_EXIT = 0x34,
NOUN_EXIT_DOWN = 0x35,
NOUN_EXIT_SIGN = 0x36,
NOUN_EXIT_TO_BACKSTAGE = 0x38,
@@ -138,11 +151,9 @@ enum Noun {
NOUN_LAMP = 0x56,
NOUN_LANTERN = 0x57,
NOUN_LARGE_NOTE = 0x58,
- NOUN_LASSO = 0x59,
NOUN_LEG = 0x5A,
NOUN_LETTER = 0x5B,
NOUN_LIGHT_FIXTURE = 0x5C,
- NOUN_LOCK = 0x5D,
NOUN_LOCKING_RAIL = 0x5E,
NOUN_LOCKRAIL = 0x5F,
NOUN_MANNEQUINS = 0x62,
@@ -169,9 +180,7 @@ enum Noun {
NOUN_PROSCENIUM_ARCH = 0x77,
NOUN_PURCHASE_LINES = 0x78,
NOUN_RAILING = 0x79,
- NOUN_READ = 0x7A,
NOUN_RED_FRAME = 0x7B,
- NOUN_REMOVE = 0x7C,
NOUN_ROPE = 0x7D,
NOUN_RUG = 0x7E,
NOUN_SANDBAG = 0x7F,
@@ -201,7 +210,6 @@ enum Noun {
NOUN_WARDROBE = 0x9E,
NOUN_WASTE_BASKET = 0x9F,
NOUN_WATER_PIPE = 0xA0,
- NOUN_WEAR = 0xA1,
NOUN_WEDDING_RING = 0xA2,
NOUN_YELLOW_FRAME = 0xA3,
NOUN_PROP = 0xA4,
@@ -273,14 +281,12 @@ enum Noun {
NOUN_DECORATIVE_VASE = 0xE9,
NOUN_MARBLE_COLUMN = 0xEA,
NOUN_BOX_FIVE = 0xEB,
- NOUN_ENTER = 0xEC,
NOUN_BOX_SIX = 0xED,
NOUN_BOX_SEVEN = 0xEE,
NOUN_BOX_EIGHT = 0xEF,
NOUN_BOX_NINE = 0xF0,
NOUN_STEP = 0xF1,
NOUN_PANEL = 0xF2,
- NOUN_WALK_BEHIND = 0xF3,
NOUN_MIDDLE_DOORWAY = 0xF4,
NOUN_LIGHT = 0xF5,
NOUN_CANDLE = 0xF6,
@@ -325,7 +331,6 @@ enum Noun {
NOUN_MIDDLE_LEVEL = 0x11D,
NOUN_LOWER_LEVEL = 0x11E,
NOUN_LADDER = 0x11F,
- NOUN_CLIMB = 0x120,
NOUN_CHANDELIER_TRAP = 0x121,
NOUN_PIECE_OF_WOOD = 0x122,
NOUN_CUT_HEMP = 0x123,
@@ -342,16 +347,12 @@ enum Noun {
NOUN_MONSIEUR_RICHARD = 0x12E,
NOUN_JULIE2 = 0x12F,
NOUN_CABLE_HOOK = 0x130,
- NOUN_ATTACH = 0x131,
NOUN_ROPE_WITH_HOOK = 0x132,
- NOUN_GRAPPLE = 0x133,
NOUN_OAR = 0x134,
NOUN_ORGAN = 0x135,
NOUN_SIT_AT = 0x136,
NOUN_ORGAN_BENCH = 0x137,
- NOUN_SIT_ON = 0x138,
NOUN_LARGE_CHAIR = 0x139,
- NOUN_SIT_IN = 0x13A,
NOUN_SARCOPHAGUS = 0x13B,
NOUN_SKULL = 0x13C,
NOUN_SKULLS = 0x13D,
@@ -376,7 +377,6 @@ enum Noun {
NOUN_BOX_TEN = 0x150,
NOUN_FOYER = 0x151,
NOUN_WALK_DOWN_STAIRCASE = 0x152,
- NOUN_WALK_DOWN_STAIRS_TO = 0x153,
NOUN_HAT_RACK = 0x154,
NOUN_VASE = 0x155,
NOUN_CLOTHES_DUMMY = 0x156,
@@ -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
@@ -484,20 +484,7 @@ protected:
SceneInfoPhantom(MADSEngine *vm) : SceneInfo(vm) {}
};
-// TODO: Temporary, remove once implemented properly
-class DummyScene : public PhantomScene {
-public:
- DummyScene(MADSEngine *vm) : PhantomScene(vm) {
- warning("Unimplemented scene");
- }
-
- virtual void setup() {}
- virtual void enter() {}
- virtual void actions() {}
-};
-
} // End of namespace Phantom
-
} // End of namespace MADS
#endif /* MADS_PHANTOM_SCENES_H */
diff --git a/engines/mads/phantom/phantom_scenes1.cpp b/engines/mads/phantom/phantom_scenes1.cpp
index 2d991fd3bc..be800cf3b3 100644
--- a/engines/mads/phantom/phantom_scenes1.cpp
+++ b/engines/mads/phantom/phantom_scenes1.cpp
@@ -11,7 +11,7 @@
* 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
+ * 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
@@ -22,6 +22,7 @@
#include "common/scummsys.h"
#include "mads/mads.h"
+#include "mads/conversations.h"
#include "mads/scene.h"
#include "mads/phantom/phantom_scenes.h"
#include "mads/phantom/phantom_scenes1.h"
@@ -31,72 +32,284 @@ namespace MADS {
namespace Phantom {
void Scene1xx::setAAName() {
- // TODO
- //int idx = 0;
- //_game._aaName = Resources::formatAAName(idx);
+ _game._aaName = Resources::formatAAName(_globals[kTempInterface]);
+ _vm->_palette->setEntry(254, 43, 47, 51);
}
void Scene1xx::sceneEntrySound() {
- // TODO
+ if (!_vm->_musicFlag)
+ return;
+
+ if (_globals[kDoneBrieConv203] == 3) {
+ _vm->_sound->command(39);
+ } else {
+ switch (_scene->_nextSceneId) {
+ case 101:
+ if (!_game._visitedScenes._sceneRevisited)
+ _vm->_sound->command(38);
+ else
+ _vm->_sound->command(16);
+ break;
+
+ case 102:
+ if (_scene->_priorSceneId == 104)
+ _vm->_sound->command(27);
+ else
+ _vm->_sound->command(16);
+ break;
+
+ case 103:
+ if (_globals[kJacquesStatus] == 2) {
+ _vm->_sound->command(32);
+ _globals[kJacquesStatus] = 3;
+ } else
+ _vm->_sound->command(16);
+ break;
+
+ case 104:
+ if ((_vm->_gameConv->restoreRunning() == 7) || (_scene->_priorSceneId == 301)) {
+ _vm->_sound->command(33);
+ } else if (!_globals[kRoom103104Transition] && !_globals[kObservedPhan104]) {
+ _vm->_sound->command(37);
+ _globals[kObservedPhan104] = true;
+ } else
+ _vm->_sound->command(16);
+ break;
+
+ case 111:
+ if (_scene->_priorSceneId == 150)
+ _vm->_sound->command(38);
+ else if (_globals[kLeaveAngelMusicOn])
+ _vm->_sound->command(34);
+ else
+ _vm->_sound->command(16);
+ break;
+ case 113:
+ if (_globals[kLeaveAngelMusicOn])
+ _vm->_sound->command(34);
+ else if (_globals[kCurrentYear] == 1993)
+ _vm->_sound->command(36);
+ else
+ _vm->_sound->command(35);
+ break;
+
+ default:
+ if ((_scene->_priorSceneId != 204) && (_scene->_nextSceneId != 150))
+ _vm->_sound->command(16);
+ break;
+ }
+ }
+}
+
+void Scene1xx::setPlayerSpritesPrefix() {
+ _vm->_sound->command(5);
+
+ Common::String oldName = _game._player._spritesPrefix;
+
+ if (!_game._player._forcePrefix)
+ _game._player._spritesPrefix = "RAL";
+
+ if (oldName != _game._player._spritesPrefix)
+ _game._player._spritesChanged = true;
+
+ _game._player._scalingVelocity = true;
}
/*------------------------------------------------------------------------*/
Scene101::Scene101(MADSEngine *vm) : Scene1xx(vm) {
-
+ _chanStatus = -1;
+ _wipeStatus = -1;
+ _callingStatus = -1;
+ _chandelierStatus = -1;
+ _callingFrame = -1;
+ _chandelierFrame = -1;
+ _convCounter = 0;
+ _talkCounter = -1;
+ _brieAnimId = 0;
+ _startWalkingFl = false;
+ _startWalking0Fl = false;
+ _anim0Running = false;
+ _anim1Running = false;
+ _startSittingFl = false;
}
void Scene101::synchronize(Common::Serializer &s) {
Scene1xx::synchronize(s);
-
+ s.syncAsSint16LE(_chanStatus);
+ s.syncAsSint16LE(_wipeStatus);
+ s.syncAsSint16LE(_callingStatus);
+ s.syncAsSint16LE(_chandelierStatus);
+ s.syncAsSint16LE(_callingFrame);
+ s.syncAsSint16LE(_chandelierFrame);
+ s.syncAsSint16LE(_convCounter);
+ s.syncAsSint16LE(_talkCounter);
+ s.syncAsSint16LE(_brieAnimId);
+ s.syncAsByte(_startWalkingFl);
+ s.syncAsByte(_startWalking0Fl);
+ s.syncAsByte(_anim0Running);
+ s.syncAsByte(_anim1Running);
+ s.syncAsByte(_startSittingFl);
}
void Scene101::setup() {
- //setPlayerSpritesPrefix();
+ setPlayerSpritesPrefix();
setAAName();
+ _scene->addActiveVocab(NOUN_MONSIEUR_BRIE);
}
void Scene101::enter() {
- // TODO
+ _vm->_disableFastwalk = true;
+
+ if (_scene->_priorSceneId != RETURNING_FROM_DIALOG) {
+ _chanStatus = _wipeStatus = -1;
+ _startWalkingFl = _startWalking0Fl = false;
+ _anim0Running = _anim1Running = false;
+ _startSittingFl = false;
+ }
+
+ // Load conversations
+ _vm->_gameConv->load(0);
+ _vm->_gameConv->load(1);
if (_globals[kCurrentYear] == 1993) {
_globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('z', -1));
- // TODO
- //_scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
} else {
- // TODO
+ _scene->_hotspots.activate(NOUN_CHANDELIER, false);
+ }
+
+ if (_globals[kBrieTalkStatus] == 0) {
+ _game._player.firstWalk(Common::Point(-20, 75), FACING_EAST, Common::Point(18, 79), FACING_EAST, true);
+ _callingStatus = 0;
+ _chandelierStatus = 3;
+ _game._player.setWalkTrigger(50);
+
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('b', 9), 1);
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('b', 8), 1);
+
+ _anim0Running = true;
+ _anim1Running = true;
+
+ _brieAnimId = _scene->_dynamicHotspots.add(NOUN_MONSIEUR_BRIE, VERB_WALKTO, SYNTAX_SINGULAR_MASC, EXT_NONE, Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots[_brieAnimId]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_brieAnimId, Common::Point(490, 119), FACING_NONE);
+ _scene->setDynamicAnim(_brieAnimId, _globals._animationIndexes[0], 0);
+ _scene->setDynamicAnim(_brieAnimId, _globals._animationIndexes[0], 1);
+ _scene->setDynamicAnim(_brieAnimId, _globals._animationIndexes[0], 2);
+ _scene->setDynamicAnim(_brieAnimId, _globals._animationIndexes[0], 3);
+ _scene->setDynamicAnim(_brieAnimId, _globals._animationIndexes[0], 4);
+
+ int tmpIdx = _scene->_dynamicHotspots.add(NOUN_MONSIEUR_BRIE, VERB_WALKTO, SYNTAX_SINGULAR_MASC, EXT_NONE, Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots[tmpIdx]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(tmpIdx, Common::Point(25, 80), FACING_NONE);
+ _scene->setDynamicAnim(tmpIdx, _globals._animationIndexes[1], 1);
+ _scene->setDynamicAnim(tmpIdx, _globals._animationIndexes[1], 2);
+
+ _talkCounter = 0;
+ } else if (_globals[kBrieTalkStatus] == 1) {
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('b', 9), 1);
+ _brieAnimId = _scene->_dynamicHotspots.add(NOUN_MONSIEUR_BRIE, VERB_WALKTO, SYNTAX_SINGULAR_MASC, EXT_NONE, Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots[_brieAnimId]._articleNumber = PREP_ON;
+ _scene->setDynamicAnim(_brieAnimId, _globals._animationIndexes[1], 1);
+ _scene->setDynamicAnim(_brieAnimId, _globals._animationIndexes[1], 2);
+ _anim1Running = true;
+ _talkCounter = 0;
+ _chandelierStatus = 3;
+
+ if (_vm->_gameConv->restoreRunning() == 1) {
+ _vm->_gameConv->run(1);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ _chandelierStatus = 4;
+ _scene->setAnimFrame(_globals._animationIndexes[1], 25);
+ }
+ } else if (_scene->_priorSceneId == 202) {
+ if (_globals[kJacquesStatus] == 1)
+ _globals[kJacquesStatus] = 2;
+ _game._player.firstWalk(Common::Point(-20, 75), FACING_EAST, Common::Point(18, 79), FACING_EAST, true);
+ } else if ((_scene->_priorSceneId == 102) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
+ _game._player.firstWalk(Common::Point(655, 130), FACING_WEST, Common::Point(625, 127), FACING_WEST, true);
+ _scene->setCamera(Common::Point(320, 0));
}
- // TODO
+ sceneEntrySound();
}
void Scene101::step() {
- // TODO
+ if (_anim0Running)
+ handleAnimation0();
+
+ if ((_globals[kWalkerConverse] == 2) || (_globals[kWalkerConverse] == 3)) {
+ ++_convCounter;
+ if (_convCounter > 200)
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ }
+
+ if (_anim1Running) {
+ handleAnimation1();
+
+ if (_scene->getAnimFrame(_globals._animationIndexes[1]) == 80) {
+ _game._player._stepEnabled = true;
+ _game._player.setWalkTrigger(55);
+ }
+ }
+
+ if (_scene->_posAdjust.x > 200 && !_startSittingFl && (_globals[kBrieTalkStatus] != 2)) {
+ _startSittingFl = true;
+ _game._player.walk(Common::Point(490, 119), FACING_NORTHEAST);
+ _game._player._stepEnabled = false;
+ _game._player.setWalkTrigger(55);
+ _chandelierStatus = 4;
+ }
+
+ if (_game._trigger == 55) {
+ _game._player._stepEnabled = true;
+ _vm->_gameConv->run(1);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ _chandelierFrame = -1;
+ _talkCounter = 0;
+ }
+
+ if (_game._trigger == 50) {
+ _vm->_gameConv->run(0);
+ _callingStatus = 1;
+ }
}
void Scene101::preActions() {
if (_action.isAction(VERB_EXIT_TO, NOUN_ORCHESTRA_PIT)) {
- // TODO: Handle Brie
- _game._player._walkOffScreenSceneId = 102;
+ if ((_globals[kBrieTalkStatus] == 2) || _startWalkingFl) {
+ _game._player._walkOffScreenSceneId = 102;
+ _globals[kBrieTalkStatus] = 2;
+ } else {
+ _vm->_gameConv->run(0);
+ _game._player._needToWalk = false;
+ }
} else if (_action.isAction(VERB_EXIT_TO, NOUN_GRAND_FOYER)) {
- // TODO: Handle Brie
- _game._player._walkOffScreenSceneId = 202;
- } else if (_action.isAction(VERB_TAKE, NOUN_MONSIEUR_BRIE)) {
- _vm->_dialogs->show(10121);
- } else if (_action.isAction(VERB_TALK_TO, NOUN_MONSIEUR_BRIE)) {
- if (_globals[kBrieTalkStatus] == 2)
+ if ((_globals[kBrieTalkStatus] == 2) || _startWalkingFl)
+ _game._player._walkOffScreenSceneId = 202;
+ else {
+ _vm->_gameConv->run(0);
_game._player._needToWalk = false;
- }
-
- // TODO
+ }
+ } else if (_action.isAction(VERB_TAKE, NOUN_MONSIEUR_BRIE))
+ _vm->_dialogs->show(10121);
+ else if (_action.isAction(VERB_TALK_TO, NOUN_MONSIEUR_BRIE) && (_globals[kBrieTalkStatus] == 2))
+ _game._player._needToWalk = false;
}
void Scene101::actions() {
- // TODO: Brie conversation
-
- // TODO: Look around
-
- if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_vm->_gameConv->activeConvId() == 0)
+ handleConversation0();
+ else if (_vm->_gameConv->activeConvId() == 1)
+ handleConversation1();
+ else if (_action._lookFlag) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(10110);
+ else
+ _vm->_dialogs->show(10111);
+ } else if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
if (_action.isObject(NOUN_AISLE)) {
_vm->_dialogs->show(10112);
} else if (_action.isObject(NOUN_CHANDELIER)) {
@@ -106,8 +319,10 @@ void Scene101::actions() {
} else if (_action.isObject(NOUN_SIDE_WALL)) {
_vm->_dialogs->show(10115);
} else if (_action.isObject(NOUN_SEATS)) {
- // TODO: Finish this
- _vm->_dialogs->show(10116);
+ if ((_globals[kBrieTalkStatus] > 1) || _startWalkingFl)
+ _vm->_dialogs->show(10119);
+ else
+ _vm->_dialogs->show(10116);
} else if (_action.isObject(NOUN_GRAND_FOYER)) {
_vm->_dialogs->show(10117);
} else if (_action.isObject(NOUN_ORCHESTRA_PIT)) {
@@ -115,64 +330,357 @@ void Scene101::actions() {
} else if (_action.isObject(NOUN_MONSIEUR_BRIE)) {
_vm->_dialogs->show(10120);
}
-
- _game._player._stepEnabled = true;
} else if (_action.isAction(VERB_TALK_TO, NOUN_MONSIEUR_BRIE)) {
if (_globals[kBrieTalkStatus] == 2)
_vm->_dialogs->show(10122);
- _game._player._stepEnabled = true;
- } else if (_action.isAction(VERB_TAKE, NOUN_MONSIEUR_BRIE)) {
- _game._player._stepEnabled = true;
+ } else if (!_action.isAction(VERB_TAKE, NOUN_MONSIEUR_BRIE))
+ return;
+
+ _action._inProgress = false;
+}
+
+void Scene101::handleConversation0() {
+ _vm->_gameConv->setHeroTrigger(90);
+
+ if (_game._trigger == 90) {
+ _globals[kBrieTalkStatus] = 1;
+ _startWalking0Fl = true;
+ }
+}
+
+void Scene101::handleConversation1() {
+ if ((_action._activeAction._verbId >= 0) && (_action._activeAction._verbId <= 27)) {
+ bool interlocutorFl = false;
+
+ if (_game._trigger == 60) {
+ switch (_action._activeAction._verbId) {
+ case 0:
+ _chandelierStatus = 6;
+ _wipeStatus = 2;
+ break;
+
+ case 1:
+ _chandelierStatus = 2;
+ _chanStatus = 9;
+ break;
+
+ case 4:
+ _chandelierStatus = 0;
+ _chanStatus = -1;
+ _wipeStatus = -1;
+ break;
+
+ case 8:
+ case 10:
+ case 18:
+ case 22:
+ case 24:
+ _startWalkingFl = true;
+ _chanStatus = -1;
+ _wipeStatus = -1;
+ _globals[kWalkerConverse] = 0;
+ _vm->_gameConv->setInterlocutorTrigger(105);
+ interlocutorFl = true;
+ break;
+
+ case 12:
+ _chandelierStatus = 5;
+ _chanStatus = -1;
+ _wipeStatus = -1;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (!interlocutorFl)
+ _vm->_gameConv->setInterlocutorTrigger(60);
+
+ _vm->_gameConv->setHeroTrigger(70);
+
+ _talkCounter = 0;
+
+ if (_game._trigger == 60) {
+ if (!_startWalkingFl)
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+
+ _chandelierStatus = 2;
+ } else if ((_game._trigger == 70) && !_startWalkingFl) {
+ _chandelierStatus = 4;
+ _chanStatus = -1;
+ _wipeStatus = -1;
+ if (!_startWalkingFl)
+ _globals[kWalkerConverse] = _vm->getRandomNumber(2, 3);
+
+ _convCounter = 0;
+ }
+ }
+}
+
+void Scene101::handleAnimation0() {
+ if (_scene->getAnimFrame(_globals._animationIndexes[0]) == _callingFrame)
+ return;
+
+ _callingFrame = _scene->getAnimFrame(_globals._animationIndexes[0]);
+ int resetFrame = -1;
+ switch (_callingFrame) {
+ case 1:
+ case 9:
+ case 12:
+ if (_callingStatus == 1) {
+ if (_callingFrame == 9) {
+ if (_startWalking0Fl) {
+ resetFrame = 13;
+ _callingStatus = 3;
+ } else
+ _callingStatus = 2;
+ } else
+ resetFrame = 1;
+ }
+
+ if (_callingStatus == 0) {
+ if (_startWalking0Fl) {
+ resetFrame = 60;
+ _callingStatus = 3;
+ } else
+ resetFrame = 0;
+ }
+
+ if (_callingStatus == 2) {
+ if (_startWalking0Fl) {
+ resetFrame = 13;
+ _callingStatus = 3;
+ } else {
+ ++_talkCounter;
+
+ if (_talkCounter < 18) {
+ if (_vm->getRandomNumber(1, 2) == 1)
+ resetFrame = 7;
+ else
+ resetFrame = 10;
+ } else {
+ resetFrame = 54;
+ _callingStatus = 0;
+ }
+ }
+ }
+ break;
+
+ case 53:
+ _anim0Running = false;
+ _scene->freeAnimation(0);
+ break;
+
+ case 59:
+ if (_startWalking0Fl) {
+ resetFrame = 60;
+ _callingStatus = 3;
+ } else {
+ resetFrame = 0;
+ _callingStatus = 0;
+ }
+ break;
+
+ case 66:
+ resetFrame = 24;
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[0], resetFrame);
+ _callingFrame = resetFrame;
+ }
+}
+
+void Scene101::handleAnimation1() {
+ if (_scene->getAnimFrame(_globals._animationIndexes[1]) == _chandelierFrame)
+ return;
+
+ _chandelierFrame = _scene->getAnimFrame(_globals._animationIndexes[1]);
+ int resetFrame = -1;
+ switch (_chandelierFrame) {
+ case 1:
+ if (_chandelierStatus == 3)
+ resetFrame = 0;
+ break;
+
+ case 11:
+ case 14:
+ case 17:
+ case 19:
+ case 26:
+ case 44:
+ case 333:
+ if (_talkCounter == _chanStatus) {
+ _chandelierStatus = 0;
+ ++_talkCounter;
+ _chanStatus = -1;
+ }
+
+ if (_talkCounter == _wipeStatus) {
+ _chandelierStatus = 6;
+ ++_talkCounter;
+ _wipeStatus = -1;
+ }
+
+ if (_startWalkingFl) {
+ if (_vm->_gameConv->activeConvId() == 1) {
+ if (_talkCounter > 13)
+ _chandelierStatus = 1;
+ } else
+ _chandelierStatus = 1;
+ }
+
+ switch (_chandelierStatus) {
+ case 0:
+ resetFrame = 27;
+ _chandelierStatus = 2;
+ break;
+
+ case 1:
+ _globals[kBrieTalkStatus] = 2;
+ resetFrame = 45;
+ if (_vm->_gameConv->activeConvId() == 1)
+ _vm->_gameConv->stop();
+ _scene->_dynamicHotspots.remove(_brieAnimId);
+ _game._player._stepEnabled = false;
+ break;
+
+ case 2:
+ ++_talkCounter;
+ if (_talkCounter < 15) {
+ switch (_vm->getRandomNumber(1, 3)) {
+ case 1:
+ resetFrame = 12;
+ break;
+
+ case 2:
+ resetFrame = 14;
+ break;
+
+ case 3:
+ resetFrame = 17;
+ }
+ } else {
+ _chandelierStatus = 4;
+ resetFrame = 25;
+ }
+ break;
+
+ case 4:
+ resetFrame = 25;
+ break;
+
+ case 5:
+ resetFrame = 21;
+ _chandelierStatus = 2;
+ break;
+
+ case 6:
+ resetFrame = 316;
+ _chandelierStatus = 2;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 315:
+ _scene->freeAnimation(1);
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[1], resetFrame);
+ _chandelierFrame = resetFrame;
}
}
/*------------------------------------------------------------------------*/
Scene102::Scene102(MADSEngine *vm) : Scene1xx(vm) {
- _animRunningFl = false;
+ _anim0Running = false;
}
void Scene102::synchronize(Common::Serializer &s) {
Scene1xx::synchronize(s);
- s.syncAsByte(_animRunningFl);
+ s.syncAsByte(_anim0Running);
}
void Scene102::setup() {
- //setPlayerSpritesPrefix();
+ setPlayerSpritesPrefix();
setAAName();
}
void Scene102::enter() {
- _animRunningFl = false;
+ _anim0Running = false;
_globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 0));
_globals._spriteIndexes[3] = _scene->_sprites.addSprites("*RAL86");
if (_globals[kCurrentYear] == 1993) {
_globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('z', -1));
- // TODO
- //_scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
} else {
- // TODO
+ _scene->_hotspots.activate(NOUN_CHANDELIER, false);
}
if (_scene->_priorSceneId == 101) {
_game._player._playerPos = Common::Point(97, 79);
_game._player._facing = FACING_SOUTHEAST;
- // TODO
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 4);
_game._player.walk(Common::Point(83, 87), FACING_SOUTHEAST);
_scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
} else if (_scene->_priorSceneId == 104) {
// Player fell from pit -> death
- // TODO
- } else if (_scene->_priorSceneId == 103 || _scene->_priorSceneId != -1) {
+ Common::Point deathPos = Common::Point(0, 0);
+ int deathScale = 0;
+ int deathDepth = 0;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+
+ switch (_globals[36]) {
+ case 0:
+ deathPos = Common::Point(221, 57);
+ deathScale = 50;
+ deathDepth = 14;
+ break;
+
+ case 1:
+ deathPos = Common::Point(219, 85);
+ deathScale = 60;
+ deathDepth = 6;
+ break;
+
+ case 2:
+ deathPos = Common::Point(257, 138);
+ deathScale = 76;
+ deathDepth = 1;
+ break;
+
+ default:
+ break;
+ }
+ _scene->_userInterface.emptyConversationList();
+ _scene->_userInterface.setup(kInputConversation);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], deathDepth);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[3], deathPos);
+ _scene->_sequences.setScale(_globals._sequenceIndexes[3], deathScale);
+ _scene->_sequences.addTimer(120, 65);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 4);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+ } else if (_scene->_priorSceneId == 103 || _scene->_priorSceneId != RETURNING_FROM_LOADING) {
_game._player._playerPos = Common::Point(282, 145);
_game._player._facing = FACING_WEST;
- _animRunningFl = true;
- // TODO: Door closing animation
+ _anim0Running = true;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('d', 1), 60);
} else if (_scene->_priorSceneId == -1) {
- // TODO
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 4);
_scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
}
@@ -180,52 +688,56 @@ void Scene102::enter() {
}
void Scene102::step() {
- if (_game._trigger == 60) { // Door closes
- // TODO
- _animRunningFl = false;
- } else if (_game._trigger == 65) { // Death
- // TODO
- _scene->_currentSceneId = 104;
+ if (_game._trigger == 60) {
+ // Door closes
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 4);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+ _anim0Running = false;
+ } else if (_game._trigger == 65) {
+ // Death
+ if (_globals[kDeathLocation] == 0)
+ _vm->_dialogs->show(10232);
+ else
+ _vm->_dialogs->show(10229);
+
+ _vm->_sound->command(16);
+ _scene->_nextSceneId = 104;
}
}
void Scene102::preActions() {
- if (_action.isAction(VERB_OPEN, NOUN_ORCHESTRA_DOOR) || _action.isAction(VERB_PUSH, NOUN_ORCHESTRA_DOOR)) {
+ if (_action.isAction(VERB_OPEN, NOUN_ORCHESTRA_DOOR) || _action.isAction(VERB_PUSH, NOUN_ORCHESTRA_DOOR))
_game._player.walk(Common::Point(282, 145), FACING_EAST);
- }
}
void Scene102::actions() {
if (_action.isAction(VERB_WALK_DOWN, NOUN_AISLE)) {
_scene->_nextSceneId = 101;
- _game._player._stepEnabled = true;
- }
-
- if (_action.isAction(VERB_WALK_THROUGH, NOUN_ORCHESTRA_DOOR) ||
+ } else if (_action.isAction(VERB_WALK_THROUGH, NOUN_ORCHESTRA_DOOR) ||
_action.isAction(VERB_PUSH, NOUN_ORCHESTRA_DOOR) ||
_action.isAction(VERB_OPEN, NOUN_ORCHESTRA_DOOR)) {
- if (_animRunningFl) {
- // TODO
+ if (_anim0Running) {
+ _scene->_sequences.addTimer(15, 70);
+ _game._player._stepEnabled = false;
} else {
- _scene->_nextSceneId = 103; // FIXME: temporary HACK - remove!
-
switch (_game._trigger) {
case 70: // try again
case 0:
- // TODO
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('d', 0), 1);
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
break;
case 1:
_scene->_nextSceneId = 103;
break;
+ default:
+ break;
}
}
-
- _game._player._stepEnabled = true;
- }
-
- // TODO: Look around
-
- if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ } else if (_action._lookFlag)
+ _vm->_dialogs->show(10210);
+ else if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
if (_action.isObject(NOUN_PIT))
_vm->_dialogs->show(10211);
else if (_action.isObject(NOUN_SEATS))
@@ -263,18 +775,8777 @@ void Scene102::actions() {
_vm->_dialogs->show(10227);
else if (_action.isObject(NOUN_CHANDELIER))
_vm->_dialogs->show(10231);
+ } else if (_action.isAction(VERB_CLOSE, NOUN_ORCHESTRA_DOOR))
+ _vm->_dialogs->show(10228);
+
+ _game._player._stepEnabled = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene103::Scene103(MADSEngine *vm) : Scene1xx(vm) {
+ _jacquesAction = -1;
+ _lastRandom = -1;
+ _standPosition = -1;
+ _hotspotPrompt1 = -1;
+ _hotspotPrompt2 = -1;
+ _hotspotPrompt3 = -1;
+ _hotspotPrompt4 = -1;
+ _hotspotPrompt5 = -1;
+ _hotspotRightFloor1 = -1;
+ _hotspotRightFloor2 = -1;
+ _hotspotLeftFloor1 = -1;
+ _hotspotLeftFloor2 = -1;
+ _hotspotGentleman = -1;
+ _convCount = -1;
+ _lastStairFrame = -1;
+ _lastJacquesFrame = -1;
+ _talkCount = -1;
+
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _anim2ActvFl = false;
+ _anim3ActvFl = false;
+ _anim4ActvFl = false;
+ _anim5ActvFl = false;
+ _anim6ActvFl = false;
+ _climbThroughTrapFl = false;
+ _guardFrameFl = false;
+ _sitFl = false;
+}
+
+void Scene103::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+
+ s.syncAsSint16LE(_jacquesAction);
+ s.syncAsSint16LE(_lastRandom);
+ s.syncAsSint16LE(_standPosition);
+ s.syncAsSint16LE(_hotspotPrompt1);
+ s.syncAsSint16LE(_hotspotPrompt2);
+ s.syncAsSint16LE(_hotspotPrompt3);
+ s.syncAsSint16LE(_hotspotPrompt4);
+ s.syncAsSint16LE(_hotspotPrompt5);
+ s.syncAsSint16LE(_hotspotRightFloor1);
+ s.syncAsSint16LE(_hotspotRightFloor2);
+ s.syncAsSint16LE(_hotspotLeftFloor1);
+ s.syncAsSint16LE(_hotspotLeftFloor2);
+ s.syncAsSint16LE(_convCount);
+ s.syncAsSint16LE(_lastStairFrame);
+
+ s.syncAsByte(_anim0ActvFl);
+ s.syncAsByte(_anim1ActvFl);
+ s.syncAsByte(_anim2ActvFl);
+ s.syncAsByte(_anim3ActvFl);
+ s.syncAsByte(_anim4ActvFl);
+ s.syncAsByte(_anim5ActvFl);
+ s.syncAsByte(_anim6ActvFl);
+ s.syncAsByte(_climbThroughTrapFl);
+ s.syncAsByte(_guardFrameFl);
+ s.syncAsByte(_sitFl);
+}
+
+void Scene103::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ _scene->_variant = 0;
+
+ if ((_globals[kPrompterStandStatus] == 1) || (_globals[kCurrentYear] == 1881)) {
+ _scene->_variant = 1;
+ if ((_globals[kJacquesStatus] == 0) && (_globals[kCurrentYear] == 1881))
+ _scene->_variant = 2;
+ else if ((_globals[kJacquesStatus] >= 1) && (_globals[kCurrentYear] == 1881))
+ _scene->_variant = 3;
+ }
+
+ _scene->addActiveVocab(NOUN_PROMPTERS_STAND);
+ _scene->addActiveVocab(NOUN_JACQUES);
+ _scene->addActiveVocab(NOUN_GENTLEMAN);
+ _scene->addActiveVocab(VERB_CLIMB);
+}
+
+void Scene103::enter() {
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _anim2ActvFl = false;
+ _anim3ActvFl = false;
+ _anim4ActvFl = false;
+ _anim5ActvFl = false;
+ _anim6ActvFl = false;
+ _climbThroughTrapFl = false;
+ _guardFrameFl = false;
+ _sitFl = false;
+ _jacquesAction = 1;
+ _lastRandom = 0;
+ _standPosition = 0;
+ }
+
+ if (_globals[kJacquesStatus] >= 1) {
+ if (_game._objects.isInRoom(OBJ_KEY)) {
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('x', 2));
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites("*RRD_9");
+ }
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('f', 3));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('c', 1));
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('f', 1));
+ } else {
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('f', 0));
+ _globals._spriteIndexes[10] = _scene->_sprites.addSprites(formAnimName('a', 3));
+ }
+
+ _globals._spriteIndexes[9] = _scene->_sprites.addSprites(formAnimName('x', 3));
+ _globals._spriteIndexes[11] = _scene->_sprites.addSprites(formAnimName('a', 2));
+ _globals._spriteIndexes[12] = _scene->_sprites.addSprites(formAnimName('f', 2));
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites("*RDR_6");
+
+ adjustRails(_scene->_variant);
+
+ _scene->_hotspots.activate(NOUN_JACQUES, false);
+ _scene->_hotspots.activate(NOUN_KEY, false);
+
+ _vm->_gameConv->load(12);
+
+ if (_globals[kTrapDoorStatus] == 0) {
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 5);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+
+ _globals._sequenceIndexes[9] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[9], false, 2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 3);
+ } else if (_globals[kTrapDoorStatus] == 1) {
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+
+ _globals._sequenceIndexes[9] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[9], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 3);
+ }
+
+ Common::Point promptPos;
+ Facing promptFacing;
+
+ if (_globals[kJacquesStatus] == 0) {
+ promptPos = Common::Point(115, 142);
+ promptFacing = FACING_NORTHEAST;
+ } else {
+ promptPos = Common::Point(171, 142);
+ promptFacing = FACING_NORTHWEST;
+ }
+
+ if ((_globals[kPrompterStandStatus] == 1) || (_globals[kCurrentYear] == 1881)) {
+ if (_globals[kJacquesStatus] >= 1) {
+ _globals._sequenceIndexes[7] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[7], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 1);
+
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 4);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(154, 139));
+
+ } else {
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 4);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(154, 139));
+
+ _globals._sequenceIndexes[12] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[12], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[12], 1);
+ }
+
+ _hotspotPrompt1 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(121, 79, 121 + 40, 79 + 63));
+ _scene->_dynamicHotspots[_hotspotPrompt1]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotPrompt1, promptPos, promptFacing);
+
+ _hotspotPrompt2 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(161, 67, 161 + 16, 67 + 75));
+ _scene->_dynamicHotspots[_hotspotPrompt2]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotPrompt2, promptPos, promptFacing);
+
+ _hotspotPrompt3 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(177, 90, 177 + 18, 90 + 52));
+ _scene->_dynamicHotspots[_hotspotPrompt3]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotPrompt3, promptPos, promptFacing);
+
+ _hotspotPrompt4 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(114, 100, 114 + 7, 100 + 38));
+ _scene->_dynamicHotspots[_hotspotPrompt4]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotPrompt4, promptPos, promptFacing);
+
+ _hotspotPrompt5 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_CLIMB, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(121, 49, 121 + 40, 49 + 30));
+ _scene->_dynamicHotspots[_hotspotPrompt5]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotPrompt5, Common::Point(196, 134), FACING_SOUTHWEST);
+ _scene->_dynamicHotspots.setCursor(_hotspotPrompt5, CURSOR_GO_UP);
+
+ _hotspotRightFloor1 = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(154, 6, 154 + 41, 6 + 6));
+ _scene->_dynamicHotspots[_hotspotRightFloor1]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotRightFloor1, Common::Point(171, 142), FACING_NONE);
+
+ _hotspotRightFloor2 = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(114, 136, 114 + 32, 136 + 6));
+ _scene->_dynamicHotspots[_hotspotRightFloor2]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotRightFloor2, Common::Point(127, 140), FACING_NONE);
+
+ if ((_globals[kJacquesStatus] == 0) && (_globals[kCurrentYear] == 1881)) {
+ if (_globals[kJacquesNameIsKnown] >= 1) {
+ _hotspotGentleman = _scene->_dynamicHotspots.add(NOUN_JACQUES, VERB_WALKTO, SYNTAX_SINGULAR_MASC, EXT_NONE, Common::Rect(156, 116, 156 + 33, 116 + 31));
+ _scene->_dynamicHotspots[_hotspotGentleman]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotGentleman, Common::Point(206, 148), FACING_NORTHWEST);
+ } else {
+ _hotspotGentleman = _scene->_dynamicHotspots.add(NOUN_GENTLEMAN, VERB_WALKTO, SYNTAX_MASC_NOT_PROPER, -1, Common::Rect(156, 116, 156 + 33, 116 + 31));
+ _scene->_dynamicHotspots[_hotspotGentleman]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotGentleman, Common::Point(206, 148), FACING_NORTHWEST);
+ }
+ int tmpIdx = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(149, 140, 149 + 13, 140 + 7));
+ _scene->_dynamicHotspots[tmpIdx]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(tmpIdx, Common::Point(155, 144), FACING_NONE);
+
+ tmpIdx = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(187, 136, 187 + 8, 136 + 7));
+ _scene->_dynamicHotspots[tmpIdx]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(tmpIdx, Common::Point(195, 139), FACING_NONE);
+ } else if ((_globals[kJacquesStatus] >= 1) && (_globals[kCurrentYear] == 1881)) {
+ _globals._sequenceIndexes[6] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[6], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 3);
+ if (_game._objects.isInRoom(OBJ_KEY)) {
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 14);
+ _scene->_hotspots.activate(NOUN_KEY, true);
+ }
+ _scene->_hotspots.activate(NOUN_JACQUES, true);
+ _scene->_dynamicHotspots.remove(_hotspotRightFloor2);
+
+ int tmpIdx = _scene->_dynamicHotspots.add(NOUN_JACQUES, VERB_WALKTO, SYNTAX_SINGULAR_MASC, EXT_NONE, Common::Rect(114, 132, 114 + 30, 132 + 10));
+ _scene->_dynamicHotspots[tmpIdx]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(tmpIdx, Common::Point(95, 144), FACING_NORTHEAST);
+
+ tmpIdx = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(94, 129, 94 + 18, 129 + 4));
+ _scene->_dynamicHotspots[tmpIdx]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(tmpIdx, Common::Point(95, 133), FACING_NONE);
+
+ tmpIdx = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(94, 132, 94 + 3, 132 + 9));
+ _scene->_dynamicHotspots[tmpIdx]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(tmpIdx, Common::Point(93, 135), FACING_NONE);
+
+ tmpIdx = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(112, 150, 112 + 21, 150 + 3));
+ _scene->_dynamicHotspots[tmpIdx]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(tmpIdx, Common::Point(118, 154), FACING_NONE);
+
+ tmpIdx = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(98, 146, 98 + 21, 146 + 4));
+ _scene->_dynamicHotspots[tmpIdx]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(tmpIdx, Common::Point(104, 148), FACING_NONE);
+ }
+ } else if (_globals[kPrompterStandStatus] == 0) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 4);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(37, 139));
+
+ _hotspotPrompt1 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(2, 79, 2 + 40, 79 + 63));
+ _scene->_dynamicHotspots[_hotspotPrompt1]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotPrompt1, Common::Point(59, 140), FACING_NORTHWEST);
+
+ _hotspotPrompt2 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(42, 67, 42 + 16, 67 + 75));
+ _scene->_dynamicHotspots[_hotspotPrompt2]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotPrompt2, Common::Point(59, 140), FACING_NORTHWEST);
+
+ _hotspotPrompt3 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(58, 90, 58 + 18, 90 + 52));
+ _scene->_dynamicHotspots[_hotspotPrompt3]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotPrompt3, Common::Point(59, 140), FACING_NORTHWEST);
+
+ _hotspotPrompt5 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_CLIMB, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(2, 49, 2 + 40, 49 + 30));
+ _scene->_dynamicHotspots[_hotspotPrompt5]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotPrompt5, Common::Point(79, 132), FACING_SOUTHWEST);
+ _scene->_dynamicHotspots.setCursor(_hotspotPrompt5, CURSOR_GO_UP);
+
+ _hotspotLeftFloor1 = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(35, 137, 35 + 40, 137 + 5));
+ _scene->_dynamicHotspots[_hotspotLeftFloor1]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotLeftFloor1, Common::Point(59, 140), FACING_NONE);
+ _hotspotLeftFloor2 = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(76, 129, 76 + 6, 129 + 6));
+ _scene->_dynamicHotspots[_hotspotLeftFloor2]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotLeftFloor2, Common::Point(80, 135), FACING_NONE);
+ }
+
+ if ((_globals[kJacquesStatus] == 0) && (_globals[kCurrentYear] == 1881)) {
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('j', 1), 1);
+ _anim0ActvFl = true;
+ _scene->setAnimFrame(_globals._animationIndexes[0], 9);
+ }
+
+ if (_scene->_priorSceneId == 104) {
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ if (_globals[kRoom103104Transition] == 0) {
+ _globals[kRoom103104Transition] = 1;
+ _globals._sequenceIndexes[10] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[10], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 4);
+ _standPosition = 1;
+ _game._player._playerPos = Common::Point(79, 132);
+ _scene->_sequences.addTimer(1, 100);
+ } else {
+ _standPosition = 2;
+ _globals._animationIndexes[3] = _scene->loadAnimation(formAnimName('w', 1), 0);
+ _anim3ActvFl = true;
+ _game._player._stepEnabled = true;
+ _game._player._playerPos = Common::Point(196, 134);
+ _scene->setAnimFrame(_globals._animationIndexes[3], 36);
+
+ _scene->deleteSequence(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 13);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(154, 139));
+ }
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ } else if (_scene->_priorSceneId == 102) {
+ _game._player.firstWalk(Common::Point(-20, 140), FACING_EAST, Common::Point(15, 147), FACING_EAST, true);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ } else if ((_scene->_priorSceneId == 105) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
+ _game._player._playerPos = Common::Point(287, 135);
+ _game._player._facing = FACING_WEST;
+ _game._player._stepEnabled = false;
+ _game._player.walk(Common::Point(252, 134), FACING_WEST);
+ _game._player.setWalkTrigger(65);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 6);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ } else if (_scene->_priorSceneId == -1) {
+ if (_standPosition == 1) {
+ _game._player._visible = false;
+ _globals._animationIndexes[5] = _scene->loadAnimation(formAnimName('w', 3), 0);
+ _anim5ActvFl = true;
+ _scene->setAnimFrame(_globals._animationIndexes[5], 33);
+ } else if (_standPosition == 2) {
+ _scene->deleteSequence(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 13);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(154, 139));
+ _game._player._visible = false;
+ _globals._animationIndexes[3] = _scene->loadAnimation(formAnimName('w', 1), 0);
+ _anim3ActvFl = true;
+ _game._player._stepEnabled = true;
+ _scene->setAnimFrame(_globals._animationIndexes[3], 36);
+ } else if (_vm->_gameConv->restoreRunning() == 12) {
+ _vm->_gameConv->run(12);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ _vm->_gameConv->exportValue(_globals[kMusicSelected]);
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ }
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene103::step() {
+ if (_anim0ActvFl)
+ handleJacquesAnim();
+
+ if (_anim3ActvFl)
+ climbRightStairs();
+
+ if (_anim5ActvFl)
+ climbLeftStairs();
+
+ if (_anim4ActvFl)
+ descendRightStairs();
+
+ if (_anim6ActvFl)
+ descendLeftStairs();
+
+ if ((_globals[kWalkerConverse] == 2) || (_globals[kWalkerConverse] == 3)) {
+ ++_convCount;
+ if (_convCount > 200)
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ }
+
+ switch (_game._trigger) {
+ case 65:
+ _scene->deleteSequence(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[1], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 6);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 66);
+ _vm->_sound->command(66);
+ break;
+
+ case 66: {
+ int syncIdx = _globals._sequenceIndexes[1];
+ _vm->_sound->command(25);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[1], SYNC_SEQ, syncIdx);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ _game._player._stepEnabled = true;
+ }
+ break;
+
+ case 80:
+ _scene->_nextSceneId = 104;
+ _scene->_reloadSceneFlag = true;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 100:
+ _scene->deleteSequence(_globals._sequenceIndexes[10]);
+ _globals._sequenceIndexes[10] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[10], false, 6, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[10], SEQUENCE_TRIGGER_EXPIRE, 0, 101);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[10], -1, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 4);
+ break;
+
+ case 101:
+ _globals._animationIndexes[5] = _scene->loadAnimation(formAnimName('w', 3), 0);
+ _anim5ActvFl = true;
+ _scene->setAnimFrame(_globals._animationIndexes[5], 33);
+ _game._player._stepEnabled = true;
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[5], SYNC_SEQ, _globals._sequenceIndexes[10]);
+ break;
+
+ default:
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 0:
+ if (_anim1ActvFl) {
+ if ((_scene->getAnimFrame(_globals._animationIndexes[1]) == 10) && !_guardFrameFl) {
+ _vm->_sound->command(64);
+ _guardFrameFl = true;
+ _scene->deleteSequence(_globals._sequenceIndexes[0]);
+ _scene->deleteSequence(_globals._sequenceIndexes[9]);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 6, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 105);
+ }
+ } else if (_anim2ActvFl) {
+ if ((_scene->getAnimFrame(_globals._animationIndexes[2]) == 7) && !_guardFrameFl) {
+ _vm->_sound->command(64);
+ _guardFrameFl = true;
+ _scene->deleteSequence(_globals._sequenceIndexes[0]);
+ _scene->deleteSequence(_globals._sequenceIndexes[9]);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[0], false, 6, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 110);
+ }
+ }
+ break;
+
+ case 105:
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ _globals._sequenceIndexes[9] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[9], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 2);
+ _guardFrameFl = false;
+ break;
+
+ case 110:
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ _globals._sequenceIndexes[9] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[9], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 2);
+ _guardFrameFl = false;
+ break;
+
+ default:
+ break;
+ }
+
+ if (_globals[kJacquesStatus] == 3) {
+ warning("TODO: add a check on the return value of _vm->_sound->command ???");
+ _vm->_sound->command(38);
+ }
+}
+
+void Scene103::preActions() {
+ if (_action.isAction(VERB_OPEN, NOUN_DOOR))
+ _game._player._needToWalk = true;
+
+ if (_action.isAction(VERB_OPEN, NOUN_DOOR_TO_PIT)) {
+ _game._player.walk(Common::Point(0, 150), FACING_WEST);
+ _game._player._walkOffScreenSceneId = 102;
+ }
+
+ if ((_standPosition != 0) && !_action.isAction(VERB_CLIMB_THROUGH, NOUN_TRAP_DOOR) &&
+ !_action.isAction(VERB_OPEN, NOUN_TRAP_DOOR) &&
+ !_action.isAction(VERB_CLIMB, NOUN_PROMPTERS_STAND) &&
+ !_action.isAction(VERB_PUSH, NOUN_TRAP_DOOR) &&
+ !_action.isAction(VERB_LOOK_THROUGH, NOUN_PROMPTERS_BOX) &&
+ !_action.isAction(VERB_PULL, NOUN_TRAP_DOOR)) {
+
+ if (_action.isAction(VERB_PULL) || _action.isAction(VERB_PUSH)) {
+ if (!_action.isObject(NOUN_LEVER) && !_game._trigger)
+ _game._player._needToWalk = false;
+ }
+
+ if ((_action.isAction(VERB_PUSH, NOUN_PROMPTERS_STAND)) || (_action.isAction(VERB_PULL, NOUN_PROMPTERS_STAND))) {
+ if (!_game._trigger)
+ _game._player._needToWalk = true;
+ }
+
+ if (_game._player._needToWalk) {
+ if (_globals[kPrompterStandStatus] == 0) {
+ switch (_game._trigger) {
+ case 0:
+ _scene->freeAnimation(5);
+ _game._player._readyToWalk = false;
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _anim5ActvFl = false;
+ _anim6ActvFl = true;
+ _globals._animationIndexes[6] = _scene->loadAnimation(formAnimName('w', 4), 1);
+ break;
+
+ case 1:
+ _game._player._playerPos = Common::Point(79, 132);
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ _standPosition = 0;
+ _game._player._readyToWalk = true;
+ if (_action.isAction(VERB_PUSH, NOUN_PROMPTERS_STAND))
+ _game._player._needToWalk = false;
+ _anim6ActvFl = false;
+ _game._player.resetFacing(FACING_NORTHEAST);
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[6]);
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ switch (_game._trigger) {
+ case 0:
+ _scene->freeAnimation(3);
+ _game._player._readyToWalk = false;
+ if (_action.isAction(VERB_PUSH, NOUN_PROMPTERS_STAND))
+ _game._player._needToWalk = true;
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _anim3ActvFl = false;
+ _anim4ActvFl = true;
+ _globals._animationIndexes[4] = _scene->loadAnimation(formAnimName('w', 2), 1);
+ break;
+
+ case 1:
+ _game._player._playerPos = Common::Point(196, 134);
+ _game._player._stepEnabled = true;
+ _game._player._readyToWalk = true;
+ if (_action.isAction(VERB_PUSH, NOUN_PROMPTERS_STAND))
+ _game._player._needToWalk = false;
+ _game._player._visible = true;
+ _standPosition = 0;
+ _anim4ActvFl = false;
+ _game._player.resetFacing(FACING_NORTHEAST);
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[4]);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ if (_standPosition == 0) {
+ if ((_action.isAction(VERB_PUSH, NOUN_PROMPTERS_STAND)) || (_action.isAction(VERB_PULL, NOUN_PROMPTERS_STAND))) {
+ if (_globals[kCurrentYear] == 1993) {
+ if (_globals[kPrompterStandStatus] == 0)
+ _game._player.walk(Common::Point(2, 138), FACING_WEST);
+ else
+ _game._player.walk(Common::Point(176, 142), FACING_WEST);
+ }
+ }
+ }
+
+ if (_action.isAction(VERB_LOOK_THROUGH, NOUN_PROMPTERS_BOX) && (_standPosition == 0) && (_globals[kPrompterStandStatus] == 0) && (_globals[kCurrentYear] == 1993))
+ _game._player.walk(Common::Point(79, 132), FACING_SOUTHWEST);
+
+ if (_action.isAction(VERB_CLIMB_THROUGH, NOUN_TRAP_DOOR) && (_standPosition == 0) && (_globals[kPrompterStandStatus] == 1) && (_globals[kTrapDoorStatus] == 0))
+ _game._player.walk(Common::Point(196, 134), FACING_SOUTHWEST);
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR_TO_PIT))
+ _game._player._walkOffScreenSceneId = 102;
+
+ if ((_action.isAction(VERB_OPEN, NOUN_DOOR) || _action.isAction(VERB_UNLOCK, NOUN_DOOR) || _action.isAction(VERB_LOCK, NOUN_DOOR)) && (_standPosition == 0))
+ _game._player.walk(Common::Point(252, 134), FACING_EAST);
+}
+
+void Scene103::actions() {
+ if (_action.isAction(VERB_OPEN, NOUN_DOOR_TO_PIT)) {
+ _scene->_nextSceneId = 102;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_vm->_gameConv->activeConvId() == 12) {
+ process_conv_jacques();
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLIMB_THROUGH, NOUN_TRAP_DOOR)) {
+ if (_globals[kTrapDoorStatus] == 1) {
+ _vm->_dialogs->show(10333);
+ _action._inProgress = false;
+ return;
+ } else if (_globals[kPrompterStandStatus] == 0) {
+ _vm->_dialogs->show(10341);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if ((_action.isAction(VERB_LOOK_THROUGH, NOUN_PROMPTERS_BOX)) && (_globals[kPrompterStandStatus] == 1)) {
+ _vm->_dialogs->show(10342);
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isAction(VERB_CLIMB, NOUN_PROMPTERS_STAND) && _standPosition == 0) ||
+ (_action.isAction(VERB_LOOK_THROUGH, NOUN_PROMPTERS_BOX) && (_standPosition == 0)) ||
+ (_action.isAction(VERB_CLIMB_THROUGH, NOUN_TRAP_DOOR) && (_standPosition == 0))) {
+ if (_globals[kPrompterStandStatus] == 0) {
+ if (_game._trigger == 0) {
+ if (_action.isAction(VERB_LOOK_THROUGH, NOUN_PROMPTERS_BOX)) {
+ _sitFl = true;
+ _globals._animationIndexes[5] = _scene->loadAnimation(formAnimName('w', 3), 115);
+ } else
+ _globals._animationIndexes[5] = _scene->loadAnimation(formAnimName('w', 3), 0);
+
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _anim5ActvFl = true;
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[5], SYNC_PLAYER, 0);
+ _action._inProgress = false;
+ return;
+ }
+ } else if (_game._trigger == 0) {
+ if (_action.isAction(VERB_CLIMB_THROUGH, NOUN_TRAP_DOOR)) {
+ _climbThroughTrapFl = true;
+ _globals._animationIndexes[3] = _scene->loadAnimation(formAnimName('w', 1), 120);
+ } else
+ _globals._animationIndexes[3] = _scene->loadAnimation(formAnimName('w', 1), 0);
+
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _anim3ActvFl = true;
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[3], SYNC_PLAYER, 0);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_CLIMB, NOUN_PROMPTERS_STAND) && (_standPosition != 0)) {
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isAction(VERB_PUSH, NOUN_PROMPTERS_STAND)) || (_action.isAction(VERB_PULL, NOUN_PROMPTERS_STAND))) {
+ if (_globals[kCurrentYear] == 1993) {
+ if (_globals[kPrompterStandStatus] == 0) {
+ switch (_game._trigger) {
+ case 0:
+ if (_globals[kPrompterStandStatus] == 0) {
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('s', 1), 75);
+ _game._player._priorTimer = _scene->_frameStartTime;
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[0], SYNC_PLAYER, 0);
+ _scene->deleteSequence(_globals._sequenceIndexes[3]);
+ }
+ break;
+
+ case 75:
+ if (_globals[kPrompterStandStatus] == 0) {
+ _globals._sequenceIndexes[12] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[12], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[12], 1);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 4);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(154, 139));
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[3], SYNC_ANIM, _globals._animationIndexes[0]);
+ _globals[kPrompterStandStatus] = 1;
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ _game._player._playerPos = Common::Point(117, 139);
+ _game._player.resetFacing(FACING_EAST);
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[0]);
+
+ _scene->_dynamicHotspots.remove(_hotspotPrompt1);
+ _scene->_dynamicHotspots.remove(_hotspotPrompt2);
+ _scene->_dynamicHotspots.remove(_hotspotPrompt3);
+ _scene->_dynamicHotspots.remove(_hotspotPrompt5);
+ _scene->_dynamicHotspots.remove(_hotspotLeftFloor1);
+ _scene->_dynamicHotspots.remove(_hotspotLeftFloor2);
+
+ _hotspotPrompt1 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(121, 79, 121 + 40, 79 + 63));
+ _scene->_dynamicHotspots[_hotspotPrompt1]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotPrompt1, Common::Point(171, 142), FACING_NORTHWEST);
+
+ _hotspotPrompt2 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(161, 67, 161 + 16, 67 + 75));
+ _scene->_dynamicHotspots[_hotspotPrompt2]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotPrompt2, Common::Point(171, 142), FACING_NORTHWEST);
+
+ _hotspotPrompt3 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(177, 90, 177 + 18, 90 + 52));
+ _scene->_dynamicHotspots[_hotspotPrompt3]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotPrompt3, Common::Point(171, 142), FACING_NORTHWEST);
+
+ _hotspotPrompt4 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(114, 100, 114 + 7, 100 + 38));
+ _scene->_dynamicHotspots[_hotspotPrompt4]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotPrompt4, Common::Point(171, 142), FACING_NORTHWEST);
+
+ _hotspotPrompt5 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_CLIMB, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(121, 49, 121 + 40, 49 + 30));
+ _scene->_dynamicHotspots[_hotspotPrompt5]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotPrompt5, Common::Point(196, 134), FACING_SOUTHWEST);
+ _scene->_dynamicHotspots.setCursor(_hotspotPrompt5, CURSOR_GO_UP);
+
+ _hotspotRightFloor1 = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(154, 6, 154 + 41, 6 + 6));
+ _scene->_dynamicHotspots[_hotspotRightFloor1]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotRightFloor1, Common::Point(171, 142), FACING_NONE);
+
+ _hotspotRightFloor2 = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(114, 136, 114 + 32, 132 + 6));
+ _scene->_dynamicHotspots[_hotspotRightFloor2]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotRightFloor2, Common::Point(127, 140), FACING_NONE);
+
+ _scene->changeVariant(1);
+ adjustRails(1);
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ switch (_game._trigger) {
+ case 0:
+ if (_globals[kPrompterStandStatus] == 1) {
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('s', 2), 75);
+ _game._player._priorTimer = _scene->_frameStartTime;
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[0], SYNC_PLAYER, 0);
+ _scene->deleteSequence(_globals._sequenceIndexes[12]);
+ _scene->deleteSequence(_globals._sequenceIndexes[3]);
+ }
+ break;
+
+ case 75:
+ if (_globals[kPrompterStandStatus] == 1) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 4);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(37, 139));
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[3], SYNC_ANIM, _globals._animationIndexes[0]);
+ _globals[kPrompterStandStatus] = 0;
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ _game._player._playerPos = Common::Point(62, 142);
+ _game._player.resetFacing(FACING_WEST);
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[0]);
+ _scene->_dynamicHotspots.remove(_hotspotPrompt1);
+ _scene->_dynamicHotspots.remove(_hotspotPrompt2);
+ _scene->_dynamicHotspots.remove(_hotspotPrompt3);
+ _scene->_dynamicHotspots.remove(_hotspotPrompt4);
+ _scene->_dynamicHotspots.remove(_hotspotPrompt5);
+ _scene->_dynamicHotspots.remove(_hotspotRightFloor1);
+ _scene->_dynamicHotspots.remove(_hotspotRightFloor2);
+
+ _hotspotPrompt1 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(2, 79, 2 + 40, 79 + 63));
+ _scene->_dynamicHotspots[_hotspotPrompt1]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotPrompt1, Common::Point(59, 140), FACING_NORTHWEST);
+
+ _hotspotPrompt2 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(42, 67, 42 + 16, 67 + 75));
+ _scene->_dynamicHotspots[_hotspotPrompt2]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotPrompt2, Common::Point(59, 140), FACING_NORTHWEST);
+
+ _hotspotPrompt3 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(58, 90, 58 + 18, 90 + 52));
+ _scene->_dynamicHotspots[_hotspotPrompt3]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotPrompt3, Common::Point(59, 140), FACING_NORTHWEST);
+
+ _hotspotLeftFloor1 = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(35, 137, 35 + 40, 137 + 5));
+ _scene->_dynamicHotspots[_hotspotLeftFloor1]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotLeftFloor1, Common::Point(59, 140), FACING_NONE);
+
+ _hotspotLeftFloor2 = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(76, 129, 76 + 6, 129 + 6));
+ _scene->_dynamicHotspots[_hotspotLeftFloor2]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotLeftFloor2, Common::Point(80, 135), FACING_NONE);
+
+ _hotspotPrompt5 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_CLIMB, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(2, 49, 2 + 40, 49 + 30));
+ _scene->_dynamicHotspots[_hotspotPrompt5]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotPrompt5, Common::Point(79, 132), FACING_SOUTHWEST);
+ _scene->_dynamicHotspots.setCursor(_hotspotPrompt5, CURSOR_GO_UP);
+
+ _scene->changeVariant(0);
+ adjustRails(0);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ } else if (_globals[kJacquesNameIsKnown])
+ _vm->_dialogs->show(10340);
else
+ _vm->_dialogs->show(10350);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR) || _action.isAction(VERB_OPEN, NOUN_DOOR) || _action.isAction(VERB_UNLOCK, NOUN_DOOR) || _action.isAction(VERB_LOCK, NOUN_DOOR)) {
+ if ((_globals[kCurrentYear] == 1881) && !_action.isAction(VERB_LOCK, NOUN_DOOR) && !_action.isAction(VERB_UNLOCK, NOUN_DOOR)) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[2] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[2], false, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], -1, -2);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[2], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_SPRITE, 3, 70);
+ break;
+
+ case 2:
+ _game._player._visible = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[2]);
+ _game._player.walk(Common::Point(295, 132), FACING_WEST);
+ _scene->_sequences.addTimer(180, 3);
+ break;
+
+ case 3:
+ _scene->_nextSceneId = 105;
+ break;
+
+ case 70:
+ _vm->_sound->command(24);
+ _scene->deleteSequence(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ _vm->_sound->command(66);
+ break;
+
+ case 71: {
+ int oldIdx = _globals._sequenceIndexes[1];
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, -2);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[1], SYNC_SEQ, oldIdx);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 5, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[2], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1: {
+ int oldIdx = _globals._sequenceIndexes[2];
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 4);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[2], SYNC_SEQ, oldIdx);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[2], false);
+ _scene->_sequences.addTimer(15, 2);
+ _vm->_sound->command(73);
+ }
+ break;
+
+ case 2:
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[2], false, 5, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[2], false);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[2]);
+ _game._player._visible = true;
+ if (_action.isAction(VERB_LOCK) || _action.isAction(VERB_UNLOCK))
+ _vm->_dialogs->show(00032);
+ else
+ _vm->_dialogs->show(10335);
+
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_KEY) && (_game._objects.isInRoom(OBJ_KEY) || _game._trigger)) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[8] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[8], false, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[8], 1, 5);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[8], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ _action._inProgress = false;
+ return;
+
+ case 1:
+ _scene->deleteSequence(_globals._sequenceIndexes[5]);
+ _scene->_hotspots.activate(NOUN_KEY, false);
+ _game._objects.addToInventory(OBJ_KEY);
+ _vm->_sound->command(26);
+ _action._inProgress = false;
+ return;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[8]);
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(20, 3);
+ _action._inProgress = false;
+ return;
+
+ case 3:
+ _globals[kPlayerScore] += 5;
+ _vm->_dialogs->showItem(OBJ_KEY, 800, 0);
+ _game._player._stepEnabled = true;
+ _action._inProgress = false;
+ return;
+
+ default:
+ break;
+ }
+ }
+
+ if (_action.isAction(VERB_TALK_TO, NOUN_GENTLEMAN) || _action.isAction(VERB_TALK_TO, NOUN_JACQUES)) {
+ if (_globals[kJacquesStatus] == 0) {
+ _vm->_gameConv->run(12);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ _vm->_gameConv->exportValue(_globals[kMusicSelected]);
+ } else
+ _vm->_dialogs->show(10343);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLIMB_THROUGH, NOUN_TRAP_DOOR) || _climbThroughTrapFl) {
+ if ((_standPosition == 2) && (_globals[kTrapDoorStatus] == 0)) {
+ switch (_game._trigger) {
+ case 0:
+ case 120:
+ if (!(_globals[kPlayerScoreFlags] & 1)) {
+ _globals[kPlayerScoreFlags] |= 1;
+ _globals[kPlayerScore] += 3;
+ }
+
+ _scene->freeAnimation(3);
+ _anim3ActvFl = false;
+ _climbThroughTrapFl = false;
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[11] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[11], false, 6, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[11], 5);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[11], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[11], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1:
+ _globals[kRoom103104Transition] = 1;
+ _scene->_nextSceneId = 104;
+ break;
+
+ default:
+ break;
+ }
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK_THROUGH, NOUN_PROMPTERS_BOX) || _sitFl) {
+ if (_standPosition == 1) {
+ switch (_game._trigger) {
+ case 0:
+ case 115:
+ _scene->freeAnimation(5);
+ _anim5ActvFl = false;
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[10] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[10], false, 6, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 4);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[10], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[10], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ if (!_sitFl)
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[10], SYNC_ANIM, _globals._animationIndexes[5]);
+ _sitFl = false;
+ break;
+
+ case 1:
+ _globals[kRoom103104Transition] = 0;
+ _scene->_nextSceneId = 104;
+ break;
+
+ default:
+ break;
+ }
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_PUSH, NOUN_LEVER) || _action.isAction(VERB_PULL, NOUN_LEVER)) {
+ if (_globals[kTrapDoorStatus] == 1) {
+ switch (_game._trigger) {
+ case 0:
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('l', 1), 1);
+ _anim1ActvFl = true;
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[1], SYNC_PLAYER, 0);
+ break;
+
+ case 1:
+ _anim1ActvFl = false;
+ _game._player._visible = true;
+ _globals[kTrapDoorStatus] = 0;
+ _game._player._stepEnabled = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[1]);
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ switch (_game._trigger) {
+ case 0:
+ _globals._animationIndexes[2] = _scene->loadAnimation(formAnimName('l', 2), 1);
+ _anim2ActvFl = true;
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[2], SYNC_PLAYER, 0);
+ break;
+
+ case 1:
+ _anim2ActvFl = false;
+ _game._player._visible = true;
+ _globals[kTrapDoorStatus] = 1;
+ _game._player._stepEnabled = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[2]);
+ break;
+
+ default:
+ break;
+ }
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ if ((_globals[kCurrentYear] == 1881) && (_globals[kJacquesStatus] >= 1))
+ _vm->_dialogs->show(10311);
+ else
+ _vm->_dialogs->show(10310);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_PROMPTERS_STAND)) {
+ if (_globals[kJacquesStatus] >= 1)
+ _vm->_dialogs->show(10349);
+ else if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(10312);
+ else
+ _vm->_dialogs->show(10345);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(10313);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_TRAP_CEILING)) {
+ _vm->_dialogs->show(10314);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DOOR)) {
+ _vm->_dialogs->show(10315);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DOOR_TO_PIT)) {
+ _vm->_dialogs->show(10316);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(10317);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PROMPTERS_BOX)) {
+ _vm->_dialogs->show(10318);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_TRAP_DOOR)) {
+ _vm->_dialogs->show(10319);
+ _action._inProgress = false;
return;
+ }
+
+ if (_action.isObject(NOUN_JUNK)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(10320);
+ else
+ _vm->_dialogs->show(10346);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CARTON)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(10321);
+ else
+ _vm->_dialogs->show(10347);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_GARBAGE_CAN)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(10322);
+ else
+ _vm->_dialogs->show(10348);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CABLE)) {
+ _vm->_dialogs->show(10323);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_JACQUES) || _action.isObject(NOUN_GENTLEMAN)) {
+ if (_globals[kJacquesStatus] == 0)
+ _vm->_dialogs->show(10324);
+ else
+ _vm->_dialogs->show(10325);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_KEY) && _game._objects.isInRoom(OBJ_KEY)) {
+ _vm->_dialogs->show(10326);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_STAIR_UNIT)) {
+ _vm->_dialogs->show(10327);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_EXPOSED_BRICK)) {
+ _vm->_dialogs->show(10328);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WATER_PIPE)) {
+ _vm->_dialogs->show(10329);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PROMPTERS_SEAT)) {
+ _vm->_dialogs->show(10338);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LEVER)) {
+ _vm->_dialogs->show(10339);
+ _action._inProgress = false;
+ return;
+ }
+
+ }
+
+ if (_action.isAction(VERB_CLOSE, NOUN_DOOR_TO_PIT)) {
+ _vm->_dialogs->show(10331);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLOSE, NOUN_DOOR)) {
+ _vm->_dialogs->show(10331);
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isAction(VERB_OPEN, NOUN_TRAP_DOOR)) || (_action.isAction(VERB_CLOSE, NOUN_TRAP_DOOR))) {
+ _vm->_dialogs->show(10344);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_JACQUES) || _action.isAction(VERB_TAKE, NOUN_GENTLEMAN)) {
+ if (_globals[kJacquesStatus] == 0) {
+ if (_globals[kJacquesNameIsKnown])
+ _vm->_dialogs->show(10336);
+ else
+ _vm->_dialogs->show(10351);
+ } else
+ _vm->_dialogs->show(10337);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene103::adjustRails(int variant) {
+ switch (variant) {
+ case 0:
+ _scene->_rails.disableNode(3);
+ _scene->_rails.disableNode(4);
+ _scene->_rails.disableNode(5);
+ _scene->_rails.disableNode(6);
+ _scene->_rails.disableNode(12);
+ _scene->_rails.disableNode(13);
+ _scene->_rails.disableNode(14);
+ break;
+
+ case 1:
+ _scene->_rails.disableNode(1);
+ _scene->_rails.disableNode(2);
+ _scene->_rails.disableNode(3);
+ _scene->_rails.disableNode(4);
+ _scene->_rails.disableNode(5);
+ _scene->_rails.disableNode(6);
+ _scene->_rails.disableNode(7);
+ _scene->_rails.disableNode(9);
+ _scene->_rails.disableNode(10);
+ _scene->_rails.disableNode(11);
+ break;
+
+ case 2:
+ _scene->_rails.disableNode(1);
+ _scene->_rails.disableNode(2);
+ _scene->_rails.disableNode(5);
+ _scene->_rails.disableNode(6);
+ _scene->_rails.disableNode(7);
+ _scene->_rails.disableNode(9);
+ _scene->_rails.disableNode(10);
+ _scene->_rails.disableNode(11);
+ break;
+
+ case 3:
+ _scene->_rails.disableNode(1);
+ _scene->_rails.disableNode(2);
+ _scene->_rails.disableNode(3);
+ _scene->_rails.disableNode(4);
+ _scene->_rails.disableNode(10);
+ _scene->_rails.disableNode(11);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene103::handleJacquesAnim() {
+ if (_scene->getAnimFrame(_globals._animationIndexes[0]) == _lastJacquesFrame)
+ return;
+
+ _lastJacquesFrame = _scene->getAnimFrame(_globals._animationIndexes[0]);
+ int resetFrame = -1;
+ int random;
+
+ switch (_lastJacquesFrame) {
+ case 1:
+ case 2:
+ case 3:
+ case 9:
+ case 17:
+ case 23:
+ case 33:
+ case 51:
+ switch (_jacquesAction) {
+ case 2:
+ random = 4;
+ _jacquesAction = 0;
+ break;
+
+ case 3:
+ random = 5;
+ _jacquesAction = 0;
+ break;
+
+ case 4:
+ random = 6;
+ break;
+
+ case 0:
+ random = _vm->getRandomNumber(1, 3);
+ ++_talkCount;
+ if (_talkCount > 22) {
+ _jacquesAction = 1;
+ random = 9;
+ }
+ break;
+
+ default:
+ random = _vm->getRandomNumber(6, 50);
+ while (_lastRandom == random)
+ random = _vm->getRandomNumber(6, 50);
+
+ _lastRandom = random;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 0;
+ break;
+
+ case 2:
+ resetFrame = 1;
+ break;
+
+ case 3:
+ resetFrame = 2;
+ break;
+
+ case 4:
+ resetFrame = 4;
+ break;
+
+ case 5:
+ resetFrame = 10;
+ break;
+
+ case 6:
+ resetFrame = 34;
+ break;
+
+ case 7:
+ resetFrame = 24;
+ break;
+
+ case 8:
+ resetFrame = 18;
+ break;
+
+ default:
+ resetFrame = 8;
+ break;
+ }
+ break;
+
+ case 36:
+ case 40:
+ case 48:
+ switch (_jacquesAction) {
+ case 0:
+ case 2:
+ case 3:
+ random = 2;
+ break;
+
+ case 4:
+ random = 1;
+ _jacquesAction = 0;
+ break;
+
+ default:
+ random = _vm->getRandomNumber(2, 50);
+ while (_lastRandom == random)
+ random = _vm->getRandomNumber(2, 50);
+ _lastRandom = random;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 37;
+ break;
+
+ case 2:
+ resetFrame = 49;
+ break;
+
+ case 3:
+ resetFrame = 41;
+ break;
+
+ default:
+ resetFrame = 35;
+ break;
+ }
+ break;
+
+ case 44:
+ random = _vm->getRandomNumber(1, 50);
+ while (_lastRandom == random)
+ random = _vm->getRandomNumber(1, 50);
+
+ _lastRandom = random;
+
+ switch (_jacquesAction) {
+ case 0:
+ case 2:
+ case 3:
+ case 4:
+ random = 1;
+ break;
+
+ default:
+ random = _vm->getRandomNumber(1, 50);
+ while (_lastRandom == random)
+ random = _vm->getRandomNumber(1, 50);
+ _lastRandom = random;
+ break;
+ }
+ switch (random) {
+ case 1:
+ resetFrame = 45;
+ break;
+
+ default:
+ resetFrame = 43;
+ break;
+ }
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[0], resetFrame);
+ _lastJacquesFrame = resetFrame;
+ }
+}
+
+void Scene103::climbRightStairs() {
+ if (_scene->getAnimFrame(_globals._animationIndexes[3]) == _lastStairFrame)
+ return;
+
+ _lastStairFrame = _scene->getAnimFrame(_globals._animationIndexes[3]);
+ int stairsResetFrame = -1;
+
+ if (_lastStairFrame == 37) {
+ stairsResetFrame = 36;
+ _standPosition = 2;
_game._player._stepEnabled = true;
}
- if (_action.isAction(VERB_CLOSE, NOUN_ORCHESTRA_DOOR)) {
- _vm->_dialogs->show(10228);
+ if (_lastStairFrame == 2) {
+ _scene->deleteSequence(3);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 13);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(154, 139));
+ }
+
+ if (stairsResetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[3], stairsResetFrame);
+ _lastStairFrame = stairsResetFrame;
+ }
+}
+
+void Scene103::climbLeftStairs() {
+ if (_scene->getAnimFrame(_globals._animationIndexes[5]) == _lastStairFrame)
+ return;
+
+ _lastStairFrame = _scene->getAnimFrame(_globals._animationIndexes[5]);
+ int stairsResetFrame = -1;
+
+ if (_lastStairFrame == 34) {
+ stairsResetFrame = 33;
+ _standPosition = 1;
+ _game._player._stepEnabled = true;
+ }
+
+ if (_lastStairFrame == 2) {
+ _scene->deleteSequence(3);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 13);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(37, 139));
+ }
+
+ if (stairsResetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[5], stairsResetFrame);
+ _lastStairFrame = stairsResetFrame;
+ }
+}
+
+void Scene103::descendRightStairs() {
+ if (_scene->getAnimFrame(_globals._animationIndexes[4]) == _lastStairFrame)
+ return;
+
+ _lastStairFrame = _scene->getAnimFrame(_globals._animationIndexes[4]);
+
+ if (_lastStairFrame == 2) {
+ _scene->deleteSequence(3);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 4);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(154, 139));
+ }
+}
+
+void Scene103::descendLeftStairs() {
+ if (_scene->getAnimFrame(_globals._animationIndexes[6]) == _lastStairFrame)
+ return;
+
+ _lastStairFrame = _scene->getAnimFrame(_globals._animationIndexes[6]);
+
+ if (_lastStairFrame == 2) {
+ _scene->deleteSequence(3);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 4);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(37, 139));
+ }
+}
+
+void Scene103::process_conv_jacques() {
+ bool quitConversationFl = false;
+
+ switch (_action._activeAction._verbId) {
+ case 1:
+ _vm->_gameConv->setInterlocutorTrigger(96);
+ if (_globals[kJacquesNameIsKnown] == 0) {
+ _globals[kJacquesNameIsKnown] = 1;
+ _scene->_dynamicHotspots.remove(_hotspotGentleman);
+ _hotspotGentleman = _scene->_dynamicHotspots.add(NOUN_JACQUES, VERB_WALKTO, SYNTAX_SINGULAR_MASC, EXT_NONE, Common::Rect(156, 116, 156 + 33, 116 + 31));
+ _scene->_dynamicHotspots[_hotspotGentleman]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_hotspotGentleman, Common::Point(206, 148), FACING_NORTHWEST);
+ }
+ break;
+
+ case 4:
+ case 6:
+ case 7:
+ case 10:
+ case 19:
+ case 30: {
+ _globals[kWalkerConverse] = 0;
+ int *val = _vm->_gameConv->getVariable(26);
+ if (*val)
+ _globals[kJacquesNameIsKnown] = 2;
+
+ quitConversationFl = true;
+ }
+ break;
+
+ case 8:
+ _vm->_gameConv->setInterlocutorTrigger(94);
+ break;
+
+ case 12:
+ _vm->_gameConv->setInterlocutorTrigger(96);
+ break;
+
+ case 29:
+ _vm->_gameConv->setInterlocutorTrigger(98);
+ break;
+
+ default:
+ break;
+ }
+
+ if ((_action._activeAction._verbId != 1) && (_action._activeAction._verbId != 8)
+ && (_action._activeAction._verbId != 12) && (_action._activeAction._verbId != 29))
+ _vm->_gameConv->setInterlocutorTrigger(90);
+
+ _vm->_gameConv->setHeroTrigger(92);
+
+ switch (_game._trigger) {
+ case 90:
+ if (!quitConversationFl)
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ _jacquesAction = 0;
+ break;
+
+ case 92:
+ if (!quitConversationFl)
+ _globals[kWalkerConverse] = _vm->getRandomNumber(2, 3);
+ _convCount = 0;
+ _jacquesAction = 1;
+ break;
+
+ case 94:
+ if (!quitConversationFl)
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ _jacquesAction = 2;
+ break;
+
+ case 96:
+ if (!quitConversationFl)
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ _jacquesAction = 3;
+ break;
+
+ case 98:
+ if (!quitConversationFl)
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ _jacquesAction = 4;
+ break;
+
+ default:
+ break;
+ }
+
+ _talkCount = 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene104::Scene104(MADSEngine *vm) : Scene1xx(vm) {
+ _anim0ActvFl = _anim1ActvFl = _anim2ActvFl = false;
+ _needToTalk = false;
+ _needToGetUp = false;
+ _sittingUp = false;
+ _beforeHeLeaves = false;
+ _beforeSheLeaves = false;
+ _needToStandUp = false;
+
+ _walkStatus = -1;
+ _walkFrame = -1;
+ _coupleStatus = -1;
+ _richStatus = -1;
+ _richTalkCount = -1;
+ _manTalkCount = -1;
+ _womanTalkCount = -1;
+ _lookCount = -1;
+ _coupleFrame = -1;
+ _lastPlayerFrame = -1;
+ _richFrame = -1;
+}
+
+void Scene104::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+
+ s.syncAsByte(_anim0ActvFl);
+ s.syncAsByte(_anim1ActvFl);
+ s.syncAsByte(_anim2ActvFl);
+ s.syncAsByte(_needToTalk);
+ s.syncAsByte(_needToGetUp);
+ s.syncAsByte(_sittingUp);
+ s.syncAsByte(_beforeHeLeaves);
+ s.syncAsByte(_beforeSheLeaves);
+ s.syncAsByte(_needToStandUp);
+
+ s.syncAsSint16LE(_walkStatus);
+ s.syncAsSint16LE(_walkFrame);
+ s.syncAsSint16LE(_coupleStatus);
+ s.syncAsSint16LE(_richStatus);
+ s.syncAsSint16LE(_richTalkCount);
+ s.syncAsSint16LE(_manTalkCount);
+ s.syncAsSint16LE(_womanTalkCount);
+ s.syncAsSint16LE(_lookCount);
+ s.syncAsSint16LE(_coupleFrame);
+ s.syncAsSint16LE(_lastPlayerFrame);
+}
+
+void Scene104::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ if (_globals[kTrapDoorStatus] == 1)
+ _scene->_variant = 1;
+
+ _scene->addActiveVocab(NOUN_MONSIEUR_RICHARD);
+}
+
+void Scene104::enter() {
+ _vm->_disableFastwalk = true;
+
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _anim2ActvFl = false;
+ _needToTalk = false;
+ _needToGetUp = false;
+ _sittingUp = false;
+ _beforeSheLeaves = false;
+ _needToStandUp = false;
+ }
+
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('a', 0));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('a', 6));
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('x', 0));
+
+ if (_globals[kCurrentYear] == 1993)
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('z', 0));
+
+ _vm->_gameConv->load(7);
+
+ if (_globals[kTrapDoorStatus] == 1) {
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 15);
+ } else {
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 15);
+ }
+
+ if (_scene->_priorSceneId == RETURNING_FROM_LOADING) {
+ if (_vm->_gameConv->restoreRunning() == 7) {
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('r', 1), 1);
+ _globals._animationIndexes[2] = _scene->loadAnimation(formAnimName('d', 1), 1);
+ _walkStatus = 0;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('m', 1), 1);
+ if (_coupleStatus < 11) {
+ _coupleStatus = 1;
+ _richStatus = 0;
+ _scene->setAnimFrame(_globals._animationIndexes[1], 14);
+ } else {
+ _coupleStatus = 17;
+ _richStatus = 4;
+ _scene->setAnimFrame(_globals._animationIndexes[1], 105);
+ _scene->setAnimFrame(_globals._animationIndexes[0], 216);
+ }
+
+ _vm->_gameConv->run(7);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ _game._player._visible = false;
+ }
+
+ } else if (_scene->_priorSceneId == 301) {
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('r', 1), 1);
+ _anim1ActvFl = true;
+ _coupleStatus = 11;
+
+ _globals._animationIndexes[2] = _scene->loadAnimation(formAnimName('d', 1), 1);
+ _anim2ActvFl = true;
+ _walkStatus = 0;
+
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('m', 1), 1);
+ _anim0ActvFl = true;
+ _richStatus = 0;
+
+ cleanInventory();
+
+ _game._player._visible = false;
+ _game._visitedScenes.pop_back();
+ _globals[kTrapDoorStatus] = 1;
+ _globals[kCurrentYear] = 1881;
+ _globals[kPrompterStandStatus] = 1;
+ _globals[kTicketPeoplePresent] = 1;
+ _globals[kMakeBrieLeave203] = false;
+ _game._player._playerPos.x = 161;
+
+ _game._visitedScenes.add(301);
+ _game._visitedScenes.add(101);
+
+ _scene->setCamera(Common::Point(60, 0));
+ _scene->_sequences.addTimer(1, 91);
+
+ } else if (_scene->_priorSceneId == 103) {
+ if (_globals[kRoom103104Transition] == 0) {
+ _scene->_userInterface.emptyConversationList();
+ _scene->_userInterface.setup(kInputConversation);
+
+ if (!_globals[kObservedPhan104]) {
+ _globals._animationIndexes[4] = _scene->loadAnimation(formAnimName('p', 1), 93);
+ _game._player._playerPos.x = 319;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _scene->setCamera(Common::Point(158, 0));
+ } else {
+ _globals._animationIndexes[5] = _scene->loadAnimation(formAnimName('p', 2), 94);
+ _game._player._playerPos.x = 319;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _scene->setCamera(Common::Point(158, 0));
+ }
+ } else {
+ _game._player._playerPos = Common::Point(319, 96);
+ _game._player._facing = FACING_SOUTH;
+ _scene->setCamera(Common::Point(158, 0));
+ }
+ } else if (_scene->_priorSceneId == 102) {
+ switch (_globals[kDeathLocation]) {
+ case 0:
+ _game._player._playerPos = Common::Point(496, 79);
+ _scene->setCamera(Common::Point(320, 0));
+ break;
+
+ case 1:
+ _game._player._playerPos = Common::Point(346, 71);
+ _scene->setCamera(Common::Point(158, 0));
+ break;
+
+ case 2:
+ _game._player._playerPos = Common::Point(172, 73);
+ break;
+
+ default:
+ break;
+ }
+ } else if (_scene->_priorSceneId == 108) {
+ if (_game._player._playerPos.x > 213)
+ _game._player._playerPos.y = 97;
+ else if (_game._player._playerPos.x > 110)
+ _game._player._playerPos.y = 128;
+ else
+ _game._player._playerPos.y = 148;
+
+ _game._player.firstWalk(Common::Point(-20, _game._player._playerPos.y), FACING_EAST, Common::Point(12, _game._player._playerPos.y), FACING_EAST, true);
+ } else if ((_scene->_priorSceneId == 107) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
+ if (_game._player._playerPos.x > 191)
+ _game._player._playerPos.y = 142;
+ else if (_game._player._playerPos.x > 104)
+ _game._player._playerPos.y = 120;
+ else
+ _game._player._playerPos.y = 95;
+
+ _game._player.firstWalk(Common::Point(655, _game._player._playerPos.y), FACING_WEST, Common::Point(627, _game._player._playerPos.y), FACING_WEST, true);
+ _scene->setCamera(Common::Point(320, 0));
+ }
+
+ if (_globals[kCurrentYear] == 1993) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+ } else
+ _scene->_hotspots.activate(NOUN_CHANDELIER, false);
+
+ if (_globals[kTrapDoorStatus] == 1) {
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 15);
+ } else {
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 15);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene104::step() {
+ if (_anim0ActvFl)
+ handleRichAnimations();
+
+ if (_anim1ActvFl)
+ handleCoupleAnimations();
+
+ if (_anim2ActvFl)
+ handleWalkAnimation();
+
+ if (_game._player._moving)
+ handlePlayerWalk();
+
+ if (_game._trigger == 91) {
+ _vm->_dialogs->show(10434);
+ _vm->_gameConv->run(7);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ }
+
+ if (_game._trigger == 93) {
+ _scene->_nextSceneId = 103;
+ _game._player._playerPos.x = 400;
+ _globals[kRoom103104Transition] = 0;
+ }
+
+ if (_game._trigger == 94) {
+ _scene->_nextSceneId = 103;
+ _globals[kRoom103104Transition] = 0;
+ }
+}
+
+void Scene104::preActions() {
+ if (_action.isAction(VERB_EXIT, NOUN_STAGE_LEFT))
+ _game._player._walkOffScreenSceneId = 108;
+
+ if (_action.isAction(VERB_EXIT, NOUN_STAGE_RIGHT))
+ _game._player._walkOffScreenSceneId = 107;
+
+ if (_action.isAction(VERB_OPEN, NOUN_TRAP_DOOR) || _action.isAction(VERB_CLOSE, NOUN_TRAP_DOOR))
+ _game._player.walk(Common::Point(320, 92), FACING_NORTH);
+}
+
+void Scene104::actions() {
+ if (_vm->_gameConv->activeConvId() == 7) {
+ processConversations();
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLIMB_THROUGH, NOUN_TRAP_DOOR)) {
+ if (_globals[kTrapDoorStatus] == 0) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._visible = false;
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 13);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 16);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 60);
+ break;
+
+ case 60:
+ _scene->_nextSceneId = 103;
+ _globals[kRoom103104Transition] = 1;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ _vm->_dialogs->show(10429);
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_JUMP_INTO, NOUN_ORCHESTRA_PIT)) {
+ switch (_game._trigger) {
+ case 0:
+ if (_game._player._playerPos.x > 400)
+ _globals[kDeathLocation] = 0;
+ else if (_game._player._playerPos.x > 200)
+ _globals[kDeathLocation] = 1;
+ else
+ _globals[kDeathLocation] = 2;
+
+ _scene->changeVariant(2);
+
+ if (_globals[kTrapDoorStatus] == 1)
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+ else
+ _scene->drawToBackground(_globals._spriteIndexes[0], 2, Common::Point(-32000, -32000), 0, 100);
+
+ _vm->_dialogs->show(10426);
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 7, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 15);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], -1, 4);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[3], _game._player._playerPos);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[3], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1:
+ _globals._sequenceIndexes[3] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[3], false, 1, 10);
+ _scene->_sequences.addTimer(60, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 4, 4);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 15);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[3], true);
+ _scene->_sequences.setMotion(_globals._sequenceIndexes[3], 0, 0, 200);
+ break;
+
+ case 2:
+ _vm->_sound->command(1);
+ _vm->_sound->command(67);
+ _scene->_nextSceneId = 102;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(10410);
+ else
+ _vm->_dialogs->show(10411);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_STAGE)) {
+ _vm->_dialogs->show(10412);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_APRON)) {
+ _vm->_dialogs->show(10413);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PROSCENIUM_ARCH)) {
+ _vm->_dialogs->show(10414);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_ACT_CURTAIN)) {
+ _vm->_dialogs->show(10415);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_ORCHESTRA_PIT)) {
+ _vm->_dialogs->show(10416);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CONDUCTORS_STAND)) {
+ _vm->_dialogs->show(10417);
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isObject(NOUN_MUSIC_STAND)) || (_action.isObject(NOUN_MUSIC_STANDS))) {
+ _vm->_dialogs->show(10418);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PROMPTERS_BOX)) {
+ _vm->_dialogs->show(10419);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_TRAP_DOOR)) {
+ _vm->_dialogs->show(10420);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_HOUSE)) {
+ if (_globals[kCurrentYear] == 1881)
+ _vm->_dialogs->show(10421);
+ else
+ _vm->_dialogs->show(10427);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_STAGE_LEFT)) {
+ _vm->_dialogs->show(10422);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_STAGE_RIGHT)) {
+ _vm->_dialogs->show(10423);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CHANDELIER)) {
+ _vm->_dialogs->show(10428);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_MONSIEUR_RICHARD)) {
+ _vm->_dialogs->show(10433);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_JUMP_INTO, NOUN_ORCHESTRA_PIT)) {
+ _vm->_dialogs->show(10426);
+ _scene->_nextSceneId = 102;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_PROMPTERS_BOX) || _action.isAction(VERB_CLOSE, NOUN_PROMPTERS_BOX)) {
+ _vm->_dialogs->show(10430);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_TRAP_DOOR)) {
+ if (_globals[kTrapDoorStatus] == 0)
+ _vm->_dialogs->show(10424);
+ else
+ _vm->_dialogs->show(10432);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLOSE, NOUN_TRAP_DOOR)) {
+ if (_globals[kTrapDoorStatus] == 1)
+ _vm->_dialogs->show(10425);
+ else
+ _vm->_dialogs->show(10433);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_CHANDELIER)) {
+ _vm->_dialogs->show(10435);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene104::cleanInventory() {
+ if (_game._objects.isInInventory(OBJ_LARGE_NOTE))
+ _game._objects.setRoom(OBJ_LARGE_NOTE, NOWHERE);
+
+ if (_game._objects.isInInventory(OBJ_SANDBAG))
+ _game._objects.setRoom(OBJ_SANDBAG, NOWHERE);
+
+ if (_game._objects.isInInventory(OBJ_SMALL_NOTE))
+ _game._objects.setRoom(OBJ_SMALL_NOTE, NOWHERE);
+
+ if (_game._objects.isInInventory(OBJ_PARCHMENT))
+ _game._objects.setRoom(OBJ_PARCHMENT, NOWHERE);
+
+ if (_game._objects.isInInventory(OBJ_BOOK))
+ _game._objects.setRoom(OBJ_BOOK, NOWHERE);
+
+ if (_game._objects.isInInventory(OBJ_RED_FRAME))
+ _game._objects.setRoom(OBJ_RED_FRAME, 105);
+
+ if (_game._objects.isInInventory(OBJ_YELLOW_FRAME))
+ _game._objects.setRoom(OBJ_YELLOW_FRAME, 107);
+
+ if (_game._objects.isInInventory(OBJ_BLUE_FRAME))
+ _game._objects.setRoom(OBJ_BLUE_FRAME, 302);
+
+ if (_game._objects.isInInventory(OBJ_GREEN_FRAME))
+ _game._objects.setRoom(OBJ_GREEN_FRAME, 307);
+}
+
+void Scene104::processConversations() {
+ bool interlocutorTriggerFl = false;
+ bool heroTriggerFl = false;
+
+ switch (_action._activeAction._verbId) {
+ case 2:
+ case 10:
+ case 12:
+ case 16:
+ case 20:
+ case 21:
+ case 24:
+ _vm->_gameConv->setInterlocutorTrigger(75);
+ interlocutorTriggerFl = true;
+ break;
+
+ case 3:
+ if (!_needToGetUp) {
+ _vm->_gameConv->setInterlocutorTrigger(67);
+ interlocutorTriggerFl = true;
+ _needToGetUp = true;
+ }
+ break;
+
+ case 8:
+ _vm->_gameConv->setInterlocutorTrigger(87);
+ interlocutorTriggerFl = true;
+ break;
+
+ case 11:
+ _vm->_gameConv->setInterlocutorTrigger(77);
+ interlocutorTriggerFl = true;
+ break;
+
+ case 14:
+ case 25:
+ if (!_game._trigger) {
+ _richStatus = 0;
+ _coupleStatus = 5;
+ _vm->_gameConv->hold();
+ }
+ break;
+
+ case 22:
+ _vm->_gameConv->setInterlocutorTrigger(75);
+ _vm->_gameConv->setHeroTrigger(79);
+ interlocutorTriggerFl = true;
+ heroTriggerFl = true;
+ break;
+
+ case 23:
+ _vm->_gameConv->setInterlocutorTrigger(89);
+ interlocutorTriggerFl = true;
+ break;
+
+ case 28:
+ _vm->_gameConv->setInterlocutorTrigger(81);
+ interlocutorTriggerFl = true;
+ break;
+
+ case 30:
+ if (!_game._trigger) {
+ _vm->_gameConv->hold();
+ _richStatus = 4;
+ }
+ break;
+
+ case 32:
+ _coupleStatus = 14;
+ heroTriggerFl = true;
+ interlocutorTriggerFl = true;
+ _vm->_gameConv->hold();
+ break;
+
+ default:
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 67:
+ _vm->_gameConv->hold();
+ _coupleStatus = 12;
+ break;
+
+ case 69:
+ if (!_beforeSheLeaves && !_beforeHeLeaves && (_coupleStatus != 14) && !_needToStandUp) {
+ _richStatus = 0;
+ if (_sittingUp)
+ _coupleStatus = 4;
+ else
+ _coupleStatus = 12;
+ }
+ break;
+
+ case 71:
+ if (!_beforeSheLeaves && !_beforeHeLeaves && (_coupleStatus != 14) && !_needToStandUp) {
+ _richStatus = 0;
+ if (_sittingUp && !_beforeSheLeaves) {
+ _coupleStatus = 3;
+ _richStatus = 0;
+ }
+ }
+ break;
+
+ case 75:
+ _richStatus = 1;
+
+ if (_sittingUp) {
+ if (_action._activeAction._verbId == 20) {
+ _lookCount = 0;
+ _coupleStatus = 9;
+ } else if ((_action._activeAction._verbId == 21) || (_action._activeAction._verbId == 22)) {
+ _lookCount = 0;
+ _coupleStatus = 10;
+ } else {
+ _coupleStatus = 1;
+ }
+ } else {
+ _coupleStatus = 11;
+ }
+ break;
+
+ case 77:
+ _richStatus = 0;
+ _coupleStatus = 8;
+ break;
+
+ case 79:
+ _richStatus = 0;
+ _coupleStatus = 7;
+ break;
+
+ case 81:
+ _richStatus = 1;
+ _beforeHeLeaves = true;
+ _coupleStatus = 15;
+ break;
+
+ case 83:
+ _vm->_gameConv->release();
+ if (_coupleStatus != 17)
+ _game._player._stepEnabled = false;
+ break;
+
+ case 87:
+ _richStatus = 3;
+ break;
+
+ case 89:
+ _richStatus = 2;
+ break;
+
+ default:
+ break;
+ }
+
+ if (!heroTriggerFl && !_beforeSheLeaves)
+ _vm->_gameConv->setHeroTrigger(71);
+
+ if (!interlocutorTriggerFl)
+ _vm->_gameConv->setInterlocutorTrigger(69);
+
+ _richTalkCount = 0;
+ _manTalkCount = 0;
+ _womanTalkCount = 0;
+}
+
+void Scene104::handleWalkAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[2]]->getCurrentFrame() == _walkFrame)
+ return;
+
+ _walkFrame = _scene->_animation[_globals._animationIndexes[2]]->getCurrentFrame();
+ int daaeResetFrame = -1;
+
+ switch (_walkFrame) {
+ case 1:
+ if (_walkStatus == 0) {
+ daaeResetFrame = 0;
+ } else {
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[2], SYNC_ANIM, _globals._animationIndexes[1]);
+ daaeResetFrame = 1;
+ }
+ break;
+
+ case 138:
+ _walkStatus = 0;
+ daaeResetFrame = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ if (daaeResetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[2], daaeResetFrame);
+ _walkFrame = daaeResetFrame;
+ }
+}
+
+void Scene104::handleRichAnimations() {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == _richFrame)
+ return;
+
+ _richFrame = _scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame();
+ int random;
+ int resetFrame = -1;
+
+ switch (_richFrame) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 8:
+ case 14:
+ case 22:
+ case 34:
+ case 40:
+ case 44:
+ case 48:
+ random = -1;
+ if (_richStatus == 1) {
+ random = _vm->getRandomNumber(1, 3);
+ ++_richTalkCount;
+ if (_richTalkCount > 15) {
+ _richStatus = 0;
+ random = 40;
+ }
+ }
+
+ if (_richStatus == 0)
+ random = _vm->getRandomNumber(7, 80);
+
+ if (_richStatus == 2) {
+ random = 4;
+ _richStatus = 1;
+ _richTalkCount = 8;
+ }
+
+ if (_richStatus == 3) {
+ random = 5;
+ _richStatus = 1;
+ _richTalkCount = 8;
+ }
+
+ if (_richStatus == 4)
+ random = 6;
+
+ if (_richStatus == 5)
+ random = 7;
+
+ switch (random) {
+ case 1:
+ resetFrame = 1;
+ break;
+
+ case 2:
+ resetFrame = 2;
+ break;
+
+ case 3:
+ resetFrame = 3;
+ break;
+
+ case 4:
+ resetFrame = 23;
+ break;
+
+ case 5:
+ resetFrame = 35;
+ break;
+
+ case 6:
+ resetFrame = 49;
+ break;
+
+ case 7:
+ resetFrame = 41;
+ break;
+
+ case 8:
+ resetFrame = 45;
+ break;
+
+ case 9:
+ resetFrame = 9;
+ break;
+
+ case 10:
+ resetFrame = 5;
+ break;
+
+ case 11:
+ resetFrame = 15;
+ break;
+
+ default:
+ resetFrame = 0;
+ break;
+ }
+ break;
+
+ case 117:
+ _coupleStatus = 13;
+ break;
+
+ case 125:
+ resetFrame = 124;
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[0], resetFrame);
+ _richFrame = resetFrame;
+ }
+}
+
+void Scene104::handleCoupleAnimations() {
+ if (_scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame() == _coupleFrame)
+ return;
+
+ _coupleFrame = _scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame();
+ int resetFrame = -1;
+ int random;
+
+ switch (_coupleFrame) {
+ case 1:
+ case 103:
+ case 104:
+ case 105:
+ if (_coupleStatus == 11)
+ resetFrame = 0;
+ else {
+ resetFrame = _vm->getRandomNumber(102, 104);
+ ++_womanTalkCount;
+ if (_womanTalkCount > 15) {
+ if (_needToGetUp) {
+ _coupleStatus = 6;
+ resetFrame = 1;
+ } else {
+ _coupleStatus = 11;
+ resetFrame = 0;
+ }
+ }
+ }
+ break;
+
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 25:
+ case 33:
+ case 41:
+ switch (_coupleFrame) {
+ case 9:
+ _coupleStatus = 6;
+ break;
+
+ case 33:
+ _vm->_gameConv->release();
+ if (_action._activeAction._verbId == 13)
+ _coupleStatus = 4;
+
+ break;
+
+ case 41:
+ _vm->_gameConv->release();
+ _sittingUp = true;
+ if (_needToTalk)
+ _coupleStatus = 3;
+ else
+ _coupleStatus = 1;
+ break;
+
+ default:
+ break;
+ }
+
+ random = -1;
+
+ switch (_coupleStatus) {
+ case 1:
+ random = 12;
+ break;
+
+ case 2:
+ case 7:
+ case 8:
+ random = 11;
+ break;
+
+ case 3:
+ random = _vm->getRandomNumber(4, 6);
+ ++_manTalkCount;
+ if (_manTalkCount > 15) {
+ _coupleStatus = 1;
+ random = 12;
+ }
+ break;
+
+ case 4:
+ if (_beforeSheLeaves) {
+ random = 10;
+ } else {
+ random = _vm->getRandomNumber(1, 3);
+ ++_womanTalkCount;
+ if (_womanTalkCount > 15) {
+ _coupleStatus = 1;
+ random = 12;
+ }
+ }
+ break;
+
+ case 5:
+ _coupleStatus = 1;
+ random = 8;
+ break;
+
+ case 6:
+ _coupleStatus = 1;
+ random = 7;
+ break;
+
+ case 13:
+ random = 9;
+ break;
+
+ case 15:
+ random = 10;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 12;
+ break;
+
+ case 2:
+ resetFrame = 13;
+ break;
+
+ case 3:
+ resetFrame = 14;
+ break;
+
+ case 4:
+ resetFrame = 9;
+ break;
+
+ case 5:
+ resetFrame = 10;
+ break;
+
+ case 6:
+ resetFrame = 11;
+ break;
+
+ case 7:
+ resetFrame = 33;
+ break;
+
+ case 8:
+ resetFrame = 25;
+ break;
+
+ case 9:
+ resetFrame = 54;
+ break;
+
+ case 10:
+ resetFrame = 41;
+ break;
+
+ case 11:
+ resetFrame = 15;
+ break;
+
+ case 12:
+ resetFrame = 14;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 17:
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ random = -1;
+ switch (_coupleStatus) {
+ case 1:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 15:
+ case 16:
+ random = 7;
+ break;
+
+ case 2:
+ random = 8;
+ break;
+
+ case 7:
+ random = _vm->getRandomNumber(4, 6);
+ ++_manTalkCount;
+ if (_manTalkCount > 15) {
+ _coupleStatus = 2;
+ random = 8;
+ }
+ break;
+
+ case 8:
+ random = _vm->getRandomNumber(1, 3);
+ ++_womanTalkCount;
+ if (_womanTalkCount > 15) {
+ _coupleStatus = 1;
+ random = 7;
+ }
+ break;
+
+ case 9:
+ random = 1;
+ ++_lookCount;
+ if (_lookCount > 6) {
+ _coupleStatus = 1;
+ random = 7;
+ }
+ break;
+
+ case 10:
+ random = 1;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 20;
+ break;
+
+ case 2:
+ resetFrame = 21;
+ break;
+
+ case 3:
+ resetFrame = 22;
+ break;
+
+ case 4:
+ resetFrame = 17;
+ break;
+
+ case 5:
+ resetFrame = 18;
+ break;
+
+ case 6:
+ resetFrame = 19;
+ break;
+
+ case 7:
+ resetFrame = 23;
+ break;
+
+ case 8:
+ resetFrame = 20;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 52:
+ _walkStatus = 1;
+ resetFrame = 54;
+ break;
+
+ case 55:
+ if (_coupleStatus != 13)
+ resetFrame = 54;
+
+ break;
+
+ case 89:
+ _vm->_gameConv->release();
+ break;
+
+ case 90:
+ if (_coupleStatus != 14) {
+ resetFrame = 89;
+ } else {
+ resetFrame = 90;
+ _globals[kTempVar] = 200;
+ }
+ break;
+
+ case 102:
+ _vm->_gameConv->release();
+ _game._player._playerPos = Common::Point(166, 126);
+ _game._player.resetFacing(FACING_SOUTH);
+ resetFrame = 105;
+ _game._player._visible = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[1]);
+ break;
+
+ case 106:
+ _coupleStatus = 17;
+ resetFrame = 105;
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[1], resetFrame);
+ _coupleFrame = resetFrame;
+ }
+}
+
+void Scene104::handlePlayerWalk() {
+ if (_game._player._frameNumber == _lastPlayerFrame)
+ return;
+
+ _lastPlayerFrame = _game._player._frameNumber;
+ switch (_game._player._facing) {
+ case FACING_NORTH:
+ case FACING_SOUTH:
+ if ((_game._player._frameNumber == 5) || (_game._player._frameNumber == 11))
+ _vm->_sound->command(68);
+ break;
+
+ case FACING_NORTHEAST:
+ case FACING_NORTHWEST:
+ case FACING_SOUTHEAST:
+ case FACING_SOUTHWEST:
+ if ((_game._player._frameNumber == 7) || (_game._player._frameNumber == 14))
+ _vm->_sound->command(68);
+ break;
+
+ case FACING_EAST:
+ case FACING_WEST:
+ if ((_game._player._frameNumber == 8) || (_game._player._frameNumber == 16))
+ _vm->_sound->command(68);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene105::Scene105(MADSEngine *vm) : Scene1xx(vm) {
+}
+
+void Scene105::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+
+}
+
+void Scene105::setup() {
+ if (_globals[kCurrentYear] == 1993)
+ _scene->_variant = 1;
+
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ _scene->addActiveVocab(NOUN_LIGHT_FIXTURE);
+}
+
+void Scene105::enter() {
+ _scene->loadSpeech(8);
+
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 2));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('x', 3));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites("*RRD_9");
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*RDR_9");
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('a', 0));
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('a', 1));
+ if (_globals[kCurrentYear] == 1993)
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('z', -1));
+
+ if ((_globals[kCurrentYear] == 1881) && (!_globals[kHintThatDaaeIsHome2])) {
+ if ((_globals[kJacquesNameIsKnown] == 2) && (_globals[kMadameNameIsKnown] == 2) &&
+ _globals[kPanelIn206] && _globals[kDoneRichConv203] && _game._objects.isInInventory(OBJ_LANTERN) &&
+ ((_game._objects.isInInventory(OBJ_CABLE_HOOK) && _game._objects.isInInventory(OBJ_ROPE)) || _game._objects.isInInventory(OBJ_ROPE_WITH_HOOK))) {
+ _globals[kHintThatDaaeIsHome2] = true;
+ _scene->_sequences.addTimer(300, 75);
+ }
+ }
+
+ if ((_game._objects.isInRoom(OBJ_LANTERN)) && (_globals[kCurrentYear] == 1881)) {
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ } else {
+ _scene->_hotspots.activate(NOUN_LANTERN, false);
+ }
+
+ if (_game._objects.isInRoom(OBJ_RED_FRAME)) {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ } else {
+ _scene->_hotspots.activate(NOUN_RED_FRAME, false);
+ }
+
+ if (_globals[kCurrentYear] == 1993) {
+ _scene->drawToBackground(_globals._spriteIndexes[3], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_PROPS, false);
+ _scene->_hotspots.activate(NOUN_BEAR_PROP, false);
+ _scene->_hotspots.activate(NOUN_STAIR_UNIT, false);
+ _scene->_hotspots.activate(NOUN_PROP, false);
+ _scene->_hotspots.activate(NOUN_ELEPHANT_PROP, false);
+ _scene->_hotspots.activate(NOUN_COLUMN_PROP, false);
+
+ int tmpIdx = _scene->_dynamicHotspots.add(NOUN_COLUMN_PROP, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(132, 24, 132 + 21, 24 + 105));
+ _scene->_dynamicHotspots.setPosition(tmpIdx, Common::Point(159, 133), FACING_NORTHWEST);
+
+ tmpIdx = _scene->_dynamicHotspots.add(NOUN_COLUMN_PROP, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(56, 45, 56 + 11, 45 + 77));
+ _scene->_dynamicHotspots.setPosition(tmpIdx, Common::Point(72, 126), FACING_NORTHWEST);
+
+ _scene->_dynamicHotspots.add(NOUN_PROP, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(0, 125, 29, 125 + 31));
+ _scene->_dynamicHotspots.add(NOUN_PROP, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(29, 136, 29 + 50, 136 + 20));
+ _scene->_dynamicHotspots.add(NOUN_PROP, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(79, 141, 79 + 53, 141 + 15));
+
+ _scene->_dynamicHotspots.add(NOUN_BEAR_PROP, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(278, 132, 278 + 21, 132 + 24));
+ _scene->_dynamicHotspots.add(NOUN_BEAR_PROP, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(299, 146, 299 + 8, 146 + 10));
+ _scene->_dynamicHotspots.add(NOUN_BEAR_PROP, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(269, 142, 269 + 8, 142 + 8));
+
+ _scene->_dynamicHotspots.add(NOUN_LIGHT_FIXTURE, VERB_LOOK_AT, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(102, 14, 102 + 24, 102 + 10));
+ }
+
+ _globals._sequenceIndexes[4] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[4], false, 2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 14);
+
+ if ((_scene->_priorSceneId == 106) || (_scene->_priorSceneId == 114)) {
+ _game._player._playerPos = Common::Point(198, 132);
+ _game._player._facing = FACING_WEST;
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 10);
+ } else if ((_scene->_priorSceneId == 103) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
+ _game._player._playerPos = Common::Point(3, 112);
+ _game._player._facing = FACING_SOUTHEAST;
+ _game._player.walk(Common::Point(45, 131), FACING_SOUTHEAST);
+ _game._player.setWalkTrigger(60);
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 8);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 10);
+ } else if (_scene->_priorSceneId == RETURNING_FROM_LOADING) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 10);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene105::step() {
+ switch (_game._trigger) {
+ case 60:
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[2], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 10);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 61);
+ _vm->_sound->command(66);
+ break;
+
+ case 61:
+ _vm->_sound->command(25);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 10);
+ _game._player._stepEnabled = true;
+ break;
+
+ case 75:
+ _scene->playSpeech(8);
+ _scene->_sequences.addTimer(120, 76);
+ break;
+
+ case 76:
+ _vm->_dialogs->show(10537);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene105::actions() {
+ if ((_action.isAction(VERB_PUSH, NOUN_THUNDER_MACHINE)) || (_action.isAction(VERB_PULL, NOUN_THUNDER_MACHINE))) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('t', 1), 70);
+ _scene->deleteSequence(_globals._sequenceIndexes[4]);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[4], SYNC_ANIM, _globals._animationIndexes[0]);
+ _scene->_sequences.setSeqPlayer(_globals._animationIndexes[0], false);
+ break;
+
+ case 70:
+ _globals._sequenceIndexes[4] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[4], false, 2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 14);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[4], SYNC_ANIM, _globals._animationIndexes[0]);
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[0]);
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLIMB_UP, NOUN_CIRCULAR_STAIRCASE)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('u', 1), 1);
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[0], SYNC_PLAYER, 0);
+ break;
+
+ case 1:
+ _scene->_nextSceneId = 106;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLIMB_DOWN, NOUN_CIRCULAR_STAIRCASE)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('d', 1), 1);
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[0], SYNC_PLAYER, 0);
+ break;
+
+ case 1:
+ _scene->_nextSceneId = 114;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_RED_FRAME) && (_game._objects.isInRoom(OBJ_RED_FRAME) || _game._trigger)) {
+ switch (_game._trigger) {
+ case (0):
+ if (_globals[kCurrentYear] == 1881) {
+ int count = 0;
+
+ if (_game._objects.isInInventory(NOUN_YELLOW_FRAME))
+ ++count;
+
+ if (_game._objects.isInInventory(NOUN_GREEN_FRAME))
+ ++count;
+
+ if (_game._objects.isInInventory(NOUN_BLUE_FRAME))
+ ++count;
+
+ if (count < 3)
+ _globals[kPlayerScore] += 5;
+ }
+
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[5] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[5], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 1, 5);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[5], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _scene->deleteSequence(_globals._sequenceIndexes[1]);
+ _scene->_hotspots.activate(NOUN_RED_FRAME, false);
+ _game._objects.addToInventory(OBJ_RED_FRAME);
+ _vm->_sound->command(26);
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[5]);
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(20, 3);
+ break;
+
+ case 3:
+ if (_globals[kCurrentYear] == 1881)
+ _vm->_dialogs->showItem(OBJ_RED_FRAME, 842, 0);
+ else
+ _vm->_dialogs->showItem(OBJ_RED_FRAME, 802, 0);
+
+ _game._player._stepEnabled = true;
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_LANTERN) && (_game._objects.isInRoom(OBJ_LANTERN) || _game._trigger)) {
+ switch (_game._trigger) {
+ case (0):
+ _globals[kPlayerScore] += 5;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[6] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[6], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[6], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[6], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_SPRITE, 4, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _scene->deleteSequence(_globals._sequenceIndexes[0]);
+ _scene->_hotspots.activate(NOUN_LANTERN, false);
+ _game._objects.addToInventory(OBJ_LANTERN);
+ _vm->_sound->command(26);
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[6]);
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(20, 3);
+ break;
+
+ case 3:
+ _vm->_dialogs->showItem(OBJ_LANTERN, 801, 0);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR) || _action.isAction(VERB_OPEN, NOUN_DOOR) || (_game._trigger) ||
+ _action.isAction(VERB_UNLOCK, NOUN_DOOR) || _action.isAction(VERB_LOCK, NOUN_DOOR)) {
+ if ((_globals[kCurrentYear] == 1881) && !_action.isAction(VERB_UNLOCK) && !_action.isAction(VERB_LOCK)){
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[6] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[6], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[6], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[6], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_SPRITE, 4, 65);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 2:
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(180, 3);
+ break;
+
+ case 3:
+ _scene->_nextSceneId = 103;
+ break;
+
+ case 65:
+ _vm->_sound->command(24);
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 66);
+ _vm->_sound->command(66);
+ break;
+
+ case 66: {
+ int tmpIdx = _globals._sequenceIndexes[2];
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 8);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[2], SYNC_SEQ, tmpIdx);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+ _game._player.walk(Common::Point(0, 111), FACING_NORTHWEST);
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[6] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[6], true, 5, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[6], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[6], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1: {
+ int tmpIdx = _globals._sequenceIndexes[6];
+ _globals._sequenceIndexes[6] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[6], true, 4);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[6], SYNC_SEQ, tmpIdx);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[6], false);
+ _vm->_sound->command(73);
+ _scene->_sequences.addTimer(15, 2);
+ }
+ break;
+
+ case 2:
+ _scene->deleteSequence(_globals._sequenceIndexes[6]);
+ _globals._sequenceIndexes[6] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[6], true, 5, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[6], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[6], false);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[6]);
+ _game._player._visible = true;
+ if (_action.isAction(VERB_LOCK) || _action.isAction(VERB_UNLOCK))
+ _vm->_dialogs->show(32);
+ else
+ _vm->_dialogs->show(10536);
+
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(10510);
+ else
+ _vm->_dialogs->show(10511);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(10512);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CIRCULAR_STAIRCASE)) {
+ _vm->_dialogs->show(10513);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LANTERN) && _game._objects.isInRoom(OBJ_LANTERN)) {
+ _vm->_dialogs->show(10514);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RED_FRAME) && _game._objects.isInRoom(OBJ_RED_FRAME)){
+ if (_globals[kCurrentYear] == 1881)
+ _vm->_dialogs->show(10530);
+ else
+ _vm->_dialogs->show(10515);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DOOR)) {
+ _vm->_dialogs->show(10516);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(10517);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PROP_TABLE)) {
+ _vm->_dialogs->show(10518);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BEAR_PROP)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(10519);
+ else
+ _vm->_dialogs->show(10538);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_ELEPHANT_PROP)) {
+ _vm->_dialogs->show(10520);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_COLUMN_PROP)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(10521);
+ else
+ _vm->_dialogs->show(10539);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_THUNDER_MACHINE)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(10522);
+ else
+ _vm->_dialogs->show(10540);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_STAIR_UNIT)) {
+ _vm->_dialogs->show(10523);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PROP)) {
+ _vm->_dialogs->show(10524);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PROPS)) {
+ _vm->_dialogs->show(10525);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_EXIT_SIGN)) {
+ _vm->_dialogs->show(10526);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FLATS)) {
+ _vm->_dialogs->show(10527);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_HEMP)) {
+ _vm->_dialogs->show(10528);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PIPE)) {
+ _vm->_dialogs->show(10529);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_GRAFFITI)) {
+ _vm->_dialogs->show(10531);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LIGHT_FIXTURE)) {
+ _vm->_dialogs->show(10535);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TALK_TO, NOUN_BEAR_PROP)) {
+ _vm->_dialogs->show(10532);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_BEAR_PROP)) {
+ _vm->_dialogs->show(10533);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLOSE, NOUN_DOOR)) {
+ _vm->_dialogs->show(10534);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene105::preActions() {
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR_TO_PIT))
+ _game._player._walkOffScreenSceneId = 102;
+
+ if (_action.isAction(VERB_OPEN, NOUN_DOOR) || _action.isAction(VERB_UNLOCK, NOUN_DOOR) || _action.isAction(VERB_LOCK, NOUN_DOOR))
+ _game._player.walk(Common::Point(33, 128), FACING_NORTHWEST);
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene106::Scene106(MADSEngine *vm) : Scene1xx(vm) {
+ _sandbagHostpotId = -1;
+}
+
+void Scene106::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+
+ s.syncAsSint16LE(_sandbagHostpotId);
+}
+
+void Scene106::setup() {
+ if (_globals[kCurrentYear] == 1881)
+ _scene->_variant = 1;
+
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene106::enter() {
+ _scene->loadSpeech(8);
+
+ if (_globals[kCurrentYear] == 1993) {
+ if (!_game._objects.isInInventory(OBJ_SANDBAG)) {
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites("*RRD_9");
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ }
+ } else {
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('z', -1));
+ if (_game._objects.isInRoom(OBJ_CABLE_HOOK) && !_game._objects.isInInventory(OBJ_ROPE_WITH_HOOK)) {
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites("*RRD_9");
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('p', 0));
+ }
+ }
+
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('a', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites("*RDR_9");
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('a', 1));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('a', 2));
+
+ if ((_globals[kCurrentYear] == 1881) && (!_globals[kHintThatDaaeIsHome1])) {
+ if ((_globals[kJacquesNameIsKnown] == 2) && (_globals[kMadameNameIsKnown] == 2)
+ && (_globals[kPanelIn206]) && (_globals[kDoneRichConv203]) && (_game._objects.isInInventory(OBJ_LANTERN))
+ && ((_game._objects.isInInventory(OBJ_CABLE_HOOK) && _game._objects.isInInventory(OBJ_ROPE))
+ || _game._objects.isInInventory(OBJ_ROPE_WITH_HOOK))) {
+ _globals[kHintThatDaaeIsHome1] = true;
+ _scene->_sequences.addTimer(300, 85);
+ }
+ }
+
+ if ((_globals[kSandbagStatus] == 1) && (_globals[kCurrentYear] == 1993) && _game._objects.isInRoom(OBJ_SANDBAG)) {
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, -2);
+ _sandbagHostpotId = _scene->_dynamicHotspots.add(NOUN_SANDBAG, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(227, 140, 227 + 18, 140 + 11));
+ _scene->_dynamicHotspots.setPosition(_sandbagHostpotId, Common::Point(224, 152), FACING_NORTHEAST);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 2);
+ }
+
+ if (_globals[kCurrentYear] == 1881) {
+ _scene->drawToBackground(_globals._spriteIndexes[7], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_BIG_PROP, false);
+ _scene->_hotspots.activate(NOUN_STATUE, false);
+ _scene->_hotspots.activate(NOUN_PLANT_PROP, false);
+ _scene->_hotspots.activate(NOUN_PEDESTAL, false);
+ _scene->_hotspots.activate(NOUN_SANDBAG, false);
+ _scene->_hotspots.activate(NOUN_CRATE, false);
+
+ _scene->_dynamicHotspots.add(NOUN_SANDBAG, VERB_LOOK_AT, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(40, 47, 40 + 11, 47 + 17));
+ _scene->_dynamicHotspots.add(NOUN_SANDBAG, VERB_LOOK_AT, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(98, 14, 98 + 5, 14 + 10));
+ _scene->_dynamicHotspots.add(NOUN_SANDBAG, VERB_LOOK_AT, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(111, 23, 111 + 6, 23 + 9));
+ _scene->_dynamicHotspots.add(NOUN_SANDBAG, VERB_LOOK_AT, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(119, 12, 119 + 5, 12 + 8));
+
+ int idx = _scene->_dynamicHotspots.add(NOUN_STAGE, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(80, 114, 80 + 24, 114 + 4));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(93, 121), FACING_NONE);
+
+ idx = _scene->_dynamicHotspots.add(NOUN_STAGE, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(106, 102, 106 + 5, 102 + 10));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(108, 109), FACING_NONE);
+ } else {
+ _scene->_hotspots.activate(NOUN_BOXES, false);
+ _scene->_hotspots.activate(NOUN_CASE, false);
+ }
+
+ if ((_game._objects.isInRoom(OBJ_CABLE_HOOK)) && (_globals[kCurrentYear] == 1881) && !_game._objects.isInInventory(OBJ_ROPE_WITH_HOOK)){
+ _globals._sequenceIndexes[8] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[8], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[8], 3);
+ } else {
+ _scene->_hotspots.activate(NOUN_CABLE_HOOK, false);
+ }
+
+ if (_scene->_priorSceneId == 109) {
+ _game._player._playerPos = Common::Point(180, 58);
+ _game._player._facing = FACING_SOUTH;
+ _game._player.walk(Common::Point(179, 63), FACING_SOUTH);
+ _game._player.setWalkTrigger(60);
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 5);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+ } else if ((_scene->_priorSceneId == 105) || (_scene->_priorSceneId == 301)) {
+ _game._player._playerPos = Common::Point(235, 142);
+ _game._player._facing = FACING_WEST;
+ _game._player.walk(Common::Point(227, 143), FACING_WEST);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+ } else if (_scene->_priorSceneId == 107) {
+ _game._player._playerPos = Common::Point(143, 68);
+ _game._player._facing = FACING_WEST;
+ _game._player.walk(Common::Point(163, 68), FACING_SOUTHEAST);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+ } else if ((_scene->_priorSceneId == 108) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
+ _game._player.firstWalk(Common::Point(-20, 130), FACING_SOUTHEAST, Common::Point(19, 147), FACING_NORTHEAST, true);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+ } else if (_scene->_priorSceneId == RETURNING_FROM_LOADING) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene106::step() {
+ switch (_game._trigger) {
+ case 85:
+ _scene->playSpeech(8);
+ _scene->_sequences.addTimer(120, 86);
+ break;
+
+ case 86:
+ _vm->_dialogs->show(10637);
+ break;
+
+ case 60:
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[2], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 5);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 61);
+ break;
+
+ case 61:
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+ _vm->_sound->command(25);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene106::actions() {
+ if ((_action.isAction(VERB_TAKE, NOUN_SANDBAG)) && (_scene->_customDest.y < 61)) {
+ _vm->_dialogs->show(10635);
+ _action._inProgress = false;
+ return;
+ } else if (_action.isAction(VERB_TAKE, NOUN_SANDBAG)) {
+ if (_game._objects.isInRoom(OBJ_SANDBAG)) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[5] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[5], false, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 1, 5);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[5], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _scene->deleteSequence(_globals._sequenceIndexes[0]);
+ _scene->_dynamicHotspots.remove(_sandbagHostpotId);
+ _vm->_sound->command(26);
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[5]);
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(20, 3);
+ break;
+
+ case 3:
+ _game._objects.addToInventory(OBJ_SANDBAG);
+ _vm->_dialogs->showItem(OBJ_SANDBAG, 803, 0);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_CABLE_HOOK)) {
+ if (_game._objects.isInRoom(OBJ_CABLE_HOOK)) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[5] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[5], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 1, 5);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[5], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ _globals[kPlayerScore] += 5;
+ break;
+
+ case 1:
+ _scene->deleteSequence(_globals._sequenceIndexes[8]);
+ _scene->_hotspots.activate(NOUN_CABLE_HOOK, false);
+ _vm->_sound->command(26);
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[5]);
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(20, 3);
+ break;
+
+ case 3:
+ _game._objects.addToInventory(OBJ_CABLE_HOOK);
+ _vm->_dialogs->showItem(OBJ_CABLE_HOOK, 822, 0);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ switch (_game._trigger) {
+ case 75:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('d', 1), 76);
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[0], SYNC_PLAYER, 0);
+ _action._inProgress = false;
+ return;
+
+ case 76:
+ _scene->_nextSceneId = 105;
+ _action._inProgress = false;
+ return;
+
+ case 80:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('u', 1), 81);
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[0], SYNC_PLAYER, 0);
+ _action._inProgress = false;
+ return;
+
+ case 81:
+ _scene->_sequences.addTimer(120, 82);
+ _action._inProgress = false;
+ return;
+
+ case 82:
+ _scene->_nextSceneId = 301;
+ _action._inProgress = false;
+ return;
+
+ default:
+ break;
+ }
+
+ if (_action.isAction(VERB_EXIT_TO, NOUN_STAGE_RIGHT_WING)) {
+ _scene->_nextSceneId = 107;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLIMB_DOWN) || _action.isAction(VERB_CLIMB_UP)) {
+ if (_globals[kSandbagStatus] == 1) {
+ switch (_game._trigger) {
+ case 0:
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('s',-1), 1);
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ break;
+
+ case 1:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[0]);
+ _game._player._visible = true;
+ _game._player._playerPos = Common::Point(225, 143);
+ _game._player.resetFacing(FACING_EAST);
+ _game._player.walk(Common::Point(236, 142), FACING_EAST);
+
+ if (_action.isAction(VERB_CLIMB_DOWN))
+ _game._player.setWalkTrigger(75);
+ else
+ _game._player.setWalkTrigger(80);
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ switch (_game._trigger) {
+ case 0:
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 4, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], 1, 9);
+ _scene->_sequences.addTimer(6, 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1:
+ _vm->_sound->command(70);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 2);
+ _sandbagHostpotId = _scene->_dynamicHotspots.add(NOUN_SANDBAG, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(227, 140, 227 + 18, 140 + 11));
+ _scene->_dynamicHotspots.setPosition(_sandbagHostpotId, Common::Point(224, 152), FACING_NORTHEAST);
+ break;
+
+ case 2:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('s', 1), 3);
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[0], SYNC_PLAYER, 0);
+ break;
+
+ case 3:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[0]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ _game._player._playerPos = Common::Point(228, 140);
+ _game._player.resetFacing(FACING_SOUTHEAST);
+ _globals[kSandbagStatus] = 1;
+ _vm->_dialogs->show(10632);
+ break;
+
+ default:
+ break;
+ }
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR) || _action.isAction(VERB_OPEN, NOUN_DOOR)) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[3] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[3], false, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[3], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_SPRITE, 4, 65);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 67);
+ break;
+
+ case 65:
+ _vm->_sound->command(24);
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 5);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 66);
+ break;
+
+ case 66: {
+ int idx = _globals._sequenceIndexes[2];
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 5);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[2], SYNC_SEQ, idx);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+ }
+ break;
+
+ case 67:
+ _game._player._visible = true;
+ _game._player.walk(Common::Point(180, 60), FACING_NORTH);
+ _game._player.setWalkTrigger(68);
+ break;
+
+ case 68:
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[2], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 69);
+ break;
+
+ case 69:
+ _vm->_sound->command(25);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _scene->_nextSceneId = 109;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(10610);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_STAGE_RIGHT_WING)) {
+ _vm->_dialogs->show(10611);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_STAGE_LEFT_WING)) {
+ _vm->_dialogs->show(10612);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_IN_TWO)) {
+ _vm->_dialogs->show(10613);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CYCLORAMA)) {
+ _vm->_dialogs->show(10614);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_STAGE)) {
+ _vm->_dialogs->show(10615);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PEDESTAL)) {
+ _vm->_dialogs->show(10616);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PLANT_PROP)) {
+ _vm->_dialogs->show(10617);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SANDBAG)) {
+ if (_scene->_customDest.y < 60) {
+ _vm->_dialogs->show(10618);
+ _action._inProgress = false;
+ return;
+ } else if (_game._objects.isInRoom(OBJ_SANDBAG)) {
+ _vm->_dialogs->show(10633);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isObject(NOUN_STATUE)) {
+ _vm->_dialogs->show(10619);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CIRCULAR_STAIRCASE)) {
+ _vm->_dialogs->show(10620);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BATTEN)) {
+ _vm->_dialogs->show(10621);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DOOR)) {
+ _vm->_dialogs->show(10622);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BOXES) || _action.isObject(NOUN_BOX)) {
+ _vm->_dialogs->show(10623);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BIG_PROP)) {
+ _vm->_dialogs->show(10624);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CRATE)) {
+ _vm->_dialogs->show(10625);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CASE)) {
+ if (_globals[kCurrentYear] == 1881)
+ _vm->_dialogs->show(10638);
+ else
+ _vm->_dialogs->show(10636);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_VENTILATION_DUCT)) {
+ _vm->_dialogs->show(10626);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_JUNK)) {
+ _vm->_dialogs->show(10627);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FLATS)) {
+ _vm->_dialogs->show(10628);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(10629);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CABLE_HOOK) && _game._objects.isInRoom(OBJ_CABLE_HOOK)) {
+ _vm->_dialogs->show(10639);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TALK_TO, NOUN_STATUE)) {
+ _vm->_dialogs->show(10630);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLOSE, NOUN_DOOR)) {
+ _vm->_dialogs->show(10634);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene106::preActions() {
+ if (_action.isAction(VERB_EXIT_TO, NOUN_STAGE_LEFT_WING))
+ _game._player._walkOffScreenSceneId = 108;
+
+ if (_action.isAction(VERB_OPEN, NOUN_DOOR))
+ _game._player.walk(Common::Point(179, 63), FACING_NORTHWEST);
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene107::Scene107(MADSEngine *vm) : Scene1xx(vm) {
+}
+
+void Scene107::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+}
+
+void Scene107::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene107::enter() {
+ if (_globals[kCurrentYear] == 1993)
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('z', -1));
+
+ if (_game._objects.isInRoom(OBJ_YELLOW_FRAME)) {
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('f', 0));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites("*RRD_9");
+ }
+
+ if (_game._objects.isInRoom(OBJ_YELLOW_FRAME)) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+ } else {
+ _scene->_hotspots.activate(NOUN_YELLOW_FRAME, false);
+ }
+
+ if (_globals[kCurrentYear] == 1993) {
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_PROP_TABLE, false);
+ } else {
+ _scene->_hotspots.activate(NOUN_HEADSET, false);
+ }
+
+ if (_scene->_priorSceneId == 106) {
+ _game._player._playerPos = Common::Point(276, 73);
+ _game._player._facing = FACING_SOUTHWEST;
+ _game._player.walk(Common::Point(248, 75), FACING_SOUTHWEST);
+ } else if ((_scene->_priorSceneId == 104) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
+ if (_game._player._playerPos.y > 128) {
+ _game._player._playerPos.x = 216;
+ _game._player._facing = FACING_NORTHWEST;
+ } else if (_game._player._playerPos.y > 99) {
+ _game._player._playerPos.x = 127;
+ _game._player._facing = FACING_NORTHWEST;
+ } else {
+ _game._player._playerPos.x = 44;
+ _game._player._facing = FACING_NORTHEAST;
+ }
+ _game._player._playerPos.y = 143;
+ }
+
+ sceneEntrySound();
+}
+
+void Scene107::step() {
+}
+
+void Scene107::actions() {
+ if (_action.isAction(VERB_WALK_ONTO, NOUN_STAGE)) {
+ _scene->_nextSceneId = 104;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK, NOUN_BACKSTAGE)) {
+ _scene->_nextSceneId = 106;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_YELLOW_FRAME) && (_game._objects.isInRoom(OBJ_YELLOW_FRAME) || _game._trigger)) {
+ switch (_game._trigger) {
+ case (0):
+ if (_globals[kCurrentYear] == 1881) {
+ int count = 0;
+ if (_game._objects.isInInventory(OBJ_GREEN_FRAME))
+ ++count;
+ if (_game._objects.isInInventory(OBJ_RED_FRAME))
+ ++count;
+ if (_game._objects.isInInventory(OBJ_BLUE_FRAME))
+ ++count;
+
+ if (count < 3)
+ _globals[kPlayerScore] += 5;
+ }
+
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[1] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[1], false, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 5);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[1], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _scene->_hotspots.activate(NOUN_YELLOW_FRAME, false);
+ _game._objects.addToInventory(OBJ_YELLOW_FRAME);
+ _vm->_sound->command(26);
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[1]);
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(20, 3);
+ break;
+
+ case 3:
+ if (_globals[kCurrentYear] == 1881)
+ _vm->_dialogs->showItem(OBJ_YELLOW_FRAME, 843, 0);
+ else
+ _vm->_dialogs->showItem(OBJ_YELLOW_FRAME, 804, 0);
+
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(10710);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_STAGE)) {
+ _vm->_dialogs->show(10711);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_IN_TWO)) {
+ _vm->_dialogs->show(10712);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_IN_ONE)) {
+ _vm->_dialogs->show(10713);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CYCLORAMA)) {
+ _vm->_dialogs->show(10714);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_COUNTERWEIGHT_SYSTEM)) {
+ _vm->_dialogs->show(10715);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PURCHASE_LINES)) {
+ _vm->_dialogs->show(10716);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LOCKRAIL)) {
+ _vm->_dialogs->show(10717);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_STAGE)) {
+ _vm->_dialogs->show(10718);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PROP_TABLE)) {
+ _vm->_dialogs->show(10719);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_ACT_CURTAIN)) {
+ _vm->_dialogs->show(10720);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LEG)) {
+ _vm->_dialogs->show(10721);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_APRON)) {
+ _vm->_dialogs->show(10722);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PROSCENIUM_ARCH)) {
+ _vm->_dialogs->show(10723);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_STAGE)) {
+ _vm->_dialogs->show(10724);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BACKSTAGE)) {
+ _vm->_dialogs->show(10725);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME) && _game._objects.isInRoom(OBJ_YELLOW_FRAME)) {
+ if (_globals[kCurrentYear] == 1881)
+ _vm->_dialogs->show(10727);
+ else
+ _vm->_dialogs->show(10726);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_HEADSET)) {
+ _vm->_dialogs->show(10728);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(10730);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_HEADSET)) {
+ _vm->_dialogs->show(10729);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TALK_TO, NOUN_HEADSET)) {
+ _vm->_dialogs->show(10732);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_PULL, NOUN_PURCHASE_LINES)) {
+ _vm->_dialogs->show(10731);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene107::preActions() {
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene108::Scene108(MADSEngine *vm) : Scene1xx(vm) {
+ _anim0ActvFl = false;
+ _handRaisedFl = false;
+ _shutUpCount = -1;
+ _maxTalkCount = -1;
+ _charAction = -1;
+ _charFrame = -1;
+ _charHotspotId = -1;
+ _charTalkCount = -1;
+ _conversationCount = -1;
+ _prevShutUpFrame = -1;
+}
+
+void Scene108::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+
+ s.syncAsByte(_anim0ActvFl);
+ s.syncAsByte(_handRaisedFl);
+ s.syncAsSint16LE(_shutUpCount);
+ s.syncAsSint16LE(_maxTalkCount);
+ s.syncAsSint16LE(_charAction);
+ s.syncAsSint16LE(_charFrame);
+ s.syncAsSint16LE(_charHotspotId);
+ s.syncAsSint16LE(_charTalkCount);
+ s.syncAsSint16LE(_conversationCount);
+ s.syncAsSint16LE(_prevShutUpFrame);
+}
+
+void Scene108::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ if (_globals[kCurrentYear] == 1993)
+ _scene->_variant = 1;
+
+ _scene->addActiveVocab(NOUN_GENTLEMAN);
+ _scene->addActiveVocab(NOUN_CHARLES);
+}
+
+void Scene108::enter() {
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ _anim0ActvFl = false;
+ _handRaisedFl = false;
+ _charTalkCount = 0;
+ _shutUpCount = 40;
+ _maxTalkCount = 15;
+ }
+
+ _vm->_gameConv->load(2);
+
+ if (_globals[kCurrentYear] == 1993) {
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('z', -1));
+ _scene->_hotspots.activate(NOUN_STOOL, false);
+ int idx = _scene->_dynamicHotspots.add(NOUN_STOOL, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(250, 68, 250 + 8, 68 + 21));
+ _scene->_dynamicHotspots[idx]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(253, 75), FACING_SOUTHEAST);
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+ } else {
+ _scene->_hotspots.activate(NOUN_HEADSET, false);
+ int idx = _scene->_dynamicHotspots.add(NOUN_WALL, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(258, 58, 258 + 6, 58 + 10));
+ _scene->_dynamicHotspots[idx]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(236, 69), FACING_NORTHEAST);
+ }
+
+ if ((_globals[kCurrentYear] == 1993) && (_globals[kDoneBrieConv203] == 0)) {
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('c', 1), 1);
+ _anim0ActvFl = true;
+
+ if (_vm->_gameConv->activeConvId() == 2) {
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ _charAction = 0;
+ _vm->_gameConv->run(2);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ _vm->_gameConv->exportValue(_globals[kJulieNameIsKnown]);
+ _vm->_gameConv->exportValue(_globals[kObservedPhan104]);
+ _scene->setAnimFrame(_globals._animationIndexes[0], 55);
+ _shutUpCount = 40;
+ } else {
+ _charAction = 2;
+ }
+
+ if (_globals[kCharlesNameIsKnown]) {
+ _charHotspotId = _scene->_dynamicHotspots.add(NOUN_CHARLES, VERB_WALK_TO, SYNTAX_SINGULAR_MASC, EXT_NONE, Common::Rect(253, 52, 253 + 15, 52 + 34));
+ _scene->_dynamicHotspots[_charHotspotId]._articleNumber = PREP_ON;
+ } else {
+ _charHotspotId = _scene->_dynamicHotspots.add(NOUN_GENTLEMAN, VERB_WALK_TO, SYNTAX_MASC_NOT_PROPER, EXT_NONE, Common::Rect(253, 52, 253 + 15, 52 + 34));
+ _scene->_dynamicHotspots[_charHotspotId]._articleNumber = PREP_ON;
+ }
+ _scene->_dynamicHotspots.setPosition(_charHotspotId, Common::Point(235, 102), FACING_NORTHEAST);
+ }
+
+ if (_scene->_priorSceneId == 106) {
+ _game._player._playerPos = Common::Point(48, 81);
+ _game._player._facing = FACING_SOUTHEAST;
+ _game._player.walk(Common::Point(71, 76), FACING_SOUTHEAST);
+ } else if ((_scene->_priorSceneId == 104) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
+ if (_game._player._playerPos.y > 128) {
+ _game._player._playerPos.x = 124;
+ _game._player._facing = FACING_NORTHEAST;
+ } else if (_game._player._playerPos.y > 99) {
+ _game._player._playerPos.x = 185;
+ _game._player._facing = FACING_NORTHEAST;
+ } else {
+ _game._player._playerPos.x = 243;
+ _game._player._facing = FACING_NORTHWEST;
+ }
+
+ _game._player._playerPos.y = 143;
+ }
+
+ sceneEntrySound();
+}
+
+void Scene108::step() {
+ if (_anim0ActvFl)
+ handleCharAnimation();
+
+ if ((_globals[kWalkerConverse] == 2) || (_globals[kWalkerConverse] == 3)) {
+ ++_conversationCount;
+ if (_conversationCount > 200)
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ }
+}
+
+void Scene108::actions() {
+ if (_vm->_gameConv->activeConvId() == 2) {
+ handleCharlesConversation();
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TALK_TO, NOUN_GENTLEMAN) || _action.isAction(VERB_TALK_TO, NOUN_CHARLES)) {
+ _charAction = 6;
+ _game._player._stepEnabled = false;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_ONTO, NOUN_STAGE)) {
+ _scene->_nextSceneId = 104;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK, NOUN_BACKSTAGE)) {
+ _scene->_nextSceneId = 106;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(10810);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(10730);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_STAGE)) {
+ _vm->_dialogs->show(10811);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_IN_TWO)) {
+ _vm->_dialogs->show(10812);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_IN_ONE)) {
+ _vm->_dialogs->show(10813);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PROSCENIUM_ARCH)) {
+ _vm->_dialogs->show(10814);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_ACT_CURTAIN)) {
+ _vm->_dialogs->show(10815);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LEG)) {
+ _vm->_dialogs->show(10816);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CYCLORAMA)) {
+ _vm->_dialogs->show(10817);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FLATS)) {
+ _vm->_dialogs->show(10818);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_STAGEMANAGERS_POST)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(10819);
+ else
+ _vm->_dialogs->show(10820);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_STOOL)) {
+ _vm->_dialogs->show(10821);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BACKSTAGE)) {
+ _vm->_dialogs->show(10822);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_STAGE)) {
+ _vm->_dialogs->show(10823);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_HEADSET)) {
+ _vm->_dialogs->show(10824);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(10826);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CHARLES) || _action.isObject(NOUN_GENTLEMAN)) {
+ _vm->_dialogs->show(10827);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_CHARLES) || _action.isAction(VERB_TAKE, NOUN_GENTLEMAN)) {
+ _vm->_dialogs->show(10828);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_HEADSET)) {
+ _vm->_dialogs->show(10825);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_STOOL) && (_globals[kCurrentYear] == 1993)) {
+ _vm->_dialogs->show(10829);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TALK_TO, NOUN_HEADSET)) {
+ _vm->_dialogs->show(10830);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene108::preActions() {
+}
+
+void Scene108::handleCharAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == _charFrame)
+ return;
+
+ _charFrame = _scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame();
+ int resetFrame = -1;
+ int random = -1;
+
+ switch (_charFrame) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 92:
+ if (_charAction == 2)
+ random = _vm->getRandomNumber(2, 15);
+
+ if (_charAction == 6) {
+ _charTalkCount = 0;
+ _charAction = 1;
+ random = 1;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 5;
+ break;
+
+ case 2:
+ resetFrame = 0;
+ break;
+
+ case 3:
+ resetFrame = 1;
+ break;
+
+ case 4:
+ resetFrame = 2;
+ break;
+
+ default:
+ resetFrame = 3;
+ break;
+ }
+ break;
+
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 27:
+ case 33:
+ case 41:
+ case 51:
+ case 52:
+ case 53:
+ case 54:
+ case 55:
+ case 56:
+ case 57:
+ case 62:
+ case 73:
+ if (_charFrame == 18) {
+ _game._player._stepEnabled = true;
+ _vm->_gameConv->run(2);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ _vm->_gameConv->exportValue(_globals[kJulieNameIsKnown]);
+ _vm->_gameConv->exportValue(_globals[kObservedPhan104]);
+ }
+
+ if (_charAction == 1) {
+ if (_handRaisedFl) {
+ random = _vm->getRandomNumber(1, 3);
+ } else {
+ random = _vm->getRandomNumber(1, 4);
+ if (random == 4)
+ random = _vm->getRandomNumber(1, 4);
+ }
+
+ if (random == 4)
+ _handRaisedFl = true;
+
+ ++_charTalkCount;
+ if (_charTalkCount > _maxTalkCount) {
+ _charAction = 0;
+ _shutUpCount = 0;
+ _prevShutUpFrame = 10;
+ random = 12;
+ }
+ } else if (_charAction == 0) {
+ int delay = _vm->getRandomNumber(10, 15);
+ ++_shutUpCount;
+ if (_shutUpCount > delay) {
+ random = _vm->getRandomNumber(10, 16);
+ _prevShutUpFrame = random;
+ if (random == 15)
+ _shutUpCount = 16;
+ else
+ _shutUpCount = 0;
+ } else {
+ random = _prevShutUpFrame;
+ }
+ } else if (_charAction == 7) {
+ _charAction = 1;
+ random = 5;
+ } else if (_charAction == 3) {
+ _charAction = 1;
+ random = 6;
+ } else if (_charAction == 5) {
+ _charAction = 1;
+ random = 7;
+ } else if (_charAction == 4) {
+ _charAction = 1;
+ random = 8;
+ } else if (_charAction == 2) {
+ random = 9;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 18;
+ break;
+
+ case 2:
+ resetFrame = 19;
+ break;
+
+ case 3:
+ resetFrame = 20;
+ break;
+
+ case 4:
+ resetFrame = 62;
+ _charTalkCount += 5;
+ break;
+
+ case 5:
+ resetFrame = 21;
+ break;
+
+ case 6:
+ resetFrame = 41;
+ break;
+
+ case 7:
+ resetFrame = 33;
+ break;
+
+ case 8:
+ resetFrame = 27;
+ break;
+
+ case 9:
+ resetFrame = 74;
+ break;
+
+ case 10:
+ resetFrame = 51;
+ break;
+
+ case 11:
+ resetFrame = 53;
+ break;
+
+ case 12:
+ resetFrame = 54;
+ break;
+
+ case 13:
+ resetFrame = 55;
+ break;
+
+ case 14:
+ resetFrame = 56;
+ break;
+
+ case 15:
+ resetFrame = 57;
+ break;
+
+ case 16:
+ resetFrame = 52;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[0], resetFrame);
+ _charFrame = resetFrame;
+ }
+}
+
+void Scene108::handleCharlesConversation() {
+ switch (_action._activeAction._verbId) {
+ case 1:
+ case 25:
+ case 26:
+ _globals[kWalkerConverse] = 0;
+ _vm->_gameConv->setHeroTrigger(64);
+ if (_action._activeAction._verbId == 26)
+ _globals[kCharlesNameIsKnown] = 2;
+ break;
+
+ case 2:
+ if (!_globals[kCharlesNameIsKnown]) {
+ _scene->_dynamicHotspots.remove(_charHotspotId);
+ _charHotspotId = _scene->_dynamicHotspots.add(NOUN_CHARLES, VERB_WALK_TO, SYNTAX_SINGULAR_MASC, EXT_NONE, Common::Rect(253, 52, 253 + 15, 52 + 34));
+ _scene->_dynamicHotspots[_charHotspotId]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_charHotspotId, Common::Point(235, 102), FACING_NORTHEAST);
+ _globals[kCharlesNameIsKnown] = true;
+ }
+ break;
+
+ case 5:
+ _vm->_gameConv->setInterlocutorTrigger(66);
+ _maxTalkCount = 35;
+ break;
+
+ case 6:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 15:
+ _maxTalkCount = 35;
+ break;
+
+ case 16:
+ _vm->_gameConv->setInterlocutorTrigger(68);
+ _maxTalkCount = 35;
+ break;
+
+ case 19:
+ _vm->_gameConv->setInterlocutorTrigger(72);
+ break;
+
+ case 22:
+ _vm->_gameConv->setInterlocutorTrigger(70);
+ break;
+
+ default:
+ _maxTalkCount = 15;
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 60:
+ _charAction = 1;
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ break;
+
+ case 62:
+ _globals[kWalkerConverse] = _vm->getRandomNumber(2, 3);
+ _conversationCount = 0;
+ _charAction = 0;
+ break;
+
+ case 64:
+ _charAction = 2;
+ break;
+
+ case 66:
+ _charAction = 5;
+ break;
+
+ case 68:
+ _charAction = 4;
+ break;
+
+ case 70:
+ _charAction = 7;
+ break;
+
+ case 72:
+ _charAction = 3;
+ break;
+
+ default:
+ break;
+ }
+
+ if ((_action._activeAction._verbId != 1) && (_action._activeAction._verbId != 5) &&
+ (_action._activeAction._verbId != 16) && (_action._activeAction._verbId != 19) &&
+ (_action._activeAction._verbId != 22) && (_action._activeAction._verbId != 25) &&
+ (_action._activeAction._verbId != 26) && (_charAction != 2)) {
+ _vm->_gameConv->setInterlocutorTrigger(60);
+ _vm->_gameConv->setHeroTrigger(62);
+ }
+
+ _charTalkCount = 0;
+ _shutUpCount = 40;
+ _handRaisedFl = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene109::Scene109(MADSEngine *vm) : Scene1xx(vm) {
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _anim2ActvFl = false;
+ _anim3ActvFl = false;
+
+ _currentFloor = -1;
+}
+
+void Scene109::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+
+ s.syncAsByte(_anim0ActvFl);
+ s.syncAsByte(_anim1ActvFl);
+ s.syncAsByte(_anim2ActvFl);
+ s.syncAsByte(_anim3ActvFl);
+
+ s.syncAsSint16LE(_currentFloor);
+}
+
+void Scene109::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene109::enter() {
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _anim2ActvFl = false;
+ _anim3ActvFl = false;
+
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 2));
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites("*RDR_6");
+
+ if (_globals[kCurrentYear] == 1881) {
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('x', 3));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('x', 4));
+
+ _scene->_hotspots.activate(NOUN_LIGHT_FIXTURE, false);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
+ _globals._sequenceIndexes[4] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[4], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 14);
+ _scene->_sequences.addTimer(1, 70);
+ } else {
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('z', 0));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('z', 1));
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('z', 2));
+
+ _scene->_hotspots.activate(NOUN_LAMP, false);
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, 1);
+ _globals._sequenceIndexes[6] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[6], false, 1);
+ _globals._sequenceIndexes[7] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[7], false, 1);
+ }
+
+ if (_scene->_priorSceneId == 106) {
+ _game._player._playerPos = Common::Point(31, 459);
+ _game._player._facing = FACING_NORTHEAST;
+ _scene->setCamera(Common::Point(0, 312));
+ _scene->sceneScale(467, 95, 442, 78);
+ _currentFloor = 1;
+ } else if (_scene->_priorSceneId == 111) {
+ if (_globals[kLeaveAngelMusicOn]) {
+ _globals[kLeaveAngelMusicOn] = false;
+ sceneEntrySound();
+ }
+ _game._player._playerPos = Common::Point(4, 136);
+ _game._player._facing = FACING_EAST;
+ _game._player.walk(Common::Point(32, 138), FACING_EAST);
+ _game._player.setWalkTrigger(60);
+ _game._player._stepEnabled = false;
+ _scene->setCamera(Common::Point(0, 0));
+ _scene->sceneScale(155, 95, 130, 78);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 3);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ _currentFloor = 3;
+ } else if ((_scene->_priorSceneId == 110) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
+ _game._player._playerPos = Common::Point(3, 292);
+ _game._player._facing = FACING_EAST;
+ _game._player.walk(Common::Point(31, 295), FACING_EAST);
+ _game._player.setWalkTrigger(65);
+ _game._player._stepEnabled = false;
+ _scene->setCamera(Common::Point(0, 156));
+ _scene->sceneScale(311, 95, 286, 78);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 3);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ _currentFloor = 2;
+ } else if (_scene->_priorSceneId == RETURNING_FROM_LOADING) {
+ if (_currentFloor == 2) {
+ _scene->setCamera(Common::Point(0, 156));
+ _scene->sceneScale(311, 95, 286, 78);
+ } else if (_currentFloor == 3) {
+ _scene->setCamera(Common::Point(0, 0));
+ _scene->sceneScale(155, 95, 130, 78);
+ } else {
+ _scene->setCamera(Common::Point(0, 312));
+ _scene->sceneScale(467, 95, 442, 78);
+ }
+ }
+
+ sceneEntrySound();
+}
+
+void Scene109::step() {
+ if (_anim0ActvFl) {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == 80)
+ _game._camY.camPanTo(156);
+ }
+
+ if (_anim1ActvFl) {
+ if (_scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame() == 80)
+ _game._camY.camPanTo(0);
+ }
+
+ if (_anim2ActvFl) {
+ if (_scene->_animation[_globals._animationIndexes[2]]->getCurrentFrame() == 7)
+ _game._camY.camPanTo(312);
+ }
+
+ if (_anim3ActvFl) {
+ if (_scene->_animation[_globals._animationIndexes[3]]->getCurrentFrame() == 14)
+ _game._camY.camPanTo(156);
+ }
+
+ switch (_game._trigger) {
+ case 60:
+ _scene->deleteSequence(_globals._sequenceIndexes[0]);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[0], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], 1, 3);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 61);
+ break;
+
+ case 61:
+ _vm->_sound->command(25);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 65:
+ _scene->deleteSequence(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[1], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 3);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 66);
+ break;
+
+ case 66:
+ _vm->_sound->command(25);
_game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+
+ if (_game._trigger == 70) {
+ int rndFrame = _vm->getRandomNumber(1, 3);
+ int rndDelay = _vm->getRandomNumber(4, 7);
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _scene->deleteSequence(_globals._sequenceIndexes[3]);
+ _scene->deleteSequence(_globals._sequenceIndexes[4]);
+
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, rndFrame);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, rndFrame);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
+
+ _globals._sequenceIndexes[4] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[4], false, rndFrame);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 14);
+
+ _scene->_sequences.addTimer(rndDelay, 70);
}
}
+void Scene109::actions() {
+ if (_action.isAction(VERB_WALK, NOUN_BACKSTAGE)) {
+ _scene->_nextSceneId = 106;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLIMB_UP, NOUN_STAIRCASE)) {
+ if (_currentFloor == 2) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player.walk(Common::Point(58, 295), FACING_EAST);
+ _game._player.setWalkTrigger(1);
+ break;
+
+ case 1:
+ _anim1ActvFl = true;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('w', 2), 2);
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[1], SYNC_PLAYER, 0);
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[1]);
+ _scene->sceneScale(155, 95, 130, 78);
+ _anim1ActvFl = false;
+ _game._player._visible = true;
+ _game._player._playerPos = Common::Point(261, 137);
+ _game._player.walk(Common::Point(281, 143), FACING_SOUTHWEST);
+ _game._player.setWalkTrigger(3);
+ break;
+
+ case 3:
+ _game._player._stepEnabled = true;
+ _currentFloor = 3;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_currentFloor == 1) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player.walk(Common::Point(58, 452), FACING_EAST);
+ _game._player.setWalkTrigger(1);
+ break;
+
+ case 1:
+ _anim0ActvFl = true;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('w', 1), 2);
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[0], SYNC_PLAYER, 0);
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[0]);
+ _scene->sceneScale(311, 95, 286, 78);
+ _anim0ActvFl = false;
+ _game._player._visible = true;
+ _game._player._playerPos = Common::Point(264, 295);
+ _game._player.walk(Common::Point(289, 299), FACING_SOUTHWEST);
+ _game._player.setWalkTrigger(3);
+ break;
+
+ case 3:
+ _game._player._stepEnabled = true;
+ _currentFloor = 2;
+ break;
+
+ default:
+ break;
+ }
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLIMB_DOWN, NOUN_STAIRCASE)) {
+ if (_currentFloor == 2) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player.walk(Common::Point(287, 291), FACING_WEST);
+ _game._player.setWalkTrigger(1);
+ break;
+
+ case 1:
+ _game._player.walk(Common::Point(269, 292), FACING_WEST);
+ _game._player.setWalkTrigger(2);
+ break;
+
+ case 2:
+ _anim2ActvFl = true;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._animationIndexes[2] = _scene->loadAnimation(formAnimName('w', 3), 3);
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[2], SYNC_PLAYER, 0);
+ break;
+
+ case 3:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[2]);
+ _scene->sceneScale(467, 95, 442, 78);
+ _anim2ActvFl = false;
+ _game._player._visible = true;
+ _game._player._playerPos = Common::Point(61, 450);
+ _game._player.walk(Common::Point(36, 450), FACING_SOUTHEAST);
+ _game._player.setWalkTrigger(4);
+ break;
+
+ case 4:
+ _game._player._stepEnabled = true;
+ _currentFloor = 1;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_currentFloor == 3) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player.walk(Common::Point(287, 137), FACING_WEST);
+ _game._player.setWalkTrigger(1);
+ break;
+
+ case 1:
+ _game._player.walk(Common::Point(269, 138), FACING_WEST);
+ _game._player.setWalkTrigger(2);
+ break;
+
+ case 2:
+ _anim3ActvFl = true;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._animationIndexes[3] = _scene->loadAnimation(formAnimName('w', 4), 3);
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[3], SYNC_PLAYER, 0);
+ break;
+
+ case 3:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[3]);
+ _scene->sceneScale(311, 95, 286, 78);
+ _anim3ActvFl = false;
+ _game._player._visible = true;
+ _game._player._playerPos = Common::Point(59, 296);
+ _game._player.walk(Common::Point(40, 294), FACING_SOUTHEAST);
+ _game._player.setWalkTrigger(4);
+ break;
+
+ case 4:
+ _game._player._stepEnabled = true;
+ _currentFloor = 2;
+ break;
+
+ default:
+ break;
+ }
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR) || _action.isAction(VERB_OPEN, NOUN_DOOR) || _game._trigger) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[8] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[8], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[8], -1, -2);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[8], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_SPRITE, 4, 75);
+ break;
+
+ case 2:
+ _game._player._visible = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[8]);
+ if (_currentFloor == 3)
+ _game._player.walk(Common::Point(2, 131), FACING_WEST);
+ else if (_currentFloor == 2)
+ _game._player.walk(Common::Point(2, 281), FACING_WEST);
+
+ _scene->_sequences.addTimer(180, 3);
+ break;
+
+ case 3:
+ if (_currentFloor == 3)
+ _scene->_nextSceneId = 111;
+ else if (_currentFloor == 2)
+ _scene->_nextSceneId = 110;
+ break;
+
+ case 75:
+ _vm->_sound->command(24);
+ if (_currentFloor == 3) {
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], 1, 3);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 76);
+ } else if (_currentFloor == 2) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 3);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 76);
+ }
+ break;
+
+ case 76:
+ if (_currentFloor == 3) {
+ int idx = _globals._sequenceIndexes[0];
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 3);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[0], SYNC_SEQ, idx);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ } else if (_currentFloor == 2) {
+ int idx = _globals._sequenceIndexes[1];
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 3);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[1], SYNC_SEQ, idx);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ }
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(10910);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_STAIRCASE)) {
+ if (_currentFloor == 1)
+ _vm->_dialogs->show(10911);
+ else if (_currentFloor == 2)
+ _vm->_dialogs->show(10921);
+ else if (_currentFloor == 3)
+ _vm->_dialogs->show(10922);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(10912);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BACKSTAGE)) {
+ _vm->_dialogs->show(10913);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DOOR)) {
+ _vm->_dialogs->show(10914);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RAILING)) {
+ _vm->_dialogs->show(10915);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(10916);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LIGHT_FIXTURE)) {
+ _vm->_dialogs->show(10917);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LAMP)) {
+ _vm->_dialogs->show(10918);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_HOLE)) {
+ _vm->_dialogs->show(10919);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CEILING)) {
+ _vm->_dialogs->show(10920);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_LAMP)) {
+ _vm->_dialogs->show(10924);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLOSE, NOUN_DOOR)) {
+ _vm->_dialogs->show(10923);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene109::preActions() {
+ if (_action.isAction(VERB_OPEN, NOUN_DOOR)) {
+ if (_currentFloor == 3)
+ _game._player.walk(Common::Point(32, 138), FACING_WEST);
+ else if (_currentFloor == 2)
+ _game._player.walk(Common::Point(31, 295), FACING_WEST);
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene110::Scene110(MADSEngine *vm) : Scene1xx(vm) {
+}
+
+void Scene110::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+}
+
+void Scene110::setup() {
+ if (_globals[kCurrentYear] == 1993)
+ _scene->_variant = 1;
+
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene110::enter() {
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites("*RDR_9");
+
+ if (_globals[kCurrentYear] == 1993) {
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('z', -1));
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_POSTER, false);
+ _scene->_hotspots.activate(NOUN_WASTE_BASKET, false);
+
+ if (_globals[kDoneBrieConv203] == 0) {
+ if (_globals[kJuliesDoor] == 0) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 3);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 8);
+ }
+ } else {
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 8);
+ }
+ } else {
+ _scene->_hotspots.activate(NOUN_BULLETIN_BOARD, false);
+ _scene->_hotspots.activate(NOUN_PAPER, false);
+ _scene->_hotspots.activate(NOUN_TRASH_BUCKET, false);
+ }
+
+ if (_scene->_priorSceneId == 112) {
+ _game._player._playerPos = Common::Point(261, 121);
+ _game._player._facing = FACING_SOUTH;
+ _game._player.walk(Common::Point(221, 131), FACING_SOUTH);
+ } else if ((_scene->_priorSceneId == 109) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
+ _game._player.firstWalk(Common::Point(335, 150), FACING_WEST, Common::Point(310, 150), FACING_WEST, true);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene110::step() {
+}
+
+void Scene110::actions() {
+ if ((_action.isAction(VERB_WALK_THROUGH, NOUN_RIGHT_DOOR) || _action.isAction(VERB_UNLOCK, NOUN_RIGHT_DOOR) || _action.isAction(VERB_LOCK, NOUN_RIGHT_DOOR))
+ && (_globals[kDoneBrieConv203] == 0) && (_globals[kCurrentYear] == 1993) && (_globals[kJuliesDoor] == 0)) {
+ _scene->_nextSceneId = 112;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_LEFT_DOOR) || _action.isAction(VERB_OPEN, NOUN_LEFT_DOOR)
+ || _action.isAction(VERB_UNLOCK, NOUN_LEFT_DOOR) || _action.isAction(VERB_LOCK, NOUN_LEFT_DOOR)) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 5, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[1], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1: {
+ int idx = _globals._sequenceIndexes[1];
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 4);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[1], SYNC_SEQ, idx);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[1], false);
+ _scene->_sequences.addTimer(30, 2);
+ _vm->_sound->command(73);
+ }
+ break;
+
+ case 2:
+ _scene->deleteSequence(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[1], false, 5, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[1], false);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[1]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ if (_action.isAction(VERB_LOCK) || _action.isAction(VERB_UNLOCK))
+ _vm->_dialogs->show(32);
+ else
+ _vm->_dialogs->show(11022);
+
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_RIGHT_DOOR) || _action.isAction(VERB_OPEN, NOUN_RIGHT_DOOR)
+ || _action.isAction(VERB_UNLOCK, NOUN_RIGHT_DOOR) || _action.isAction(VERB_LOCK, NOUN_RIGHT_DOOR)) {
+ if (((_globals[kCurrentYear] == 1881) || (_globals[kDoneBrieConv203] >= 1))
+ && !_action.isAction(VERB_UNLOCK, NOUN_RIGHT_DOOR) && !_action.isAction(VERB_LOCK, NOUN_RIGHT_DOOR)) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 5, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[1], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1: {
+ int idx = _globals._sequenceIndexes[1];
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 4);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[1], SYNC_SEQ, idx);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[1], false);
+ _scene->_sequences.addTimer(30, 2);
+ _vm->_sound->command(73);
+ }
+ break;
+
+ case 2:
+ _scene->deleteSequence(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[1], false, 5, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[1], false);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[1]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ if (_action.isAction(VERB_LOCK) || _action.isAction(VERB_UNLOCK))
+ _vm->_dialogs->show(32);
+ else
+ _vm->_dialogs->show(11023);
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ } else if (_globals[kJuliesDoor] == 1) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[1] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[1], false, 7, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[1], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_SPRITE, 4, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 1:
+ _vm->_sound->command(24);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 10, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], -1, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 10);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 2:
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 3);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 10);
+ break;
+
+ case 3:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[1]);
+ _game._player._visible = true;
+ _game._player.walk(Common::Point(261, 121), FACING_NORTHEAST);
+ _game._player.setWalkTrigger(4);
+ break;
+
+ case 4:
+ _scene->_nextSceneId = 112;
+ _globals[kJuliesDoor] = 0;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(11010);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(11011);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(11012);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CEILING)) {
+ _vm->_dialogs->show(11013);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_STAIRWELL)) {
+ _vm->_dialogs->show(11014);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RIGHT_DOOR)) {
+ if (_globals[kDoneBrieConv203] >= 1)
+ _vm->_dialogs->show(11016);
+ else if (_globals[kChrisFStatus] == 1)
+ _vm->_dialogs->show(11015);
+ else
+ _vm->_dialogs->show(11016);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LEFT_DOOR)) {
+ _vm->_dialogs->show(11016);
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isObject(NOUN_WASTE_BASKET)) || (_action.isObject(NOUN_TRASH_BUCKET))) {
+ _vm->_dialogs->show(11017);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_POSTER)) {
+ _vm->_dialogs->show(11018);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BULLETIN_BOARD)) {
+ _vm->_dialogs->show(11019);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PAPER)) {
+ _vm->_dialogs->show(11029);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_WASTE_BASKET) || _action.isAction(VERB_TAKE, NOUN_TRASH_BUCKET)) {
+ _vm->_dialogs->show(11020);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LIGHT_FIXTURE)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(11021);
+ else
+ _vm->_dialogs->show(11028);
+
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_PAPER)) {
+ _vm->_dialogs->show(11030);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLOSE, NOUN_RIGHT_DOOR)) {
+ if (_globals[kDoneBrieConv203] >= 1)
+ _vm->_dialogs->show(11026);
+ else if (_globals[kChrisFStatus] == 1)
+ _vm->_dialogs->show(11024);
+ else
+ _vm->_dialogs->show(11026);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLOSE, NOUN_LEFT_DOOR)) {
+ _vm->_dialogs->show(11025);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_RIGHT_DOOR)) {
+ if ((_globals[kChrisFStatus] == 1) && (_globals[kDoneBrieConv203] == 0))
+ _vm->_dialogs->show(11027);
+
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene110::preActions() {
+ if (_action.isAction(VERB_EXIT_TO, NOUN_STAIRWELL))
+ _game._player._walkOffScreenSceneId = 109;
+
+ if (_action.isAction(VERB_OPEN, NOUN_LEFT_DOOR) || _action.isAction(VERB_UNLOCK, NOUN_LEFT_DOOR) || _action.isAction(VERB_LOCK, NOUN_LEFT_DOOR))
+ _game._player.walk(Common::Point(111, 126), FACING_NORTHEAST);
+
+ if (_action.isAction(VERB_OPEN, NOUN_RIGHT_DOOR) || _action.isAction(VERB_WALK_THROUGH, NOUN_RIGHT_DOOR)
+ || _action.isAction(VERB_UNLOCK, NOUN_RIGHT_DOOR) || _action.isAction(VERB_LOCK, NOUN_RIGHT_DOOR)) {
+ if ((_globals[kCurrentYear] == 1881) || (_globals[kDoneBrieConv203] >= 1))
+ _game._player.walk(Common::Point(221, 131), FACING_NORTHEAST);
+ else if ((_globals[kJuliesDoor] == 1) || _action.isAction(VERB_OPEN))
+ _game._player.walk(Common::Point(223, 128), FACING_NORTHEAST);
+ else if (_globals[kJuliesDoor] == 0)
+ _game._player.walk(Common::Point(261, 120), FACING_NORTHEAST);
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_PAPER))
+ _game._player._needToWalk = true;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene111::Scene111(MADSEngine *vm) : Scene1xx(vm) {
+ _removeAxe = false;
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _closedFl = false;
+ _listenFrame = -1;
+ _listenStatus = -1;
+
+}
+
+void Scene111::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+
+ s.syncAsByte(_removeAxe);
+ s.syncAsByte(_anim0ActvFl);
+ s.syncAsByte(_anim1ActvFl);
+ s.syncAsByte(_closedFl);
+ s.syncAsSint16LE(_listenFrame);
+ s.syncAsSint16LE(_listenStatus);
+}
+
+void Scene111::setup() {
+ if (_globals[kCurrentYear] == 1993)
+ _scene->_variant = 1;
+
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene111::enter() {
+ _scene->_hotspots.activate(NOUN_HOOK, false);
+
+ _removeAxe = false;
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _closedFl = true;
+
+ if (_globals[kCurrentYear] == 1881) {
+ if ((_globals[kJacquesNameIsKnown] == 2) && (_globals[kMadameNameIsKnown] == 2) && (_globals[kPanelIn206]) &&
+ (_globals[kDoneRichConv203]) && (_game._objects.isInInventory(OBJ_LANTERN)) &&
+ ((_game._objects.isInInventory(OBJ_CABLE_HOOK) && _game._objects.isInInventory(OBJ_ROPE)) || _game._objects.isInInventory(OBJ_ROPE_WITH_HOOK))) {
+ _closedFl = false;
+ } else
+ _closedFl = true;
+ } else
+ _closedFl = false;
+
+ if (_globals[kJacquesStatus]) {
+ _scene->_hotspots.activate(NOUN_HOOK, true);
+ _scene->_hotspots.activate(NOUN_FIRE_AXE, false);
+ }
+
+ _vm->_gameConv->load(14);
+
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites("*RDR_9");
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('a', 1));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('a', 3));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('x', 0));
+
+ if (_globals[kCurrentYear] == 1881)
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('a', 2));
+
+ if (_globals[kCurrentYear] == 1993) {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('z', -1));
+ _scene->drawToBackground(_globals._spriteIndexes[1], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_LAMP, false);
+ int idx = _scene->_dynamicHotspots.add(NOUN_WALL, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(35, 82, 35 + 13, 82 + 11));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(78, 122), FACING_NORTHEAST);
+ } else {
+ _scene->_hotspots.activate(NOUN_LIGHT, false);
+ if (_globals[kChristineDoorStatus] == 2) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 10);
+ _scene->drawToBackground(_globals._spriteIndexes[4], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_FIRE_AXE, false);
+ _scene->_hotspots.activate(NOUN_DOOR_CHUNKS, true);
+ _scene->_hotspots.activate(NOUN_HANDLE, true);
+ _scene->_hotspots.activate(NOUN_AXE, true);
+ }
+ }
+
+ if ((_globals[kChristineDoorStatus] == 0) && (_scene->_priorSceneId != 113) && !_closedFl) {
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, 3);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 14);
+ }
+
+ if ((_globals[kCurrentYear] == 1993) || (_globals[kChristineDoorStatus] <= 1)) {
+ if (!_globals[kJacquesStatus]) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 5);
+ _scene->_hotspots.activate(NOUN_AXE, false);
+ }
+ _scene->_hotspots.activate(NOUN_DOOR_CHUNKS, false);
+ _scene->_hotspots.activate(NOUN_HANDLE, false);
+ }
+
+ if (_scene->_priorSceneId == 113) {
+ _game._player._playerPos = Common::Point(146, 108);
+ _game._player.walk(Common::Point(112, 126), FACING_SOUTH);
+
+ if (!_globals[kLeaveAngelMusicOn])
+ sceneEntrySound();
+
+ if (_globals[kChristineDoorStatus] != 2) {
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, 3);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 14);
+
+ if ((_globals[kCurrentYear] == 1881) && (_globals[kLeaveAngelMusicOn])) {
+ _game._player.setWalkTrigger(60);
+ _game._player._stepEnabled = false;
+ _globals[kChristineDoorStatus] = 1;
+ _globals[kChrisKickedRaoulOut] = true;
+ _globals[kHintThatDaaeIsHome1] = true;
+ _globals[kHintThatDaaeIsHome2] = true;
+ }
+ }
+ } else if ((_scene->_priorSceneId == 109) || (_scene->_priorSceneId != RETURNING_FROM_LOADING))
+ _game._player.firstWalk(Common::Point(335, 150), FACING_WEST, Common::Point(311, 150), FACING_WEST, true);
+
+ sceneEntrySound();
+}
+
+void Scene111::step() {
+ if (_anim0ActvFl)
+ handleListenAnimation();
+
+ if (!_removeAxe && _anim1ActvFl && (_scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame() == 5)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _game._objects.addToInventory(OBJ_FIRE_AXE);
+ _removeAxe = true;
+ }
+
+ if (_game._objects.isInInventory(OBJ_FIRE_AXE) && _anim1ActvFl && (_scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame() == 36))
+ _game._objects.setRoom(OBJ_FIRE_AXE, NOWHERE);
+
+ if (_game._player._playerPos == Common::Point(145, 108))
+ _scene->_nextSceneId = 113;
+
+ switch (_game._trigger) {
+ case 60:
+ _scene->deleteSequence(_globals._sequenceIndexes[5]);
+ _globals._sequenceIndexes[5] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[5], false, 7, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 62);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], -1, -2);
+ break;
+
+ case 62:
+ _vm->_sound->command(25);
+ _game._player._stepEnabled = true;
+ _vm->_gameConv->run(14);
+ if (_game._difficulty == DIFFICULTY_EASY)
+ _vm->_gameConv->exportValue(1);
+ else
+ _vm->_gameConv->exportValue(0);
+
+ _game._player.walk(Common::Point(119, 124), FACING_EAST);
+ _game._player.setWalkTrigger(64);
+ break;
+
+ case 64:
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('l', 1), 70);
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[0], SYNC_PLAYER, 0);
+ _anim0ActvFl = true;
+ _listenStatus = 0;
+ _game._player._visible = false;
+ break;
+
+ case 70:
+ _game._player._visible = true;
+ _anim0ActvFl = false;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[0]);
+ _scene->_sequences.addTimer(30, 71);
+ break;
+
+ case 71:
+ _vm->_gameConv->release();
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene111::actions() {
+ if (_vm->_gameConv->activeConvId() == 14) {
+ handleListenConversation();
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_RIGHT_DOOR) || _action.isAction(VERB_OPEN, NOUN_RIGHT_DOOR) || _action.isAction(VERB_UNLOCK) || _action.isAction(VERB_LOCK)) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 5, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[0], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ _action._inProgress = false;
+ return;
+
+ case 1: {
+ int idx = _globals._sequenceIndexes[0];
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 4);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[0], SYNC_SEQ, idx);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[0], false);
+ _scene->_sequences.addTimer(30, 2);
+ _vm->_sound->command(73);
+ _action._inProgress = false;
+ return;
+ }
+
+ case 2:
+ _scene->deleteSequence(_globals._sequenceIndexes[0]);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[0], false, 5, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[0], false);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ _action._inProgress = false;
+ return;
+
+ case 3:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[0]);
+ _game._player._visible = true;
+ if (_action.isAction(VERB_LOCK) || _action.isAction(VERB_UNLOCK))
+ _vm->_dialogs->show(32);
+ else
+ _vm->_dialogs->show(11123);
+
+ _game._player._stepEnabled = true;
+ _action._inProgress = false;
+ return;
+
+ default:
+ break;
+ }
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_LEFT_DOOR) || _action.isAction(VERB_OPEN, NOUN_LEFT_DOOR) || _action.isAction(VERB_UNLOCK, NOUN_LEFT_DOOR) || _action.isAction(VERB_LOCK, NOUN_LEFT_DOOR)) {
+ if ((_globals[kChristineDoorStatus] == 1) || _closedFl || _action.isAction(VERB_UNLOCK, NOUN_LEFT_DOOR) || _action.isAction(VERB_LOCK, NOUN_LEFT_DOOR)) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 5, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[0], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ _action._inProgress = false;
+ return;
+
+ case 1: {
+ int idx = _globals._sequenceIndexes[0];
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 4);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[0], SYNC_SEQ, idx);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[0], false);
+ _scene->_sequences.addTimer(30, 2);
+ _vm->_sound->command(73);
+ _action._inProgress = false;
+ return;
+ }
+
+ case 2:
+ _scene->deleteSequence(_globals._sequenceIndexes[0]);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[0], false, 5, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[0], false);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ _action._inProgress = false;
+ return;
+
+ case 3:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[0]);
+ _game._player._visible = true;
+
+ if (_action.isAction(VERB_LOCK) || _action.isAction(VERB_UNLOCK))
+ _vm->_dialogs->show(32);
+ else if ((_globals[kChrisKickedRaoulOut]) && (_globals[kTicketPeoplePresent] == 1) && (_globals[kJacquesStatus] == 0))
+ _vm->_dialogs->show(11135);
+ else
+ _vm->_dialogs->show(11124);
+
+ _game._player._stepEnabled = true;
+ _action._inProgress = false;
+ return;
+
+ default:
+ break;
+ }
+ } else if (_globals[kChristineDoorStatus] == 2) {
+ _vm->_dialogs->show(11137);
+ _action._inProgress = false;
+ return;
+ } else {
+ _vm->_dialogs->show(11126);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_FIRE_AXE)) {
+ if ((_globals[kCurrentYear] == 1881) && (_globals[kJacquesStatus] == 0) && (_globals[kChristineDoorStatus] == 1) && (_globals[kChrisKickedRaoulOut])) {
+ switch (_game._trigger) {
+ case 0:
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('q', -1), 1);
+ _scene->_hotspots.activate(NOUN_FIRE_AXE, false);
+ _scene->_hotspots.activate(NOUN_DOOR_CHUNKS, true);
+ _scene->_hotspots.activate(NOUN_HANDLE, true);
+ _scene->_hotspots.activate(NOUN_AXE, true);
+ _anim1ActvFl = true;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ break;
+
+ case 1:
+ _globals[kChristineDoorStatus] = 2;
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[3], SYNC_ANIM, _globals._animationIndexes[1]);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 10);
+ _scene->drawToBackground(_globals._spriteIndexes[4], 1, Common::Point(-32000, -32000), 0, 100);
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[1]);
+ _game._player._visible = true;
+ _game._player._playerPos = Common::Point(126, 126);
+ _anim1ActvFl = false;
+ _game._player.walk(Common::Point(145, 108), FACING_NORTHEAST);
+ _game._player.resetFacing(FACING_NORTHWEST);
+ break;
+
+ default:
+ break;
+ }
+ } else if (_globals[kCurrentYear] == 1993 && _globals[kMakeBrieLeave203])
+ _vm->_dialogs->show(11142);
+ else
+ _vm->_dialogs->show(11134);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(11110);
+ else
+ _vm->_dialogs->show(11111);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(11112);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(11113);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CEILING)) {
+ _vm->_dialogs->show(11114);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_STAIRWELL)) {
+ _vm->_dialogs->show(11115);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_TABLE)) {
+ _vm->_dialogs->show(11118);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PLANT)) {
+ _vm->_dialogs->show(11119);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FIRE_AXE)) {
+ _vm->_dialogs->show(11120);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_HANDLE)) {
+ _vm->_dialogs->show(11121);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_AXE)) {
+ _vm->_dialogs->show(11122);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DOOR_CHUNKS)) {
+ _vm->_dialogs->show(11129);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LIGHT)) {
+ _vm->_dialogs->show(11131);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LAMP)) {
+ _vm->_dialogs->show(11132);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_HOOK)) {
+ _vm->_dialogs->show(11141);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LEFT_DOOR)) {
+ if (_globals[kJacquesStatus])
+ _vm->_dialogs->show(11140);
+ else if (_globals[kChristineDoorStatus] == 2)
+ _vm->_dialogs->show(11130);
+ else if ((_globals[kChrisKickedRaoulOut]) && (_globals[kTicketPeoplePresent] == 1))
+ _vm->_dialogs->show(11136);
+ else if ((_globals[kChristineDoorStatus] == 1) || _closedFl)
+ _vm->_dialogs->show(11117);
+ else if (_globals[kChristineDoorStatus] == 0)
+ _vm->_dialogs->show(11116);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RIGHT_DOOR)) {
+ _vm->_dialogs->show(11117);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_CLOSE, NOUN_RIGHT_DOOR)) {
+ _vm->_dialogs->show(11128);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLOSE, NOUN_LEFT_DOOR)) {
+ if (_closedFl)
+ _vm->_dialogs->show(11128);
+ else if ((_globals[kChristineDoorStatus] == 2) && (!_globals[kTicketPeoplePresent]))
+ _vm->_dialogs->show(11138);
+ else if (_globals[kChristineDoorStatus] == 1)
+ _vm->_dialogs->show(11127);
+ else if (_globals[kChristineDoorStatus] == 0)
+ _vm->_dialogs->show(11125);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_LEFT_DOOR)) {
+ if (_globals[kChristineDoorStatus] == 0)
+ _vm->_dialogs->show(11126);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene111::preActions() {
+ if (_action.isAction(VERB_EXIT_TO, NOUN_STAIRWELL)) {
+ if (_globals[kLeaveAngelMusicOn]) {
+ _vm->_dialogs->show(11139);
+ _game._player._needToWalk = false;
+ _game._player.cancelCommand();
+ } else
+ _game._player._walkOffScreenSceneId = 109;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_FIRE_AXE) && _game._objects.isInRoom(OBJ_FIRE_AXE) && (_globals[kCurrentYear] == 1881)
+ && (_globals[kChristineDoorStatus] == 1) && (_globals[kChrisKickedRaoulOut]) && (_globals[kJacquesStatus] == 0))
+ _game._player.walk(Common::Point(119, 124), FACING_EAST);
+
+ if (_action.isAction(VERB_OPEN, NOUN_RIGHT_DOOR) || _action.isAction(VERB_UNLOCK, NOUN_RIGHT_DOOR) || _action.isAction(VERB_LOCK, NOUN_RIGHT_DOOR))
+ _game._player.walk(Common::Point(219, 131), FACING_NORTHEAST);
+
+ if (_action.isAction(VERB_OPEN, NOUN_LEFT_DOOR) || _action.isAction(VERB_UNLOCK, NOUN_LEFT_DOOR) || _action.isAction(VERB_LOCK, NOUN_LEFT_DOOR))
+ _game._player.walk(Common::Point(109, 124), FACING_NORTHEAST);
+
+ if ((_action.isAction(VERB_WALK_THROUGH, NOUN_LEFT_DOOR) || _action.isAction(VERB_UNLOCK, NOUN_LEFT_DOOR) || _action.isAction(VERB_LOCK, NOUN_LEFT_DOOR))
+ && !_closedFl && ((_globals[kChristineDoorStatus] == 2) || (_globals[kChristineDoorStatus] == 0)))
+ _game._player.walk(Common::Point(145, 108), FACING_NORTHEAST);
+}
+
+void Scene111::handleListenAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == _listenFrame)
+ return;
+
+ int nextFrame = -1;
+ _listenFrame = _scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame();
+
+ if (_listenFrame == 6) {
+ if (_listenStatus == 0)
+ nextFrame = 5;
+ else if (_listenStatus == 1)
+ nextFrame = 7;
+ }
+
+ if (nextFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[0], nextFrame);
+ _listenFrame = nextFrame;
+ }
+}
+
+void Scene111::handleListenConversation() {
+ if (_action._activeAction._verbId == 1)
+ _vm->_gameConv->setInterlocutorTrigger(66);
+
+ if (_action._activeAction._verbId == 7)
+ _vm->_gameConv->setInterlocutorTrigger(68);
+
+ if (_game._trigger == 66)
+ _listenStatus = 0;
+
+ if (_game._trigger == 68) {
+ _listenStatus = 1;
+ _vm->_gameConv->hold();
+ }
+
+ if ((_action._activeAction._verbId != 1) && (_action._activeAction._verbId != 7))
+ _vm->_gameConv->setInterlocutorTrigger(72);
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene112::Scene112(MADSEngine *vm) : Scene1xx(vm) {
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _raoulAction = -1;
+ _raoulFrame = -1;
+ _didOptionFl = -1;
+ _julieFrame = -1;
+ _julieAction = -1;
+ _julieHotspotId = -1;
+ _julieCounter = -1;
+}
+
+void Scene112::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+
+ s.syncAsByte(_anim0ActvFl);
+ s.syncAsByte(_anim1ActvFl);
+ s.syncAsSint16LE(_raoulAction);
+ s.syncAsSint16LE(_raoulFrame);
+ s.syncAsSint16LE(_didOptionFl);
+ s.syncAsSint16LE(_julieFrame);
+ s.syncAsSint16LE(_julieAction);
+ s.syncAsSint16LE(_julieCounter);
+}
+
+void Scene112::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ _scene->addActiveVocab(NOUN_WOMAN);
+ _scene->addActiveVocab(NOUN_JULIE);
+}
+
+void Scene112::enter() {
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ _raoulAction = 2;
+ _didOptionFl = 0;
+ }
+
+ _vm->_gameConv->load(3);
+
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('j', 1), 1);
+ _anim0ActvFl = true;
+ _julieAction = 2;
+ _scene->setAnimFrame(_globals._animationIndexes[0], 3);
+ if (_globals[kJulieNameIsKnown] == 2) {
+ _julieHotspotId = _scene->_dynamicHotspots.add(NOUN_JULIE, VERB_WALK_TO, SYNTAX_SINGULAR_FEM, EXT_NONE, Common::Rect(255, 82, 255 + 30, 82 + 44));
+ _scene->_dynamicHotspots[_julieHotspotId]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_julieHotspotId, Common::Point(216, 137), FACING_NORTHEAST);
+ _scene->_hotspots.activate(NOUN_WOMAN, false);
+ }
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('r', 1), 1);
+ _anim1ActvFl = true;
+ _scene->setAnimFrame(_globals._animationIndexes[1], 82);
+ _raoulAction = 2;
+
+ if (_vm->_gameConv->restoreRunning() == 3) {
+ _vm->_gameConv->run(3);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ _scene->setAnimFrame(_globals._animationIndexes[1], 17);
+ _raoulAction = 1;
+ _game._player._playerPos = Common::Point(53, 128);
+ _game._player._facing = FACING_EAST;
+ _game._player._visible = false;
+ } else if ((_scene->_priorSceneId == 110) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
+ _game._player._playerPos = Common::Point(128, 145);
+ _game._player._facing = FACING_NORTH;
+ }
+
+ sceneEntrySound();
+}
+
+void Scene112::step() {
+ if (_anim0ActvFl)
+ handleJulieAnimation();
+
+ if (_anim1ActvFl)
+ handleRaoulChair();
+}
+
+void Scene112::actions() {
+ if (_vm->_gameConv->activeConvId() == 3) {
+ handleConversation();
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isAction(VERB_TALK_TO, NOUN_JULIE)) || (_action.isAction(VERB_TALK_TO, NOUN_WOMAN))) {
+ if (_globals[kJulieNameIsKnown] > 0) {
+ _game._player._visible = false;
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[1], SYNC_PLAYER, 0);
+ _scene->setAnimFrame(_globals._animationIndexes[1], 1);
+ _raoulAction = 1;
+ }
+ _vm->_gameConv->run(3);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_EXIT_TO, NOUN_CORRIDOR)) {
+ _scene->_nextSceneId = 110;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(11210);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(11211);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(11212);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_MIRROR)) {
+ _vm->_dialogs->show(11213);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BALLET_BAR)) {
+ _vm->_dialogs->show(11214);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CORRIDOR)) {
+ _vm->_dialogs->show(11215);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_THROW_RUGS)) {
+ _vm->_dialogs->show(11216);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DRESSING_SCREEN)) {
+ _vm->_dialogs->show(11217);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DRESSING_TABLE)) {
+ _vm->_dialogs->show(11218);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CHAIR)) {
+ _vm->_dialogs->show(11219);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PLANT)) {
+ _vm->_dialogs->show(11220);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_COAT_RACK)) {
+ _vm->_dialogs->show(11221);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_UMBRELLA)) {
+ _vm->_dialogs->show(11222);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PAINTINGS)) {
+ _vm->_dialogs->show(11223);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_TRASH_BUCKET)) {
+ _vm->_dialogs->show(11224);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SHELF)) {
+ _vm->_dialogs->show(11225);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CONTAINER)) {
+ _vm->_dialogs->show(11226);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_TORN_POSTER)) {
+ _vm->_dialogs->show(11227);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_POSTER)) {
+ _vm->_dialogs->show(11228);
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isObject(NOUN_REVIEW)) || (_action.isObject(NOUN_REVIEWS))) {
+ _vm->_dialogs->show(11229);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_JULIE)) {
+ _vm->_dialogs->show(11231);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_COSTUME_RACK)) {
+ _vm->_dialogs->show(11232);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LIGHT_FIXTURE)) {
+ _vm->_dialogs->show(11233);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WARDROBE)) {
+ _vm->_dialogs->show(11234);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WOMAN)) {
+ _vm->_dialogs->show(11237);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE)) {
+ if (_action.isObject(NOUN_WOMAN) || _action.isObject(NOUN_JULIE)) {
+ _vm->_dialogs->show(11238);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_WARDROBE)) {
+ _vm->_dialogs->show(11235);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_CONTAINER)) {
+ _vm->_dialogs->show(11236);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene112::preActions() {
+ if ((_action.isAction(VERB_TALK_TO, NOUN_JULIE) || _action.isAction(VERB_TALK_TO, NOUN_WOMAN)) && (_globals[kJulieNameIsKnown] > 0))
+ _game._player.walk(Common::Point(53, 128), FACING_EAST);
+}
+
+void Scene112::handleConversation() {
+ switch (_action._activeAction._verbId) {
+ case 1:
+ if (!_game._trigger && (_raoulAction == 2))
+ _vm->_gameConv->setInterlocutorTrigger(68);
+ break;
+
+ case 3:
+ case 4:
+ if (_globals[kJulieNameIsKnown] < 2) {
+ _globals[kJulieNameIsKnown] = 2;
+ _scene->_hotspots.activate(NOUN_WOMAN, false);
+ _julieHotspotId = _scene->_dynamicHotspots.add(NOUN_JULIE, VERB_WALK_TO, SYNTAX_SINGULAR_FEM, EXT_NONE, Common::Rect(255, 82, 255 + 30, 82 + 44));
+ _scene->_dynamicHotspots[_julieHotspotId]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_julieHotspotId, Common::Point(216, 137), FACING_NORTHEAST);
+ }
+ break;
+
+ case 5:
+ _vm->_gameConv->setInterlocutorTrigger(74);
+ _globals[kJulieNameIsKnown] = 1;
+ break;
+
+ case 6:
+ case 7:
+ case 10:
+ case 23:
+ case 27:
+ _vm->_gameConv->setInterlocutorTrigger(74);
+ _globals[kJulieNameIsKnown] = 2;
+ break;
+
+ case 13:
+ _julieAction = 1;
+ _raoulAction = 1;
+ break;
+
+ case 14:
+ case 15:
+ case 16:
+ _julieAction = 0;
+ _raoulAction = 1;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 60:
+ _julieAction = 0;
+ _raoulAction = 1;
+ break;
+
+ case 62:
+ _julieAction = 2;
+ if (_raoulAction != 2)
+ _raoulAction = 0;
+ break;
+
+ case 68:
+ _scene->_sequences.addTimer(120, 70);
+ _vm->_gameConv->hold();
+ break;
+
+ case 70:
+ _game._player.walk(Common::Point(53, 128), FACING_EAST);
+ _game._player.setWalkTrigger(72);
+ break;
+
+ case 72:
+ _vm->_gameConv->release();
+ _game._player._visible = false;
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[1], SYNC_PLAYER, 0);
+ _scene->setAnimFrame(_globals._animationIndexes[1], 1);
+ _raoulAction = 1;
+ break;
+
+ case 74:
+ _raoulAction = 3;
+ _vm->_gameConv->hold();
+ break;
+
+ default:
+ break;
+ }
+
+ if ((_action._activeAction._verbId != 0) && (_action._activeAction._verbId != 1) &&
+ (_action._activeAction._verbId != 2) && (_action._activeAction._verbId != 5) &&
+ (_action._activeAction._verbId != 6) && (_action._activeAction._verbId != 7) &&
+ (_action._activeAction._verbId != 10) && (_action._activeAction._verbId != 23) &&
+ (_action._activeAction._verbId != 27)) {
+ _vm->_gameConv->setInterlocutorTrigger(60);
+ _vm->_gameConv->setHeroTrigger(62);
+ }
+
+ if (_action._activeAction._verbId == 18)
+ _globals[kCanFindBookInLibrary] = true;
+
+ _julieCounter = 0;
+}
+
+void Scene112::handleJulieAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == _julieFrame)
+ return;
+
+ _julieFrame = _scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame();
+ int random = -1;
+ int resetFrame = -1;
+
+ switch (_julieFrame) {
+ case 1:
+ case 2:
+ case 3:
+ case 22:
+ case 39:
+ case 71:
+ case 107:
+ switch (_julieAction) {
+ case 0:
+ random = _vm->getRandomNumber(4, 6);
+ ++_julieCounter;
+ if (_julieCounter > 25)
+ _julieAction = 2;
+ break;
+
+ case 1:
+ random = 3;
+ break;
+
+ case 2:
+ random = _vm->getRandomNumber(1, 3);
+ while (_didOptionFl == random)
+ random = _vm->getRandomNumber(1, 3);
+ _didOptionFl = random;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 22;
+ break;
+
+ case 2:
+ resetFrame = 39;
+ break;
+
+ case 3:
+ resetFrame = 83;
+ break;
+
+ case 4:
+ resetFrame = 0;
+ break;
+
+ case 5:
+ resetFrame = 1;
+ break;
+
+ case 6:
+ resetFrame = 2;
+ break;
+
+ default:
+ break;
+ }
+ break;
+ case 56:
+ case 77:
+ case 83:
+ random = _vm->getRandomNumber(1, 3);
+ while (_didOptionFl == random)
+ random = _vm->getRandomNumber(1, 3);
+ _didOptionFl = random;
+
+ if ((_julieAction == 0) || (_julieAction == 1))
+ random = 3;
+
+ switch (random) {
+ case 1:
+ resetFrame = 71;
+ break;
+
+ case 2:
+ resetFrame = 77;
+ break;
+
+ case 3:
+ resetFrame = 56;
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ case 95:
+ if (_julieAction == 1)
+ random = 2;
+ else
+ random = 1;
+
+ switch (random) {
+ case 1:
+ resetFrame = 95;
+ break;
+
+ case 2:
+ resetFrame = 107;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 130:
+ resetFrame = 95;
+ _julieAction = 2;
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[0], resetFrame);
+ _julieFrame = resetFrame;
+ }
+}
+
+void Scene112::handleRaoulChair() {
+ if (_scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame() == _raoulFrame)
+ return;
+
+ _raoulFrame = _scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame();
+ int resetFrame = -1;
+ int random = -1;
+
+ switch (_raoulFrame) {
+ case 18:
+ case 30:
+ case 41:
+ case 49:
+ case 56:
+ case 65:
+ switch (_raoulAction) {
+ case 0:
+ random = _vm->getRandomNumber(1, 4);
+ _raoulAction = 1;
+ break;
+
+ case 2:
+ random = 6;
+ break;
+
+ case 3:
+ random = 5;
+ _raoulAction = 2;
+ break;
+
+ default:
+ random = _vm->getRandomNumber(7, 50);
+ while (_didOptionFl == random)
+ random = _vm->getRandomNumber(7, 50);
+ _didOptionFl = random;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 49;
+ break;
+
+ case 2:
+ resetFrame = 41;
+ break;
+
+ case 3:
+ resetFrame = 18;
+ break;
+
+ case 4:
+ resetFrame = 30;
+ break;
+
+ case 5:
+ resetFrame = 65;
+ break;
+
+ case 6:
+ resetFrame = 82;
+ break;
+
+ case 7:
+ resetFrame = 56;
+ break;
+
+ default:
+ resetFrame = 17;
+ break;
+ }
+ break;
+
+ case 61:
+ if (_raoulAction == 1)
+ random = 1;
+ else
+ random = 2;
+
+ switch (random) {
+ case 1:
+ resetFrame = 60;
+ break;
+
+ case 2:
+ resetFrame = 61;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 82:
+ _raoulAction = 2;
+ _game._player._visible = true;
+ _vm->_gameConv->release();
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[1]);
+ break;
+
+ case 83:
+ if (_raoulAction == 2)
+ random = 1;
+ else
+ random = 2;
+
+ switch (random) {
+ case 1:
+ resetFrame = 82;
+ break;
+
+ case 2:
+ resetFrame = 0;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[1], resetFrame);
+ _raoulFrame = resetFrame;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene113::Scene113(MADSEngine *vm) : Scene1xx(vm) {
+ _standingAndTalking = false;
+ _dayWantsToTalk = false;
+ _musicPlaying = false;
+ _afterKissFl = false;
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _anim2ActvFl = false;
+ _anim3ActvFl = false;
+ _anim4ActvFl = false;
+ _prevent1 = false;
+ _prevent2 = false;
+ _raoulStandingFl = false;
+ _armsOutFl = false;
+
+ _dayStatus = -1;
+ _raoulAction = -1;
+ _christineHotspotId1 = -1;
+ _christineHotspotId2 = -1;
+ _raoulCount = -1;
+ _dayCount = -1;
+ _standCount = -1;
+ _julieStatus = -1;
+ _florentStatus = -1;
+ _florentFrame = -1;
+ _florentCount = -1;
+ _dayFrame = -1;
+ _lastDayResetFrame = -1;
+ _raoulFrame = -1;
+ _julieFrame = -1;
+ _julieCount = -1;
+}
+
+void Scene113::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+
+ s.syncAsByte(_standingAndTalking);
+ s.syncAsByte(_dayWantsToTalk);
+ s.syncAsByte(_musicPlaying);
+ s.syncAsByte(_afterKissFl);
+ s.syncAsByte(_anim0ActvFl);
+ s.syncAsByte(_anim1ActvFl);
+ s.syncAsByte(_anim2ActvFl);
+ s.syncAsByte(_anim3ActvFl);
+ s.syncAsByte(_anim4ActvFl);
+ s.syncAsByte(_prevent1);
+ s.syncAsByte(_prevent2);
+ s.syncAsByte(_raoulStandingFl);
+ s.syncAsByte(_armsOutFl);
+
+ s.syncAsSint16LE(_dayStatus);
+ s.syncAsSint16LE(_raoulAction);
+ s.syncAsSint16LE(_christineHotspotId1);
+ s.syncAsSint16LE(_christineHotspotId2);
+ s.syncAsSint16LE(_raoulCount);
+ s.syncAsSint16LE(_dayCount);
+ s.syncAsSint16LE(_standCount);
+ s.syncAsSint16LE(_julieStatus);
+ s.syncAsSint16LE(_florentStatus);
+ s.syncAsSint16LE(_florentFrame);
+ s.syncAsSint16LE(_florentCount);
+ s.syncAsSint16LE(_dayFrame);
+ s.syncAsSint16LE(_lastDayResetFrame);
+ s.syncAsSint16LE(_raoulFrame);
+ s.syncAsSint16LE(_julieFrame);
+ s.syncAsSint16LE(_julieCount);
+}
+
+void Scene113::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ _scene->addActiveVocab(NOUN_CHRISTINE);
+ _scene->addActiveVocab(NOUN_WOMAN);
+ _scene->addActiveVocab(NOUN_JULIE);
+}
+
+void Scene113::enter() {
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ _standingAndTalking = false;
+ _dayWantsToTalk = false;
+ _musicPlaying = false;
+ _afterKissFl = false;
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _anim2ActvFl = false;
+ _anim3ActvFl = false;
+ _anim4ActvFl = false;
+ _prevent1 = false;
+ _prevent2 = false;
+ _raoulStandingFl = false;
+ _armsOutFl = false;
+ }
+
+ _scene->_hotspots.activate(NOUN_SMALL_NOTE, false);
+ _scene->_hotspots.activate(NOUN_DRESSING_GOWN, false);
+ _scene->_hotspots.activate(NOUN_CHRISTINE, false);
+ _scene->_hotspots.activate(NOUN_JULIE, false);
+ _scene->_hotspots.activate(NOUN_LIGHT_FIXTURE, false);
+
+ if (_globals[kCurrentYear] == 1993) {
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('z', -1));
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('f', 0));
+
+ if (_game._objects.isInRoom(OBJ_SMALL_NOTE))
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('f', 1));
+
+ if ((_globals[kDoneBrieConv203] == 1) || (_globals[kDoneBrieConv203] == 3))
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('c', 3));
+ }
+
+ if (_globals[kCurrentYear] == 1993) {
+ _vm->_gameConv->load(4);
+ if ((_globals[kDoneBrieConv203] == 1) || (_globals[kDoneBrieConv203] == 3))
+ _vm->_gameConv->load(6);
+ } else {
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites("*faceral", false);
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites("*facecrsd", false);
+ _vm->_gameConv->load(13);
+ }
+
+ if (_globals[kCurrentYear] == 1993) {
+ _scene->drawToBackground(_globals._spriteIndexes[3], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_VASE, false);
+ _scene->_hotspots.activate(NOUN_FAN, false);
+ _scene->_hotspots.activateAtPos(NOUN_LIGHT_FIXTURE, true, Common::Point(155, 17));
+ } else {
+ _scene->_hotspots.activateAtPos(NOUN_LIGHT_FIXTURE, true, Common::Point(150, 46));
+ _scene->_hotspots.activate(NOUN_NOTICE, false);
+ }
+
+ if (_scene->_priorSceneId == RETURNING_FROM_LOADING) {
+ if (_globals[kCurrentYear] == 1881) {
+ if (_dayStatus <= 3) {
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('r', 1), 1);
+ _anim1ActvFl = true;
+ }
+
+ if (_raoulAction == 3)
+ _scene->setAnimFrame(_globals._animationIndexes[1], 33);
+ else {
+ _raoulAction = 1;
+ _game._player._visible = false;
+ _scene->setAnimFrame(_globals._animationIndexes[1], 8);
+ }
+
+ if (_musicPlaying) {
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('d', 2), 0);
+ _anim0ActvFl = true;
+ _christineHotspotId1 = _scene->_dynamicHotspots.add(NOUN_CHRISTINE, VERB_WALK_TO, SYNTAX_SINGULAR_FEM, EXT_NONE, Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots[_christineHotspotId1]._articleNumber = PREP_ON;
+ _scene->setDynamicAnim(_christineHotspotId1, _globals._animationIndexes[0], 13);
+ _scene->setDynamicAnim(_christineHotspotId1, _globals._animationIndexes[0], 14);
+ _scene->setDynamicAnim(_christineHotspotId1, _globals._animationIndexes[0], 16);
+ _scene->setAnimFrame(_globals._animationIndexes[0], 212);
+ _game._player._visible = true;
+ _anim1ActvFl = false;
+ } else {
+ switch (_dayStatus) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('d', 1), 0);
+ _anim0ActvFl = true;
+ _dayStatus = 2;
+ _scene->setAnimFrame(_globals._animationIndexes[0], 208);
+ _scene->_hotspots.activate(NOUN_CHRISTINE, true);
+ _scene->_hotspots.activateAtPos(NOUN_CHRISTINE, false, Common::Point(220, 130));
+ break;
+
+ default:
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('d', 2), 0);
+ _anim0ActvFl = true;
+ _dayStatus = 7;
+ _game._player._visible = false;
+ _scene->setAnimFrame(_globals._animationIndexes[0], 165);
+ break;
+ }
+ _christineHotspotId1 = _scene->_dynamicHotspots.add(NOUN_CHRISTINE, VERB_WALK_TO, SYNTAX_SINGULAR_FEM, EXT_NONE, Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots[_christineHotspotId1]._articleNumber = PREP_ON;
+ _scene->setDynamicAnim(_christineHotspotId1, _globals._animationIndexes[0], 13);
+ _scene->setDynamicAnim(_christineHotspotId1, _globals._animationIndexes[0], 14);
+ _scene->setDynamicAnim(_christineHotspotId1, _globals._animationIndexes[0], 16);
+ }
+
+ if (_dayStatus == 2) {
+ _scene->_hotspots.activate(NOUN_CHRISTINE, true);
+ _scene->_hotspots.activateAtPos(NOUN_CHRISTINE, false, Common::Point(220, 130));
+ } else {
+ _game._player._playerPos = Common::Point(175, 148);
+ _game._player._facing = FACING_NORTHEAST;
+ }
+
+ } else if ((_globals[kDoneBrieConv203] == 1) || (_globals[kDoneBrieConv203] == 3)) {
+ _globals._animationIndexes[4] = _scene->loadAnimation(formAnimName('x', 1), 1);
+ _julieStatus = 0;
+ _anim4ActvFl = true;
+ _globals[kMakeBrieLeave203] = true;
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+ _scene->_hotspots.activate(NOUN_DRESSING_GOWN, true);
+ _scene->_hotspots.activate(NOUN_JULIE, true);
+ _scene->_hotspots.activateAtPos(NOUN_CHRISTINE, true, Common::Point(220, 130));
+ } else if (_globals[kCurrentYear] == 1993) {
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ _globals._animationIndexes[2] = _scene->loadAnimation(formAnimName('f', 1), 1);
+ _anim2ActvFl = true;
+
+ if (_florentStatus != 3)
+ _florentStatus = 1;
+
+ _globals._animationIndexes[3] = _scene->loadAnimation(formAnimName('r', 1), 1);
+ _anim3ActvFl = true;
+
+ if (_raoulAction == 3)
+ _scene->setAnimFrame(_globals._animationIndexes[3], 33);
+ else {
+ _scene->setAnimFrame(_globals._animationIndexes[3], 8);
+ _raoulAction = 1;
+ _game._player._playerPos = Common::Point(201, 120);
+ _game._player._facing = FACING_SOUTH;
+ _game._player._visible = false;
+ }
+
+ if (_florentStatus == 3)
+ _scene->setAnimFrame(_globals._animationIndexes[2], 41);
+
+ if (_globals[kFlorentNameIsKnown] >= 1) {
+ _christineHotspotId2 = _scene->_dynamicHotspots.add(NOUN_CHRISTINE, VERB_WALK_TO, SYNTAX_SINGULAR_FEM, EXT_NONE, Common::Rect(43, 118, 43 + 15, 118 + 29));
+ _scene->_dynamicHotspots[_christineHotspotId2]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_christineHotspotId2, Common::Point(106, 127), FACING_SOUTHWEST);
+ } else {
+ _christineHotspotId2 = _scene->_dynamicHotspots.add(NOUN_WOMAN, VERB_WALK_TO, SYNTAX_FEM_NOT_PROPER, EXT_NONE, Common::Rect(43, 118, 43 + 15, 118 + 29));
+ _scene->_dynamicHotspots[_christineHotspotId2]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_christineHotspotId2, Common::Point(106, 127), FACING_SOUTHWEST);
+ }
+
+ _scene->_hotspots.activate(NOUN_DRESSING_GOWN, true);
+
+ if (_game._objects.isInRoom(OBJ_SMALL_NOTE)) {
+ _scene->_hotspots.activate(NOUN_SMALL_NOTE, true);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 13);
+ }
+ }
+ } else if (_globals[kCurrentYear] == 1993) {
+ if ((_globals[kDoneBrieConv203] == 1) || (_globals[kDoneBrieConv203] == 3)) {
+ if (!(_globals[kPlayerScoreFlags] & 4)) {
+ _globals[kPlayerScoreFlags] = _globals[kPlayerScoreFlags] | 4;
+ _globals[kPlayerScore] += 5;
+ }
+
+ _globals._animationIndexes[4] = _scene->loadAnimation(formAnimName('x', 1), 1);
+ _julieStatus = 0;
+ _anim4ActvFl = true;
+ _globals[kMakeBrieLeave203] = true;
+ _game._player._playerPos = Common::Point(190, 148);
+ _game._player._facing = FACING_NORTH;
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+ _scene->_hotspots.activate(NOUN_DRESSING_GOWN, true);
+ _scene->_hotspots.activate(NOUN_JULIE, true);
+ _scene->_hotspots.activateAtPos(NOUN_CHRISTINE, true, Common::Point(220, 130));
+ _game._player.walk(Common::Point(175, 128), FACING_NORTHEAST);
+ _game._player.setWalkTrigger(102);
+ } else {
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+
+ _globals._animationIndexes[2] = _scene->loadAnimation(formAnimName('f', 1), 1);
+ _florentStatus = 1;
+ _anim2ActvFl = true;
+
+ _globals._animationIndexes[3] = _scene->loadAnimation(formAnimName('r', 1), 1);
+ _raoulAction = 3;
+ _anim3ActvFl = true;
+ _scene->setAnimFrame(_globals._animationIndexes[3], 33);
+
+ if (_globals[kFlorentNameIsKnown] >= 1) {
+ _christineHotspotId2 = _scene->_dynamicHotspots.add(NOUN_CHRISTINE, VERB_WALK_TO, SYNTAX_SINGULAR_FEM, EXT_NONE, Common::Rect(43, 118, 43 + 15, 118 + 29));
+ _scene->_dynamicHotspots[_christineHotspotId2]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_christineHotspotId2, Common::Point(106, 127), FACING_SOUTHWEST);
+ } else {
+ _christineHotspotId2 = _scene->_dynamicHotspots.add(NOUN_WOMAN, VERB_WALK_TO, SYNTAX_FEM_NOT_PROPER, EXT_NONE, Common::Rect(43, 118, 43 + 15, 118 + 29));
+ _scene->_dynamicHotspots[_christineHotspotId2]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_christineHotspotId2, Common::Point(106, 127), FACING_SOUTHWEST);
+ }
+
+ _game._player._playerPos = Common::Point(190, 148);
+ _game._player._facing = FACING_NORTH;
+
+ _scene->_hotspots.activate(NOUN_DRESSING_GOWN, true);
+ if (_game._objects.isInRoom(OBJ_SMALL_NOTE)) {
+ _scene->_hotspots.activate(NOUN_SMALL_NOTE, true);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 13);
+ }
+ }
+ } else if ((_globals[kCurrentYear] == 1881) && (! _globals[kChrisKickedRaoulOut])) {
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('r', 1), 1);
+ _raoulAction = 3;
+ _anim1ActvFl = true;
+ _scene->setAnimFrame(_globals._animationIndexes[1], 33);
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('d', 1), 1);
+ _dayStatus = 2;
+ _anim0ActvFl = true;
+
+ _scene->_hotspots.activate(NOUN_CHRISTINE, true);
+ _scene->_hotspots.activateAtPos(NOUN_CHRISTINE, false, Common::Point(220, 130));
+ _scene->_sequences.addTimer(60, 60);
+ _game._player._playerPos = Common::Point(190, 148);
+ _game._player._facing = FACING_NORTH;
+ } else if ((_globals[kCurrentYear] == 1881) && _globals[kChrisKickedRaoulOut]) {
+ _globals[kChrisKickedRaoulOut] = 2;
+ _game._player._playerPos = Common::Point(190, 148);
+ _game._player._facing = FACING_NORTH;
+ _globals[kCameFromFade] = true;
+ _game._player._stepEnabled = false;
+ _globals[kPlayerScore] += 8;
+ _scene->_sequences.addTimer(60, 110);
+ } else if (_scene->_priorSceneId == 111) {
+ _game._player._playerPos = Common::Point(190, 148);
+ _game._player._facing = FACING_NORTH;
+ }
+
+ switch (_vm->_gameConv->restoreRunning()) {
+ case 4:
+ _vm->_gameConv->run(4);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ break;
+
+ case 6:
+ _vm->_gameConv->run(6);
+ break;
+
+ case 13:
+ _vm->_gameConv->run(13);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ break;
+
+ default:
+ break;
+ }
+
+ sceneEntrySound();
+}
+
+void Scene113::step() {
+ if (_anim1ActvFl)
+ handleRaoulAnimation2();
+
+ if (_anim4ActvFl)
+ handleJulieAnimation();
+
+ if (_anim2ActvFl)
+ handleFlorentAnimation();
+
+ if (_anim3ActvFl) {
+ handleRaoulAnimation();
+
+ if ((!_game._objects.isInInventory(OBJ_SMALL_NOTE)) && (_scene->_animation[_globals._animationIndexes[3]]->getCurrentFrame() == 26)) {
+ _scene->_hotspots.activate(NOUN_SMALL_NOTE, false);
+ _game._objects.addToInventory(OBJ_SMALL_NOTE);
+ _scene->deleteSequence(_globals._sequenceIndexes[1]);
+ _vm->_sound->command(26);
+ _vm->_dialogs->showItem(OBJ_SMALL_NOTE, 806, 2);
+ }
+ }
+
+ if ((_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == 86) && (!_prevent2)) {
+ _scene->freeAnimation(_globals._animationIndexes[0]);
+ _prevent2 = true;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('d', 2), 0);
+ _scene->setAnimFrame (_globals._animationIndexes[0], 86);
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[0], SYNC_CLOCK, 0);
+ _scene->animations_tick();
+ }
+
+ if (_anim0ActvFl) {
+ handleDayAnimation();
+
+ if ((_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == 95) && (!_armsOutFl)) {
+ _standingAndTalking = true;
+ _dayStatus = 7;
+ _raoulAction = 3;
+ _armsOutFl = true;
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[0], SYNC_ANIM, _globals._animationIndexes[1]);
+ }
+
+ if ((_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == 165) && !_afterKissFl)
+ _afterKissFl = true;
+ }
+
+ switch (_game._trigger) {
+ case 60:
+ if (!_game._visitedScenes._sceneRevisited)
+ _vm->_dialogs->show(11342);
+ break;
+
+ case 102:
+ _game._player._stepEnabled = true;
+ _vm->_gameConv->run(6);
+ break;
+
+ case 108:
+ _vm->_dialogs->show(11332);
+ _vm->_dialogs->show(11333);
+ _scene->_nextSceneId = 150;
+ _globals[kLeaveAngelMusicOn] = false;
+ break;
+
+ case 110:
+ _vm->_dialogs->show(11331);
+ _game._player.walk(Common::Point(272, 138), FACING_EAST);
+ _game._player.setWalkTrigger(108);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene113::actions() {
+ if (_vm->_gameConv->activeConvId() == 13) {
+ handleLoveConversation();
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_vm->_gameConv->activeConvId() == 4) {
+ handleFlorentConversation();
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_vm->_gameConv->activeConvId() == 6) {
+ handleDeadConversation();
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isAction(VERB_TALK_TO, NOUN_WOMAN)) || (_action.isAction(VERB_TALK_TO, NOUN_CHRISTINE))) {
+ if (_globals[kCurrentYear] == 1881) {
+ _game._player._stepEnabled = true;
+ _vm->_gameConv->run(13);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ } else if (_globals[kDoneBrieConv203]) {
+ _vm->_dialogs->show(11348);
+ } else {
+ _game._player._stepEnabled = true;
+ _vm->_gameConv->run(4);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_EXIT_TO, NOUN_CORRIDOR)) {
+ if (_globals[kDoneBrieConv203] == 1)
+ _globals[kDoneBrieConv203] = 3;
+
+ _scene->_nextSceneId = 111;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ if (_globals[kCurrentYear] == 1993) {
+ if (_globals[kDoneBrieConv203])
+ _vm->_dialogs->show(11340);
+ else
+ _vm->_dialogs->show(11310);
+ } else {
+ _vm->_dialogs->show(11311);
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(11312);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RUG)) {
+ _vm->_dialogs->show(11313);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(11314);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_COUCH)) {
+ _vm->_dialogs->show(11315);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_MURAL)) {
+ _vm->_dialogs->show(11316);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PAINTING)) {
+ if (_globals[kCurrentYear] == 1881)
+ _vm->_dialogs->show(11317);
+ else
+ _vm->_dialogs->show(11343);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PAINTING)) {
+ _vm->_dialogs->show(11317);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DRESSING_TABLE)) {
+ _vm->_dialogs->show(11318);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CHAIR)) {
+ _vm->_dialogs->show(11319);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_MIRROR)) {
+ if (_globals[kCurrentYear] == 1993) {
+ _vm->_dialogs->show(11344);
+ } else {
+ _vm->_dialogs->show(11320);
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FAN)) {
+ _vm->_dialogs->show(11321);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_VASE)) {
+ _vm->_dialogs->show(11322);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_HAT_RACK)) {
+ _vm->_dialogs->show(11323);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LIGHT_FIXTURE)) {
+ _vm->_dialogs->show(11324);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CEILING)) {
+ _vm->_dialogs->show(11325);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WARDROBE)) {
+ _vm->_dialogs->show(11326);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DRESSING_SCREEN)) {
+ _vm->_dialogs->show(11327);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CORRIDOR)) {
+ _vm->_dialogs->show(11328);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DRESSING_GOWN)) {
+ _vm->_dialogs->show(11330);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SMALL_NOTE) && _game._objects.isInRoom(OBJ_SMALL_NOTE)) {
+ _vm->_dialogs->show(11349);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CHRISTINE) && _globals[kDoneBrieConv203]) {
+ _vm->_dialogs->show(11338);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_JULIE)) {
+ _vm->_dialogs->show(11339);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_NOTICE)) {
+ _vm->_dialogs->show(11347);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CLOTHES_DUMMY)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(11345);
+ else
+ _vm->_dialogs->show(11346);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WOMAN) || _action.isObject(NOUN_CHRISTINE)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(11341);
+ else {
+ if (_musicPlaying)
+ _vm->_dialogs->show(11336);
+ else
+ _vm->_dialogs->show(11342);
+ }
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_WARDROBE)) {
+ _vm->_dialogs->show(11329);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_SMALL_NOTE) && _game._objects.isInRoom(OBJ_SMALL_NOTE)) {
+ _vm->_dialogs->show(11334);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_DRESSING_GOWN)) {
+ _vm->_dialogs->show(11335);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_CHRISTINE) || _action.isAction(VERB_TAKE, NOUN_WOMAN)) {
+ _vm->_dialogs->show(11337);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene113::preActions() {
+ if (_action.isAction(VERB_WALK_UP, NOUN_AISLE))
+ _game._player._walkOffScreenSceneId = 101;
+
+ if (_action.isAction(VERB_LOOK, NOUN_MIRROR))
+ _game._player.walk(Common::Point(272, 138), FACING_EAST);
+
+ if (! _action.isAction(VERB_EXIT_TO, NOUN_CORRIDOR) && !_globals[kChrisKickedRaoulOut]
+ && !_action.isAction(VERB_LOOK, NOUN_CHRISTINE) && !_action.isAction(VERB_TAKE, NOUN_CHRISTINE) && _musicPlaying) {
+ _vm->_gameConv->run(13);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ _game._player.cancelCommand();
+ } else if (_action.isAction(VERB_TALK_TO, NOUN_WOMAN) || _action.isAction(VERB_TALK_TO, NOUN_CHRISTINE)) {
+ _game._player.walk(Common::Point(106, 127), FACING_SOUTHWEST);
+ }
+
+ if (!_action.isAction(VERB_EXIT_TO, NOUN_CORRIDOR) && !_action.isAction(VERB_LOOK, NOUN_JULIE)
+ && !_action.isAction(VERB_LOOK, NOUN_CHRISTINE) && !_action._lookFlag && (_globals[kDoneBrieConv203] != 0)
+ && (_globals[kCurrentYear] == 1993)) {
+ if (_action.isAction(VERB_TALK_TO, NOUN_CHRISTINE)) {
+ _game._player._needToWalk = false;
+
+ } else if (_action.isAction(VERB_LOOK)) {
+ _game._player._needToWalk = false;
+
+ } else if (_action.isAction(VERB_TALK_TO, NOUN_JULIE)) {
+ _game._player._needToWalk = false;
+ _vm->_gameConv->run(6);
+ _game._player.cancelCommand();
+
+ } else {
+ _vm->_dialogs->show(11350);
+ _game._player._needToWalk = false;
+ _game._player.cancelCommand();
+ }
+ }
+}
+
+void Scene113::handleFlorentAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[2]]->getCurrentFrame() == _florentFrame)
+ return;
+
+ int random;
+ _florentFrame = _scene->_animation[_globals._animationIndexes[2]]->getCurrentFrame();
+ int resetFrame = -1;
+
+ switch (_florentFrame) {
+ case 1:
+ case 11:
+ case 23:
+ case 38:
+ case 45:
+ random = _vm->getRandomNumber(4, 30);
+
+ if (_florentStatus == 2) {
+ random = 1;
+ }
+
+ if (_florentStatus == 0) {
+ random = 2;
+ }
+
+ if (_florentStatus == 3) {
+ random = 3;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 2;
+ _florentStatus = 1;
+ break;
+
+ case 2:
+ resetFrame = 28;
+ break;
+
+ case 3:
+ resetFrame = 39;
+ break;
+
+ case 4:
+ resetFrame = 12;
+ break;
+
+ default:
+ resetFrame = 0;
+ break;
+ }
+ break;
+
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 33:
+ random = _vm->getRandomNumber(5, 20);
+
+ if (_florentStatus == 0) {
+ random = _vm->getRandomNumber(1, 4);
+ ++_florentCount;
+ if (_florentCount > 5) {
+ _florentStatus = 1;
+ random = 5;
+ }
+ }
+
+ if ((_florentStatus == 2) ||
+ (_florentStatus == 3)) {
+ random = 5;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 23;
+ break;
+
+ case 2:
+ resetFrame = 24;
+ break;
+
+ case 3:
+ resetFrame = 25;
+ break;
+
+ case 4:
+ resetFrame = 26;
+ break;
+
+ case 5:
+ resetFrame = 34;
+ break;
+
+ default:
+ resetFrame = 32;
+ break;
+ }
+ break;
+
+ case 42:
+ if (_florentStatus == 3)
+ resetFrame = 41;
+
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[2], resetFrame);
+ _florentFrame = resetFrame;
+ }
+}
+
+void Scene113::handleDayAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == _dayFrame)
+ return;
+
+ _dayFrame = _scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame();
+ int random;
+ int resetFrame = -1;
+ switch (_dayFrame) {
+ case 1:
+ case 4:
+ case 14:
+ case 17:
+ case 20:
+ case 26:
+ case 166:
+ case 206:
+ case 207:
+ case 208:
+ case 209:
+ case 210:
+ case 211:
+ case 219:
+ case 231:
+ case 253:
+ switch (_dayStatus) {
+ case 0:
+ random = _vm->getRandomNumber(1, 3);
+ ++_dayCount;
+ if (_dayCount < 6) {
+ if (random == 1) {
+ resetFrame = 1;
+ } else if (random == 2) {
+ resetFrame = 15;
+ } else {
+ resetFrame = 18;
+ }
+ } else {
+ _dayStatus = 1;
+ resetFrame = 25;
+ _dayWantsToTalk = false;
+ }
+ break;
+
+ case 1:
+ if (_dayWantsToTalk) {
+ _dayStatus = 0;
+ _dayWantsToTalk = false;
+ resetFrame = 1;
+ } else {
+ resetFrame = 25;
+ }
+ break;
+
+ case 2:
+ random = _vm->getRandomNumber(1, 50);
+ switch (random) {
+ case 1:
+ resetFrame = 212;
+ break;
+
+ case 2:
+ resetFrame = 219;
+ break;
+
+ case 3:
+ resetFrame = 231;
+ break;
+
+ default:
+ resetFrame = 0;
+ break;
+ }
+ break;
+
+ case 3:
+ resetFrame = 5;
+ _dayStatus = 0;
+ break;
+
+ case 4:
+ resetFrame = 31;
+ break;
+
+ case 5:
+ resetFrame = _vm->getRandomNumber(205, 207);
+ ++_standCount;
+ if (_standCount > 18) {
+ _dayStatus = 7;
+ resetFrame = 165;
+ }
+ if (_musicPlaying)
+ resetFrame = 167;
+ break;
+
+ case 6:
+ resetFrame = _vm->getRandomNumber(208, 210);
+ while (_lastDayResetFrame == resetFrame)
+ resetFrame = _vm->getRandomNumber(208, 210);
+
+ _lastDayResetFrame = resetFrame;
+
+ ++_standCount;
+ if (_standCount > 18) {
+ _dayStatus = 7;
+ resetFrame = 165;
+ }
+
+ if (_musicPlaying)
+ resetFrame = 167;
+ break;
+
+ case 7:
+ resetFrame = 165;
+ if (_musicPlaying)
+ resetFrame = 167;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 182:
+ _game._player._visible = true;
+ _vm->_gameConv->release();
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[1]);
+ _game._player._playerPos = Common::Point(175, 148);
+ _game._player._turnToFacing = FACING_NORTHEAST;
+ _game._player.resetFacing(FACING_SOUTHEAST);
+ _game._player._turnToFacing = FACING_NORTHEAST;
+ break;
+
+ case 205:
+ case 212:
+ resetFrame = 211;
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[0], resetFrame);
+ _dayFrame = resetFrame;
+ }
+}
+
+void Scene113::handleRaoulAnimation() {
+ if (_globals[kFlorentNameIsKnown] == 2)
+ _raoulAction = 3;
+
+ if (_scene->_animation[_globals._animationIndexes[3]]->getCurrentFrame() == _raoulFrame)
+ return;
+
+ _raoulFrame = _scene->_animation[_globals._animationIndexes[3]]->getCurrentFrame();
+ int resetFrame = -1;
+
+ switch (_raoulFrame) {
+ case 9:
+ case 10:
+ case 11:
+ case 34:
+ case 33:
+ if (_raoulFrame == 33)
+ _vm->_gameConv->release();
+
+ switch (_raoulAction) {
+ case 0:
+ resetFrame = _vm->getRandomNumber(7, 9);
+ ++_raoulCount;
+
+ if (_raoulCount > 17) {
+ _raoulAction = 1;
+ resetFrame = 8;
+ }
+ break;
+
+ case 1:
+ resetFrame = 8;
+ break;
+
+ case 2:
+ resetFrame = 11;
+ break;
+
+ case 3:
+ resetFrame = 33;
+ break;
+
+ case 4:
+ resetFrame = 38;
+ _raoulStandingFl = true;
+ _vm->_gameConv->hold();
+ break;
+
+ case 5:
+ resetFrame = 20;
+ _raoulAction = 1;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 19:
+ if ((_raoulAction == 5) && (!_game._objects.isInInventory(OBJ_SMALL_NOTE))) {
+ resetFrame = 20;
+ _raoulAction = 1;
+ } else if (_raoulAction == 4) {
+ resetFrame = 38;
+ _raoulStandingFl = true;
+ } else if (_raoulAction == 0) {
+ resetFrame = 9;
+ } else {
+ resetFrame = 8;
+ _raoulAction = 1;
+ }
+ break;
+
+ case 42:
+ if (_raoulAction == 4) {
+ if (!_prevent2) {
+ _vm->_gameConv->release();
+ }
+ resetFrame = 33;
+ _raoulAction = 3;
+ _game._player._visible = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[3]);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[3], resetFrame);
+ _raoulFrame = resetFrame;
+ }
+}
+
+void Scene113::handleRaoulAnimation2() {
+ if (_scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame() == _raoulFrame)
+ return;
+
+ _raoulFrame = _scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame();
+ int resetFrame = -1;
+ switch (_raoulFrame) {
+ case 9:
+ case 10:
+ case 11:
+ case 34:
+ switch (_raoulAction) {
+ case 0:
+ resetFrame = _vm->getRandomNumber(7, 9);
+ ++_raoulCount;
+
+ if (_raoulCount > 17) {
+ _raoulAction = 1;
+ resetFrame = 8;
+ }
+ break;
+
+ case 1:
+ resetFrame = 8;
+ break;
+
+ case 2:
+ resetFrame = 11;
+ break;
+
+ case 3:
+ resetFrame = 33;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 19:
+ if (_raoulAction == 0)
+ resetFrame = 9;
+ else {
+ resetFrame = 8;
+ _raoulAction = 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[1], resetFrame);
+ _raoulFrame = resetFrame;
+ }
+}
+
+void Scene113::handleJulieAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[4]]->getCurrentFrame() == _julieFrame)
+ return;
+
+ _julieFrame = _scene->_animation[_globals._animationIndexes[4]]->getCurrentFrame();
+ int resetFrame = -1;
+ int random;
+
+ switch (_julieFrame) {
+ case 1:
+ case 2:
+ case 3:
+ case 11:
+ case 16:
+ case 17:
+ switch (_julieStatus) {
+ case 0:
+ random = _vm->getRandomNumber(4, 20);
+ break;
+
+ case 1:
+ random = _vm->getRandomNumber(1, 3);
+ ++_julieCount;
+ if (_julieCount > 20) {
+ _julieStatus = 0;
+ random = 6;
+ }
+ break;
+
+ default:
+ random = -1;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 0;
+ break;
+
+ case 2:
+ resetFrame = 1;
+ break;
+
+ case 3:
+ resetFrame = 2;
+ break;
+
+ case 4:
+ resetFrame = 12;
+ break;
+
+ case 5:
+ resetFrame = 4;
+ break;
+
+ default:
+ resetFrame = 16;
+ break;
+ }
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[4], resetFrame);
+ _julieFrame = resetFrame;
+ }
+}
+
+void Scene113::handleDeadConversation() {
+ switch (_game._trigger) {
+ case 106:
+ _julieStatus = 1;
+ break;
+
+ case 104:
+ _julieStatus = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ _vm->_gameConv->setInterlocutorTrigger(106);
+ _vm->_gameConv->setHeroTrigger(104);
+
+ _julieCount = 0;
+}
+
+void Scene113::handleFlorentConversation() {
+ switch (_action._activeAction._verbId) {
+ case 3:
+ case 4:
+ if (!_prevent1) {
+ _globals[kFlorentNameIsKnown] = 1;
+ _vm->_gameConv->setInterlocutorTrigger(82);
+ _scene->_dynamicHotspots.remove(_christineHotspotId2);
+ _christineHotspotId2 = _scene->_dynamicHotspots.add(NOUN_CHRISTINE, VERB_WALK_TO, SYNTAX_SINGULAR_FEM, EXT_NONE, Common::Rect(43, 118, 43 + 15, 118 + 29));
+ _scene->_dynamicHotspots[_christineHotspotId2]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(_christineHotspotId2, Common::Point(106, 127), FACING_SOUTHWEST);
+ _prevent1 = true;
+ }
+ break;
+
+ case 19:
+ _florentStatus = 2;
+ _vm->_gameConv->setInterlocutorTrigger(86);
+ break;
+
+ case 25:
+ if (_raoulAction != 3)
+ _raoulAction = 4;
+ break;
+
+ case 26:
+ if (!_prevent2) {
+ _scene->_sequences.addTimer(120, 92);
+ _vm->_gameConv->setInterlocutorTrigger(96);
+ _florentStatus = 0;
+ _prevent2 = true;
+ }
+ break;
+
+ case 27:
+ case 30:
+ _vm->_gameConv->setInterlocutorTrigger(98);
+ break;
+
+ case 28:
+ case 29:
+ _vm->_gameConv->setInterlocutorTrigger(100);
+ break;
+
+ default:
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 62:
+ if ((_action._activeAction._verbId != 3) && (_action._activeAction._verbId != 4) && (_action._activeAction._verbId != 19) &&
+ (_action._activeAction._verbId != 27) && (_action._activeAction._verbId != 28) && (_action._activeAction._verbId != 29)) {
+ if ((_raoulAction != 5) && (_raoulAction != 4) && !_raoulStandingFl)
+ _raoulAction = 0;
+
+ if ((_florentStatus != 3) && (_florentStatus != 2))
+ _florentStatus = 1;
+ }
+ break;
+
+ case 66:
+ if ((_florentStatus != 3) &&
+ (_florentStatus != 2)) {
+ if (_vm->getRandomNumber(1, 5) == 1)
+ _florentStatus = 0;
+ }
+
+ if ((_raoulAction != 3) && (_raoulAction != 5) && (_raoulAction != 4) && (!_raoulStandingFl)) {
+ _raoulAction = 1;
+ if (_vm->getRandomNumber(1, 2) == 1)
+ _raoulAction = 2;
+ }
+ break;
+
+ case 80:
+ _vm->_gameConv->release();
+ _game._player._visible = false;
+ _raoulAction = 1;
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[3], SYNC_PLAYER, 0);
+ _scene->setAnimFrame(_globals._animationIndexes[3], 1);
+ break;
+
+ case 82:
+ _florentStatus = 0;
+ _scene->_sequences.addTimer(120, 84);
+ _vm->_gameConv->hold();
+ break;
+
+ case 84:
+ _game._player.walk(Common::Point(201, 120), FACING_SOUTH);
+ _game._player.setWalkTrigger(80);
+ break;
+
+ case 86:
+ _raoulAction = 5;
+ _vm->_gameConv->hold();
+ break;
+
+ case 92:
+ _game._player.walk(Common::Point(68, 142), FACING_SOUTHWEST);
+ _game._player.setWalkTrigger(94);
+ break;
+
+ case 94:
+ _globals[kStopWalkerDisabled] = true;
+ _globals[kFlorentNameIsKnown] = 2;
+ _vm->_gameConv->release();
+ break;
+
+ case 96:
+ _vm->_gameConv->hold();
+ break;
+
+ case 98:
+ _florentStatus = 3;
+ break;
+
+ case 100:
+ _florentStatus = 1;
+ _globals[kStopWalkerDisabled] = false;
+ break;
+
+ default:
+ break;
+ }
+
+ if ((_action._activeAction._verbId != 3) && (_action._activeAction._verbId != 4) && (_action._activeAction._verbId != 19) &&
+ (_action._activeAction._verbId != 28) && (_action._activeAction._verbId != 29) && (_action._activeAction._verbId != 27) &&
+ (_action._activeAction._verbId != 30) && (_action._activeAction._verbId != 26))
+ _vm->_gameConv->setInterlocutorTrigger(66);
+
+ _vm->_gameConv->setHeroTrigger(62);
+ _raoulCount = 0;
+ _florentCount = 0;
+}
+
+void Scene113::handleLoveConversation() {
+ switch (_action._activeAction._verbId) {
+ case 1:
+ case 2:
+ if (!_prevent1) {
+ _vm->_gameConv->setInterlocutorTrigger(82);
+ _prevent1 = true;
+ }
+ break;
+
+ case 21:
+ if (!_armsOutFl) {
+ _dayStatus = 4;
+ _scene->_sequences.addTimer(1, 70);
+ _scene->_userInterface.emptyConversationList();
+ _scene->_userInterface.setup(kInputConversation);
+ _scene->_hotspots.activate(NOUN_CHRISTINE, false);
+ _vm->_gameConv->hold();
+ }
+ break;
+
+ case 27:
+ _vm->_sound->command(34);
+ _globals[kLeaveAngelMusicOn] = true;
+ break;
+
+ case 31:
+ if (!_musicPlaying) {
+ _vm->_gameConv->hold();
+ _dayStatus = 7;
+ _musicPlaying = true;
+ _christineHotspotId1 = _scene->_dynamicHotspots.add(NOUN_CHRISTINE, VERB_WALK_TO, SYNTAX_SINGULAR_FEM, EXT_NONE, Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots[_christineHotspotId1]._articleNumber = PREP_ON;
+ _scene->setDynamicAnim(_christineHotspotId1, _globals._animationIndexes[0], 14);
+ _scene->setDynamicAnim(_christineHotspotId1, _globals._animationIndexes[0], 16);
+ }
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 62:
+ if (_action._activeAction._verbId != 0) {
+ if (_standingAndTalking) {
+ _dayStatus = 6;
+ } else if (_dayStatus != 4) {
+ _dayStatus = 1;
+ _raoulAction = 0;
+ _dayWantsToTalk = false;
+ }
+ }
+ break;
+
+ case 66:
+ if (_standingAndTalking) {
+ _dayStatus = 5;
+
+ } else {
+ if (_action._activeAction._verbId == 19) {
+ _dayStatus = 3;
+ } else {
+ _dayStatus = 1;
+ _dayWantsToTalk = true;
+ }
+
+ if (_raoulAction != 3) {
+ _raoulAction = 1;
+ if (_vm->getRandomNumber(1, 2) == 1)
+ _raoulAction = 2;
+ }
+ }
+ break;
+
+ case 70:
+ if (_armsOutFl) {
+ _vm->_gameConv->release();
+ _vm->_gameConv->setInterlocutorTrigger(76);
+ }
+ break;
+
+ case 72:
+ if (_afterKissFl)
+ _vm->_gameConv->release();
+ else
+ _scene->_sequences.addTimer(1, 72);
+ break;
+
+ case 76:
+ _vm->_gameConv->hold();
+ _scene->_sequences.addTimer(1, 72);
+ break;
+
+ case 78:
+ if (_armsOutFl) {
+ _vm->_gameConv->release();
+ _vm->_gameConv->setInterlocutorTrigger(76);
+ }
+ break;
+
+ case 80:
+ _vm->_gameConv->release();
+ _game._player._visible = false;
+ _raoulAction = 1;
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[1], SYNC_PLAYER, 0);
+ _scene->setAnimFrame(_globals._animationIndexes[1], 1);
+ break;
+
+ case 82:
+ _scene->_sequences.addTimer(120, 84);
+ _vm->_gameConv->hold();
+ _dayStatus = 1;
+ _dayWantsToTalk = true;
+ break;
+
+ case 84:
+ _game._player.walk(Common::Point(201, 120), FACING_SOUTH);
+ _game._player.setWalkTrigger(80);
+ break;
+
+ default:
+ break;
+ }
+
+ if ((_action._activeAction._verbId != 21) && (_action._activeAction._verbId != 1) && (_action._activeAction._verbId != 2))
+ _vm->_gameConv->setInterlocutorTrigger(66);
+
+ _vm->_gameConv->setHeroTrigger(62);
+
+ _raoulCount = 0;
+ _dayCount = 0;
+ _standCount = 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene114::Scene114(MADSEngine *vm) : Scene1xx(vm) {
+}
+
+void Scene114::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+}
+
+void Scene114::setup() {
+ if (_globals[kCurrentYear] == 1993)
+ _scene->_variant = 1;
+
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene114::enter() {
+ if (_globals[kCurrentYear] == 1993) {
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('z', -1));
+ } else if (_game._objects.isInRoom(OBJ_ROPE) && !_game._objects.isInInventory(OBJ_ROPE_WITH_HOOK)) {
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('f', 0));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites("*RDR_9");
+ }
+
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('a', 0));
+
+ if ((_game._objects.isInRoom(OBJ_ROPE)) && (_globals[kCurrentYear] == 1881) && !_game._objects.isInInventory(OBJ_ROPE_WITH_HOOK)) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 2);
+ } else
+ _scene->_hotspots.activate(NOUN_ROPE, false);
+
+ if (_globals[kCurrentYear] == 1993) {
+ _scene->_hotspots.activate(NOUN_CYLINDER, false);
+ _scene->_hotspots.activate(NOUN_MANNEQUINS, false);
+ _scene->_hotspots.activate(NOUN_PROP, false);
+ _scene->_hotspots.activate(NOUN_BUST, false);
+ _scene->_hotspots.activate(NOUN_SCAFFOLDING, false);
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+ } else {
+ _scene->_hotspots.activate(NOUN_BOXES, false);
+ _scene->_hotspots.activate(NOUN_DINETTE_SET, false);
+ _scene->_hotspots.activate(NOUN_CRATE, false);
+ _scene->_hotspots.activate(NOUN_CASES, false);
+ }
+
+ if ((_scene->_priorSceneId == 105) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
+ _game._player._playerPos = Common::Point(218, 123);
+ _game._player._facing = FACING_WEST;
+ }
+
+ sceneEntrySound();
+}
+
+void Scene114::step() {
+}
+
+void Scene114::actions() {
+ if (_action.isAction(VERB_CLIMB_UP, NOUN_CIRCULAR_STAIRCASE)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('u', 1), 1);
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[0], SYNC_PLAYER, 0);
+ break;
+
+ case 1:
+ _scene->_nextSceneId = 105;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLIMB_UP, NOUN_CIRCULAR_STAIRCASE)) {
+ _scene->_nextSceneId = 105;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_ROPE) && (_game._objects.isInRoom(OBJ_ROPE) || _game._trigger)) {
+ switch (_game._trigger) {
+ case (0):
+ _globals[kPlayerScore] += 5;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[1] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[1], false, 6, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 3);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[1], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_SPRITE, 3, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _scene->_hotspots.activate(NOUN_ROPE, false);
+ _game._objects.addToInventory(OBJ_ROPE);
+ _vm->_sound->command(26);
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[1]);
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(20, 3);
+ break;
+
+ case 3:
+ _vm->_dialogs->showItem(OBJ_ROPE, 807, 0);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(11410);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(11411);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CIRCULAR_STAIRCASE)) {
+ _vm->_dialogs->show(11412);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_ROPE) && _game._objects.isInRoom(OBJ_ROPE)) {
+ _vm->_dialogs->show(11413);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(11414);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_MANNEQUINS)) {
+ _vm->_dialogs->show(11415);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FLAT)) {
+ _vm->_dialogs->show(11416);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SCAFFOLDING)) {
+ _vm->_dialogs->show(11417);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_MUMMY_PROP)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(11418);
+ else
+ _vm->_dialogs->show(11433);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CRATES)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(11419);
+ else
+ _vm->_dialogs->show(11434);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CRATE)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(11420);
+ else
+ _vm->_dialogs->show(11435);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CARTONS)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(11421);
+ else
+ _vm->_dialogs->show(11436);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CARTON)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(11422);
+ else
+ _vm->_dialogs->show(11437);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PROP)) {
+ _vm->_dialogs->show(11423);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BUST)) {
+ _vm->_dialogs->show(11424);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_MUG)) {
+ _vm->_dialogs->show(11425);
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isObject(NOUN_CASES)) || (_action.isObject(NOUN_CASE))) {
+ _vm->_dialogs->show(11426);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BOXES) || _action.isObject(NOUN_BOX)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(11427);
+ else
+ _vm->_dialogs->show(11439);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BOX)) {
+ if (_globals[kCurrentYear] == 1881) {
+ _vm->_dialogs->show(11439);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isObject(NOUN_DINETTE_SET)) {
+ _vm->_dialogs->show(11428);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CYLINDER)) {
+ _vm->_dialogs->show(11429);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_CARTONS)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(11421);
+ else
+ _vm->_dialogs->show(11436);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_CARTON)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(11422);
+ else
+ _vm->_dialogs->show(11437);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_CRATES)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(11419);
+ else
+ _vm->_dialogs->show(11434);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_CRATE)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(11419);
+ else
+ _vm->_dialogs->show(11435);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_CASES)) {
+ _vm->_dialogs->show(11426);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_BOXES) || _action.isAction(VERB_OPEN, NOUN_BOX)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(11427);
+ else
+ _vm->_dialogs->show(11439);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_MUG)) {
+ _vm->_dialogs->show(11430);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_MUMMY_PROP)) {
+ _vm->_dialogs->show(11431);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TALK_TO, NOUN_MUMMY_PROP)) {
+ _vm->_dialogs->show(11432);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene114::preActions() {
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene150::Scene150(MADSEngine *vm) : Scene1xx(vm) {
+}
+
+void Scene150::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+}
+
+void Scene150::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene150::enter() {
+ warning("TODO: Switch to letter box view. See definition of MADS_MENU_Y");
+
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+
+ if (_scene->_priorSceneId == 113)
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('l', 1), 1);
+ else if (_scene->_priorSceneId == 203) {
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('f', 1), 2);
+ sceneEntrySound();
+ } else if (_scene->_priorSceneId == 306)
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('e', 1), 4);
+ else if (_scene->_priorSceneId == 208)
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('h', 1), 3);
+ else
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('q', 1), 5);
+}
+
+void Scene150::step() {
+ if (_game._trigger == 1)
+ _scene->_nextSceneId = 203;
+
+ if (_game._trigger == 2)
+ _scene->_nextSceneId = 111;
+
+ if (_game._trigger == 4)
+ _scene->_nextSceneId = 204;
+
+ if (_game._trigger == 3) {
+ _globals[kJacquesStatus] = 1;
+ _scene->_nextSceneId = 205;
+ }
+
+ if (_game._trigger == 5)
+ _game._winStatus = 1;
+
+ if (_scene->_nextSceneId != _scene->_currentSceneId) {
+ byte pal[768];
+ _vm->_palette->getFullPalette(pal);
+ Common::fill(&pal[12], &pal[756], 0);
+ _vm->_palette->setFullPalette(pal);
+ }
+}
+
+void Scene150::actions() {
+}
+
+void Scene150::preActions() {
+}
/*------------------------------------------------------------------------*/
diff --git a/engines/mads/phantom/phantom_scenes1.h b/engines/mads/phantom/phantom_scenes1.h
index 0f5f56a4cf..cadfcefbef 100644
--- a/engines/mads/phantom/phantom_scenes1.h
+++ b/engines/mads/phantom/phantom_scenes1.h
@@ -55,8 +55,20 @@ public:
class Scene101 : public Scene1xx {
private:
- // TODO
-
+ int _chanStatus;
+ int _wipeStatus;
+ int _callingStatus;
+ int _chandelierStatus;
+ int _callingFrame;
+ int _chandelierFrame;
+ int _talkCounter;
+ int _convCounter;
+ int _brieAnimId;
+ bool _startWalkingFl;
+ bool _startWalking0Fl;
+ bool _anim0Running;
+ bool _anim1Running;
+ bool _startSittingFl;
public:
Scene101(MADSEngine *vm);
virtual void synchronize(Common::Serializer &s);
@@ -66,11 +78,16 @@ public:
virtual void step();
virtual void preActions();
virtual void actions();
+
+ void handleConversation0();
+ void handleConversation1();
+ void handleAnimation0();
+ void handleAnimation1();
};
class Scene102 : public Scene1xx {
private:
- bool _animRunningFl;
+ bool _anim0Running;
public:
Scene102(MADSEngine *vm);
@@ -83,6 +100,321 @@ public:
virtual void actions();
};
+class Scene103 : public Scene1xx {
+private:
+ int _jacquesAction;
+ int _lastRandom;
+ int _standPosition;
+ int _hotspotPrompt1;
+ int _hotspotPrompt2;
+ int _hotspotPrompt3;
+ int _hotspotPrompt4;
+ int _hotspotPrompt5;
+ int _hotspotRightFloor1;
+ int _hotspotRightFloor2;
+ int _hotspotLeftFloor1;
+ int _hotspotLeftFloor2;
+ int _hotspotGentleman;
+ int _convCount;
+ int _lastStairFrame;
+ int _lastJacquesFrame;
+ int _talkCount;
+
+ bool _anim0ActvFl;
+ bool _anim1ActvFl;
+ bool _anim2ActvFl;
+ bool _anim3ActvFl;
+ bool _anim4ActvFl;
+ bool _anim5ActvFl;
+ bool _anim6ActvFl;
+ bool _climbThroughTrapFl;
+ bool _guardFrameFl;
+ bool _sitFl;
+
+ void adjustRails(int variant);
+ void handleJacquesAnim();
+ void climbRightStairs();
+ void climbLeftStairs();
+ void descendRightStairs();
+ void descendLeftStairs();
+ void process_conv_jacques();
+
+public:
+ Scene103(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene104 : public Scene1xx {
+private:
+ bool _anim0ActvFl;
+ bool _anim1ActvFl;
+ bool _anim2ActvFl;
+ bool _needToGetUp;
+ bool _needToStandUp;
+ bool _needToTalk;
+ bool _sittingUp;
+ bool _beforeSheLeaves;
+ bool _beforeHeLeaves;
+
+ int _walkStatus;
+ int _walkFrame;
+ int _coupleStatus;
+ int _coupleFrame;
+ int _richStatus;
+ int _richFrame;
+ int _manTalkCount;
+ int _womanTalkCount;
+ int _lookCount;
+ int _richTalkCount;
+ int _lastPlayerFrame;
+
+ void cleanInventory();
+ void processConversations();
+ void handleWalkAnimation();
+ void handleCoupleAnimations();
+ void handleRichAnimations();
+ void handlePlayerWalk();
+
+public:
+ Scene104(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene105 : public Scene1xx {
+public:
+ Scene105(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene106 : public Scene1xx {
+private:
+ int _sandbagHostpotId;
+public:
+ Scene106(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene107 : public Scene1xx {
+public:
+ Scene107(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene108 : public Scene1xx {
+private:
+ bool _anim0ActvFl;
+ bool _handRaisedFl;
+ int _shutUpCount;
+ int _maxTalkCount;
+ int _charAction;
+ int _charFrame;
+ int _charTalkCount;
+ int _charHotspotId;
+ int _conversationCount;
+ int _prevShutUpFrame;
+
+ void handleCharAnimation();
+ void handleCharlesConversation();
+
+public:
+ Scene108(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene109 : public Scene1xx {
+private:
+ bool _anim0ActvFl;
+ bool _anim1ActvFl;
+ bool _anim2ActvFl;
+ bool _anim3ActvFl;
+ int _currentFloor;
+
+public:
+ Scene109(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene110 : public Scene1xx {
+public:
+ Scene110(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene111 : public Scene1xx {
+private:
+ bool _removeAxe;
+ bool _anim0ActvFl;
+ bool _anim1ActvFl;
+ bool _closedFl;
+ int _listenFrame;
+ int _listenStatus;
+
+ void handleListenAnimation();
+ void handleListenConversation();
+
+public:
+ Scene111(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene112 : public Scene1xx {
+private:
+ bool _anim0ActvFl;
+ bool _anim1ActvFl;
+
+ int _raoulAction;
+ int _raoulFrame;
+ int _didOptionFl;
+ int _julieFrame;
+ int _julieAction;
+ int _julieCounter;
+ int _julieHotspotId;
+
+ void handleConversation();
+ void handleJulieAnimation();
+ void handleRaoulChair();
+
+public:
+ Scene112(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene113 : public Scene1xx {
+private:
+ bool _standingAndTalking;
+ bool _dayWantsToTalk;
+ bool _musicPlaying;
+ bool _afterKissFl;
+ bool _anim0ActvFl;
+ bool _anim1ActvFl;
+ bool _anim2ActvFl;
+ bool _anim3ActvFl;
+ bool _anim4ActvFl;
+ bool _prevent1;
+ bool _prevent2;
+ bool _raoulStandingFl;
+ bool _armsOutFl;
+
+ int _christineHotspotId1;
+ int _christineHotspotId2;
+ int _dayStatus;
+ int _dayFrame;
+ int _dayCount;
+ int _florentStatus;
+ int _florentFrame;
+ int _florentCount;
+ int _julieStatus;
+ int _julieFrame;
+ int _julieCount;
+ int _raoulAction;
+ int _raoulFrame;
+ int _raoulCount;
+ int _lastDayResetFrame;
+ int _standCount;
+
+ void handleFlorentAnimation();
+ void handleDayAnimation();
+ void handleRaoulAnimation();
+ void handleRaoulAnimation2();
+ void handleJulieAnimation();
+ void handleDeadConversation();
+ void handleFlorentConversation();
+ void handleLoveConversation();
+
+public:
+ Scene113(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene114 : public Scene1xx {
+public:
+ Scene114(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene150 : public Scene1xx {
+public:
+ Scene150(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
} // End of namespace Phantom
} // End of namespace MADS
diff --git a/engines/mads/phantom/phantom_scenes2.cpp b/engines/mads/phantom/phantom_scenes2.cpp
new file mode 100644
index 0000000000..8789553962
--- /dev/null
+++ b/engines/mads/phantom/phantom_scenes2.cpp
@@ -0,0 +1,7001 @@
+/* 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 "mads/mads.h"
+#include "mads/conversations.h"
+#include "mads/scene.h"
+#include "mads/phantom/phantom_scenes.h"
+#include "mads/phantom/phantom_scenes2.h"
+
+namespace MADS {
+
+namespace Phantom {
+
+void Scene2xx::setAAName() {
+ _game._aaName = Resources::formatAAName(_globals[kTempInterface]);
+ _vm->_palette->setEntry(254, 43, 47, 51);
+}
+
+void Scene2xx::sceneEntrySound() {
+ if (!_vm->_musicFlag)
+ return;
+
+ switch (_scene->_nextSceneId) {
+ case 206:
+ if (!_globals[kKnockedOverHead])
+ _vm->_sound->command(16);
+ break;
+
+ case 208:
+ _vm->_sound->command(34);
+ break;
+
+ default:
+ if (_scene->_nextSceneId != 250)
+ _vm->_sound->command(16);
+ break;
+ }
+}
+
+void Scene2xx::setPlayerSpritesPrefix() {
+ _vm->_sound->command(5);
+
+ if (_scene->_nextSceneId == 208)
+ _game._player._spritesPrefix = "";
+ else {
+ Common::String oldName = _game._player._spritesPrefix;
+ if (!_game._player._forcePrefix)
+ _game._player._spritesPrefix = "RAL";
+ if (oldName != _game._player._spritesPrefix)
+ _game._player._spritesChanged = true;
+ }
+
+ _game._player._scalingVelocity = true;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene201::Scene201(MADSEngine *vm) : Scene2xx(vm) {
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _needHoldFl = false;
+ _sellerCount = -1;
+ _sellerStatus = -1;
+ _sellerFrame = -1;
+ _raoulFrame = -1;
+ _raoulStatus = -1;
+}
+
+void Scene201::synchronize(Common::Serializer &s) {
+ Scene2xx::synchronize(s);
+
+ s.syncAsByte(_anim0ActvFl);
+ s.syncAsByte(_anim1ActvFl);
+ s.syncAsByte(_needHoldFl);
+ s.syncAsSint16LE(_sellerCount);
+ s.syncAsSint16LE(_sellerStatus);
+ s.syncAsSint16LE(_sellerFrame);
+ s.syncAsSint16LE(_raoulFrame);
+ s.syncAsSint16LE(_raoulStatus);
+}
+
+void Scene201::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene201::enter() {
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ }
+
+ _sellerCount = 0;
+ _needHoldFl = false;
+
+ _vm->_gameConv->load(16);
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('f', 0));
+
+ if (_globals[kTicketPeoplePresent]) {
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('s', 1), 0);
+ _anim1ActvFl = true;
+ _sellerStatus = 2;
+ _scene->setAnimFrame(_globals._animationIndexes[1], 5);
+ } else {
+ _scene->_hotspots.activate(NOUN_TICKET_SELLER, false);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ }
+
+ if (_vm->_gameConv->restoreRunning() == 16) {
+ _game._player._playerPos = Common::Point(72, 101);
+ _game._player._facing = FACING_NORTHWEST;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('r', 1), 0);
+ _anim0ActvFl = true;
+ _raoulStatus = 1;
+ _game._player._visible = false;
+
+ _vm->_gameConv->run(16);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ _vm->_gameConv->exportPointer(&_globals[kChristineToldEnvelope]);
+ }
+
+ if ((_scene->_priorSceneId == 202) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
+ _game._player._playerPos = Common::Point(314, 86);
+ _game._player.walk(Common::Point(266, 98), FACING_SOUTHWEST);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene201::step() {
+ if (_anim0ActvFl)
+ handleRaoulAnimation();
+
+ if (_anim1ActvFl)
+ handleSellerAnimation();
+
+ if ((_needHoldFl) && (_vm->_gameConv->activeConvId() != 16)) {
+ _game._player._stepEnabled = false;
+ _needHoldFl = false;
+ }
+}
+
+void Scene201::actions() {
+ if (_vm->_gameConv->activeConvId() == 16) {
+ handleConversation();
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_ARCHWAY)) {
+ _scene->_nextSceneId = 202;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TALK_TO, NOUN_TICKET_SELLER)) {
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('r', 1), 0);
+ _anim0ActvFl = true;
+ _raoulStatus = 1;
+ _vm->_gameConv->run(16);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ _vm->_gameConv->exportPointer(&_globals[kChristineToldEnvelope]);
+ _game._player._visible = false;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(20110);
+ else
+ _vm->_dialogs->show(20111);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(20112);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(20113);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BUST)) {
+ _vm->_dialogs->show(20114);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PEDESTAL)) {
+ _vm->_dialogs->show(20115);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BARRIER)) {
+ _vm->_dialogs->show(20116);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PLACARD)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(20117);
+ else
+ _vm->_dialogs->show(20118);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_TICKET_WINDOW)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(20119);
+ else
+ _vm->_dialogs->show(20120);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_ARCHWAY)) {
+ _vm->_dialogs->show(20121);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_TICKET_SELLER)) {
+ _vm->_dialogs->show(20123);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_TICKET_SELLER)) {
+ _vm->_dialogs->show(20124);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TALK_TO, NOUN_BUST)) {
+ _vm->_dialogs->show(20122);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene201::preActions() {
+ if ((_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) && _action.isObject(NOUN_PLACARD))
+ _game._player.walk(Common::Point(147, 104), FACING_NORTHWEST);
+}
+
+void Scene201::handleRaoulAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == _raoulFrame)
+ return;
+
+ _raoulFrame = _scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame();
+ int random = -1;
+ int resetFrame = -1;
+
+ switch (_raoulFrame) {
+ case 1:
+ case 19:
+ case 49:
+ random = _vm->getRandomNumber(4, 50);
+
+ switch (_raoulStatus) {
+ case 0:
+ random = 1;
+ break;
+
+ case 2:
+ random = 2;
+ _game._player._stepEnabled = false;
+ break;
+
+ case 3:
+ random = 3;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 9;
+ _raoulStatus = 1;
+ break;
+
+ case 2:
+ resetFrame = 1;
+ break;
+
+ case 3:
+ _game._player._visible = true;
+ _sellerStatus = 2;
+ _anim0ActvFl = false;
+ resetFrame = 49;
+ _game._player._stepEnabled = true;
+ _needHoldFl = false;
+ break;
+
+ case 4:
+ resetFrame = 19;
+ break;
+
+ default:
+ resetFrame = 0;
+ break;
+
+ }
+ break;
+
+ case 5:
+ _scene->deleteSequence(_globals._sequenceIndexes[1]);
+ _game._objects.addToInventory(OBJ_ENVELOPE);
+ _vm->_sound->command(26);
+ _vm->_dialogs->showItem(OBJ_ENVELOPE, 834, 0);
+ break;
+
+ case 9:
+ _game._player._visible = true;
+ _anim0ActvFl = false;
+ _game._player._stepEnabled = true;
+ resetFrame = 49;
+ break;
+
+ case 23:
+ case 35:
+ case 45:
+ random = _vm->getRandomNumber(3, 70);
+
+ switch (_raoulStatus) {
+ case 0:
+ random = 2;
+ break;
+
+ case 2:
+ case 3:
+ random = 1;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 45;
+ break;
+
+ case 2:
+ resetFrame = 23;
+ _raoulStatus = 1;
+ break;
+
+ case 3:
+ resetFrame = 35;
+ break;
+
+ default:
+ resetFrame = 22;
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[0], resetFrame);
+ _raoulFrame = resetFrame;
+ }
+}
+
+void Scene201::handleSellerAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame() == _sellerFrame )
+ return;
+
+ int random = -1;
+ int resetFrame = -1;
+ _sellerFrame = _scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame();
+
+ switch (_sellerFrame ) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 10:
+ if (_sellerFrame == 10)
+ _raoulStatus = 2;
+
+ switch (_sellerStatus) {
+ case 0:
+ random = 1;
+ break;
+
+ case 1:
+ random = _vm->getRandomNumber(1, 5);
+ ++_sellerCount;
+ if (_sellerCount > 30) {
+ _sellerStatus = 0;
+ random = 6;
+ }
+ break;
+
+ case 2:
+ if (_sellerFrame == 6)
+ random = 6;
+ else if (_sellerFrame == 7)
+ random = 7;
+ else
+ random = _vm->getRandomNumber(6, 7);
+
+ ++_sellerCount;
+ if (_sellerCount > 30) {
+ _sellerCount = 0;
+ random = _vm->getRandomNumber(6, 7);
+ }
+ break;
+
+ case 3:
+ random = 8;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 0;
+ break;
+
+ case 2:
+ resetFrame = 1;
+ break;
+
+ case 3:
+ resetFrame = 2;
+ break;
+
+ case 4:
+ resetFrame = 3;
+ break;
+
+ case 5:
+ resetFrame = 4;
+ break;
+
+ case 6:
+ resetFrame = 5;
+ break;
+
+ case 7:
+ resetFrame = 6;
+ break;
+
+ case 8:
+ resetFrame = 7;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 9:
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ _sellerStatus = 2;
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[1], resetFrame);
+ _sellerFrame = resetFrame;
+ }
+}
+
+void Scene201::handleConversation() {
+ bool interlocutorFl = false;
+ bool heroFl = false;
+
+ switch (_action._activeAction._verbId) {
+ case 4:
+ case 12:
+ case 13:
+ case 14:
+ _vm->_gameConv->setInterlocutorTrigger(90);
+ _needHoldFl = true;
+ interlocutorFl = true;
+ break;
+
+ case 6:
+ _sellerStatus = 3;
+ _needHoldFl = true;
+ interlocutorFl = true;
+ heroFl = true;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 65:
+ if (_sellerStatus != 3)
+ _sellerStatus = 1;
+ break;
+
+ case 70:
+ if (_sellerStatus != 3) {
+ _sellerStatus = 0;
+ _raoulStatus = 0;
+ }
+ break;
+
+ case 90:
+ _vm->_gameConv->setHeroTrigger(91);
+ heroFl = true;
+ break;
+
+ case 91:
+ _raoulStatus = 3;
+ heroFl = true;
+ interlocutorFl = true;
+ break;
+
+ default:
+ break;
+ }
+
+ if (!heroFl)
+ _vm->_gameConv->setHeroTrigger(70);
+
+ if (!interlocutorFl)
+ _vm->_gameConv->setInterlocutorTrigger(65);
+
+ _sellerCount = 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene202::Scene202(MADSEngine *vm) : Scene2xx(vm) {
+ _ticketGivenFl = false;
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _skipWalkFl = false;
+
+ for (int i = 0; i < 5; i++) {
+ _chandeliersPosX[i] = -1;
+ _chandeliersHotspotId[i] = -1;
+ }
+
+ _conversationCount = -1;
+ _usherStatus = -1;
+ _usherFrame = -1;
+ _usherCount = -1;
+ _degasStatus = -1;
+ _degasFrame = -1;
+}
+
+void Scene202::synchronize(Common::Serializer &s) {
+ Scene2xx::synchronize(s);
+
+ s.syncAsByte(_ticketGivenFl);
+ s.syncAsByte(_anim0ActvFl);
+ s.syncAsByte(_anim1ActvFl);
+ s.syncAsByte(_skipWalkFl);
+
+ for (int i = 0; i < 5; i++) {
+ s.syncAsSint16LE(_chandeliersPosX[i]);
+ s.syncAsSint16LE(_chandeliersHotspotId[i]);
+ }
+
+ s.syncAsSint16LE(_conversationCount);
+ s.syncAsSint16LE(_usherStatus);
+ s.syncAsSint16LE(_usherFrame);
+ s.syncAsSint16LE(_usherCount);
+ s.syncAsSint16LE(_degasStatus);
+ s.syncAsSint16LE(_degasFrame);
+}
+
+void Scene202::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ if (_globals[kTicketPeoplePresent] == 2)
+ _scene->_variant = 1;
+
+ _scene->addActiveVocab(NOUN_CHANDELIER);
+ _scene->addActiveVocab(NOUN_EDGAR_DEGAS);
+}
+
+void Scene202::enter() {
+ _vm->_disableFastwalk = true;
+ _ticketGivenFl = false;
+ _chandeliersPosX[0] = 77;
+ _chandeliersPosX[1] = 192;
+ _chandeliersPosX[2] = 319;
+ _chandeliersPosX[3] = 445;
+ _chandeliersPosX[4] = 560;
+
+ if (_globals[kTicketPeoplePresent] == 2)
+ _globals[kMakeRichLeave203] = true;
+
+ if ((_globals[kDegasNameIsKnown]) || (_globals[kCurrentYear] == 1993))
+ _scene->_hotspots.activate(NOUN_GENTLEMAN, false);
+
+ for (int i = 0; i < 5; i++) {
+ _globals._sequenceIndexes[2 + i] = -1;
+ _chandeliersHotspotId[i] = -1;
+ }
+
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _skipWalkFl = false;
+ }
+
+ _conversationCount = 0;
+ _vm->_gameConv->load(17);
+ _vm->_gameConv->load(9);
+
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites("*RDR_9");
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('f', 0));
+
+ if (_globals[kTicketPeoplePresent] == 2) {
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('b', 0), 0);
+ _anim0ActvFl = true;
+ _usherStatus = 2;
+ } else
+ _scene->_hotspots.activate(NOUN_USHER, false);
+
+ if (_globals[kDegasNameIsKnown])
+ _anim1ActvFl = false;
+
+ if ((_globals[kCurrentYear] == 1881) && (!_globals[kDegasNameIsKnown])) {
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('d', 1), 100);
+ _anim1ActvFl = true;
+ _degasStatus = 4;
+ }
+
+ if (_vm->_gameConv->restoreRunning() == 17) {
+ _vm->_gameConv->run(17);
+ _vm->_gameConv->exportValue(_game._objects.isInInventory(OBJ_TICKET));
+ _vm->_gameConv->exportValue(0);
+ _game._player._playerPos = Common::Point(569, 147);
+ _game._player._facing = FACING_NORTHEAST;
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ }
+
+ if (_vm->_gameConv->restoreRunning() == 9) {
+ _vm->_gameConv->run(9);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ _game._player._playerPos = Common::Point(400, 141);
+ _game._player._facing = FACING_NORTHWEST;
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ }
+
+ if (_scene->_priorSceneId == 201) {
+ _game._player._playerPos = Common::Point(3, 141);
+ _game._player.walk(Common::Point(40, 141), FACING_EAST);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ } else if (_scene->_priorSceneId == 203) {
+ _game._player._playerPos = Common::Point(134, 112);
+ _game._player._facing = FACING_SOUTH;
+ _game._player._stepEnabled = false;
+ _game._player.walk(Common::Point(126, 123), FACING_SOUTH);
+ _game._player.setWalkTrigger(60);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 5);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ } else if (_scene->_priorSceneId == 204) {
+ _game._player._playerPos = Common::Point(253, 117);
+ _game._player.walk(Common::Point(255, 133), FACING_SOUTH);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ _scene->setCamera(Common::Point(70, 0));
+ } else if (_scene->_priorSceneId == 205) {
+ _game._player._playerPos = Common::Point(510, 117);
+ _game._player.walk(Common::Point(512, 133), FACING_SOUTH);
+ _scene->setCamera(Common::Point(320, 0));
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ } else if ((_scene->_priorSceneId == 101) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
+ _game._player._playerPos = Common::Point(636, 143);
+ _game._player.walk(Common::Point(598, 143), FACING_WEST);
+ _scene->setCamera(Common::Point(320, 0));
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ } else if (_scene->_priorSceneId == RETURNING_FROM_LOADING) {
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ }
+
+ handleChandeliersPositions();
+ sceneEntrySound();
+}
+
+void Scene202::step() {
+ if (_game._camX._currentFrameFl)
+ handleChandeliersPositions();
+
+ if (_anim0ActvFl)
+ handleUsherAnimation();
+
+ if (_game._trigger == 100)
+ _anim1ActvFl = false;
+
+ if (_anim1ActvFl)
+ handleDegasAnimation();
+
+ if ((_globals[kCurrentYear] == 1881) && !_globals[kDegasNameIsKnown] && (_game._player._playerPos.x < 405) && !_skipWalkFl) {
+ _game._player.walk(Common::Point(400, 141), FACING_NORTHWEST);
+ _game._player.setWalkTrigger(90);
+ _game._player._stepEnabled = false;
+ _skipWalkFl = true;
+ }
+
+ if (_game._trigger == 90) {
+ _game._player._stepEnabled = true;
+ _vm->_gameConv->run(9);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ }
+
+ switch (_game._trigger) {
+ case 60:
+ _scene->deleteSequence(_globals._sequenceIndexes[0]);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[0], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], 1, 5);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 61);
+ break;
+
+ case 61:
+ _vm->_sound->command(25);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+
+ if ((_globals[kWalkerConverse] == 2) || (_globals[kWalkerConverse] == 3)) {
+ ++_conversationCount;
+ if (_conversationCount > 200)
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ }
+}
+
+void Scene202::actions() {
+ if (_vm->_gameConv->activeConvId() == 17) {
+ handleConversation1();
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_vm->_gameConv->activeConvId() == 9) {
+ handleConversation2();
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_globals[kTicketPeoplePresent] == 2) && (_action.isAction(VERB_WALK_THROUGH, NOUN_RIGHT_ARCHWAY) || _action.isAction(VERB_TALK_TO, NOUN_USHER))) {
+ _vm->_gameConv->run(17);
+ _vm->_gameConv->exportValue(_game._objects.isInInventory(OBJ_TICKET));
+ _vm->_gameConv->exportValue(0);
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_GIVE, NOUN_TICKET, NOUN_USHER)) {
+ _ticketGivenFl = true;
+ _vm->_gameConv->run(17);
+ _vm->_gameConv->exportValue(_game._objects.isInInventory(OBJ_TICKET));
+ _vm->_gameConv->exportValue(1);
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TALK_TO, NOUN_GENTLEMAN) || _action.isAction(VERB_TALK_TO, NOUN_EDGAR_DEGAS)) {
+ if (!_globals[kDegasNameIsKnown] ) {
+ _vm->_gameConv->run(9);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ } else
+ _vm->_dialogs->show(20224);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_LEFT_DOOR) || _action.isAction(VERB_OPEN, NOUN_LEFT_DOOR)) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[1] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[1], false, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[1], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_SPRITE, 4, 80);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 82);
+ break;
+
+ case 80:
+ _scene->deleteSequence(_globals._sequenceIndexes[0]);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], 1, 5);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 81);
+ _vm->_sound->command(24);
+ break;
+
+ case 81: {
+ int idx = _globals._sequenceIndexes[0];
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 5);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[0], SYNC_SEQ, idx);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ _game._player.walk(Common::Point(134, 112), FACING_NORTH);
+ _game._player.setWalkTrigger(83);
+ }
+ break;
+
+ case 82:
+ _game._player._visible = true;
+ break;
+
+ case 83:
+ _scene->deleteSequence(_globals._sequenceIndexes[0]);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[0], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], 1, 5);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 84);
+ _vm->_sound->command(25);
+ break;
+
+ case 84:
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 5);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 1);
+ _scene->_nextSceneId = 203;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_LEFT_ARCHWAY)) {
+ _scene->_nextSceneId = 201;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_RIGHT_ARCHWAY)) {
+ _scene->_nextSceneId = 101;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_MIDDLE_DOOR)) {
+ _scene->_nextSceneId = 204;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_RIGHT_DOOR)) {
+ _scene->_nextSceneId = 205;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(20210);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(20211);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(20212);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LEFT_ARCHWAY)) {
+ _vm->_dialogs->show(20213);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RIGHT_ARCHWAY)) {
+ _vm->_dialogs->show(20214);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LEFT_DOOR)) {
+ _vm->_dialogs->show(20215);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_MIDDLE_DOOR)) {
+ _vm->_dialogs->show(20216);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RIGHT_DOOR)) {
+ _vm->_dialogs->show(20217);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LIGHT_FIXTURE)) {
+ _vm->_dialogs->show(20218);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_OVERDOOR_MEDALLION)) {
+ _vm->_dialogs->show(20219);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DECORATIVE_MOLDING)) {
+ _vm->_dialogs->show(20220);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PAINTING)) {
+ _vm->_dialogs->show(20221);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_EDGAR_DEGAS) || _action.isObject(NOUN_GENTLEMAN)) {
+ _vm->_dialogs->show(20223);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_USHER)) {
+ _vm->_dialogs->show(20225);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CHANDELIER)) {
+ _vm->_dialogs->show(20218);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE) && (_action.isObject(NOUN_GENTLEMAN) || _action.isObject(NOUN_EDGAR_DEGAS))) {
+ _vm->_dialogs->show(20226);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_USHER)) {
+ _vm->_dialogs->show(20227);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLOSE, NOUN_DOOR)) {
+ _vm->_dialogs->show(20222);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene202::preActions() {
+ if (_action.isAction(VERB_OPEN, NOUN_LEFT_DOOR))
+ _game._player.walk(Common::Point(126, 123), FACING_NORTHEAST);
+
+ if ((_globals[kTicketPeoplePresent] == 2) && _action.isAction(VERB_WALK_THROUGH, NOUN_RIGHT_ARCHWAY))
+ _game._player.walk(Common::Point(569, 147), FACING_NORTHEAST);
+
+ if (_action.isAction(VERB_TAKE, NOUN_GENTLEMAN) || _action.isAction(VERB_TAKE, NOUN_EDGAR_DEGAS))
+ _game._player._needToWalk = false;
+}
+
+void Scene202::handleConversation1() {
+ bool interlocutorFl = false;
+ bool heroFl = false;
+
+ switch (_action._activeAction._verbId) {
+ case 0:
+ if (!_ticketGivenFl)
+ _usherStatus = 4;
+
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ interlocutorFl = true;
+ heroFl = true;
+ break;
+
+ case 3:
+ _vm->_gameConv->setInterlocutorTrigger(72);
+ _vm->_gameConv->setHeroTrigger(76);
+ interlocutorFl = true;
+ heroFl = true;
+ break;
+
+ case 4:
+ _vm->_gameConv->setHeroTrigger(76);
+ heroFl = true;
+ interlocutorFl = true;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 70:
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ _usherStatus = 0;
+ break;
+
+ case 72:
+ _usherStatus = 17;
+ break;
+
+ case 74:
+ _globals[kWalkerConverse] = _vm->getRandomNumber(2, 3);
+ _usherStatus = 2;
+ _conversationCount = 0;
+ break;
+
+ case 76:
+ _globals[kWalkerConverse] = 0;
+ _ticketGivenFl = false;
+ heroFl = true;
+ interlocutorFl = true;
+ break;
+
+ default:
+ break;
+ }
+
+ if (!heroFl)
+ _vm->_gameConv->setHeroTrigger(74);
+
+ if (!interlocutorFl)
+ _vm->_gameConv->setInterlocutorTrigger(70);
+
+ _usherCount = 0;
+}
+
+void Scene202::handleConversation2() {
+ bool interlocutorFl = false;
+ bool heroFl = false;
+
+ switch (_action._activeAction._verbId) {
+ case 1:
+ _globals[kDegasNameIsKnown] = 1;
+ break;
+
+ case 10:
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ _vm->_gameConv->setHeroTrigger(96);
+ interlocutorFl = true;
+ heroFl = true;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 74:
+ _globals[kWalkerConverse] = _vm->getRandomNumber(2, 3);
+ _degasStatus = 4;
+ _conversationCount = 0;
+ break;
+
+ case 93:
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ switch (_action._activeAction._verbId) {
+ case 1:
+ _degasStatus = 1;
+ break;
+
+ case 2:
+ _degasStatus = 2;
+ break;
+
+ default:
+ if ((_action._activeAction._verbId != 11) && (_action._activeAction._verbId != 12))
+ _degasStatus = 0;
+ break;
+ }
+ break;
+
+ case 96:
+ _vm->_gameConv->setInterlocutorTrigger(97);
+ interlocutorFl = true;
+ heroFl = true;
+ break;
+
+ case 97:
+ _vm->_gameConv->setHeroTrigger(98);
+ _degasStatus = 0;
+ interlocutorFl = true;
+ heroFl = true;
+ break;
+
+ case 98:
+ _globals[kWalkerConverse] = 0;
+ _degasStatus = 3;
+
+ if (_globals[kDegasNameIsKnown] == 1) {
+ int idx = _scene->_dynamicHotspots.add(NOUN_EDGAR_DEGAS, VERB_WALK_TO, SYNTAX_SINGULAR_MASC, EXT_NONE, Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots[idx]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(596, 144), FACING_EAST);
+ _scene->setDynamicAnim(idx, _globals._animationIndexes[1], 1);
+ } else {
+ int idx = _scene->_dynamicHotspots.add(NOUN_GENTLEMAN, VERB_WALK_TO, SYNTAX_SINGULAR_MASC, EXT_NONE, Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots[idx]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(596, 144), FACING_EAST);
+ _scene->setDynamicAnim(idx, _globals._animationIndexes[1], 1);
+ }
+
+ _globals[kDegasNameIsKnown] = 2;
+ interlocutorFl = true;
+ heroFl = true;
+ _scene->_hotspots.activate(NOUN_GENTLEMAN, false);
+ _game._player._stepEnabled = false;
+ _vm->_gameConv->hold();
+ break;
+
+ default:
+ break;
+ }
+
+ if (!heroFl)
+ _vm->_gameConv->setHeroTrigger(74);
+
+ if (!interlocutorFl)
+ _vm->_gameConv->setInterlocutorTrigger(93);
+}
+
+void Scene202::handleChandeliersPositions() {
+ int center = _scene->_posAdjust.x + 160;
+
+ for (int chandelier = 0; chandelier < 5; chandelier++) {
+ if (_globals._sequenceIndexes[chandelier + 2] >= 0)
+ _scene->deleteSequence(_globals._sequenceIndexes[chandelier + 2]);
+
+ int diff = center - _chandeliersPosX[chandelier];
+ int dir = 0;
+
+ if (diff < 0)
+ dir = 1;
+ else if (diff > 0)
+ dir = -1;
+
+ int shiftBase = (int)(abs(diff) / 5);
+ if (dir < 0)
+ shiftBase = -shiftBase;
+
+ int posX = _chandeliersPosX[chandelier] + shiftBase - 1;
+ int posY = _scene->_sprites[_globals._spriteIndexes[2]]->getFrameHeight(0) - 1;
+ int frameWidth = _scene->_sprites[_globals._spriteIndexes[2]]->getFrameWidth(0);
+
+ if (((posX - ((frameWidth >> 1) + 1)) >= (_scene->_posAdjust.x + 320)) || ((posX + ((frameWidth >> 1) + 1)) < _scene->_posAdjust.x))
+ _globals._sequenceIndexes[chandelier + 2] = -1;
+ else {
+ if (_chandeliersHotspotId[chandelier] != -1)
+ _scene->_dynamicHotspots.remove(_chandeliersHotspotId[chandelier]);
+
+ _chandeliersHotspotId[chandelier] = _scene->_dynamicHotspots.add(NOUN_CHANDELIER, VERB_LOOK_AT, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(posX - 8, posY - 12, posX + 8, posY + 1));
+
+ _globals._sequenceIndexes[chandelier + 2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[chandelier + 2], Common::Point(posX, posY));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[chandelier + 2], 1);
+ }
+ }
+}
+
+void Scene202::handleUsherAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == _usherFrame)
+ return;
+
+ _usherFrame = _scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame();
+ int resetFrame = -1;
+ int random;
+ switch (_usherFrame) {
+ case 1:
+ case 13:
+ case 35:
+ case 51:
+ case 52:
+ case 53:
+ case 54:
+ switch (_usherStatus) {
+ case 0:
+ random = _vm->getRandomNumber(1, 3);
+ ++_usherCount;
+ if (_usherCount > 15) {
+ if (_action._activeAction._verbId == 0) {
+ _usherStatus = 3;
+ random = 5;
+ } else {
+ _usherStatus = 2;
+ random = 7;
+ }
+ }
+ break;
+
+ case 3:
+ random = 5;
+ break;
+
+ case 4:
+ random = 6;
+ break;
+
+ case 17:
+ random = 4;
+ break;
+
+ default:
+ random = 7;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 51;
+ break;
+
+ case 2:
+ resetFrame = 52;
+ break;
+
+ case 3:
+ resetFrame = 53;
+ break;
+
+ case 4:
+ resetFrame = 21;
+ _usherStatus = 17;
+ break;
+
+ case 5:
+ resetFrame = 1;
+ break;
+
+ case 6:
+ resetFrame = 35;
+ _usherStatus = 0;
+ break;
+
+ default:
+ resetFrame = 0;
+ break;
+ }
+ break;
+
+ case 7:
+ if (_usherStatus == 3)
+ random = 1;
+ else
+ random = 2;
+
+ if (random == 1)
+ resetFrame = 6;
+ else
+ resetFrame = 7;
+
+ break;
+
+ case 28:
+ if (_usherStatus == 17) {
+ random = 1;
+ ++_usherCount;
+ if (_usherCount > 15) {
+ _usherStatus = 2;
+ random = 2;
+ }
+ } else
+ random = 2;
+
+ if (random == 1)
+ resetFrame = 27;
+ else
+ resetFrame = 28;
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[0], resetFrame);
+ _usherFrame = resetFrame;
+ }
+}
+
+void Scene202::handleDegasAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame() == _degasFrame)
+ return;
+
+ _degasFrame = _scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame();
+ int resetFrame = -1;
+ int random;
+
+ switch (_degasFrame) {
+ case 1:
+ case 17:
+ case 58:
+ switch (_degasStatus) {
+ case 0:
+ _degasStatus = 4;
+ random = 1;
+ break;
+
+ case 1:
+ case 2:
+ case 3:
+ random = 2;
+ break;
+
+ default:
+ random = _vm->getRandomNumber(3, 50);
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 1;
+ break;
+
+ case 2:
+ resetFrame = 58;
+ break;
+
+ case 3:
+ resetFrame = 58;
+ break;
+
+ default:
+ resetFrame = 0;
+ break;
+ }
+ break;
+
+ case 33:
+ case 40:
+ case 55:
+ case 62:
+ switch (_degasStatus) {
+ case 0:
+ _degasStatus = 4;
+ random = 1;
+ break;
+
+ case 1:
+ _degasStatus = 4;
+ random = 2;
+ break;
+
+ case 2:
+ _degasStatus = 4;
+ random = 3;
+ break;
+
+ case 3:
+ random = 4;
+ break;
+
+ default:
+ random = _vm->getRandomNumber(5, 50);
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 33;
+ break;
+
+ case 2:
+ resetFrame = 17;
+ break;
+
+ case 3:
+ resetFrame = 42;
+ break;
+
+ case 4:
+ resetFrame = 62;
+ break;
+
+ case 5:
+ resetFrame = 41;
+ break;
+
+ case 6:
+ resetFrame = 55;
+ break;
+
+ default:
+ resetFrame = 39;
+ break;
+ }
+ break;
+
+ case 42:
+ switch (_degasStatus) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ random = 1;
+ break;
+
+ default:
+ random = _vm->getRandomNumber(1, 50);
+ break;
+ }
+
+ if (random == 1)
+ resetFrame = 39;
+ else
+ resetFrame = 41;
+
+ break;
+
+ case 110:
+ _vm->_gameConv->release();
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[1], resetFrame);
+ _degasFrame = resetFrame;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene203::Scene203(MADSEngine *vm) : Scene2xx(vm) {
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _anim2ActvFl = false;
+ _anim3ActvFl = false;
+ _showNoteFl = false;
+
+ _brieStatus = -1;
+ _brieFrame = -1;
+ _brieCount = -1;
+ _raoulStatus = -1;
+ _raoulFrame = -1;
+ _raoulCount = -1;
+ _richardStatus = -1;
+ _richardFrame = -1;
+ _daaeStatus = -1;
+ _daaeFrame = -1;
+ _conversationCount = -1;
+}
+
+void Scene203::synchronize(Common::Serializer &s) {
+ Scene2xx::synchronize(s);
+
+ s.syncAsByte(_anim0ActvFl);
+ s.syncAsByte(_anim1ActvFl);
+ s.syncAsByte(_anim2ActvFl);
+ s.syncAsByte(_anim3ActvFl);
+ s.syncAsByte(_showNoteFl);
+
+ s.syncAsSint16LE(_brieStatus);
+ s.syncAsSint16LE(_brieFrame);
+ s.syncAsSint16LE(_brieCount);
+ s.syncAsSint16LE(_raoulStatus);
+ s.syncAsSint16LE(_raoulFrame);
+ s.syncAsSint16LE(_raoulCount);
+ s.syncAsSint16LE(_richardStatus);
+ s.syncAsSint16LE(_richardFrame);
+ s.syncAsSint16LE(_daaeStatus);
+ s.syncAsSint16LE(_daaeFrame);
+ s.syncAsSint16LE(_conversationCount);
+}
+
+void Scene203::setup() {
+ if (_globals[kCurrentYear] == 1993)
+ _scene->_variant = 1;
+
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene203::enter() {
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _anim2ActvFl = false;
+ _anim3ActvFl = false;
+ _showNoteFl = false;
+ }
+
+ _conversationCount = 0;
+ _scene->_hotspots.activate(NOUN_LETTER, false);
+ _scene->_hotspots.activate(NOUN_PARCHMENT, false);
+ _scene->_hotspots.activate(NOUN_NOTICE, false);
+
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('p', 1));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('p', 0));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites("*RDR_6");
+
+ if (_globals[kCurrentYear] == 1993) {
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('z', -1));
+ _vm->_gameConv->load(5);
+ } else {
+ _vm->_gameConv->load(8);
+ _vm->_gameConv->load(15);
+ }
+
+ if (_globals[kCurrentYear] == 1993) {
+ if (_game._objects.isInRoom(OBJ_PARCHMENT)) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 3);
+ _scene->_hotspots.activate(NOUN_PARCHMENT, true);
+ }
+
+ _scene->_hotspots.activate(NOUN_MONSIEUR_RICHARD, false);
+ _scene->_hotspots.activate(NOUN_MANAGERS_CHAIR, false);
+
+ if (!_globals[kMakeBrieLeave203]) {
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('b', 9), 1);
+ _anim0ActvFl = true;
+ _brieStatus = 4;
+ } else {
+ _scene->_hotspots.activate(NOUN_MONSIEUR_BRIE, false);
+ _scene->_hotspots.activate(NOUN_MANAGERS_CHAIR, true);
+ }
+
+ if ((_scene->_priorSceneId == RETURNING_FROM_LOADING) && (_vm->_gameConv->restoreRunning() == 5)) {
+ _brieStatus = 4;
+ _raoulStatus = 0;
+ _anim1ActvFl = true;
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('c', 1), 0);
+ _scene->setAnimFrame(_globals._animationIndexes[1], 9);
+ _vm->_gameConv->run(5);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ _vm->_gameConv->exportValue(_game._objects.isInInventory(OBJ_SMALL_NOTE));
+ _vm->_gameConv->exportValue(_globals[kReadBook]);
+ _vm->_gameConv->exportValue(_game._objects.isInInventory(OBJ_LARGE_NOTE));
+ _vm->_gameConv->exportValue(_globals[kLookedAtCase]);
+ _vm->_gameConv->exportValue(_globals[kCharlesNameIsKnown]);
+ _vm->_gameConv->exportValue(_globals[kCanFindBookInLibrary]);
+ _vm->_gameConv->exportValue(_globals[kFlorentNameIsKnown]);
+ _vm->_gameConv->exportValue(_globals[kSandbagStatus]);
+ _vm->_gameConv->exportValue(_globals[kObservedPhan104]);
+ }
+
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_CANDLE, false);
+ } else if (_globals[kJacquesStatus] == 0) {
+ _scene->_hotspots.activate(NOUN_DESK_LAMP, false);
+ _scene->_hotspots.activate(NOUN_MONSIEUR_BRIE, false);
+ _scene->_hotspots.activate(NOUN_MANAGERS_CHAIR, false);
+
+ if (!_globals[kMakeRichLeave203]) {
+ _globals._animationIndexes[2] = _scene->loadAnimation(formAnimName('r', 1), 1);
+ _anim2ActvFl = true;
+ _richardStatus = 4;
+ } else {
+ _scene->_hotspots.activate(NOUN_MONSIEUR_RICHARD, false);
+ _scene->_hotspots.activate(NOUN_MANAGERS_CHAIR, true);
+ }
+
+ if ((_scene->_priorSceneId == RETURNING_FROM_LOADING) && (_vm->_gameConv->restoreRunning() == 8)) {
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('c', 1), 0);
+ _scene->setAnimFrame(_globals._animationIndexes[1], 9);
+ _anim1ActvFl = true;
+ _game._player._visible = false;
+ _raoulStatus = 0;
+ _vm->_gameConv->run(8);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ }
+
+ if (_game._objects.isInRoom(OBJ_LETTER)) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 3);
+ _scene->_hotspots.activate(NOUN_LETTER, true);
+ }
+
+ if (_game._objects.isInRoom(OBJ_NOTICE)) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 3);
+ _scene->_hotspots.activate(NOUN_NOTICE, true);
+ }
+ } else {
+ _scene->_hotspots.activate(NOUN_MONSIEUR_BRIE, false);
+ _scene->_hotspots.activate(NOUN_MONSIEUR_RICHARD, false);
+ _scene->_hotspots.activate(NOUN_DESK_LAMP, false);
+ }
+
+ if (_vm->_gameConv->restoreRunning() == 15) {
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 14);
+ _game._player._playerPos = Common::Point(98, 137);
+ _game._player._facing = FACING_NORTHEAST;
+ _vm->_gameConv->run(15);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ _vm->_gameConv->exportPointer(&_globals[kChristineToldEnvelope]);
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ }
+
+ if (_scene->_priorSceneId == RETURNING_FROM_LOADING) {
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 14);
+ } else if (_scene->_priorSceneId == 202) {
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 14);
+ _game._player._playerPos = Common::Point(195, 147);
+ _game._player._facing = FACING_NORTH;
+ } else if (_scene->_priorSceneId == 150) {
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 14);
+ _game._player._playerPos = Common::Point(98, 137);
+ _game._player._facing = FACING_NORTHEAST;
+ _vm->_gameConv->run(15);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ _vm->_gameConv->exportPointer(&_globals[kChristineToldEnvelope]);
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ } else if ((_scene->_priorSceneId == 204) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 1);
+ _game._player._playerPos = Common::Point(319, 123);
+ _game._player._facing = FACING_SOUTHWEST;
+ _game._player.walk(Common::Point(276, 123), FACING_WEST);
+ _game._player.setWalkTrigger(95);
+ _game._player._stepEnabled = false;
+ }
+
+ sceneEntrySound();
+}
+
+void Scene203::step() {
+ if (_anim0ActvFl)
+ handleBrieAnimation();
+
+ if (_anim1ActvFl)
+ handleRaoulAnimation();
+
+ if (_anim2ActvFl)
+ handleRichardAnimation();
+
+ if (_anim3ActvFl)
+ handleDaaeAnimation();
+
+ if ((_globals[kWalkerConverse] == 2) || (_globals[kWalkerConverse] == 3)) {
+ ++_conversationCount;
+ if (_conversationCount > 200)
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ }
+
+ switch (_game._trigger) {
+ case 95:
+ _scene->deleteSequence(_globals._sequenceIndexes[5]);
+ _globals._sequenceIndexes[5] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[5], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 10);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 96);
+ break;
+
+ case 96:
+ _vm->_sound->command(25);
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 14);
+ if (_vm->_gameConv->activeConvId() != 15)
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene203::actions() {
+ if (_vm->_gameConv->activeConvId() == 5) {
+ handleBrieConversation();
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_vm->_gameConv->activeConvId() == 8) {
+ handleRichardConversation();
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_vm->_gameConv->activeConvId() == 15) {
+ handleRichardAndDaaeConversation();
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR) || _action.isAction(VERB_OPEN, NOUN_DOOR) || _game._trigger) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[4] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[4], false, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[4], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_SPRITE, 4, 90);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 92);
+ break;
+
+ case 90:
+ _vm->_sound->command(24);
+ _scene->deleteSequence(_globals._sequenceIndexes[5]);
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 91);
+ break;
+
+ case 91:
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 1);
+ break;
+
+ case 92:
+ _game._player._visible = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[4]);
+ _game._player.walk(Common::Point(319, 123), FACING_WEST);
+ _game._player.setWalkTrigger(93);
+ break;
+
+ case 93:
+ _scene->_nextSceneId = 204;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TALK_TO, NOUN_MONSIEUR_BRIE)) {
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('c', 1), 0);
+ _anim1ActvFl = true;
+ _game._player._visible = false;
+ _raoulStatus = 0;
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[1], SYNC_PLAYER, 0);
+
+ _vm->_gameConv->run(5);
+ _vm->_gameConv->hold();
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ _vm->_gameConv->exportValue(_game._objects.isInInventory(OBJ_SMALL_NOTE));
+ _vm->_gameConv->exportValue(_globals[kReadBook]);
+ _vm->_gameConv->exportValue(_game._objects.isInInventory(OBJ_LARGE_NOTE));
+ _vm->_gameConv->exportValue(_globals[kLookedAtCase]);
+ if (_globals[kCharlesNameIsKnown] == 2)
+ _vm->_gameConv->exportValue(1);
+ else
+ _vm->_gameConv->exportValue(0);
+
+ _vm->_gameConv->exportValue(_globals[kCanFindBookInLibrary]);
+ _vm->_gameConv->exportValue(_globals[kFlorentNameIsKnown]);
+ _vm->_gameConv->exportValue(_globals[kSandbagStatus]);
+ _vm->_gameConv->exportValue(_globals[kObservedPhan104]);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TALK_TO, NOUN_MONSIEUR_RICHARD)) {
+ if (_globals[kCameFromFade]) {
+ _vm->_gameConv->run(15);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ _vm->_gameConv->exportPointer(&_globals[kChristineToldEnvelope]);
+ } else {
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('c', 1), 0);
+ _anim1ActvFl = true;
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _raoulStatus = 0;
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[1], SYNC_PLAYER, 0);
+
+ _vm->_gameConv->run(8);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ _vm->_gameConv->hold();
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_EXIT_TO, NOUN_GRAND_FOYER)) {
+ _scene->_nextSceneId = 202;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ if (_globals[kMakeBrieLeave203])
+ _vm->_dialogs->show(20337);
+ else
+ _vm->_dialogs->show(20310);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(20311);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(20312);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BOOKCASE)) {
+ _vm->_dialogs->show(20313);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DOORWAY)) {
+ _vm->_dialogs->show(20314);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_COMFY_CHAIR)) {
+ _vm->_dialogs->show(20315);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DESK)) {
+ _vm->_dialogs->show(20316);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_MANAGERS_CHAIR)) {
+ _vm->_dialogs->show(20317);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DESK_LAMP)) {
+ _vm->_dialogs->show(20318);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LAMP)) {
+ _vm->_dialogs->show(20319);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LIGHT_FIXTURE)) {
+ _vm->_dialogs->show(20320);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WINDOW)) {
+ _vm->_dialogs->show(20321);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SHEERS)) {
+ _vm->_dialogs->show(20322);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_TAPESTRY)) {
+ _vm->_dialogs->show(20323);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_GRAND_FOYER)) {
+ _vm->_dialogs->show(20324);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_TABLE)) {
+ _vm->_dialogs->show(20325);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CANDLE)) {
+ _vm->_dialogs->show(20326);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_MONSIEUR_BRIE)) {
+ _vm->_dialogs->show(20327);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_MONSIEUR_RICHARD)) {
+ _vm->_dialogs->show(20328);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PARCHMENT) && _game._objects.isInRoom(OBJ_PARCHMENT)) {
+ _vm->_dialogs->show(20329);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LETTER) && _game._objects.isInRoom(OBJ_LETTER)) {
+ _vm->_dialogs->show(20331);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_NOTICE) && _game._objects.isInRoom(OBJ_NOTICE)) {
+ _vm->_dialogs->show(20333);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_PARCHMENT)) {
+ _vm->_dialogs->show(20330);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_LETTER)) {
+ _vm->_dialogs->show(20332);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_NOTICE)) {
+ _vm->_dialogs->show(20334);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_MONSIEUR_BRIE)) {
+ _vm->_dialogs->show(20335);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_MONSIEUR_RICHARD)) {
+ _vm->_dialogs->show(20336);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene203::preActions() {
+ if (_action.isAction(VERB_TALK_TO, NOUN_MONSIEUR_RICHARD)) {
+ if (_globals[kCameFromFade])
+ _game._player.walk(Common::Point(98, 137), FACING_NORTHEAST);
+ else
+ _game._player.walk(Common::Point(154, 131), FACING_NORTHWEST);
+ }
+
+ if (_action.isAction(VERB_TALK_TO, NOUN_MONSIEUR_BRIE))
+ _game._player.walk(Common::Point(154, 131), FACING_NORTHWEST);
+
+ if (_action.isAction(VERB_OPEN, NOUN_DOOR))
+ _game._player.walk(Common::Point(276, 123), FACING_EAST);
+}
+
+void Scene203::handleBrieConversation() {
+ bool interlocutorFl = false;
+ bool heroFl = false;
+
+ switch (_action._activeAction._verbId) {
+ case 9:
+ case 12:
+ case 35:
+ case 42:
+ _vm->_gameConv->setInterlocutorTrigger(70);
+ interlocutorFl = true;
+ heroFl = true;
+ break;
+
+ case 14:
+ if (!_game._trigger) {
+ _vm->_gameConv->hold();
+ _raoulStatus = 5;
+ }
+ break;
+
+ case 17:
+ _raoulStatus = 0;
+ _vm->_gameConv->hold();
+ break;
+
+ case 24:
+ _vm->_gameConv->setInterlocutorTrigger(78);
+ interlocutorFl = true;
+ break;
+
+ case 20:
+ case 25:
+ _vm->_gameConv->setInterlocutorTrigger(76);
+ interlocutorFl = true;
+ break;
+
+ case 37:
+ if (!_game._trigger) {
+ _vm->_gameConv->hold();
+ if (_vm->_sound->_preferRoland)
+ _vm->_sound->command(65);
+ else
+ _scene->playSpeech(1);
+
+ _scene->_sequences.addTimer(60, 110);
+ }
+ break;
+
+ case 41:
+ _globals[kDoneBrieConv203] = 1;
+ _globals[kChrisFStatus] = 0;
+ break;
+
+ case 44:
+ if (!_game._trigger) {
+ _vm->_gameConv->hold();
+ _raoulStatus = 3;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 60:
+ _brieStatus = 0;
+ break;
+
+ case 65:
+ _brieStatus = 4;
+ break;
+
+ case 70:
+ _vm->_gameConv->setHeroTrigger(71);
+ interlocutorFl = true;
+ heroFl = true;
+ break;
+
+ case 71:
+ _raoulStatus = 2;
+ break;
+
+ case 74:
+ _vm->_gameConv->hold();
+ _raoulStatus = 3;
+ break;
+
+ case 76:
+ _brieStatus = 1;
+ break;
+
+ case 78:
+ _brieStatus = 2;
+ break;
+
+ case 110:
+ _vm->_gameConv->release();
+ break;
+
+ default:
+ break;
+ }
+
+ if (!heroFl && (_raoulStatus != 5))
+ _vm->_gameConv->setHeroTrigger(65);
+
+ if (!interlocutorFl)
+ _vm->_gameConv->setInterlocutorTrigger(60);
+
+ _brieCount = 0;
+ _raoulCount = 0;
+}
+
+void Scene203::handleRichardConversation() {
+ bool interlocutorFl = false;
+ bool heroFl = false;
+
+ switch (_action._activeAction._verbId) {
+ case 4:
+ _vm->_gameConv->setInterlocutorTrigger(83);
+ interlocutorFl = true;
+ break;
+
+ case 5:
+ case 15:
+ case 20:
+ case 21:
+ case 27:
+ _vm->_gameConv->setInterlocutorTrigger(70);
+ interlocutorFl = true;
+ heroFl = true;
+ break;
+
+ case 7:
+ if (_game._objects.isInRoom(OBJ_NOTICE) && !_game._trigger) {
+ _vm->_gameConv->hold();
+ _raoulStatus = 3;
+ }
+ break;
+
+ case 9:
+ if (_game._objects.isInRoom(OBJ_LETTER) && !_game._trigger) {
+ _vm->_gameConv->hold();
+ _raoulStatus = 4;
+ }
+ break;
+
+ case 17:
+ _vm->_gameConv->setInterlocutorTrigger(85);
+ interlocutorFl = true;
+ break;
+
+ case 19:
+ _vm->_gameConv->setInterlocutorTrigger(81);
+ interlocutorFl = true;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 65:
+ _richardStatus = 4;
+ break;
+
+ case 70:
+ _vm->_gameConv->setHeroTrigger(71);
+ interlocutorFl = true;
+ heroFl = true;
+ break;
+
+ case 71: {
+ _raoulStatus = 2;
+ int *val1 = _vm->_gameConv->getVariable(24);
+ int *val2 = _vm->_gameConv->getVariable(26);
+ if ((*val1) && (*val2)) {
+ _globals[kDoneRichConv203] = true;
+ _globals[kMadameGiryShowsUp] = true;
+ }
+ }
+ break;
+
+ case 74:
+ _vm->_gameConv->hold();
+ _raoulStatus = 3;
+ break;
+
+ case 81:
+ _richardStatus = 2;
+ break;
+
+ case 83:
+ _richardStatus = 1;
+ break;
+
+ case 85:
+ _richardStatus = 3;
+ break;
+
+ case 100:
+ _richardStatus = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ if (!heroFl && (_raoulStatus != 5))
+ _vm->_gameConv->setHeroTrigger(65);
+
+ if (!interlocutorFl)
+ _vm->_gameConv->setInterlocutorTrigger(100);
+
+ _brieCount = 0;
+ _raoulCount = 0;
+}
+
+void Scene203::handleRichardAndDaaeConversation() {
+ bool interlocutorFl = false;
+ bool heroFl = false;
+
+ switch (_action._activeAction._verbId) {
+ case 5:
+ if (!_game._trigger) {
+ _vm->_gameConv->hold();
+
+ _vm->_sound->command(24);
+ _scene->deleteSequence(_globals._sequenceIndexes[5]);
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 90);
+ interlocutorFl = true;
+ heroFl = true;
+ }
+ break;
+
+ case 11:
+ if (!_game._trigger) {
+ _vm->_gameConv->hold();
+ _daaeStatus = 3;
+ }
+ break;
+
+ case 13:
+ case 14:
+ case 15:
+ _globals[kChristineDoorStatus] = 1;
+ _globals[kTicketPeoplePresent] = 2;
+ heroFl = true;
+ interlocutorFl = true;
+ _vm->_gameConv->setInterlocutorTrigger(115);
+ break;
+
+ default:
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 65:
+ if (_globals[kWalkerConverse] != 0)
+ _globals[kWalkerConverse] = _vm->getRandomNumber(2, 3);
+
+ if ((_richardStatus != 5) && (_richardStatus != 7))
+ _richardStatus = 4;
+
+ _conversationCount = 0;
+ break;
+
+ case 90:
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 1);
+ _globals._animationIndexes[3] = _scene->loadAnimation(formAnimName('d', 1), 0);
+ _anim3ActvFl = true;
+ _daaeStatus = 0;
+ break;
+
+ case 100:
+ if (_globals[kWalkerConverse] != 0)
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+
+ if ((_action._activeAction._verbId == 7) || (_action._activeAction._verbId == 9))
+ _daaeStatus = 1;
+ else if (_richardStatus == 7)
+ _richardStatus = 5;
+ else if (_richardStatus != 5)
+ _richardStatus = 0;
+
+ break;
+
+ case 115:
+ _globals[kWalkerConverse] = 0;
+ heroFl = true;
+ interlocutorFl = true;
+ break;
+
+ default:
+ break;
+ }
+
+ if (!heroFl)
+ _vm->_gameConv->setHeroTrigger(65);
+
+ if (!interlocutorFl)
+ _vm->_gameConv->setInterlocutorTrigger(100);
+
+ _brieCount = 0;
+ _raoulCount = 0;
+}
+
+void Scene203::handleBrieAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == _brieFrame)
+ return;
+
+ _brieFrame = _scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame();
+ int resetFrame = -1;
+ int random = -1;
+
+ switch (_brieFrame) {
+ case 1:
+ case 2:
+ case 4:
+ case 11:
+ case 22:
+ case 31:
+ case 35:
+ case 29:
+ random = _vm->getRandomNumber(6, 45);
+
+ switch (_brieStatus) {
+ case 0:
+ random = _vm->getRandomNumber(1, 2);
+ ++_brieCount;
+ if (_brieCount > 20) {
+ _brieStatus = 4;
+ random = 45;
+ }
+ break;
+
+ case 1:
+ random = 5;
+ break;
+
+ case 2:
+ random = 4;
+ break;
+
+ case 3:
+ random = 3;
+ _brieStatus = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 0;
+ break;
+
+ case 2:
+ resetFrame = 1;
+ break;
+
+ case 3:
+ resetFrame = 2;
+ break;
+
+ case 4:
+ resetFrame = 22;
+ _brieStatus = 0;
+ break;
+
+ case 5:
+ resetFrame = 13;
+ break;
+
+ case 6:
+ resetFrame = 4;
+ break;
+
+ case 7:
+ resetFrame = 29;
+ break;
+
+ case 8:
+ resetFrame = 31;
+ break;
+
+ default:
+ resetFrame = 0;
+ break;
+ }
+ break;
+
+ case 30:
+ random = _vm->getRandomNumber(1, 45);
+
+ switch (_brieStatus) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ random = 1;
+ break;
+ }
+
+ if (random == 1)
+ resetFrame = 30;
+ else
+ resetFrame = 29;
+
+ break;
+
+ case 8:
+ random = _vm->getRandomNumber(1, 45);
+
+ switch (_brieStatus) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ random = 3;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 11;
+ break;
+
+ case 2:
+ resetFrame = 12;
+ break;
+
+ case 3:
+ resetFrame = 8;
+ break;
+
+ default:
+ resetFrame = 7;
+ break;
+ }
+ break;
+
+ case 12:
+ random = _vm->getRandomNumber(1, 45);
+
+ switch (_brieStatus) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ random = 1;
+ break;
+ }
+
+ if (random == 1)
+ resetFrame = 7;
+ else
+ resetFrame = 11;
+
+ break;
+
+ case 13:
+ random = _vm->getRandomNumber(1, 45);
+
+ switch (_brieStatus) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ random = 1;
+ break;
+ }
+
+ if (random == 1)
+ resetFrame = 7;
+ else
+ resetFrame = 12;
+
+ break;
+
+ case 17:
+ case 18:
+ switch (_brieStatus) {
+ case 0:
+ case 2:
+ case 3:
+ random = 3;
+ break;
+ case 1:
+ random = _vm->getRandomNumber(1, 2);
+ ++_brieCount;
+ if (_brieCount > 20) {
+ _brieStatus = 4;
+ random = 3;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 16;
+ break;
+
+ case 2:
+ resetFrame = 17;
+ break;
+
+ case 3:
+ resetFrame = 18;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 33:
+ case 40:
+ random = _vm->getRandomNumber(1, 45);
+
+ switch (_brieStatus) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ random = 1;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 33;
+ break;
+
+ case 2:
+ resetFrame = 35;
+ break;
+
+ default:
+ resetFrame = 32;
+ break;
+ }
+ break;
+
+ case 38:
+ random = _vm->getRandomNumber(1, 45);
+
+ switch (_brieStatus) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ random = 1;
+ break;
+ }
+
+ if (random == 1)
+ resetFrame = 38;
+ else
+ resetFrame = 37;
+
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[0], resetFrame);
+ _brieFrame = resetFrame;
+ }
+}
+
+void Scene203::handleRichardAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[2]]->getCurrentFrame() == _richardFrame)
+ return;
+
+ _richardFrame = _scene->_animation[_globals._animationIndexes[2]]->getCurrentFrame();
+ int resetFrame = -1;
+ int random = -1;
+
+ switch (_richardFrame) {
+ case 1:
+ case 2:
+ case 3:
+ case 7:
+ case 15:
+ case 25:
+ case 37:
+ case 53:
+ case 59:
+ case 63:
+ case 67:
+ case 69:
+ case 79:
+ case 87:
+ case 108:
+ random = _vm->getRandomNumber(8, 45);
+
+ switch (_richardStatus) {
+ case 0:
+ random = _vm->getRandomNumber(1, 3);
+ ++_brieCount;
+ if (_brieCount > 20) {
+ _richardStatus = 4;
+ random = 45;
+ }
+ break;
+
+ case 1:
+ random = 4;
+ _richardStatus = 0;
+ break;
+
+ case 2:
+ random = 5;
+ _richardStatus = 0;
+ break;
+
+ case 3:
+ random = 6;
+ _richardStatus = 0;
+ break;
+
+ case 5:
+ random = 7;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 0;
+ break;
+
+ case 2:
+ resetFrame = 1;
+ break;
+
+ case 3:
+ resetFrame = 2;
+ break;
+
+ case 4:
+ resetFrame = 69;
+ break;
+
+ case 5:
+ resetFrame = 53;
+ _richardStatus = 0;
+ break;
+
+ case 6:
+ resetFrame = 42;
+ break;
+
+ case 7:
+ resetFrame = 87;
+ break;
+
+ case 8:
+ resetFrame = 25;
+ break;
+
+ case 9:
+ resetFrame = 15;
+ break;
+
+ case 10:
+ resetFrame = 3;
+ break;
+
+ case 11:
+ resetFrame = 7;
+ break;
+
+ case 12:
+ resetFrame = 59;
+ break;
+
+ case 13:
+ resetFrame = 63;
+ break;
+
+ case 14:
+ resetFrame = 67;
+ break;
+
+ case 15:
+ resetFrame = 79;
+ break;
+
+ default:
+ resetFrame = 0;
+ break;
+ }
+ break;
+
+ case 5:
+ random = _vm->getRandomNumber(1, 45);
+
+ switch (_richardStatus) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 5:
+ random = 1;
+ break;
+ }
+
+ if (random == 1)
+ resetFrame = 5;
+ else
+ resetFrame = 4;
+
+ break;
+
+ case 11:
+ random = _vm->getRandomNumber(1, 45);
+
+ switch (_richardStatus) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 5:
+ random = 1;
+ break;
+ }
+
+ if (random == 1)
+ resetFrame = 11;
+ else
+ resetFrame = 10;
+
+ break;
+
+ case 61:
+ random = _vm->getRandomNumber(1, 45);
+
+ switch (_richardStatus) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 5:
+ random = 1;
+ break;
+ }
+
+ if (random == 1)
+ resetFrame = 61;
+ else
+ resetFrame = 60;
+
+ break;
+
+ case 65:
+ random = _vm->getRandomNumber(1, 45);
+
+ switch (_richardStatus) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 5:
+ random = 1;
+ break;
+ }
+
+ if (random == 1)
+ resetFrame = 65;
+ else
+ resetFrame = 64;
+
+ break;
+
+ case 68:
+ random = _vm->getRandomNumber(1, 45);
+
+ switch (_richardStatus) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 5:
+ random = 1;
+ break;
+ }
+
+ if (random == 1)
+ resetFrame = 68;
+ else
+ resetFrame = 67;
+
+ break;
+
+ case 83:
+ random = _vm->getRandomNumber(1, 45);
+
+ switch (_richardStatus) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 5:
+ random = 1;
+ break;
+ }
+
+ if (random == 1)
+ resetFrame = 83;
+ else
+ resetFrame = 82;
+
+ break;
+
+ case 92:
+ _vm->_gameConv->release();
+ break;
+
+ case 93:
+ case 94:
+ case 95:
+ if (_richardStatus == 5) {
+ random = _vm->getRandomNumber(1, 3);
+ ++_brieCount;
+ if (_brieCount > 20) {
+ _richardStatus = 7;
+ random = 4;
+ }
+ } else
+ random = 4;
+
+ switch (random) {
+ case 1:
+ resetFrame = 92;
+ break;
+
+ case 2:
+ resetFrame = 93;
+ break;
+
+ case 3:
+ resetFrame = 94;
+ break;
+
+ case 4:
+ resetFrame = 95;
+ break;
+ }
+ break;
+
+ case 100:
+ case 101:
+ case 102:
+ switch (_richardStatus) {
+ case 5:
+ random = _vm->getRandomNumber(1, 3);
+ ++_brieCount;
+ if (_brieCount > 20) {
+ _richardStatus = 7;
+ random = 1;
+ }
+ break;
+
+ case 7:
+ random = 1;
+ break;
+
+ default:
+ random = 4;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 99;
+ break;
+
+ case 2:
+ resetFrame = 100;
+ break;
+
+ case 3:
+ resetFrame = 101;
+ break;
+
+ case 4:
+ resetFrame = 102;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 31:
+ random = _vm->getRandomNumber(1, 45);
+
+ switch (_richardStatus) {
+ case 0 :
+ case 1:
+ case 2:
+ case 3:
+ case 5:
+ random = 1;
+ break;
+ }
+
+ if (random == 1)
+ resetFrame = 31;
+ else
+ resetFrame = 30;
+
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[2], resetFrame);
+ _richardFrame = resetFrame;
+ }
+}
+
+void Scene203::handleRaoulAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame() == _raoulFrame)
+ return;
+
+ _raoulFrame = _scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame();
+ int resetFrame = -1;
+ int random = -1;
+
+ switch (_raoulFrame) {
+ case 9:
+ case 21:
+ case 57:
+ _vm->_gameConv->release();
+ break;
+
+ case 10:
+ case 22:
+ case 30:
+ case 34:
+ case 58:
+ if (_raoulFrame == 22)
+ _raoulStatus = 0;
+
+ random = _vm->getRandomNumber(5, 45);
+
+ switch (_raoulStatus) {
+ case 1:
+ random = 1;
+ break;
+
+ case 2:
+ _game._player._stepEnabled = false;
+ random = 2;
+ break;
+
+ case 3:
+ case 5:
+ random = 3;
+ break;
+
+ case 4:
+ random = 4;
+ break;
+
+ default:
+ random = _vm->getRandomNumber(5, 100);
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 22;
+ break;
+
+ case 2:
+ resetFrame = 34;
+ break;
+
+ case 3:
+ resetFrame = 10;
+ break;
+
+ case 4:
+ resetFrame = 45;
+ break;
+
+ case 5:
+ resetFrame = 30;
+ break;
+
+ default:
+ resetFrame = 9;
+ break;
+ }
+ break;
+
+ case 16:
+ switch (_raoulStatus) {
+ case 3:
+ random = 1;
+ break;
+
+ case 0:
+ case 2:
+ random = 2;
+ break;
+
+ case 5:
+ random = 3;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ if (_globals[kCurrentYear] == 1881) {
+ resetFrame = 16;
+ _scene->deleteSequence(_globals._sequenceIndexes[1]);
+ _scene->_hotspots.activate(NOUN_NOTICE, false);
+ _game._objects.addToInventory(OBJ_NOTICE);
+ _vm->_sound->command(26);
+ _scene->_speechReady = -1;
+ _vm->_dialogs->showItem(OBJ_NOTICE, 814, 5);
+ _raoulStatus = 0;
+ } else {
+ resetFrame = 16;
+ _scene->deleteSequence(_globals._sequenceIndexes[1]);
+ _scene->_hotspots.activate(NOUN_PARCHMENT, false);
+ _game._objects.addToInventory(OBJ_PARCHMENT);
+ _vm->_sound->command(26);
+ _scene->_speechReady = -1;
+ _vm->_dialogs->showItem(OBJ_PARCHMENT, 812, 3);
+ _raoulStatus = 0;
+ }
+ break;
+
+ case 2:
+ if (_showNoteFl) {
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _showNoteFl = false;
+ }
+ break;
+
+ default:
+ if (!_showNoteFl) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], true, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 3);
+ _vm->_gameConv->release();
+ _showNoteFl = true;
+ }
+ resetFrame = 15;
+ break;
+ }
+ break;
+
+ case 26:
+ random = _vm->getRandomNumber(1, 45);
+
+ switch (_raoulStatus) {
+ case 0:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ random = 1;
+ break;
+
+ case 1:
+ random = 2;
+ break;
+ }
+
+ if (random == 1)
+ resetFrame = 26;
+ else
+ resetFrame = 25;
+
+ break;
+
+ case 45:
+ _anim1ActvFl = false;
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[1]);
+ resetFrame = 58;
+ if (_globals[kDoneBrieConv203] && (_globals[kCurrentYear] == 1993)) {
+ _globals[kPrompterStandStatus] = 1;
+ _scene->_nextSceneId = 150;
+ }
+ break;
+
+ case 52:
+ _scene->deleteSequence(_globals._sequenceIndexes[3]);
+ _scene->_hotspots.activate(NOUN_LETTER, false);
+ _game._objects.addToInventory(OBJ_LETTER);
+ _vm->_sound->command(26);
+ _scene->_speechReady = -1;
+ _vm->_dialogs->showItem(OBJ_LETTER, 813, 4);
+ _raoulStatus = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[1], resetFrame);
+ _raoulFrame = resetFrame;
+ }
+}
+
+void Scene203::handleDaaeAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[3]]->getCurrentFrame() == _daaeFrame)
+ return;
+
+ _daaeFrame = _scene->_animation[_globals._animationIndexes[3]]->getCurrentFrame();
+ int resetFrame = -1;
+ int random = -1;
+
+ switch (_daaeFrame) {
+ case 20:
+ _vm->_gameConv->release();
+ _richardStatus = 5;
+ break;
+
+ case 175:
+ _richardStatus = 4;
+ break;
+
+ case 198:
+ _vm->_gameConv->release();
+ break;
+
+ case 201:
+ _scene->_sequences.addTimer(1, 95);
+ break;
+
+ case 76:
+ case 92:
+ case 102:
+ case 123:
+ switch (_daaeStatus) {
+ case 1:
+ random = _vm->getRandomNumber(1, 2);
+ _daaeStatus = 2;
+ break;
+
+ case 2:
+ random = 3;
+ _daaeStatus = 0;
+ break;
+
+ case 3:
+ random = 4;
+ break;
+
+ default:
+ random = 5;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 79;
+ break;
+
+ case 2:
+ resetFrame = 92;
+ break;
+
+ case 3:
+ resetFrame = 102;
+ break;
+
+ case 4:
+ resetFrame = 123;
+ break;
+
+ case 5:
+ resetFrame = 75;
+ break;
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[3], resetFrame);
+ _daaeFrame = resetFrame;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene204::Scene204(MADSEngine *vm) : Scene2xx(vm) {
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _anim2ActvFl = false;
+ _anim3ActvFl = false;
+ _raoulDown = false;
+ _florentGone = false;
+ _skip1Fl = false;
+ _skip2Fl = false;
+ _skip3Fl = false;
+ _endGameFl = false;
+
+ _brieStatus = -1;
+ _brieFrame = -1;
+ _florStatus = -1;
+ _florFrame = -1;
+ _raoulStatus = -1;
+ _raoulFrame = -1;
+ _raoulCount = -1;
+}
+
+void Scene204::synchronize(Common::Serializer &s) {
+ Scene2xx::synchronize(s);
+
+ s.syncAsByte(_anim0ActvFl);
+ s.syncAsByte(_anim1ActvFl);
+ s.syncAsByte(_anim2ActvFl);
+ s.syncAsByte(_anim3ActvFl);
+ s.syncAsByte(_raoulDown);
+ s.syncAsByte(_florentGone);
+ s.syncAsByte(_skip1Fl);
+ s.syncAsByte(_skip2Fl);
+ s.syncAsByte(_skip3Fl);
+ s.syncAsByte(_endGameFl);
+
+ s.syncAsSint16LE(_brieStatus);
+ s.syncAsSint16LE(_brieFrame);
+ s.syncAsSint16LE(_florStatus);
+ s.syncAsSint16LE(_florFrame);
+ s.syncAsSint16LE(_raoulStatus);
+ s.syncAsSint16LE(_raoulFrame);
+ s.syncAsSint16LE(_raoulCount);
+}
+
+void Scene204::setup() {
+ if ((_globals[kCurrentYear] == 1993) || _globals[kRightDoorIsOpen504])
+ _scene->_variant = 1;
+
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene204::enter() {
+ _skip3Fl = false;
+
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _anim2ActvFl = false;
+ _anim3ActvFl = false;
+ _florentGone = false;
+ _skip1Fl = false;
+ _skip2Fl = false;
+ _endGameFl = false;
+ _raoulDown = true;
+ }
+
+ if (_globals[kTicketPeoplePresent] == 2)
+ _globals[kMakeRichLeave203] = true;
+
+ if (_globals[kRightDoorIsOpen504])
+ _endGameFl = true;
+
+ warning("TODO: If end of game, remove the walking areas");
+
+ _scene->_hotspots.activate(NOUN_BOOK, false);
+ _vm->_gameConv->load(22);
+
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('p', 0));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('x', 6));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites("*RALRH_9");
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites("*RDRR_6");
+
+ if (_game._objects.isInRoom(OBJ_BOOK) || (_globals[kCurrentYear] == 1881) || _endGameFl) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 5);
+ if (_globals[kScannedBookcase] && (_globals[kCurrentYear] == 1993))
+ _scene->_hotspots.activate(NOUN_BOOK, true);
+ }
+
+ if ((_globals[kCurrentYear] == 1993) || _endGameFl) {
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('z', -1));
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_sprites.remove(_globals._spriteIndexes[0]);
+ _scene->_hotspots.activate(NOUN_CANDLE, false);
+ _scene->_hotspots.activate(NOUN_BUST, false);
+ _scene->_hotspots.activate(NOUN_COFFEE_TABLE, false);
+
+ int idx = _scene->_dynamicHotspots.add(NOUN_COFFEE_TABLE, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(83, 140, 83 + 45, 140 + 12));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(84, 150), FACING_SOUTHEAST);
+
+ idx = _scene->_dynamicHotspots.add(NOUN_GRAND_FOYER, VERB_EXIT_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(199, 147, 199 + 52, 147 + 8));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(224, 152), FACING_SOUTH);
+ _scene->_dynamicHotspots.setCursor(idx, CURSOR_GO_DOWN);
+
+ idx = _scene->_dynamicHotspots.add(NOUN_GRAND_FOYER, VERB_EXIT_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(145, 147, 145 + 54, 147 + 8));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(175, 152), FACING_SOUTH);
+ _scene->_dynamicHotspots.setCursor(idx, CURSOR_GO_DOWN);
+ } else {
+ _scene->_hotspots.activate(NOUN_LIGHT, false);
+ _scene->_hotspots.activate(NOUN_GLASS_CASE, false);
+
+ int idx = _scene->_dynamicHotspots.add(NOUN_COMFY_CHAIR, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(220, 147, 220 + 6, 147 + 8));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(220, 150), FACING_SOUTHEAST);
+
+ idx = _scene->_dynamicHotspots.add(NOUN_COMFY_CHAIR, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(226, 134, 226 + 12, 134 + 21));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(220, 150), FACING_SOUTHEAST);
+
+ idx = _scene->_dynamicHotspots.add(NOUN_COMFY_CHAIR, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(238, 128, 238 + 13, 128 + 27));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(220, 150), FACING_SOUTHEAST);
+
+ idx = _scene->_dynamicHotspots.add(NOUN_GRAND_FOYER, VERB_EXIT_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(199, 147, 199 + 19, 147 + 8));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(209, 152), FACING_SOUTH);
+ _scene->_dynamicHotspots.setCursor(idx, CURSOR_GO_DOWN);
+
+ idx = _scene->_dynamicHotspots.add(NOUN_GRAND_FOYER, VERB_EXIT_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(84, 147, 84 + 61, 147 + 8));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(115, 152), FACING_SOUTH);
+ _scene->_dynamicHotspots.setCursor(idx, CURSOR_GO_DOWN);
+ }
+
+ if ((_scene->_priorSceneId == 306) || (_endGameFl)) {
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('f', 0));
+ _scene->drawToBackground(_globals._spriteIndexes[6], 1, Common::Point(-32000, -32000), 0, 100);
+ } else if (_globals[kCurrentYear] == 1993) {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('f', 1));
+ _scene->drawToBackground(_globals._spriteIndexes[1], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_sprites.remove(_globals._spriteIndexes[1]);
+ }
+
+ if (_scene->_priorSceneId == RETURNING_FROM_LOADING) {
+ if (_endGameFl) {
+ _game.loadQuoteSet(0x75, 0);
+
+ _globals._animationIndexes[2] = _scene->loadAnimation(formAnimName('r', 1), 0);
+ _anim2ActvFl = true;
+
+ if (_florentGone) {
+ _scene->setAnimFrame(_globals._animationIndexes[2], 9);
+ _raoulStatus = 1;
+ } else {
+ _scene->setAnimFrame(_globals._animationIndexes[2], 32);
+ _raoulStatus = 4;
+ }
+
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('m', 1), 0);
+ _anim0ActvFl = true;
+ _brieStatus = 2;
+
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('f', 1), 0);
+ _anim1ActvFl = true;
+ _florStatus = 2;
+
+ if (_florentGone)
+ _scene->setAnimFrame(_globals._animationIndexes[1], 172);
+ else if (!_raoulDown)
+ _scene->setAnimFrame(_globals._animationIndexes[1], 21);
+
+ _game._player._visible = false;
+ _vm->_gameConv->run(22);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ } else {
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 5);
+ }
+ } else if (_scene->_priorSceneId == 202) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 5);
+ if (_globals[kCurrentYear] == 1993)
+ _game._player._playerPos = Common::Point(175, 145);
+ else
+ _game._player._playerPos = Common::Point(115, 147);
+
+ _game._player._facing = FACING_NORTHWEST;
+ } else if (_scene->_priorSceneId == 150) {
+ int size = _game._objects.size();
+ for (int i = 0; i < size; i++)
+ _game._objects.setRoom(i, 1);
+
+ _game.loadQuoteSet(0x75, 0);
+
+ _globals._animationIndexes[2] = _scene->loadAnimation(formAnimName('r', 1), 0);
+ _anim2ActvFl = true;
+ _raoulStatus = 4;
+ _scene->setAnimFrame(_globals._animationIndexes[2], 32);
+
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('m', 1), 0);
+ _anim0ActvFl = true;
+ _brieStatus = 2;
+
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('f', 1), 0);
+ _anim1ActvFl = true;
+ _raoulDown = true;
+ _florStatus = 2;
+
+ _game._player._visible = false;
+ _endGameFl = true;
+
+ _vm->_gameConv->run(22);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ } else if ((_scene->_priorSceneId == 203) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
+ _game._player.firstWalk(Common::Point(-10, 136), FACING_EAST, Common::Point(30, 140), FACING_EAST, true);
+ _game._player.setWalkTrigger(70);
+ _game._player._stepEnabled = false;
+ }
+
+ sceneEntrySound();
+}
+
+void Scene204::step() {
+ if (_anim0ActvFl)
+ handleBrieAnimation();
+
+ if (_anim1ActvFl)
+ handleFlorAnimation();
+
+ if (_anim2ActvFl)
+ handleRaoulAnimation();
+
+ if (_anim3ActvFl)
+ handleEndAnimation();
+
+ if (_game._trigger == 85)
+ _scene->_nextSceneId = 250;
+
+ if ((_vm->_gameConv->activeConvId() != 22) && !_skip1Fl && _endGameFl) {
+ _game._player._stepEnabled = false;
+ _skip1Fl = true;
+ }
+
+ if (_game._trigger == 70) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[3], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 10);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ } else if (_game._trigger == 71) {
+ _vm->_sound->command(25);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 5);
+ _game._player._stepEnabled = true;
+ }
+}
+
+void Scene204::actions() {
+ if (_vm->_gameConv->activeConvId() == 22) {
+ handleConversation();
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR) || _action.isAction(VERB_OPEN, NOUN_DOOR)) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[5] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[5], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[5], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_SPRITE, 4, 60);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 61);
+ break;
+
+ case 60:
+ _vm->_sound->command(24);
+ _scene->deleteSequence(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], -1, -2);
+ break;
+
+ case 61:
+ _game._player._visible = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[5]);
+ _game._player.walk(Common::Point(0, 136), FACING_WEST);
+ _game._player.setWalkTrigger(62);
+ break;
+
+ case 62:
+ _scene->_nextSceneId = 203;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_BOOK) && (_game._objects.isInRoom(OBJ_BOOK) || _game._trigger)) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[4] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[4], false, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], -1, -2);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[4], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_SPRITE, 8, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _scene->_hotspots.activate(NOUN_BOOK, false);
+ _game._objects.addToInventory(OBJ_BOOK);
+ _vm->_sound->command(26);
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[4]);
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(20, 3);
+ break;
+
+ case 3:
+ _vm->_dialogs->showItem(OBJ_BOOK, 815, 0);
+ _globals[kReadBook] = true;
+ _globals[kPlayerScore] += 5;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_EXIT_TO, NOUN_GRAND_FOYER)) {
+ _scene->_nextSceneId = 202;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(20410);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(20411);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(20412);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RUG)) {
+ _vm->_dialogs->show(20413);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_GLASS_CASE)) {
+ _vm->_dialogs->show(20414);
+ _globals[kLookedAtCase] = true;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CEILING)) {
+ if (_globals[kSandbagStatus] == 0)
+ _vm->_dialogs->show(20429);
+ else
+ _vm->_dialogs->show(20416);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BOOKCASE)) {
+ if (_globals[kCanFindBookInLibrary] && (_globals[kCurrentYear] == 1993)) {
+ if ((_scene->_customDest.x < 46) && !_game._objects.isInInventory(OBJ_BOOK)) {
+ if (!_globals[kScannedBookcase]) {
+ _vm->_dialogs->show(20433);
+ _scene->_hotspots.activate(NOUN_BOOK, true);
+ _globals[kScannedBookcase] = true;
+ } else {
+ _vm->_dialogs->show(20437);
+ }
+ } else {
+ _vm->_dialogs->show(20417);
+ }
+ } else {
+ _vm->_dialogs->show(20417);
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SOFA)) {
+ _vm->_dialogs->show(20418);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_END_TABLE)) {
+ _vm->_dialogs->show(20419);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LAMP)) {
+ _vm->_dialogs->show(20420);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BUST)) {
+ _vm->_dialogs->show(20421);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_COFFEE_TABLE)) {
+ _vm->_dialogs->show(20422);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_COMFY_CHAIR)) {
+ _vm->_dialogs->show(20423);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DECORATIVE_VASE )) {
+ _vm->_dialogs->show(20424);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PAINTING)) {
+ _vm->_dialogs->show(20425);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_GRAND_FOYER)) {
+ _vm->_dialogs->show(20426);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DOOR)) {
+ _vm->_dialogs->show(20427);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WINDOW)) {
+ _vm->_dialogs->show(20428);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BOOK) && _game._objects.isInRoom(OBJ_BOOK)) {
+ _vm->_dialogs->show(20434);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TALK_TO, NOUN_BUST)) {
+ _vm->_dialogs->show(20436);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene204::preActions() {
+ if (_action.isAction(VERB_LOOK, NOUN_BOOKCASE))
+ _game._player._needToWalk = true;
+
+ if (_action.isAction(VERB_LOOK, NOUN_BOOK) && _game._objects.isInRoom(OBJ_BOOK))
+ _game._player._needToWalk = true;
+
+ if (_action.isAction(VERB_OPEN, NOUN_DOOR))
+ _game._player.walk(Common::Point(27, 139), FACING_WEST);
+}
+
+void Scene204::handleConversation() {
+ bool interlocutorFl = false;
+ bool heroFl = false;
+
+ switch (_action._activeAction._verbId) {
+ case 6:
+ case 7:
+ case 8:
+ if (_raoulDown) {
+ _vm->_gameConv->hold();
+ _raoulDown = false;
+ }
+ break;
+
+ case 17:
+ if (!_game._trigger) {
+ _florStatus = 3;
+ _florentGone = true;
+ interlocutorFl = true;
+ heroFl = true;
+ _vm->_gameConv->hold();
+ }
+ break;
+
+ case 25:
+ if (!_game._trigger) {
+ _raoulStatus = 5;
+ _florStatus = 5;
+ interlocutorFl = true;
+ heroFl = true;
+ _vm->_gameConv->hold();
+ }
+ break;
+
+ case 29:
+ interlocutorFl = true;
+ heroFl = true;
+ if (!_game._trigger) {
+ _brieStatus = 3;
+ _vm->_gameConv->hold();
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 75:
+ if (_florentGone) {
+ if (_raoulStatus != 2)
+ _raoulStatus = 0;
+ } else
+ _florStatus = 4;
+
+ break;
+
+ case 80:
+ if (_florentGone) {
+ if ((_action._activeAction._verbId != 18) && (_action._activeAction._verbId != 23))
+ _brieStatus = 0;
+ } else {
+ switch (_action._activeAction._verbId) {
+ case 1:
+ case 7:
+ case 8:
+ case 9:
+ case 13:
+ case 15:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ _brieStatus = 0;
+ break;
+
+ default:
+ _florStatus = 0;
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (!heroFl && !_raoulDown)
+ _vm->_gameConv->setHeroTrigger(75);
+
+ if (!interlocutorFl)
+ _vm->_gameConv->setInterlocutorTrigger(80);
+
+ _raoulCount = 0;
+}
+
+void Scene204::handleBrieAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == _brieFrame)
+ return;
+
+ _brieFrame = _scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame();
+ int resetFrame = -1;
+ int random;
+
+ switch (_brieFrame) {
+ case 80:
+ _vm->_gameConv->release();
+ _raoulStatus = 2;
+ break;
+
+ case 173:
+ _game._player._stepEnabled = true;
+ _vm->_dialogs->show(20430);
+ _game._player._stepEnabled = false;
+ break;
+
+ case 174:
+ _raoulStatus = 3;
+ resetFrame = 173;
+ break;
+
+ case 1:
+ case 22:
+ case 49:
+ case 7:
+ case 13:
+ case 33:
+ case 61:
+ switch (_brieStatus) {
+ case 0:
+ random = _vm->getRandomNumber(1, 4);
+ _brieStatus = 2;
+ break;
+
+ case 1:
+ random = 5;
+ break;
+
+ case 3:
+ random = 6;
+ break;
+
+ case 4:
+ random = 7;
+ break;
+
+ default:
+ random = 8;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 1;
+ _brieStatus = 2;
+ break;
+
+ case 2:
+ resetFrame = 7;
+ _brieStatus = 2;
+ break;
+
+ case 3:
+ resetFrame = 22;
+ _brieStatus = 2;
+ break;
+
+ case 4:
+ resetFrame = 49;
+ _brieStatus = 2;
+ break;
+
+ case 5:
+ resetFrame = 13;
+ _brieStatus = 2;
+ break;
+
+ case 6:
+ resetFrame = 61;
+ break;
+
+ default:
+ resetFrame = 0;
+ break;
+ }
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[0], resetFrame);
+ _brieFrame = resetFrame;
+ }
+}
+
+void Scene204::handleFlorAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame() == _florFrame)
+ return;
+
+ _florFrame = _scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame();
+ int resetFrame = -1;
+ int random;
+
+ switch (_florFrame) {
+ case 80:
+ _scene->setAnimFrame(_globals._animationIndexes[2], 1);
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[2], SYNC_ANIM, _globals._animationIndexes[1]);
+ _raoulStatus = 1;
+ break;
+
+ case 86:
+ _vm->_gameConv->release();
+ break;
+
+ case 173:
+ resetFrame = 172;
+ break;
+
+ case 1:
+ case 2:
+ case 3:
+ if (_raoulDown) {
+ random = _vm->getRandomNumber(1, 1000);
+ if (random < 300)
+ resetFrame = 0;
+ else if (random < 600)
+ resetFrame = 1;
+ else
+ resetFrame = 2;
+ }
+ break;
+
+ case 21:
+ case 180:
+ _vm->_gameConv->release();
+ break;
+
+ case 22:
+ case 50:
+ case 30:
+ case 174:
+ case 175:
+ case 176:
+ case 181:
+ switch (_florStatus) {
+ case 0:
+ random = 1;
+ _florStatus = 2;
+ break;
+
+ case 1:
+ random = 2;
+ _florStatus = 2;
+ break;
+
+ case 3:
+ random = 3;
+ break;
+
+ case 5:
+ random = 4;
+ _florStatus = 2;
+ break;
+
+ case 4:
+ random = _vm->getRandomNumber(5, 7);
+ ++_raoulCount;
+ if (_raoulCount > 17) {
+ _florStatus = 2;
+ random = 8;
+ }
+ break;
+
+ default:
+ random = 7;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 22;
+ break;
+
+ case 2:
+ resetFrame = 30;
+ break;
+
+ case 3:
+ resetFrame = 53;
+ break;
+
+ case 4:
+ resetFrame = 176;
+ break;
+
+ case 5:
+ resetFrame = 173;
+ break;
+
+ case 6:
+ resetFrame = 174;
+ break;
+
+ case 7:
+ resetFrame = 175;
+ break;
+
+ default:
+ resetFrame = 21;
+ break;
+ }
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[1], resetFrame);
+ _florFrame = resetFrame;
+ }
+}
+
+void Scene204::handleRaoulAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[2]]->getCurrentFrame() == _raoulFrame)
+ return;
+
+ _raoulFrame = _scene->_animation[_globals._animationIndexes[2]]->getCurrentFrame();
+ int resetFrame = -1;
+ int random;
+
+ switch (_raoulFrame) {
+ case 1:
+ if (_raoulStatus == 4)
+ resetFrame = 0;
+
+ break;
+
+ case 10:
+ case 14:
+ case 20:
+ case 258:
+ switch (_raoulStatus) {
+ case 0:
+ random = _vm->getRandomNumber(1, 2);
+ _raoulStatus = 1;
+ break;
+
+ case 2:
+ random = 3;
+ break;
+
+ case 5:
+ random = 4;
+ break;
+
+ default:
+ random = 5;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 10;
+ _raoulStatus = 1;
+ break;
+
+ case 2:
+ resetFrame = 14;
+ _raoulStatus = 1;
+ break;
+
+ case 3:
+ resetFrame = 20;
+ break;
+
+ case 4:
+ resetFrame = 253;
+ _raoulStatus = 1;
+ break;
+
+ default:
+ resetFrame = 9;
+ break;
+ }
+ break;
+
+ case 31:
+ if (_raoulStatus == 3)
+ resetFrame = 33;
+ else
+ resetFrame = 30;
+
+ break;
+
+ case 33:
+ resetFrame = 32;
+ break;
+
+ case 114:
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _game._objects.addToInventory(OBJ_BOOK);
+ break;
+
+ case 213:
+ _game._player._stepEnabled = true;
+ _vm->_dialogs->showItem(OBJ_BOOK, 20431, 0);
+ _game._player._stepEnabled = false;
+ break;
+
+ case 229:
+ _game._player._stepEnabled = true;
+ _vm->_dialogs->showItem(OBJ_BOOK, 20432, 0);
+ _game._player._stepEnabled = false;
+ break;
+
+ case 237:
+ _scene->freeAnimation(_globals._animationIndexes[1]);
+ _scene->freeAnimation(_globals._animationIndexes[0]);
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _anim3ActvFl = true;
+ _globals._animationIndexes[3] = _scene->loadAnimation(formAnimName('e', 1), 0);
+ _scene->loadSpeech(9);
+ break;
+
+ case 253:
+ resetFrame = 244;
+ break;
+
+ case 257:
+ _vm->_gameConv->release();
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[2], resetFrame);
+ _raoulFrame = resetFrame;
+ }
+}
+
+void Scene204::handleEndAnimation() {
+ if ((_scene->_animation[_globals._animationIndexes[3]]->getCurrentFrame() == 15) && !_skip3Fl) {
+ _scene->playSpeech(9);
+ _skip3Fl = true;
+ }
+
+ if ((_scene->_animation[_globals._animationIndexes[3]]->getCurrentFrame() == 26) && !_skip2Fl) {
+ _scene->_sequences.addTimer(300, 85);
+ _scene->_kernelMessages.add(Common::Point(123, 137), 0x1110, 0, 0, 360, _game.getQuote(0x75));
+ _skip2Fl = true;
+ }
+
+ if (_scene->_animation[_globals._animationIndexes[3]]->getCurrentFrame() == 27)
+ _scene->setAnimFrame(_globals._animationIndexes[3], 12);
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene205::Scene205(MADSEngine *vm) : Scene2xx(vm) {
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _noConversationHold = false;
+ _giveTicketFl = false;
+
+ _richardFrame = -1;
+ _richardStatus = -1;
+ _richardCount = -1;
+ _giryFrame = -1;
+ _giryStatus = -1;
+ _giryCount = -1;
+ _conversationCounter = -1;
+ _lastRandom = -1;
+}
+
+void Scene205::synchronize(Common::Serializer &s) {
+ Scene2xx::synchronize(s);
+
+ s.syncAsByte(_anim0ActvFl);
+ s.syncAsByte(_anim1ActvFl);
+ s.syncAsByte(_noConversationHold);
+ s.syncAsByte(_giveTicketFl);
+
+ s.syncAsSint16LE(_richardFrame);
+ s.syncAsSint16LE(_richardStatus);
+ s.syncAsSint16LE(_richardCount);
+ s.syncAsSint16LE(_giryFrame);
+ s.syncAsSint16LE(_giryStatus);
+ s.syncAsSint16LE(_giryCount);
+ s.syncAsSint16LE(_conversationCounter);
+ s.syncAsSint16LE(_lastRandom);
+}
+
+void Scene205::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ if (_globals[kCurrentYear] != 1881)
+ return;
+
+ if (_globals[kJacquesStatus] == 1)
+ _scene->_variant = 3;
+ else if (_globals[kJacquesStatus] == 0) {
+ if (_globals[kMadameGiryLocation] == 0)
+ _scene->_variant = 2;
+ else if (_globals[kMadameGiryLocation] == 1)
+ _scene->_variant = 1;
+ }
+}
+
+void Scene205::enter() {
+ _vm->_disableFastwalk = true;
+
+ if (_globals[kJacquesStatus] != 1) {
+ _scene->_rails.disableNode(6);
+ _scene->_rails.disableNode(7);
+ _scene->_rails.disableNode(8);
+ _scene->_rails.disableNode(9);
+ }
+
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ _lastRandom = -1;
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ }
+
+ _conversationCounter = 0;
+ _noConversationHold = false;
+ _giveTicketFl = false;
+
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('f', 0));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('f', 1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites("*RDR_9");
+
+ _scene->_hotspots.activate(NOUN_MONSIEUR_RICHARD, false);
+ _scene->_hotspots.activate(NOUN_MADAME_GIRY, false);
+ _scene->_hotspots.activate(NOUN_WOMAN, false);
+
+ _vm->_gameConv->load(18);
+ _vm->_gameConv->load(10);
+ _vm->_gameConv->load(11);
+
+ if (_globals[kCurrentYear] == 1881) {
+ if ((_globals[kMadameGiryShowsUp]) && (_globals[kJacquesStatus] == 0)) {
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('g', 1), 1);
+ _anim1ActvFl = true;
+ _giryStatus = 2;
+
+ int idx = _scene->_dynamicHotspots.add(NOUN_MADAME_GIRY, VERB_WALK_TO, SYNTAX_SINGULAR_FEM, EXT_NONE, Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots[idx]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(75, 84), FACING_NORTHWEST);
+ _scene->setDynamicAnim(idx, _globals._animationIndexes[1], 1);
+ _scene->setDynamicAnim(idx, _globals._animationIndexes[1], 2);
+
+ switch (_globals[kMadameGiryLocation]) {
+ case 0:
+ _scene->setAnimFrame(_globals._animationIndexes[1], 138);
+ _scene->_hotspots.activateAtPos(NOUN_MADAME_GIRY, true, Common::Point(62, 54));
+ _scene->_hotspots.activateAtPos(NOUN_MADAME_GIRY, true, Common::Point(62, 66));
+ break;
+
+ case 1:
+ if (_globals[kMadameNameIsKnown] >= 1) {
+ _scene->_hotspots.activateAtPos(NOUN_MADAME_GIRY, true, Common::Point(113, 44));
+ _scene->_hotspots.activateAtPos(NOUN_MADAME_GIRY, true, Common::Point(107, 66));
+ } else
+ _scene->_hotspots.activate(NOUN_WOMAN, true);
+
+ break;
+
+ case 2:
+ _scene->setAnimFrame(_globals._animationIndexes[1], 273);
+ _scene->_hotspots.activateAtPos(NOUN_MADAME_GIRY, true, Common::Point(283, 51));
+ _scene->_hotspots.activateAtPos(NOUN_MADAME_GIRY, true, Common::Point(289, 62));
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (_scene->_priorSceneId == RETURNING_FROM_LOADING) {
+ if (_vm->_gameConv->restoreRunning() == 10) {
+ int count = 0;
+
+ if (_game._objects.isInInventory(OBJ_RED_FRAME))
+ ++count;
+ if (_game._objects.isInInventory(OBJ_GREEN_FRAME))
+ ++count;
+ if (_game._objects.isInInventory(OBJ_YELLOW_FRAME))
+ ++count;
+ if (_game._objects.isInInventory(OBJ_BLUE_FRAME))
+ ++count;
+
+ _vm->_gameConv->run(10);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ _vm->_gameConv->exportValue(_game._difficulty);
+
+ if (count > 2)
+ _vm->_gameConv->exportValue(1);
+ else
+ _vm->_gameConv->exportValue(0);
+
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ _noConversationHold = true;
+
+ if (_giryStatus == 4)
+ _scene->setAnimFrame(_globals._animationIndexes[1], 66);
+ else
+ _giryStatus = 2;
+ } else if (_vm->_gameConv->restoreRunning() == 11) {
+ _vm->_gameConv->run(11);
+ _vm->_gameConv->exportValue(_game._objects.isInInventory(OBJ_TICKET));
+ _vm->_gameConv->exportValue(0);
+ _vm->_gameConv->exportValue(0);
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ }
+ }
+ }
+
+ if (_scene->_priorSceneId == RETURNING_FROM_LOADING) {
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+
+ if (_globals[kJacquesStatus] == 1) {
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('b', 9), 1);
+ _anim0ActvFl = true;
+ _richardStatus = 3;
+ _scene->_hotspots.activate(NOUN_MONSIEUR_RICHARD, true);
+
+ if (_vm->_gameConv->restoreRunning() == 18) {
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ _richardStatus = 3;
+ _vm->_gameConv->run(18);
+ _scene->setAnimFrame(_globals._animationIndexes[0], 1);
+ }
+ }
+ }
+
+ if (_scene->_priorSceneId == 206) {
+ _game._player._playerPos = Common::Point(37, 64);
+ _game._player._facing = FACING_SOUTH;
+ _game._player.walk(Common::Point(41, 67), FACING_SOUTH);
+ _game._player.setWalkTrigger(90);
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ if (_globals[kJacquesStatus] == 1) {
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('b', 9), 1);
+ _anim0ActvFl = true;
+ _richardStatus = 3;
+ _scene->_hotspots.activate(NOUN_MONSIEUR_RICHARD, true);
+ }
+ } else if (_scene->_priorSceneId == 207) {
+ _game._player._playerPos = Common::Point(263, 59);
+ _game._player._facing = FACING_SOUTH;
+ _game._player.walk(Common::Point(262, 63), FACING_SOUTH);
+ _game._player.setWalkTrigger(95);
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ } else if (_scene->_priorSceneId == 150) {
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('b', 9), 1);
+ _anim0ActvFl = true;
+ _richardStatus = 3;
+ _game._player._playerPos = Common::Point(132, 112);
+ _game._player._facing = FACING_NORTHWEST;
+ _globals[kDoorsIn205] = 1;
+ _globals[kTicketPeoplePresent] = 0;
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, -1);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ _scene->_hotspots.activate(NOUN_MONSIEUR_RICHARD, true);
+ _vm->_gameConv->run(18);
+ } else if ((_scene->_priorSceneId == 202) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
+ if (_globals[kJacquesStatus] == 1) {
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('b', 9), 1);
+ _anim0ActvFl = true;
+ _richardStatus = 3;
+ _scene->_hotspots.activate(NOUN_MONSIEUR_RICHARD, true);
+ }
+
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+
+ _game._player.firstWalk(Common::Point(-20, 144), FACING_EAST, Common::Point(19, 144), FACING_NORTHEAST, true);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene205::step() {
+ if (_anim0ActvFl)
+ handleRichardAnimation();
+
+ if (_anim1ActvFl)
+ handleGiryAnimation();
+
+ if ((_globals[kWalkerConverse] == 2) || (_globals[kWalkerConverse] == 3)) {
+ ++_conversationCounter;
+ if (_conversationCounter > 200)
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ }
+
+ if (_giveTicketFl && !_action.isAction(VERB_GIVE)) {
+ _globals[kWalkerConverse] = 0;
+ _game._player.walk(Common::Point(_game._player._playerPos.x + 5, _game._player._playerPos.y - 10), FACING_NORTHWEST);
+ _game._player.setWalkTrigger(100);
+ _giveTicketFl = false;
+ }
+
+ switch (_game._trigger) {
+ case 100:
+ _game._player._visible = false;
+ _globals._sequenceIndexes[2] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[2], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], -1, -2);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[2], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 102);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_SPRITE, 4, 101);
+ break;
+
+ case 101:
+ _game._objects.setRoom(OBJ_TICKET, NOWHERE);
+ _giryStatus = 2;
+ break;
+
+ case 102:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[2]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ _vm->_gameConv->release();
+ break;
+
+ default:
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 90:
+ _scene->deleteSequence(_globals._sequenceIndexes[0]);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[0], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 91);
+ break;
+
+ case 91:
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ _vm->_sound->command(25);
+ _game._player._stepEnabled = true;
+ break;
+
+ case 95:
+ _scene->deleteSequence(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[1], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 96);
+ break;
+
+ case 96:
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ _vm->_sound->command(25);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene205::actions() {
+ if (_vm->_gameConv->activeConvId() == 18) {
+ handleConversation18();
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_vm->_gameConv->activeConvId() == 10) {
+ handleConversation10();
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_vm->_gameConv->activeConvId() == 11) {
+ handleConversation11();
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isAction(VERB_OPEN, NOUN_BOX_FIVE)) || (_action.isAction(VERB_ENTER, NOUN_BOX_FIVE))) {
+ if (_globals[kTicketPeoplePresent] == 2) {
+ if (_globals[kMadameGiryLocation] == 2) {
+ _vm->_gameConv->run(11);
+ _vm->_gameConv->exportValue(_game._objects.isInInventory(OBJ_TICKET));
+ _vm->_gameConv->exportValue(3);
+ _vm->_gameConv->exportValue(0);
+ } else {
+ _vm->_gameConv->run(11);
+ _vm->_gameConv->exportValue(_game._objects.isInInventory(OBJ_TICKET));
+ _vm->_gameConv->exportValue(4);
+ _vm->_gameConv->exportValue(0);
+ }
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_WALK_DOWN_STAIRS_TO, NOUN_GRAND_FOYER)) {
+ if (_globals[kTicketPeoplePresent] == 2) {
+ if (_globals[kMadameGiryLocation] == 2) {
+ _vm->_gameConv->run(11);
+ _vm->_gameConv->exportValue(_game._objects.isInInventory(OBJ_TICKET));
+ _vm->_gameConv->exportValue(1);
+ _vm->_gameConv->exportValue(0);
+ } else {
+ _vm->_gameConv->run(11);
+ _vm->_gameConv->exportValue(_game._objects.isInInventory(OBJ_TICKET));
+ _vm->_gameConv->exportValue(2);
+ _vm->_gameConv->exportValue(0);
+ }
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if ((_action.isAction(VERB_ENTER)) || (_action.isAction(VERB_OPEN)) || _action.isAction(VERB_UNLOCK) || _action.isAction(VERB_LOCK)) {
+ if (((_action.isObject(NOUN_BOX_FIVE) && ((_globals[kDoorsIn205] == 0) || (_globals[kDoorsIn205] == 2)))
+ || _action.isAction(VERB_UNLOCK) || _action.isAction(VERB_LOCK))
+ || ((_action.isObject(NOUN_BOX_NINE) && ((_globals[kDoorsIn205] == 0) || (_globals[kDoorsIn205] == 1))))
+ || (_action.isObject(NOUN_BOX_SIX)) || (_action.isObject(NOUN_BOX_SEVEN)) || (_action.isObject(NOUN_BOX_EIGHT))) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 5, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[2], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ _action._inProgress = false;
+ return;
+
+ case 1: {
+ int idx = _globals._sequenceIndexes[2];
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 4);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[2], SYNC_SEQ, idx);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[2], false);
+ _vm->_sound->command(72);
+ _scene->_sequences.addTimer(15, 2);
+ _action._inProgress = false;
+ return;
+ }
+
+ case 2:
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[2], false, 5, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[2], false);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ _action._inProgress = false;
+ return;
+
+ case 3:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[2]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ if (_action.isAction(VERB_UNLOCK) || _action.isAction(VERB_LOCK))
+ _vm->_dialogs->show(20528);
+ else
+ _vm->_dialogs->show(20527);
+
+ _action._inProgress = false;
+ return;
+
+ default:
+ break;
+ }
+ } else if (((_action.isObject(NOUN_BOX_FIVE)) && ((_globals[kDoorsIn205] == 3) || (_globals[kDoorsIn205] == 1)))
+ || ((_action.isObject(NOUN_BOX_NINE)) && ((_globals[kDoorsIn205] == 3) || (_globals[kDoorsIn205] == 2)))) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[2] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[2], false, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], -1, -2);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[2], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_SPRITE, 4, 80);
+ _action._inProgress = false;
+ return;
+
+ case 80:
+ _vm->_sound->command(24);
+ if (_action.isObject(NOUN_BOX_FIVE)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[0]);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 81);
+ } else if (_action.isObject(NOUN_BOX_NINE)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 81);
+ }
+ _action._inProgress = false;
+ return;
+
+ case 81:
+ if (_action.isObject(NOUN_BOX_FIVE)) {
+ int idx = _globals._sequenceIndexes[0];
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, -2);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[0], SYNC_SEQ, idx);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ } else if (_action.isObject(NOUN_BOX_NINE)) {
+ int idx = _globals._sequenceIndexes[1];
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, -2);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[1], SYNC_SEQ, idx);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ }
+ _action._inProgress = false;
+ return;
+
+ case 2:
+ _game._player._visible = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[2]);
+ if (_action.isObject(NOUN_BOX_FIVE)) {
+ _game._player.walk(Common::Point(37, 64), FACING_NORTH);
+ _game._player.setWalkTrigger(3);
+
+ } else if (_action.isObject(NOUN_BOX_NINE)) {
+ _game._player.walk(Common::Point(263, 59), FACING_NORTH);
+ _game._player.setWalkTrigger(3);
+ }
+ _action._inProgress = false;
+ return;
+
+ case 3:
+ if (_action.isObject(NOUN_BOX_FIVE)) {
+ _scene->_nextSceneId = 206;
+ _globals[kMadameGiryLocation] = 1;
+ } else if (_action.isObject(NOUN_BOX_NINE)) {
+ _scene->_nextSceneId = 207;
+ _globals[kMadameGiryLocation] = 1;
+ }
+ _action._inProgress = false;
+ return;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ if (_action.isAction(VERB_TALK_TO, NOUN_MONSIEUR_RICHARD)) {
+ _vm->_gameConv->run(18);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TALK_TO, NOUN_MADAME_GIRY) || _action.isAction(VERB_TALK_TO, NOUN_WOMAN) || _action.isAction(VERB_GIVE, NOUN_TICKET, NOUN_MADAME_GIRY)) {
+ if (_globals[kTicketPeoplePresent] == 2) {
+ if ((_globals[kDoorsIn205] == 2) || (_globals[kDoorsIn205] == 3)) {
+ if (_globals[kMadameGiryLocation] == 2) {
+ _vm->_gameConv->run(11);
+ _vm->_gameConv->exportValue(_game._objects.isInInventory(OBJ_TICKET));
+ _vm->_gameConv->exportValue(1);
+
+ if (_action.isAction(VERB_GIVE))
+ _vm->_gameConv->exportValue(1);
+ else
+ _vm->_gameConv->exportValue(0);
+ } else {
+ _vm->_gameConv->run(11);
+ _vm->_gameConv->exportValue(_game._objects.isInInventory(OBJ_TICKET));
+ _vm->_gameConv->exportValue(2);
+
+ if (_action.isAction(VERB_GIVE))
+ _vm->_gameConv->exportValue(1);
+ else
+ _vm->_gameConv->exportValue(0);
+ }
+ } else {
+ _vm->_gameConv->run(11);
+ _vm->_gameConv->exportValue(_game._objects.isInInventory(OBJ_TICKET));
+ _vm->_gameConv->exportValue(0);
+
+ if (_action.isAction(VERB_GIVE))
+ _vm->_gameConv->exportValue(1);
+ else
+ _vm->_gameConv->exportValue(0);
+ }
+ } else {
+ int count = 0;
+
+ if (_game._objects.isInInventory(OBJ_RED_FRAME))
+ ++count;
+ if (_game._objects.isInInventory(OBJ_GREEN_FRAME))
+ ++count;
+ if (_game._objects.isInInventory(OBJ_YELLOW_FRAME))
+ ++count;
+ if (_game._objects.isInInventory(OBJ_BLUE_FRAME))
+ ++count;
+
+ _vm->_gameConv->run(10);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ _vm->_gameConv->exportValue(_game._difficulty);
+
+ if (count > 2)
+ _vm->_gameConv->exportValue(1);
+ else
+ _vm->_gameConv->exportValue(0);
+
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(20510);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_BOX_SIX)) {
+ _vm->_dialogs->show(20511);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BOX_SEVEN)) {
+ _vm->_dialogs->show(20512);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BOX_EIGHT)) {
+ _vm->_dialogs->show(20513);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BOX_NINE)) {
+ if ((_globals[kDoorsIn205] == 0) || (_globals[kDoorsIn205] == 1))
+ _vm->_dialogs->show(20516);
+ else
+ _vm->_dialogs->show(20517);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BOX_FIVE)) {
+ if ((_globals[kDoorsIn205] == 0) || (_globals[kDoorsIn205] == 2))
+ _vm->_dialogs->show(20514);
+ else
+ _vm->_dialogs->show(20515);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(20518);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_MARBLE_COLUMN)) {
+ _vm->_dialogs->show(20519);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CEILING)) {
+ _vm->_dialogs->show(20520);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(20521);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BUST)) {
+ _vm->_dialogs->show(20522);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CARPET)) {
+ _vm->_dialogs->show(20523);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_GRAND_FOYER)) {
+ _vm->_dialogs->show(20524);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WOMAN) || _action.isObject(NOUN_MADAME_GIRY)) {
+ _vm->_dialogs->show(20525);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_MONSIEUR_RICHARD)) {
+ _vm->_dialogs->show(20526);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TALK_TO, NOUN_BUST)) {
+ _vm->_dialogs->show(20529);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_BOX_TEN) || _action.isAction(VERB_ENTER, NOUN_BOX_TEN) || _action.isAction(VERB_LOOK, NOUN_BOX_TEN)) {
+ _vm->_dialogs->show(20513);
+ _action._inProgress = false;
+ return;
+ }
+
+ // FIX: the original was doing a | between the two 'objects'
+ if (_action.isAction(VERB_TAKE) && (_action.isObject(NOUN_WOMAN) || _action.isObject(NOUN_MADAME_GIRY))) {
+ _vm->_dialogs->show(20530);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene205::preActions() {
+ if (_action.isObject(NOUN_BOX_FIVE) && (_action.isAction(VERB_LOCK) || _action.isAction(VERB_UNLOCK) || _action.isAction(VERB_OPEN)))
+ _game._player.walk(Common::Point(37, 67), FACING_NORTHEAST);
+
+ if (_action.isObject(NOUN_BOX_SIX) && (_action.isAction(VERB_LOCK) || _action.isAction(VERB_UNLOCK) || _action.isAction(VERB_OPEN)))
+ _game._player.walk(Common::Point(80, 68), FACING_NORTHEAST);
+
+ if (_action.isObject(NOUN_BOX_SEVEN) && (_action.isAction(VERB_LOCK) || _action.isAction(VERB_UNLOCK) || _action.isAction(VERB_OPEN)))
+ _game._player.walk(Common::Point(167, 65), FACING_NORTHEAST);
+
+ if (_action.isObject(NOUN_BOX_EIGHT) && (_action.isAction(VERB_LOCK) || _action.isAction(VERB_UNLOCK) || _action.isAction(VERB_OPEN)))
+ _game._player.walk(Common::Point(212, 64), FACING_NORTHEAST);
+
+ if (_action.isObject(NOUN_BOX_NINE) && (_action.isAction(VERB_LOCK) || _action.isAction(VERB_UNLOCK) || _action.isAction(VERB_OPEN)))
+ _game._player.walk(Common::Point(258, 63), FACING_NORTHEAST);
+
+ if (_action.isAction(VERB_WALK_DOWN_STAIRS_TO, NOUN_GRAND_FOYER) && (_globals[kDoorsIn205] != 2) && (_globals[kDoorsIn205] != 3)) {
+ _game._player._walkOffScreenSceneId = 202;
+ _globals[kMadameGiryLocation] = 1;
+ }
+}
+
+void Scene205::handleConversation18() {
+ int interlocutorFl = false;
+ int heroFl = false;
+
+ switch (_action._activeAction._verbId) {
+ case 0:
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ _richardStatus = 0;
+ break;
+
+ case 3:
+ case 4:
+ _vm->_gameConv->setHeroTrigger(64);
+ _globals[kRanConvIn205] = true;
+ heroFl = true;
+ interlocutorFl = true;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 64:
+ _globals[kWalkerConverse] = 0;
+ heroFl = true;
+ interlocutorFl = true;
+ break;
+
+ case 62:
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+ _richardStatus = 0;
+ break;
+
+ case 60:
+ _globals[kWalkerConverse] = _vm->getRandomNumber(2, 3);
+ _richardStatus = 3;
+ _conversationCounter = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ if (!heroFl)
+ _vm->_gameConv->setHeroTrigger(60);
+
+ if (!interlocutorFl)
+ _vm->_gameConv->setInterlocutorTrigger(62);
+
+ _richardCount = 0;
+}
+
+void Scene205::handleConversation10() {
+ int interlocutorFl = false;
+ int heroFl = false;
+
+ switch (_action._activeAction._verbId) {
+ case 9:
+ _vm->_gameConv->setInterlocutorTrigger(68);
+ interlocutorFl = true;
+ _globals[kMadameNameIsKnown] = 1;
+ _scene->_hotspots.activate(NOUN_WOMAN, false);
+ _scene->_hotspots.activateAtPos(NOUN_MADAME_GIRY, true, Common::Point(113, 44));
+ _scene->_hotspots.activateAtPos(NOUN_MADAME_GIRY, true, Common::Point(107, 66));
+ break;
+
+ case 10:
+ _globals[kMadameNameIsKnown] = 1;
+ _scene->_hotspots.activate(NOUN_WOMAN, false);
+ _scene->_hotspots.activateAtPos(NOUN_MADAME_GIRY, true, Common::Point(113, 44));
+ _scene->_hotspots.activateAtPos(NOUN_MADAME_GIRY, true, Common::Point(107, 66));
+ break;
+
+ case 7:
+ if (!_game._trigger) {
+ _giryStatus = 6;
+ _globals[kMadameNameIsKnown] = 2;
+ _globals[kMadameGiryLocation] = 0;
+ _scene->changeVariant(2);
+ _scene->_rails.disableNode(6);
+ _scene->_rails.disableNode(7);
+ _scene->_rails.disableNode(8);
+ _scene->_rails.disableNode(9);
+ _scene->_hotspots.activateAtPos(NOUN_MADAME_GIRY, false, Common::Point(113, 44));
+ _scene->_hotspots.activateAtPos(NOUN_MADAME_GIRY, false, Common::Point(107, 66));
+ interlocutorFl = true;
+ heroFl = true;
+ if (_globals[kDoorsIn205] == 0)
+ _globals[kDoorsIn205] = 1;
+ else if (_globals[kDoorsIn205] == 2)
+ _globals[kDoorsIn205] = 3;
+ }
+ break;
+
+ case 13:
+ case 45:
+ _vm->_gameConv->setInterlocutorTrigger(70);
+ interlocutorFl = true;
+ break;
+
+ case 21:
+ if (!_game._trigger && !_noConversationHold) {
+ _vm->_gameConv->hold();
+ _giryStatus = 4;
+ } else
+ _noConversationHold = false;
+
+ break;
+
+ case 17:
+ _vm->_gameConv->setInterlocutorTrigger(72);
+ interlocutorFl = true;
+ break;
+
+ case 11:
+ if (!_game._trigger) {
+ _vm->_gameConv->setInterlocutorTrigger(74);
+ }
+ heroFl = true;
+ interlocutorFl = true;
+ break;
+
+ case 23:
+ case 25:
+ if ((!_game._trigger) && (_giryStatus == 4)) {
+ _vm->_gameConv->hold();
+ _giryStatus = 0;
+ }
+ break;
+
+ case 4:
+ case 5:
+ case 8:
+ case 14:
+ case 16:
+ case 19:
+ case 40:
+ case 46:
+ _vm->_gameConv->setInterlocutorTrigger(64);
+ interlocutorFl = true;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 64:
+ switch (_action._activeAction._verbId) {
+ case 5:
+ case 14:
+ case 16:
+ case 19:
+ case 40:
+ case 46:
+ _giryStatus = 0;
+ break;
+ }
+ _globals[kWalkerConverse] = 0;
+ heroFl = true;
+ interlocutorFl = true;
+ break;
+
+ case 68:
+ _giryStatus = 5;
+ break;
+
+ case 74:
+ _giryStatus = 8;
+ _globals[kWalkerConverse] = 0;
+ heroFl = true;
+ interlocutorFl = true;
+ break;
+
+ case 72:
+ _giryStatus = 3;
+ break;
+
+ case 70:
+ if (_action._activeAction._verbId == 13) {
+ _globals[kWalkerConverse] = 0;
+ heroFl = true;
+ interlocutorFl = true;
+ }
+ _giryStatus = 1;
+ break;
+
+ case 66:
+ if (_globals[kWalkerConverse] != 0)
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+
+ if ((_giryStatus != 4) && (_giryStatus != 6) && (_giryStatus != 7))
+ _giryStatus = 0;
+ break;
+
+ case 60:
+ if (_globals[kWalkerConverse] != 0)
+ _globals[kWalkerConverse] = _vm->getRandomNumber(2, 3);
+
+ if ((_giryStatus != 4) && (_giryStatus != 6) && (_giryStatus != 7))
+ _giryStatus = 2;
+
+ _conversationCounter = 0;
+ break;
+ }
+
+ if (!heroFl)
+ _vm->_gameConv->setHeroTrigger(60);
+
+ if (!interlocutorFl)
+ _vm->_gameConv->setInterlocutorTrigger(66);
+
+ _giryCount = 0;
+}
+
+void Scene205::handleConversation11() {
+ int interlocutorFl = false;
+ int heroFl = false;
+
+ switch (_action._activeAction._verbId) {
+ case 5:
+ if (!_game._trigger) {
+ _vm->_gameConv->hold();
+ _giryStatus = 9;
+ }
+ break;
+
+ case 8:
+ if (!_game._trigger) {
+ _vm->_gameConv->hold();
+ _giryStatus = 7;
+ _vm->_gameConv->setInterlocutorTrigger(64);
+ _game._player.walk(Common::Point(225,79), FACING_NORTHEAST);
+ interlocutorFl = true;
+ _globals[kMadameGiryLocation] = 2;
+ _scene->changeVariant(4);
+ _scene->_rails.disableNode(6);
+ _scene->_rails.disableNode(7);
+ _scene->_rails.disableNode(8);
+ _scene->_rails.disableNode(9);
+ _scene->_hotspots.activateAtPos(NOUN_MADAME_GIRY, false, Common::Point(113, 44));
+ _scene->_hotspots.activateAtPos(NOUN_MADAME_GIRY, false, Common::Point(107, 66));
+ if (_globals[kDoorsIn205] == 0)
+ _globals[kDoorsIn205] = 2;
+ else if (_globals[kDoorsIn205] == 1)
+ _globals[kDoorsIn205] = 3;
+ }
+ break;
+
+ case 9:
+ case 10:
+ case 12:
+ case 13:
+ case 14:
+ _vm->_gameConv->setInterlocutorTrigger(64);
+ interlocutorFl = true;
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 64:
+ switch (_action._activeAction._verbId) {
+ case 6:
+ case 10:
+ case 12:
+ case 13:
+ case 14:
+ _giryStatus = 0;
+ break;
+ }
+ _globals[kWalkerConverse] = 0;
+ heroFl = true;
+ interlocutorFl = true;
+ break;
+
+ case 110:
+ _vm->_gameConv->hold();
+ _giryStatus = 7;
+ break;
+
+ case 66:
+ if (_globals[kWalkerConverse] != 0)
+ _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
+
+ if (_giryStatus != 9)
+ _giryStatus = 0;
+ break;
+
+ case 60:
+ if (_globals[kWalkerConverse] != 0)
+ _globals[kWalkerConverse] = _vm->getRandomNumber(2, 3);
+
+ if (_giryStatus != 9)
+ _giryStatus = 2;
+
+ _conversationCounter = 0;
+ break;
+ }
+
+ if (!heroFl)
+ _vm->_gameConv->setHeroTrigger(60);
+
+ if (!interlocutorFl)
+ _vm->_gameConv->setInterlocutorTrigger(66);
+
+ _giryCount = 0;
+}
+
+void Scene205::handleRichardAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == _richardFrame)
+ return;
+
+ _richardFrame = _scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame();
+ int random;
+ int resetFrame = -1;
+
+ switch (_richardFrame) {
+ case 1:
+ case 2:
+ case 3:
+ case 11:
+ case 19:
+ case 35:
+ case 47:
+ case 57:
+ case 69:
+ switch (_richardStatus) {
+ case 0:
+ random = _vm->getRandomNumber(1, 3);
+ ++_richardCount;
+ if (_richardCount > 30) {
+ _richardStatus = 3;
+ random = 9;
+ }
+ break;
+
+ case 1:
+ random = 4;
+ _richardStatus = 0;
+ break;
+
+ case 2:
+ random = 6;
+ break;
+
+ case 4:
+ random = 5;
+ _richardStatus = 0;
+ break;
+
+ default:
+ random = _vm->getRandomNumber(7, 50);
+ while (_lastRandom == random)
+ random = _vm->getRandomNumber(7, 50);
+
+ _lastRandom = random;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 0;
+ break;
+
+ case 2:
+ resetFrame = 1;
+ break;
+
+ case 3:
+ resetFrame = 2;
+ break;
+
+ case 4:
+ resetFrame = 11;
+ break;
+
+ case 5:
+ resetFrame = 3;
+ break;
+
+ case 6:
+ resetFrame = 57;
+ break;
+
+ case 7:
+ resetFrame = 23;
+ break;
+
+ case 8:
+ resetFrame = 19;
+ break;
+
+ case 9:
+ resetFrame = 21;
+ break;
+
+ case 10:
+ resetFrame = 25;
+ break;
+
+ case 11:
+ resetFrame = 35;
+ break;
+
+ case 12:
+ resetFrame = 47;
+ break;
+
+ default:
+ resetFrame = 0;
+ break;
+ }
+ break;
+
+ case 30:
+ switch (_richardStatus) {
+ case 0:
+ case 1:
+ case 2:
+ case 4:
+ random = 1;
+ break;
+
+ default:
+ random = _vm->getRandomNumber(1, 50);
+ break;
+ }
+
+ if (random == 1)
+ resetFrame = 30;
+ else
+ resetFrame = 29;
+
+ break;
+
+ case 24:
+ switch (_richardStatus) {
+ case 1:
+ case 2:
+ case 4:
+ case 0:
+ random = 1;
+ break;
+
+ default:
+ random = _vm->getRandomNumber(1, 30);
+ break;
+ }
+
+ if (random == 1)
+ resetFrame = 0;
+ else
+ resetFrame = 23;
+
+ break;
+
+ case 20:
+ switch (_richardStatus) {
+ case 1:
+ case 2:
+ case 4:
+ case 0:
+ random = 1;
+ break;
+
+ default:
+ random = _vm->getRandomNumber(1, 50);
+ break;
+ }
+
+ if (random == 1)
+ resetFrame = 0;
+ else
+ resetFrame = 19;
+
+ break;
+
+ case 22:
+ switch (_richardStatus) {
+ case 1:
+ case 2:
+ case 4:
+ case 0:
+ random = 1;
+ break;
+
+ default:
+ random = _vm->getRandomNumber(1, 50);
+ break;
+ }
+
+ if (random == 1)
+ resetFrame = 0;
+ else
+ resetFrame = 21;
+
+ break;
+
+ case 41:
+ switch (_richardStatus) {
+ case 1:
+ case 2:
+ case 4:
+ case 0:
+ random = 1;
+ break;
+
+ default:
+ random = _vm->getRandomNumber(1, 50);
+ break;
+ }
+
+ if (random == 1)
+ resetFrame = 41;
+ else
+ resetFrame = 40;
+
+ break;
+
+ case 52:
+ switch (_richardStatus) {
+ case 0:
+ case 1:
+ case 2:
+ case 4:
+ random = 1;
+ break;
+
+ default:
+ random = _vm->getRandomNumber(1, 50);
+ break;
+ }
+
+ if (random == 1)
+ resetFrame = 52;
+ else
+ resetFrame = 51;
+
+ break;
+
+ case 65:
+ switch (_richardStatus) {
+ case 0:
+ case 1:
+ case 2:
+ case 4:
+ random = 1;
+ break;
+
+ default:
+ random = _vm->getRandomNumber(1, 50);
+ break;
+ }
+
+ if (random == 1)
+ resetFrame = 65;
+ else
+ resetFrame = 64;
+
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[0], resetFrame);
+ _richardFrame = resetFrame;
+ }
+}
+
+void Scene205::handleGiryAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame() == _giryFrame)
+ return;
+
+ _giryFrame = _scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame();
+ int random;
+ int resetFrame = -1;
+
+ switch (_giryFrame) {
+ case 77:
+ _vm->_gameConv->release();
+ break;
+
+ case 1:
+ case 2:
+ case 3:
+ case 44:
+ case 14:
+ case 21:
+ case 35:
+ case 56:
+ case 78:
+ case 284:
+ switch (_giryStatus) {
+ case 0:
+ random = _vm->getRandomNumber(1, 3);
+ ++_giryCount;
+ if (_giryCount > 30) {
+ _giryStatus = 2;
+ random = 100;
+ }
+ break;
+
+ case 8:
+ random = 4;
+ _giryStatus = 0;
+ break;
+
+ case 3:
+ random = 5;
+ _giryStatus = 0;
+ break;
+
+ case 1:
+ random = 6;
+ break;
+
+ case 5:
+ _giryStatus = 0;
+ random = 7;
+ break;
+
+ case 4:
+ random = 8;
+ break;
+
+ case 6:
+ random = 9;
+ _giryStatus = 2;
+ break;
+
+ case 7:
+ random = 10;
+ _giryStatus = 2;
+ break;
+
+ case 9:
+ random = 11;
+ break;
+
+ default:
+ random = _vm->getRandomNumber(12, 100);
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 0;
+ break;
+
+ case 2:
+ resetFrame = 1;
+ break;
+
+ case 3:
+ resetFrame = 2;
+ break;
+
+ case 4:
+ resetFrame = 3;
+ break;
+
+ case 5:
+ resetFrame = 16;
+ break;
+
+ case 6:
+ resetFrame = 21;
+ break;
+
+ case 7:
+ resetFrame = 44;
+ break;
+
+ case 8:
+ resetFrame = 56;
+ break;
+
+ case 9:
+ resetFrame = 78;
+ _vm->_gameConv->hold();
+ break;
+
+ case 10:
+ resetFrame = 140;
+ break;
+
+ case 11:
+ resetFrame = 276;
+ break;
+
+ case 12:
+ resetFrame = 35;
+ break;
+
+ default:
+ resetFrame = 0;
+ break;
+ }
+ break;
+
+ case 27:
+ case 28:
+ case 29:
+ switch (_giryStatus) {
+ case 0:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ random = 4;
+ break;
+
+ default:
+ random = _vm->getRandomNumber(1, 3);
+ ++_giryCount;
+ if (_giryCount > 30) {
+ _giryStatus = 2;
+ random = 100;
+ }
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 26;
+ break;
+
+ case 2:
+ resetFrame = 27;
+ break;
+
+ case 3:
+ resetFrame = 28;
+ break;
+
+ default:
+ resetFrame = 29;
+ break;
+ }
+ break;
+
+ case 265:
+ _scene->_hotspots.activateAtPos(NOUN_MADAME_GIRY, true, Common::Point(283, 51));
+ _scene->_hotspots.activateAtPos(NOUN_MADAME_GIRY, true, Common::Point(289, 62));
+ _vm->_gameConv->release();
+ break;
+
+ case 274:
+ case 275:
+ case 276:
+ if (_giryStatus == 0) {
+ random = _vm->getRandomNumber(1, 3);
+ ++_giryCount;
+ if (_giryCount > 30) {
+ _giryStatus = 2;
+ random = 100;
+ }
+ } else
+ random = 100;
+
+ switch (random) {
+ case 1:
+ resetFrame = 273;
+ break;
+
+ case 2:
+ resetFrame = 274;
+ break;
+
+ case 3:
+ resetFrame = 275;
+ break;
+
+ default:
+ resetFrame = 273;
+ break;
+ }
+ break;
+
+ case 85:
+ _vm->_gameConv->release();
+ break;
+
+ case 110:
+ _scene->_hotspots.activateAtPos(NOUN_MADAME_GIRY, true, Common::Point(62, 54));
+ _scene->_hotspots.activateAtPos(NOUN_MADAME_GIRY, true, Common::Point(62, 66));
+ break;
+
+ case 138:
+ case 139:
+ case 140:
+ switch (_giryStatus) {
+ case 0:
+ case 1:
+ random = _vm->getRandomNumber(1, 3);
+ ++_giryCount;
+ if (_giryCount > 30) {
+ _giryStatus = 2;
+ random = 100;
+ }
+ break;
+
+ default:
+ random = 100;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ resetFrame = 137;
+ break;
+
+ case 2:
+ resetFrame = 138;
+ break;
+
+ case 3:
+ resetFrame = 139;
+ break;
+
+ default:
+ resetFrame = 137;
+ break;
+ }
+ break;
+
+ case 66:
+ _vm->_gameConv->release();
+ break;
+
+ case 67:
+ switch (_giryStatus) {
+ case 0:
+ case 9:
+ case 2:
+ case 3:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ random = 1;
+ break;
+
+ default:
+ random = 100;
+ break;
+ }
+
+ if (random == 1)
+ resetFrame = 67;
+ else
+ resetFrame = 66;
+
+ break;
+
+ case 8:
+ case 9:
+ switch (_giryStatus) {
+ case 0:
+ case 9:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ random = 1;
+ break;
+
+ default:
+ random = 100;
+ break;
+ }
+
+ if (random == 1)
+ resetFrame = 9;
+ else
+ resetFrame = 8;
+
+ break;
+
+ case 280:
+ _giveTicketFl = true;
+ break;
+
+ case 281:
+ switch (_giryStatus) {
+ case 0:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ random = 1;
+ break;
+
+ default:
+ random = 100;
+ break;
+ }
+
+ if (random == 1)
+ resetFrame = 281;
+ else
+ resetFrame = 280;
+
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[1], resetFrame);
+ _giryFrame = resetFrame;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene206::Scene206(MADSEngine *vm) : Scene2xx(vm) {
+ _anim0ActvFl = false;
+ _skip1Fl = false;
+ _skip2Fl = false;
+}
+
+void Scene206::synchronize(Common::Serializer &s) {
+ Scene2xx::synchronize(s);
+
+ s.syncAsByte(_anim0ActvFl);
+ s.syncAsByte(_skip1Fl);
+ s.syncAsByte(_skip2Fl);
+}
+
+void Scene206::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene206::enter() {
+ _anim0ActvFl = false;
+ _skip1Fl = false;
+ _skip2Fl = false;
+
+ _scene->loadSpeech(1);
+ _vm->_gameConv->load(26);
+
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 2));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('x', 3));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites("*RDR_9");
+
+ if (_scene->_priorSceneId != 308) {
+ if (_globals[kPanelIn206] == 0) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ } else {
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 3);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 13);
+ }
+ }
+
+ if (_globals[kPanelIn206] == 0) {
+ _scene->_hotspots.activate(NOUN_PANEL, false);
+ _scene->_hotspots.activate(NOUN_KEYHOLE, false);
+ }
+
+ if (_game._objects.isInRoom(OBJ_CRUMPLED_NOTE)) {
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('p', 0));
+ _globals._sequenceIndexes[4] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[4], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 10);
+ } else
+ _scene->_hotspots.activate(NOUN_CRUMPLED_NOTE, false);
+
+ if (_globals[kTrapDoorStatus] == 0) {
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ }
+
+ if (_globals[kRightDoorIsOpen504] && !_globals[kKnockedOverHead]) {
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('h', 1), 88);
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _anim0ActvFl = true;
+ } else if (_scene->_priorSceneId == 308) {
+ _game._player._playerPos = Common::Point(67, 127);
+ _game._player._stepEnabled = false;
+ _game._player.walk(Common::Point(108, 137), FACING_EAST);
+ _game._player.setWalkTrigger(82);
+ } else if ((_scene->_priorSceneId == 205) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
+ _game._player._playerPos = Common::Point(153, 148);
+ _game._player._facing = FACING_NORTH;
+ }
+
+ sceneEntrySound();
+}
+
+void Scene206::step() {
+ switch (_game._trigger) {
+ case 82:
+ _vm->_sound->command(24);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[3], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 13);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 83);
+ break;
+
+ case 83:
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 3);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 13);
+ _game._player._stepEnabled = true;
+ break;
+
+ case 88:
+ _game._player._playerPos = Common::Point(168, 138);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ _anim0ActvFl = false;
+ _game._player.resetFacing(FACING_WEST);
+ break;
+
+ default:
+ break;
+ }
+
+ if (_anim0ActvFl && !_skip1Fl) {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == 118) {
+ _globals[kKnockedOverHead] = true;
+ _skip1Fl = true;
+ _scene->_sequences.addTimer(1, 84);
+ }
+ }
+
+ if (_anim0ActvFl && !_skip2Fl) {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == 61) {
+ if (_vm->_sound->_preferRoland)
+ _vm->_sound->command(65);
+ else
+ _scene->playSpeech(1);
+
+ _skip2Fl = true;
+ }
+ }
+
+ switch (_game._trigger) {
+ case 84:
+ _vm->_sound->command(24);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[3], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 13);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 85);
+ break;
+
+ case 85:
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 3);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 13);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene206::actions() {
+ if (_action.isAction(VERB_EXIT_TO, NOUN_LOGE_CORRIDOR)) {
+ if (_globals[kRightDoorIsOpen504]) {
+ if (_vm->_sound->_preferRoland)
+ _vm->_sound->command(65);
+ else
+ _scene->playSpeech(1);
+
+ _vm->_gameConv->run(26);
+ _vm->_gameConv->exportValue(4);
+ } else
+ _scene->_nextSceneId = 205;
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_CRUMPLED_NOTE) && (_game._objects.isInRoom(OBJ_CRUMPLED_NOTE) || _game._trigger)) {
+ switch (_game._trigger) {
+ case (0):
+ _globals[kPlayerScore] += 5;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[5] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[5], false, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], -1, -2);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[5], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_SPRITE, 4, 77);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 78);
+ _action._inProgress = false;
+ return;
+
+ case 77:
+ _scene->deleteSequence(_globals._sequenceIndexes[4]);
+ _scene->_hotspots.activate(NOUN_CRUMPLED_NOTE, false);
+ _game._objects.addToInventory(OBJ_CRUMPLED_NOTE);
+ _vm->_sound->command(26);
+ _action._inProgress = false;
+ return;
+
+ case 78:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[5]);
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(20, 79);
+ _action._inProgress = false;
+ return;
+
+ case 79:
+ _vm->_dialogs->showItem(OBJ_CRUMPLED_NOTE, 816, 6);
+ _game._player._stepEnabled = true;
+ _action._inProgress = false;
+ return;
+
+ default:
+ break;
+ }
+ }
+
+ if (_action.isAction(VERB_WALK_BEHIND, NOUN_PANEL) || _action.isAction(VERB_OPEN, NOUN_PANEL)
+ || ((_game._trigger >= 70) && (_game._trigger < 77))) {
+ if (_globals[kPanelIn206] == 3) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[5] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[5], true, 7, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 1, 3);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[5], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_SPRITE, 3, 70);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ break;
+
+ case 70:
+ _vm->_sound->command(24);
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 13);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], -1, -2);
+ break;
+
+ case 71:
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ _game._player.walk(Common::Point(67, 127), FACING_NORTHWEST);
+ _game._player.setWalkTrigger(72);
+ break;
+
+ case 72:
+ _vm->_sound->command(24);
+ _scene->deleteSequence(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[3], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 13);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 73);
+ break;
+
+ case 73:
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+ _scene->_nextSceneId = 308;
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[5] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[5], true, 7, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 1, 3);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[5], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 74);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_SPRITE, 3, 75);
+ break;
+
+ case 74:
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ _vm->_dialogs->show(20625);
+ break;
+
+ case 75:
+ _vm->_sound->command(72);
+ break;
+
+ default:
+ break;
+ }
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_UNLOCK, NOUN_PANEL) || _action.isAction(VERB_LOCK, NOUN_PANEL) || _action.isAction(VERB_PUT, NOUN_KEY, NOUN_KEYHOLE)
+ || _action.isAction(VERB_UNLOCK, NOUN_KEYHOLE) || _action.isAction(VERB_LOCK, NOUN_KEYHOLE) || (_game._trigger >= 64)) {
+ if (_globals[kPanelIn206] >= 1) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], true, 7, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 1, 3);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[5], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 64);
+ break;
+
+ case 64: {
+ _vm->_sound->command(71);
+ int idx = _globals._sequenceIndexes[5];
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], true, -2);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[5], SYNC_SEQ, idx);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[5], false);
+ _scene->_sequences.addTimer(30, 65);
+ }
+ break;
+
+ case 65:
+ _scene->deleteSequence(_globals._sequenceIndexes[5]);
+ _globals._sequenceIndexes[5] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[5], true, 7, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 1, 3);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[5], false);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 66);
+ break;
+
+ case 66:
+ if (_action.isAction(VERB_LOCK)) {
+ _globals[kPanelIn206] = 2;
+ _vm->_dialogs->show(20629);
+ } else if (_action.isAction(VERB_UNLOCK)) {
+ _globals[kPanelIn206] = 3;
+ _vm->_dialogs->show(20628);
+ }
+
+ if (_action.isAction(VERB_PUT)) {
+ if (_globals[kPanelIn206] <= 2) {
+ _globals[kPanelIn206] = 3;
+ _vm->_dialogs->show(20628);
+ } else {
+ _globals[kPanelIn206] = 2;
+ _vm->_dialogs->show(20629);
+ }
+ }
+
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[5]);
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(20610);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(20611);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(20612);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RIGHT_COLUMN)) {
+ _vm->_dialogs->show(20614);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_KEYHOLE)) {
+ _vm->_dialogs->show(20615);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RAIL)) {
+ _vm->_dialogs->show(20616);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SEAT)) {
+ _vm->_dialogs->show(20617);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LOGE_CORRIDOR)) {
+ _vm->_dialogs->show(20618);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_STAGE)) {
+ if (_globals[kJacquesStatus])
+ _vm->_dialogs->show(20630);
+ else
+ _vm->_dialogs->show(20619);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_HOUSE)) {
+ _vm->_dialogs->show(20620);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CEILING)) {
+ _vm->_dialogs->show(20621);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_HOUSE_LIGHT)) {
+ _vm->_dialogs->show(20622);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PANEL)) {
+ if (_globals[kPanelIn206] == 3)
+ _vm->_dialogs->show(20624);
+ else
+ _vm->_dialogs->show(20626);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isObject(NOUN_LEFT_COLUMN)) && (!_game._trigger)) {
+ if (_globals[kPanelIn206] == 0) {
+ _vm->_dialogs->show(20613);
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('k', 1), 95);
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ } else
+ _vm->_dialogs->show(20623);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CRUMPLED_NOTE) && _game._objects.isInRoom(OBJ_CRUMPLED_NOTE)) {
+ _vm->_dialogs->show(20627);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ switch (_game._trigger) {
+ case 95:
+ _game._player._visible = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[0]);
+ _scene->_hotspots.activate(NOUN_PANEL, true);
+ _scene->_hotspots.activate(NOUN_KEYHOLE, true);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 3);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 13);
+ if (!(_globals[kPlayerScoreFlags] & 8)) {
+ _globals[kPlayerScoreFlags] |= 8;
+ _globals[kPlayerScore] += 5;
+ }
+ _scene->_sequences.addTimer(15, 96);
+
+ _action._inProgress = false;
+ return;
+
+ case 96:
+ _game._player._stepEnabled = true;
+ _globals[kPanelIn206] = 1;
+ _vm->_dialogs->show(20623);
+ _action._inProgress = false;
+ return;
+
+ default:
+ break;
+ }
+}
+
+void Scene206::preActions() {
+ if (_action.isAction(VERB_LOOK, NOUN_LEFT_COLUMN))
+ _game._player._needToWalk = true;
+
+ if (_action.isAction(VERB_UNLOCK, NOUN_PANEL) || _action.isAction(VERB_WALK_BEHIND, NOUN_PANEL)
+ || _action.isAction(VERB_LOCK, NOUN_PANEL) || _action.isAction(VERB_OPEN, NOUN_PANEL))
+ _game._player.walk(Common::Point(108, 137), FACING_NORTHWEST);
+
+ if (_action.isObject(NOUN_LEFT_COLUMN) && (_globals[kPanelIn206] == 0))
+ _game._player.walk(Common::Point(103, 137), FACING_NORTHWEST);
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene207::Scene207(MADSEngine *vm) : Scene2xx(vm) {
+ _skip1Fl = false;
+ _anim0ActvFl = false;
+}
+
+void Scene207::synchronize(Common::Serializer &s) {
+ Scene2xx::synchronize(s);
+
+ s.syncAsByte(_skip1Fl);
+ s.syncAsByte(_anim0ActvFl);
+}
+
+void Scene207::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene207::enter() {
+ _scene->loadSpeech(2);
+ _skip1Fl = false;
+ _anim0ActvFl = false;
+
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('a', 0));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('c', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 0));
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 10);
+
+ if ((_scene->_priorSceneId == 205) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
+ _game._player._playerPos = Common::Point(159, 147);
+ _game._player._facing = FACING_NORTH;
+ }
+
+ sceneEntrySound();
+}
+
+void Scene207::step() {
+ if (_anim0ActvFl && !_skip1Fl) {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == 6) {
+ if (_vm->_sound->_preferRoland)
+ _vm->_sound->command(69);
+ else
+ _scene->playSpeech(2);
+
+ _skip1Fl = true;
+ }
+ }
+}
+
+void Scene207::actions() {
+ if (_action.isAction(VERB_TAKE, NOUN_SEAT)) {
+ switch (_game._trigger) {
+ case 0:
+ _globals[kPlayerScore] += 5;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _vm->_sound->command(3);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 7, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 10);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1:
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 10);
+ _scene->_sequences.addTimer(120, 2);
+ _scene->_sequences.addTimer(240, 3);
+ break;
+
+ case 2:
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 6, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 4);
+ break;
+
+ case 3:
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('s', 1), 5);
+ _anim0ActvFl = true;
+ _scene->deleteSequence(_globals._sequenceIndexes[1]);
+ break;
+
+ case 4:
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ break;
+
+ case 5:
+ _scene->_nextSceneId = 208;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_EXIT_TO, NOUN_LOGE_CORRIDOR)) {
+ _scene->_nextSceneId = 205;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(20710);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(20711);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(20712);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LEFT_COLUMN)) {
+ _vm->_dialogs->show(20713);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RIGHT_COLUMN)) {
+ _vm->_dialogs->show(20714);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RAIL)) {
+ _vm->_dialogs->show(20715);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SEAT)) {
+ _vm->_dialogs->show(20716);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LOGE_CORRIDOR)) {
+ _vm->_dialogs->show(20717);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_STAGE)) {
+ _vm->_dialogs->show(20718);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_HOUSE)) {
+ _vm->_dialogs->show(20719);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CEILING)) {
+ _vm->_dialogs->show(20720);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_HOUSE_LIGHT)) {
+ _vm->_dialogs->show(20721);
+ _action._inProgress = false;
+ return;
+ }
+ }
+}
+
+void Scene207::preActions() {
+ if (_action.isAction(VERB_TAKE, NOUN_SEAT))
+ _game._player.walk(Common::Point(139, 124), FACING_NORTH);
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene208::Scene208(MADSEngine *vm) : Scene2xx(vm) {
+ _skip1Fl = false;
+ _skip2Fl = false;
+
+ _topLeftPeopleFrame = -1;
+ _topRightPeopleFrame = -1;
+ _middleLeftPeopleFrame = -1;
+ _centerPeopleFrame = -1;
+ _middleRightPeopleFrame = -1;
+ _bottomLeftPeopleFrame = -1;
+ _bottomMiddlePeopleFrame = -1;
+ _bottomRightPeopleFrame = -1;
+ _direction = -1;
+}
+
+void Scene208::synchronize(Common::Serializer &s) {
+ Scene2xx::synchronize(s);
+
+ s.syncAsByte(_skip1Fl);
+ s.syncAsByte(_skip2Fl);
+
+ s.syncAsSint16LE(_topLeftPeopleFrame);
+ s.syncAsSint16LE(_topRightPeopleFrame);
+ s.syncAsSint16LE(_middleLeftPeopleFrame);
+ s.syncAsSint16LE(_centerPeopleFrame);
+ s.syncAsSint16LE(_middleRightPeopleFrame);
+ s.syncAsSint16LE(_bottomLeftPeopleFrame);
+ s.syncAsSint16LE(_bottomMiddlePeopleFrame);
+ s.syncAsSint16LE(_bottomRightPeopleFrame);
+ s.syncAsSint16LE(_direction);
+}
+
+void Scene208::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene208::enter() {
+ _scene->loadSpeech(1);
+
+ _skip1Fl = false;
+ _skip2Fl = false;
+
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 2));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('x', 3));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('x', 4));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('x', 5));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('x', 6));
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('x', 7));
+
+ _scene->_userInterface.emptyConversationList();
+ _scene->_userInterface.setup(kInputConversation);
+
+ _scene->loadSpeech(1);
+
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+
+ _topLeftPeopleFrame = 2;
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, _topLeftPeopleFrame);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 1);
+ _scene->_sequences.addTimer(120, 60);
+
+ _topRightPeopleFrame = 2;
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, _topRightPeopleFrame);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ _scene->_sequences.addTimer(30, 62);
+
+ _middleLeftPeopleFrame = 2;
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, _middleLeftPeopleFrame);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _scene->_sequences.addTimer(30, 64);
+
+ _centerPeopleFrame = 1;
+ _direction = 1;
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, _centerPeopleFrame);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
+ _scene->_sequences.addTimer(300, 66);
+
+ _middleRightPeopleFrame = 3;
+ _globals._sequenceIndexes[4] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[4], false, _middleRightPeopleFrame);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 1);
+ _scene->_sequences.addTimer(60, 68);
+
+ _bottomLeftPeopleFrame = 4;
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, _bottomLeftPeopleFrame);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 1);
+ _scene->_sequences.addTimer(60, 70);
+
+ _bottomMiddlePeopleFrame = 4;
+ _globals._sequenceIndexes[6] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[6], false, _bottomMiddlePeopleFrame);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 14);
+ _scene->_sequences.addTimer(30, 72);
+
+ _bottomRightPeopleFrame = 3;
+ _globals._sequenceIndexes[7] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[7], false, _bottomRightPeopleFrame);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 1);
+ _scene->_sequences.addTimer(15, 74);
+
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('p', 1), 80);
+
+ sceneEntrySound();
+}
+
+void Scene208::step() {
+ animateTopLeftPeople();
+ animateTopRightPeople();
+ animateMiddleLeftPeople();
+ animateCenterPeople();
+ animateMiddleRightPeople();
+ animateBottomLeftPeople();
+ animateBottomMiddlePeople();
+ animateBottomRightPeople();
+
+ if (!_skip1Fl) {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == 49) {
+ if (_vm->_sound->_preferRoland)
+ _vm->_sound->command(65);
+ else
+ _scene->playSpeech(1);
+
+ _skip1Fl = true;
+ }
+ }
+
+ if (!_skip2Fl) {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == 68) {
+ if (_vm->_sound->_preferRoland)
+ _vm->_sound->command(65);
+ else
+ _scene->playSpeech(1);
+
+ _skip2Fl = true;
+ }
+ }
+
+ if (_game._trigger == 80)
+ _scene->_nextSceneId = 150;
+}
+
+void Scene208::actions() {
+}
+
+void Scene208::preActions() {
+}
+
+void Scene208::animateTopLeftPeople() {
+
+ if (_game._trigger != 60)
+ return;
+
+ _scene->deleteSequence(_globals._sequenceIndexes[0]);
+
+ int triggerVal;
+ int rndVal = _vm->getRandomNumber(1, 2);
+ if (_topLeftPeopleFrame == 3)
+ triggerVal = 1;
+ else
+ triggerVal = rndVal;
+
+ if (rndVal == triggerVal) {
+ _topLeftPeopleFrame += _vm->getRandomNumber(-1, 1);
+ if (_topLeftPeopleFrame == 0)
+ _topLeftPeopleFrame = 1;
+ else if (_topLeftPeopleFrame == 4)
+ _topLeftPeopleFrame = 3;
+ }
+
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, _topLeftPeopleFrame);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 1);
+ int delay = _vm->getRandomNumber(15, 60);
+ _scene->_sequences.addTimer(delay, 60);
+}
+
+void Scene208::animateTopRightPeople() {
+ if (_game._trigger != 62)
+ return;
+
+ _scene->deleteSequence(_globals._sequenceIndexes[1]);
+
+ int triggerVal;
+ int rndVal = _vm->getRandomNumber(1, 2);
+ if (_topRightPeopleFrame == 4)
+ triggerVal = 1;
+ else
+ triggerVal = rndVal;
+
+ if (rndVal == triggerVal) {
+ _topRightPeopleFrame += _vm->getRandomNumber(-1, 1);
+ if (_topRightPeopleFrame == 0)
+ _topRightPeopleFrame = 1;
+ else if (_topRightPeopleFrame == 5)
+ _topRightPeopleFrame = 4;
+ }
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, _topRightPeopleFrame);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ int delay = _vm->getRandomNumber(15, 60);
+ _scene->_sequences.addTimer(delay, 62);
+}
+
+void Scene208::animateMiddleLeftPeople() {
+ if (_game._trigger != 64)
+ return;
+
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ int delay = _vm->getRandomNumber(60, 120);
+
+ int triggerVal;
+ int rndVal = _vm->getRandomNumber(1, 2);
+ if (_middleLeftPeopleFrame == 2)
+ triggerVal = 1;
+ else
+ triggerVal = rndVal;
+
+ if (rndVal == triggerVal) {
+ _middleLeftPeopleFrame += _vm->getRandomNumber(-1, 1);
+ if (_middleLeftPeopleFrame == 0)
+ _middleLeftPeopleFrame = 1;
+ else if (_middleLeftPeopleFrame == 5)
+ _middleLeftPeopleFrame = 4;
+ }
+
+ if ((_centerPeopleFrame == 3) && (_middleLeftPeopleFrame < 4)) {
+ ++_middleLeftPeopleFrame;
+ delay = 10;
+ }
+
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, _middleLeftPeopleFrame);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _scene->_sequences.addTimer(delay, 64);
+}
+
+
+void Scene208::animateCenterPeople() {
+ if (_game._trigger != 66)
+ return;
+
+ _scene->deleteSequence(_globals._sequenceIndexes[3]);
+
+ int delay;
+
+ if (_direction) {
+ ++_centerPeopleFrame;
+ delay = 15;
+ if (_centerPeopleFrame == 4) {
+ delay = _vm->getRandomNumber(300, 420);
+ --_centerPeopleFrame;
+ _direction = 0;
+ }
+ } else {
+ --_centerPeopleFrame;
+ delay = 15;
+ if (_centerPeopleFrame == 0) {
+ delay = _vm->getRandomNumber(600, 900);
+ ++_centerPeopleFrame;
+ _direction = 1;
+ }
+ }
+
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, _centerPeopleFrame);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
+ _scene->_sequences.addTimer(delay, 66);
+}
+
+void Scene208::animateMiddleRightPeople() {
+ if (_game._trigger != 68)
+ return;
+
+ _scene->deleteSequence(_globals._sequenceIndexes[4]);
+
+ int triggerVal;
+ int rndVal = _vm->getRandomNumber(1, 2);
+ if (_middleRightPeopleFrame == 1)
+ triggerVal = 1;
+ else
+ triggerVal = rndVal;
+
+ if (rndVal == triggerVal) {
+ _middleRightPeopleFrame += _vm->getRandomNumber(-1, 1);
+ if (_middleRightPeopleFrame == 0)
+ _middleRightPeopleFrame = 1;
+ else if (_middleRightPeopleFrame == 4)
+ _middleRightPeopleFrame = 3;
+
+ if (_centerPeopleFrame == 3)
+ _middleRightPeopleFrame = 3;
+ }
+
+ _globals._sequenceIndexes[4] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[4], false, _middleRightPeopleFrame);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 1);
+ int delay = _vm->getRandomNumber(15, 60);
+ _scene->_sequences.addTimer(delay, 68);
+}
+
+void Scene208::animateBottomLeftPeople() {
+ if (_game._trigger != 70)
+ return;
+
+ _scene->deleteSequence(_globals._sequenceIndexes[5]);
+
+ int triggerVal;
+ int rndVal = _vm->getRandomNumber(1, 2);
+ if (_bottomLeftPeopleFrame == 4)
+ triggerVal = 1;
+ else
+ triggerVal = rndVal;
+
+ if (rndVal == triggerVal) {
+ _bottomLeftPeopleFrame += _vm->getRandomNumber(-1, 1);
+ if (_bottomLeftPeopleFrame == 0)
+ _bottomLeftPeopleFrame = 1;
+ else if (_bottomLeftPeopleFrame == 5)
+ _bottomLeftPeopleFrame = 4;
+ }
+
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, _bottomLeftPeopleFrame);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 1);
+ int delay = _vm->getRandomNumber(15, 60);
+ _scene->_sequences.addTimer(delay, 70);
+}
+
+void Scene208::animateBottomMiddlePeople() {
+ if (_game._trigger != 72)
+ return;
+
+ _scene->deleteSequence(_globals._sequenceIndexes[6]);
+
+ int triggerVal;
+ int rndVal = _vm->getRandomNumber(1, 2);
+ if (_bottomMiddlePeopleFrame == 4)
+ triggerVal = 1;
+ else
+ triggerVal = rndVal;
+
+ if (rndVal == triggerVal) {
+ _bottomMiddlePeopleFrame += _vm->getRandomNumber(-1, 1);
+ if (_bottomMiddlePeopleFrame == 0)
+ _bottomMiddlePeopleFrame = 1;
+ else if (_bottomMiddlePeopleFrame == 5)
+ _bottomMiddlePeopleFrame = 4;
+ }
+
+ _globals._sequenceIndexes[6] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[6], false, _bottomMiddlePeopleFrame);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 14);
+ int delay = _vm->getRandomNumber(15, 60);
+ _scene->_sequences.addTimer(delay, 72);
+}
+
+void Scene208::animateBottomRightPeople() {
+ if (_game._trigger != 74)
+ return;
+
+ _scene->deleteSequence(_globals._sequenceIndexes[7]);
+
+ int triggerVal;
+ int rndVal = _vm->getRandomNumber(1, 2);
+ if ((_bottomRightPeopleFrame == 3) || (_bottomRightPeopleFrame == 1))
+ triggerVal = 1;
+ else
+ triggerVal = rndVal;
+
+ if (rndVal == triggerVal) {
+ _bottomRightPeopleFrame += _vm->getRandomNumber(-1, 1);
+ if (_bottomRightPeopleFrame == 0)
+ _bottomRightPeopleFrame = 1;
+ else if (_bottomRightPeopleFrame == 4)
+ _bottomRightPeopleFrame = 3;
+ }
+
+ _globals._sequenceIndexes[7] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[7], false, _bottomRightPeopleFrame);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 1);
+ int delay = _vm->getRandomNumber(15, 60);
+ _scene->_sequences.addTimer(delay, 74);
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene250::Scene250(MADSEngine *vm) : Scene2xx(vm) {
+}
+
+void Scene250::synchronize(Common::Serializer &s) {
+ Scene2xx::synchronize(s);
+}
+
+void Scene250::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene250::enter() {
+ warning("TODO: Switch to letter box view. See definition of MADS_MENU_Y");
+
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+
+ _game.loadQuoteSet(0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0);
+ _globals._animationIndexes[0] = _scene->loadAnimation("*RM150Q1", 1);
+}
+
+void Scene250::step() {
+ if (_game._trigger == 1)
+ _scene->_sequences.addTimer(12, 2);
+
+ if (_game._trigger == 2) {
+ int y = 68;
+
+ _scene->_kernelMessages.add(Common::Point(160, y), 0x1110, 0x20, 0, 900, _game.getQuote(0x36));
+ y += 16;
+
+ if (_globals[kPlayerScore] > 250)
+ _globals[kPlayerScore] = 250;
+
+ Common::String message = Common::String::format("%d", _globals[kPlayerScore]);
+ message += " ";
+ message += _game.getQuote(0x37);
+ message += " 250 ";
+ message += _game.getQuote(0x38);
+
+ _scene->_kernelMessages.add(Common::Point(160, y), 0x1110, 0x20, 3, 900, message);
+ y += 16;
+
+ _scene->_kernelMessages.add(Common::Point(160, y), 0x1110, 0x20, 0, 900, _game.getQuote(0x39));
+ y += 16;
+
+ int score = _globals[kPlayerScore];
+ int messageId;
+
+ if (score <= 25)
+ // Score level: Stage sweeper
+ messageId = 0x3A;
+ else if (score <= 50)
+ // Score level: Dresser
+ messageId = 0x3B;
+ else if (score <= 75)
+ // Score level: Usher
+ messageId = 0x3C;
+ else if (score <= 100)
+ // Score level: Stagehand
+ messageId = 0x3D;
+ else if (score <= 150)
+ // Score level: Chorus member
+ messageId = 0x3E;
+ else if (score <= 200)
+ // Score level: Supporting player
+ messageId = 0x3F;
+ else if (score <= 249)
+ // Score level: Star player
+ messageId = 0x40;
+ else
+ // Score level: Director
+ messageId = 0x41;
+
+ _scene->_kernelMessages.add(Common::Point(160, y), 0x1110, 0x20, 0, 900, _game.getQuote(messageId));
+ _scene->_sequences.addTimer(930, 3);
+ }
+
+ if (_game._trigger == 3)
+ _game._winStatus = 1;
+}
+
+void Scene250::actions() {
+}
+
+void Scene250::preActions() {
+}
+
+/*------------------------------------------------------------------------*/
+
+} // End of namespace Phantom
+} // End of namespace MADS
diff --git a/engines/mads/phantom/phantom_scenes2.h b/engines/mads/phantom/phantom_scenes2.h
new file mode 100644
index 0000000000..7e86e2ce0f
--- /dev/null
+++ b/engines/mads/phantom/phantom_scenes2.h
@@ -0,0 +1,307 @@
+/* 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 MADS_PHANTOM_SCENES2_H
+#define MADS_PHANTOM_SCENES2_H
+
+#include "common/scummsys.h"
+#include "common/serializer.h"
+#include "mads/game.h"
+#include "mads/scene.h"
+#include "mads/phantom/phantom_scenes.h"
+
+namespace MADS {
+
+namespace Phantom {
+
+class Scene2xx : public PhantomScene {
+protected:
+ /**
+ * Plays an appropriate sound when entering a scene
+ */
+ void sceneEntrySound();
+
+ /**
+ *Sets the AA file to use for the scene
+ */
+ void setAAName();
+
+ /**
+ * Updates the prefix used for getting player sprites for the scene
+ */
+ void setPlayerSpritesPrefix();
+public:
+ Scene2xx(MADSEngine *vm) : PhantomScene(vm) {}
+};
+
+class Scene201 : public Scene2xx {
+private:
+ bool _anim0ActvFl;
+ bool _anim1ActvFl;
+ bool _needHoldFl;
+ int _sellerCount;
+ int _sellerStatus;
+ int _sellerFrame;
+ int _raoulFrame;
+ int _raoulStatus;
+
+ void handleSellerAnimation();
+ void handleRaoulAnimation();
+ void handleConversation();
+
+public:
+ Scene201(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene202 : public Scene2xx {
+private:
+ bool _ticketGivenFl;
+ bool _anim0ActvFl;
+ bool _anim1ActvFl;
+ bool _skipWalkFl;
+ int _chandeliersPosX[5];
+ int _chandeliersHotspotId[5];
+ int _conversationCount;
+ int _usherStatus;
+ int _usherFrame;
+ int _usherCount;
+ int _degasStatus;
+ int _degasFrame;
+
+ void handleConversation1();
+ void handleConversation2();
+ void handleUsherAnimation();
+ void handleDegasAnimation();
+ void handleChandeliersPositions();
+
+public:
+ Scene202(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene203 : public Scene2xx {
+private:
+ bool _anim0ActvFl;
+ bool _anim1ActvFl;
+ bool _anim2ActvFl;
+ bool _anim3ActvFl;
+ bool _showNoteFl;
+
+ int _brieStatus;
+ int _brieFrame;
+ int _brieCount;
+ int _raoulStatus;
+ int _raoulFrame;
+ int _raoulCount;
+ int _richardStatus;
+ int _richardFrame;
+ int _daaeStatus;
+ int _daaeFrame;
+ int _conversationCount;
+
+ void handleBrieConversation();
+ void handleRichardConversation();
+ void handleRichardAndDaaeConversation();
+ void handleBrieAnimation();
+ void handleRichardAnimation();
+ void handleRaoulAnimation();
+ void handleDaaeAnimation();
+
+public:
+ Scene203(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene204 : public Scene2xx {
+private:
+ bool _anim0ActvFl;
+ bool _anim1ActvFl;
+ bool _anim2ActvFl;
+ bool _anim3ActvFl;
+ bool _raoulDown;
+ bool _florentGone;
+ bool _skip1Fl;
+ bool _skip2Fl;
+ bool _skip3Fl;
+ bool _endGameFl;
+
+ int _brieStatus;
+ int _brieFrame;
+ int _florStatus;
+ int _florFrame;
+ int _raoulStatus;
+ int _raoulFrame;
+ int _raoulCount;
+
+ void handleConversation();
+ void handleBrieAnimation();
+ void handleFlorAnimation();
+ void handleRaoulAnimation();
+ void handleEndAnimation();
+
+public:
+ Scene204(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene205 : public Scene2xx {
+private:
+ bool _anim0ActvFl;
+ bool _anim1ActvFl;
+ bool _noConversationHold;
+ bool _giveTicketFl;
+
+ int _richardFrame;
+ int _richardStatus;
+ int _richardCount;
+ int _giryFrame;
+ int _giryStatus;
+ int _giryCount;
+ int _conversationCounter;
+ int _lastRandom;
+
+ void handleConversation18();
+ void handleConversation10();
+ void handleConversation11();
+ void handleRichardAnimation();
+ void handleGiryAnimation();
+
+public:
+ Scene205(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene206 : public Scene2xx {
+private:
+ bool _anim0ActvFl;
+ bool _skip1Fl;
+ bool _skip2Fl;
+
+public:
+ Scene206(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene207 : public Scene2xx {
+private:
+ bool _skip1Fl;
+ bool _anim0ActvFl;
+
+public:
+ Scene207(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene208 : public Scene2xx {
+private:
+ bool _skip1Fl;
+ bool _skip2Fl;
+
+ int _topLeftPeopleFrame;
+ int _topRightPeopleFrame;
+ int _middleLeftPeopleFrame;
+ int _centerPeopleFrame;
+ int _middleRightPeopleFrame;
+ int _bottomLeftPeopleFrame;
+ int _bottomMiddlePeopleFrame;
+ int _bottomRightPeopleFrame;
+ int _direction;
+
+ void animateTopLeftPeople();
+ void animateTopRightPeople();
+ void animateMiddleLeftPeople();
+ void animateCenterPeople();
+ void animateMiddleRightPeople();
+ void animateBottomLeftPeople();
+ void animateBottomMiddlePeople();
+ void animateBottomRightPeople();
+
+public:
+ Scene208(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene250 : public Scene2xx {
+public:
+ Scene250(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+} // End of namespace Phantom
+} // End of namespace MADS
+
+#endif /* MADS_PHANTOM_SCENES2_H */
diff --git a/engines/mads/phantom/phantom_scenes3.cpp b/engines/mads/phantom/phantom_scenes3.cpp
new file mode 100644
index 0000000000..9fd15d3552
--- /dev/null
+++ b/engines/mads/phantom/phantom_scenes3.cpp
@@ -0,0 +1,2767 @@
+/* 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 "mads/mads.h"
+#include "mads/conversations.h"
+#include "mads/scene.h"
+#include "mads/phantom/phantom_scenes.h"
+#include "mads/phantom/phantom_scenes3.h"
+
+namespace MADS {
+
+namespace Phantom {
+
+void Scene3xx::setAAName() {
+ _game._aaName = Resources::formatAAName(_globals[kTempInterface]);
+ _vm->_palette->setEntry(254, 43, 47, 51);
+}
+
+void Scene3xx::sceneEntrySound() {
+ if (!_vm->_musicFlag)
+ return;
+
+ switch (_scene->_nextSceneId) {
+ case 303:
+ case 304:
+ case 305:
+ case 307:
+ case 308:
+ if (_globals[kKnockedOverHead])
+ _vm->_sound->command(33);
+ else
+ _vm->_sound->command(16);
+ break;
+
+ case 310:
+ case 320:
+ case 330:
+ case 340:
+ _vm->_sound->command(36);
+ break;
+
+ default:
+ if (_scene->_nextSceneId != 306)
+ _vm->_sound->command(16);
+ break;
+ }
+}
+
+void Scene3xx::setPlayerSpritesPrefix() {
+ _vm->_sound->command(5);
+
+ if ((_scene->_nextSceneId == 304) || (_scene->_nextSceneId == 305) || (_scene->_nextSceneId == 306) || (_scene->_nextSceneId == 310))
+ _game._player._spritesPrefix = "";
+ else {
+ Common::String oldName = _game._player._spritesPrefix;
+ if (!_game._player._forcePrefix)
+ _game._player._spritesPrefix = "RAL";
+ if (oldName != _game._player._spritesPrefix)
+ _game._player._spritesChanged = true;
+ }
+
+ _game._player._scalingVelocity = true;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene301::Scene301(MADSEngine *vm) : Scene3xx(vm) {
+ _anim0ActvFl = false;
+ _skip1Fl = false;
+ _skip2Fl = false;
+
+ _lightingHotspotId = -1;
+ _sandbagHotspotId = -1;
+}
+
+void Scene301::synchronize(Common::Serializer &s) {
+ Scene3xx::synchronize(s);
+
+ s.syncAsByte(_anim0ActvFl);
+ s.syncAsByte(_skip1Fl);
+ s.syncAsByte(_skip2Fl);
+
+ s.syncAsSint16LE(_lightingHotspotId);
+ s.syncAsSint16LE(_sandbagHotspotId);
+}
+
+void Scene301::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene301::enter() {
+ _vm->_disableFastwalk = true;
+
+ _anim0ActvFl = false;
+ _skip2Fl = false;
+ _skip1Fl = false;
+
+ _scene->loadSpeech(6);
+
+ _scene->_hotspots.activate(NOUN_CABLE, false);
+ _scene->_hotspots.activate(NOUN_STOOL, false);
+
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('a', 0));
+
+ if (_globals[kCurrentYear] == 1993) {
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('a', 1));
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('z', 0));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('z', 1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('z', 2));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('z', 3));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('z', 4));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('z', 5));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('z', 6));
+
+ _lightingHotspotId = _scene->_dynamicHotspots.add(NOUN_LIGHTING_INSTRUMENT, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(50, 116, 50 + 19, 116 + 10));
+ _scene->_dynamicHotspots.setPosition(_lightingHotspotId, Common::Point(67, 129), FACING_NORTHWEST);
+ _lightingHotspotId = _scene->_dynamicHotspots.add(NOUN_LIGHTING_INSTRUMENT, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(126, 118, 126 + 29, 118 + 8));
+ _scene->_dynamicHotspots.setPosition(_lightingHotspotId, Common::Point(152, 129), FACING_NORTHWEST);
+
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
+
+ _globals._sequenceIndexes[4] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[4], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 14);
+
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 14);
+
+ _globals._sequenceIndexes[6] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[6], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 14);
+
+ _scene->_hotspots.activate(NOUN_CABLE, true);
+ } else {
+ _sandbagHotspotId = _scene->_dynamicHotspots.add(NOUN_SANDBAG, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(464, 114, 464 + 11, 114 + 9));
+ _scene->_dynamicHotspots.setPosition(_sandbagHotspotId, Common::Point(475, 125), FACING_NORTHWEST);
+ _scene->_dynamicHotspots.add(NOUN_SANDBAG, VERB_LOOK_AT, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(468, 42, 468 + 6, 42 + 13));
+ _scene->_hotspots.activate(NOUN_STOOL, true);
+ _scene->_hotspots.activate(NOUN_BIG_PROP, false);
+ }
+
+ if (_scene->_priorSceneId == 302) {
+ _game._player.firstWalk(Common::Point(-20, 132), FACING_WEST, Common::Point(19, 132), FACING_EAST, true);
+ _scene->setCamera(Common::Point(0, 0));
+ } else if ((_scene->_priorSceneId == 106) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
+ _game._player._playerPos = Common::Point(568, 133);
+ _game._player._facing = FACING_WEST;
+ _scene->setCamera(Common::Point(320, 0));
+ }
+
+ if (!_game._visitedScenes._sceneRevisited) {
+ _globals._spriteIndexes[9] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._sequenceIndexes[9] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[9], false, 7, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 5);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[9], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[9], SEQUENCE_TRIGGER_EXPIRE, 0, 64);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene301::step() {
+ if ((_globals[kDoneBrieConv203] == 3) && (_scene->_posAdjust.x < 320) && (_game._player._playerPos.x < 350)) {
+ _game._player.cancelCommand();
+ _game._player.walk(Common::Point(256, 130), FACING_NORTHWEST);
+ _game._player.setWalkTrigger(60);
+ _globals[kDoneBrieConv203] = 0;
+ _game._player._stepEnabled = false;
+ }
+
+ if (_game._trigger == 60) {
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('p', 1), 0);
+ _anim0ActvFl = true;
+ _game._player._visible = false;
+ _globals[kPlayerScore] += 10;
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[0], SYNC_PLAYER, 0);
+ }
+
+ if (_anim0ActvFl && !_skip1Fl) {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == 50) {
+ _scene->playSpeech(6);
+ _skip1Fl = true;
+ }
+ }
+
+ if (_anim0ActvFl) {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == 61) {
+ _scene->setAnimFrame(_globals._animationIndexes[0], 60);
+ if (!_skip2Fl) {
+ _vm->_sound->command(1);
+ _scene->_sequences.addTimer(420, 70);
+ _skip2Fl = true;
+ }
+ }
+ }
+
+ if (_game._trigger == 70) {
+ _scene->_userInterface.noInventoryAnim();
+ // CHECKME: Not sure about the next function call
+ _scene->_userInterface.refresh();
+ _scene->_nextSceneId = 104;
+ }
+
+ if (_game._trigger == 64)
+ _scene->_sequences.addTimer(60, 65);
+
+ if (_game._trigger == 65)
+ _vm->_dialogs->show(30137);
+}
+
+void Scene301::actions() {
+ if (_action.isAction(VERB_CLIMB_DOWN, NOUN_CIRCULAR_STAIRCASE)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('d', 1), 1);
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[0], SYNC_PLAYER, 0);
+ break;
+
+ case 1:
+ _scene->_nextSceneId = 106;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(30110);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_GRID)) {
+ _vm->_dialogs->show(30111);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CATWALK)) {
+ _vm->_dialogs->show(30112);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SIDE_WALL)) {
+ _vm->_dialogs->show(30113);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BACK_WALL)) {
+ _vm->_dialogs->show(30114);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SUPPORT)) {
+ _vm->_dialogs->show(30115);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_ACT_CURTAIN)) {
+ _vm->_dialogs->show(30116);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_HOUSE)) {
+ _vm->_dialogs->show(30117);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_OTHER_CATWALK)) {
+ _vm->_dialogs->show(30118);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_GRIDWORK)) {
+ _vm->_dialogs->show(30119);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BEAM_POSITION)) {
+ _vm->_dialogs->show(30120);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LIGHTING_INSTRUMENT)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(30121);
+ else
+ _vm->_dialogs->show(30122);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_TARP)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(30123);
+ else
+ _vm->_dialogs->show(30140);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_COUNTERWEIGHT_SYSTEM)) {
+ _vm->_dialogs->show(30124);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SANDBAG) && (_action._mainObjectSource == CAT_HOTSPOT)) {
+ _vm->_dialogs->show(30125);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BATTEN)) {
+ _vm->_dialogs->show(30126);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_STOOL)) {
+ _vm->_dialogs->show(30127);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_HEMP)) {
+ _vm->_dialogs->show(30128);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CIRCULAR_STAIRCASE)) {
+ _vm->_dialogs->show(30129);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CATWALK_OVER_HOUSE)) {
+ _vm->_dialogs->show(30130);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_STAIRCASE_POST)) {
+ _vm->_dialogs->show(30131);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RAILING)) {
+ _vm->_dialogs->show(30132);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CYCLORAMA)) {
+ _vm->_dialogs->show(30133);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BIG_PROP)) {
+ _vm->_dialogs->show(30134);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PROSCENIUM_ARCH)) {
+ _vm->_dialogs->show(30135);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CABLE)) {
+ _vm->_dialogs->show(30136);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_HEMP)) {
+ _vm->_dialogs->show(30138);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_PULL, NOUN_HEMP)) {
+ _vm->_dialogs->show(30141);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_SANDBAG) && (_action._mainObjectSource == CAT_HOTSPOT)) {
+ _vm->_dialogs->show(30139);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_TARP)) {
+ _vm->_dialogs->show(30142);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene301::preActions() {
+ if (_action.isAction(VERB_EXIT_TO, NOUN_CATWALK_OVER_HOUSE))
+ _game._player._walkOffScreenSceneId = 302;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene302::Scene302(MADSEngine *vm) : Scene3xx(vm) {
+}
+
+void Scene302::synchronize(Common::Serializer &s) {
+ Scene3xx::synchronize(s);
+}
+
+void Scene302::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene302::enter() {
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('p', 0));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites("*RRD_9");
+
+ if (_game._objects.isInRoom(OBJ_BLUE_FRAME)) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+ } else
+ _scene->_hotspots.activate(NOUN_BLUE_FRAME, false);
+
+ if (_globals[kCurrentYear] == 1993) {
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('z', -1));
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+ }
+
+ if (_scene->_priorSceneId == 303)
+ _game._player.firstWalk(Common::Point(-20, 134), FACING_WEST, Common::Point(15, 134), FACING_EAST, true);
+ else if ((_scene->_priorSceneId == 301) || (_scene->_priorSceneId != RETURNING_FROM_LOADING))
+ _game._player.firstWalk(Common::Point(340, 134), FACING_WEST, Common::Point(297, 134), FACING_WEST, true);
+
+ sceneEntrySound();
+}
+
+void Scene302::step() {
+}
+
+void Scene302::actions() {
+ if (_action.isAction(VERB_TAKE, NOUN_BLUE_FRAME) && (_game._objects.isInRoom(OBJ_BLUE_FRAME) || _game._trigger)) {
+ switch (_game._trigger) {
+ case (0):
+ if (_globals[kCurrentYear] == 1881) {
+ int count = 0;
+ if (_game._objects.isInInventory(OBJ_YELLOW_FRAME))
+ ++count;
+ if (_game._objects.isInInventory(OBJ_RED_FRAME))
+ ++count;
+ if (_game._objects.isInInventory(OBJ_GREEN_FRAME))
+ ++count;
+ if (count < 3)
+ _globals[kPlayerScore] += 5;
+ }
+
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[1] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[1], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 5);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[1], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _scene->_hotspots.activate(NOUN_BLUE_FRAME, false);
+ _game._objects.addToInventory(OBJ_BLUE_FRAME);
+ _vm->_sound->command(26);
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[1]);
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(20, 3);
+ break;
+
+ case 3:
+ if (_globals[kCurrentYear] == 1881)
+ _vm->_dialogs->showItem(OBJ_BLUE_FRAME, 844, 0);
+ else
+ _vm->_dialogs->showItem(OBJ_BLUE_FRAME, 817, 0);
+
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(30210);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_CATWALK)) {
+ _vm->_dialogs->show(30211);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_GRID)) {
+ _vm->_dialogs->show(30212);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_HEMP)) {
+ _vm->_dialogs->show(30213);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SIDE_WALL)) {
+ _vm->_dialogs->show(30214);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CATWALK)) {
+ _vm->_dialogs->show(30215);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RAILING)) {
+ _vm->_dialogs->show(30216);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BEAM_POSITION)) {
+ _vm->_dialogs->show(30217);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LIGHTING_INSTRUMENT)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(30218);
+ else
+ _vm->_dialogs->show(30219);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME) && _game._objects.isInRoom(OBJ_BLUE_FRAME)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(30220);
+ else
+ _vm->_dialogs->show(30221);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SUPPORT)) {
+ _vm->_dialogs->show(30222);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_OTHER_CATWALK)) {
+ _vm->_dialogs->show(30223);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_HEMP)) {
+ _vm->_dialogs->show(30224);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_PULL, NOUN_HEMP)) {
+ _vm->_dialogs->show(30141);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene302::preActions() {
+ if (_action.isAction(VERB_EXIT_TO, NOUN_CATWALK)) {
+ if (_scene->_customDest.x > 160)
+ _game._player._walkOffScreenSceneId = 301;
+ else
+ _game._player._walkOffScreenSceneId = 303;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene303::Scene303(MADSEngine *vm) : Scene3xx(vm) {
+ _anim0ActvFl = false;
+ _hempHotspotId = -1;
+ _skipFrameCheckFl = -1;
+}
+
+void Scene303::synchronize(Common::Serializer &s) {
+ Scene3xx::synchronize(s);
+
+ s.syncAsByte(_anim0ActvFl);
+ s.syncAsSint16LE(_hempHotspotId);
+ s.syncAsSint16LE(_skipFrameCheckFl);
+}
+
+void Scene303::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ _scene->addActiveVocab(NOUN_CHANDELIER_CABLE);
+ _scene->addActiveVocab(VERB_CLIMB_DOWN);
+}
+
+void Scene303::enter() {
+ _anim0ActvFl = false;
+ _skipFrameCheckFl = false;
+
+ if (_globals[kRightDoorIsOpen504])
+ _vm->_gameConv->load(26);
+
+ if (_globals[kCurrentYear] == 1993) {
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('z', -1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('p', 0));
+ }
+
+ if ((_game._objects.isInRoom(OBJ_LARGE_NOTE)) && (_globals[kCurrentYear] == 1993)) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 4);
+ } else
+ _scene->_hotspots.activate(NOUN_LARGE_NOTE, false);
+
+ if (_globals[kCurrentYear] == 1993)
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+ else {
+ _hempHotspotId = _scene->_dynamicHotspots.add(NOUN_CHANDELIER_CABLE, VERB_CLIMB_DOWN, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(74, 92, 74 + 7, 92 + 12));
+ _scene->_dynamicHotspots.setPosition(_hempHotspotId, Common::Point(95, 107), FACING_NORTHWEST);
+ _scene->_dynamicHotspots[_hempHotspotId]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setCursor(_hempHotspotId, CURSOR_GO_DOWN);
+ }
+
+ if (_scene->_priorSceneId == 307)
+ _game._player.firstWalk(Common::Point(-20, 135), FACING_EAST, Common::Point(16, 135), FACING_EAST, true);
+ else if (_scene->_priorSceneId == 304) {
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('u', 1), 60);
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ } else if (_scene->_priorSceneId == 305) {
+ _game._objects.addToInventory(OBJ_SWORD);
+ _game._player._playerPos = Common::Point(117, 92);
+ _game._player._facing = FACING_SOUTHWEST;
+ } else if ((_scene->_priorSceneId == 302) || (_scene->_priorSceneId != RETURNING_FROM_LOADING))
+ _game._player.firstWalk(Common::Point(340, 136), FACING_WEST, Common::Point(303, 136), FACING_WEST, true);
+
+ _scene->_rails.disableLine(5, 9);
+ _scene->_rails.disableLine(5, 12);
+ _scene->_rails.disableLine(5, 8);
+ _scene->_rails.disableLine(6, 3);
+ _scene->_rails.disableLine(6, 2);
+ _scene->_rails.disableLine(11, 3);
+ _scene->_rails.disableLine(11, 4);
+ _scene->_rails.disableLine(10, 2);
+ _scene->_rails.disableLine(4, 9);
+ _scene->_rails.disableLine(8, 0);
+
+ sceneEntrySound();
+}
+
+void Scene303::step() {
+ if (_game._trigger == 60) {
+ _game._player._playerPos = Common::Point(110, 95);
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[0]);
+ _game._player.resetFacing(FACING_SOUTHWEST);
+ }
+
+ if (_anim0ActvFl) {
+ if ((_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() >= 6) && !_skipFrameCheckFl) {
+ _skipFrameCheckFl = true;
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _scene->_hotspots.activate(NOUN_LARGE_NOTE, false);
+ _game._objects.addToInventory(OBJ_LARGE_NOTE);
+ _vm->_sound->command(26);
+ }
+ }
+}
+
+void Scene303::actions() {
+ if ((_action.isAction(VERB_TAKE, NOUN_LARGE_NOTE) && _game._objects.isInRoom(OBJ_LARGE_NOTE)) || ((_game._trigger > 0) && _game._trigger < 3)) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('n', 1), 1);
+ _anim0ActvFl = true;
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[0], SYNC_PLAYER, 0);
+ _globals[kPlayerScore] += 5;
+ break;
+
+ case 1:
+ _anim0ActvFl = false;
+ _game._player._visible = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[0]);
+ _scene->_sequences.addTimer(20, 2);
+ break;
+
+ case 2:
+ _vm->_dialogs->showItem(OBJ_LARGE_NOTE, 818, 7);
+ _game._player._stepEnabled = true;
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLIMB_INTO, NOUN_HOLE) || _action.isAction(VERB_CLIMB_DOWN, NOUN_CHANDELIER_CABLE)) {
+ if (_globals[kCurrentYear] == 1881) {
+ switch (_game._trigger) {
+ case 0:
+ if (_globals[kRightDoorIsOpen504])
+ _vm->_dialogs->show(30331);
+
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('d', 1), 3);
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[0], SYNC_PLAYER, 0);
+ break;
+
+ case 3:
+ _scene->_nextSceneId = 304;
+ break;
+
+ default:
+ break;
+ }
+ } else
+ _vm->_dialogs->show(30325);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_EXIT_TO, NOUN_CATWALK)) {
+ if (_globals[kRightDoorIsOpen504]) {
+ if (_vm->_sound->_preferRoland)
+ _vm->_sound->command(74);
+ else
+ _scene->playSpeech(1);
+
+ _vm->_gameConv->run(26);
+ _vm->_gameConv->exportValue(4);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(30310);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ // CHECKME: That's illogical, the check is always false... Should be out of the big 'look' check
+ // It looks to me like an original bug
+ if (_action.isAction(VERB_EXIT_TO, NOUN_CATWALK)) {
+ _vm->_dialogs->show(30316);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CATWALK)) {
+ _vm->_dialogs->show(30311);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_GRID)) {
+ _vm->_dialogs->show(30312);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CHANDELIER_CABLE)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(30317);
+ else if (_globals[kRightDoorIsOpen504])
+ _vm->_dialogs->show(30330);
+ else
+ _vm->_dialogs->show(30329);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_HEMP)) {
+ _vm->_dialogs->show(30313);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BACK_WALL)) {
+ _vm->_dialogs->show(30314);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DUCTWORK)) {
+ _vm->_dialogs->show(30315);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CRATE)) {
+ _vm->_dialogs->show(30318);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SUPPORT)) {
+ _vm->_dialogs->show(30319);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PIECE_OF_WOOD)) {
+ _vm->_dialogs->show(30320);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RAILING)) {
+ _vm->_dialogs->show(30321);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CHANDELIER_TRAP)) {
+ _vm->_dialogs->show(30322);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_HOLE)) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(30326);
+ else
+ _vm->_dialogs->show(30323);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LARGE_NOTE) && _game._objects.isInRoom(OBJ_LARGE_NOTE)) {
+ _vm->_dialogs->show(30324);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_WALK_TO, NOUN_HOLE)) {
+ _vm->_dialogs->show(30325);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_HEMP)) {
+ _vm->_dialogs->show(30327);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_PULL, NOUN_HEMP)) {
+ _vm->_dialogs->show(30141);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene303::preActions() {
+ if (_action.isAction(VERB_EXIT_TO, NOUN_CATWALK) && !_globals[kRightDoorIsOpen504]) {
+ if (_scene->_customDest.x > 160)
+ _game._player._walkOffScreenSceneId = 302;
+ else
+ _game._player._walkOffScreenSceneId = 307;
+ }
+
+ if (_action.isAction(VERB_CLIMB_INTO, NOUN_HOLE) || _action.isAction(VERB_CLIMB_DOWN, NOUN_CHANDELIER_CABLE))
+ _game._player.walk(Common::Point(110, 95), FACING_SOUTHWEST);
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene304::Scene304(MADSEngine *vm) : Scene3xx(vm) {
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _anim2ActvFl = false;
+
+ _raoulFrame = -1;
+ _raoulStatus = -1;
+ _fightFrame = -1;
+ _fightStatus = -1;
+ _fightCount = -1;
+ _phantomFrame = -1;
+ _phantomStatus = -1;
+}
+
+void Scene304::synchronize(Common::Serializer &s) {
+ Scene3xx::synchronize(s);
+
+ s.syncAsByte(_anim0ActvFl);
+ s.syncAsByte(_anim1ActvFl);
+ s.syncAsByte(_anim2ActvFl);
+
+ s.syncAsSint16LE(_raoulFrame);
+ s.syncAsSint16LE(_raoulStatus);
+ s.syncAsSint16LE(_fightFrame);
+ s.syncAsSint16LE(_fightStatus);
+ s.syncAsSint16LE(_fightCount);
+ s.syncAsSint16LE(_phantomFrame);
+ s.syncAsSint16LE(_phantomStatus);
+}
+
+void Scene304::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene304::enter() {
+ _game._player._playerPos.x = 0;
+
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _anim2ActvFl = false;
+ }
+
+ if (_globals[kRightDoorIsOpen504])
+ _vm->_gameConv->load(23);
+
+ if (!_globals[kRightDoorIsOpen504]) {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('f', 1));
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('n', 1), 0);
+ _anim0ActvFl = true;
+ _raoulStatus = 1;
+ _game._player._stepEnabled = false;
+ } else {
+ _scene->_userInterface.setup(kInputLimitedSentences);
+
+ if (_scene->_priorSceneId == 305) {
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('f', 0));
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+
+ _game._player._stepEnabled = false;
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('f', 1), 0);
+ _anim1ActvFl = true;
+ _scene->setAnimFrame(_globals._animationIndexes[1], 138);
+
+ } else {
+
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('f', 0));
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('f', 1), 0);
+ _anim1ActvFl = true;
+ _phantomStatus = 0;
+
+ _globals._animationIndexes[2] = _scene->loadAnimation(formAnimName('r', 1), 0);
+ _anim2ActvFl = true;
+ _fightStatus = 0;
+
+ _game._player._stepEnabled = false;
+ _fightCount = 0;
+
+ _globals[kPlayerScore] += 10;
+
+ _vm->_gameConv->run(23);
+ _vm->_gameConv->hold();
+ }
+ }
+
+
+ if ((_scene->_priorSceneId == RETURNING_FROM_LOADING) && !_globals[kRightDoorIsOpen504]) {
+ _scene->setAnimFrame(_globals._animationIndexes[0], 53);
+ _game._player._stepEnabled = true;
+ }
+
+ _game._player._visible = false;
+
+ sceneEntrySound();
+}
+
+void Scene304::step() {
+ if (_anim0ActvFl)
+ handleRaoulAnimation();
+
+ if (_anim1ActvFl)
+ handlePhantomAnimation();
+
+ if (_anim2ActvFl)
+ handleFightAnimation();
+}
+
+void Scene304::actions() {
+ if (_vm->_gameConv->activeConvId() == 23) {
+ handleConversation23();
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLIMB_THROUGH, NOUN_OPENING) || _action.isAction(VERB_CLIMB, NOUN_CHANDELIER_CABLE)) {
+ _raoulStatus = 0;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(30410);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_CEILING)) {
+ _vm->_dialogs->show(30411);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DOME)) {
+ _vm->_dialogs->show(30412);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LATTICEWORK)) {
+ _vm->_dialogs->show(30413);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_OPENING)) {
+ _vm->_dialogs->show(30414);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CHANDELIER)) {
+ _vm->_dialogs->show(30415);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CHANDELIER_CABLE)) {
+ _vm->_dialogs->show(30416);
+ _action._inProgress = false;
+ return;
+ }
+ }
+}
+
+void Scene304::preActions() {
+}
+
+void Scene304::handleConversation23() {
+ switch (_action._activeAction._verbId) {
+ case 5:
+ _phantomStatus = 1;
+ _vm->_gameConv->hold();
+ break;
+
+ case 6:
+ if (_phantomStatus != 1)
+ _fightStatus = 0;
+
+ _vm->_gameConv->hold();
+ break;
+
+ case 9:
+ if (_phantomStatus != 1)
+ _fightStatus = 2;
+
+ break;
+
+ case 12:
+ _phantomStatus = 2;
+ break;
+
+ default:
+ break;
+ }
+
+ _fightCount = 0;
+}
+
+void Scene304::handleRaoulAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == _raoulFrame)
+ return;
+
+ _raoulFrame = _scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame();
+ int resetFrame = -1;
+
+ switch (_raoulFrame) {
+ case 20:
+ _game._player._stepEnabled = true;
+ resetFrame = 53;
+ break;
+
+ case 53:
+ _scene->_nextSceneId = 303;
+ break;
+
+ case 54:
+ case 55:
+ case 56:
+ if (_raoulStatus == 0) {
+ resetFrame = 20;
+ _game._player._stepEnabled = false;
+ } else {
+ int random = _vm->getRandomNumber(1, 50);
+ switch (_raoulFrame) {
+ case 54:
+ if (random == 1)
+ resetFrame = 54;
+ else if (random == 2)
+ resetFrame = 55;
+ else
+ resetFrame = _raoulFrame - 1;
+
+ break;
+
+ case 55:
+ if (random == 1)
+ resetFrame = 54;
+ else if (random == 2)
+ resetFrame = 53;
+ else
+ resetFrame = _raoulFrame - 1;
+
+ break;
+
+ case 56:
+ if (random == 1)
+ resetFrame = 55;
+ else if (random == 2)
+ resetFrame = 53;
+ else
+ resetFrame = _raoulFrame - 1;
+
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[0], resetFrame);
+ _raoulFrame = resetFrame;
+ }
+}
+
+void Scene304::handlePhantomAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame() == _phantomFrame)
+ return;
+
+ _phantomFrame = _scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame();
+ int resetFrame = -1;
+
+ switch (_phantomFrame) {
+ case 7:
+ case 11:
+ resetFrame = _vm->getRandomNumber(6, 7);
+
+ if (_phantomStatus == 1)
+ resetFrame = 7;
+
+ break;
+
+ case 9:
+ case 15:
+ switch (_vm->getRandomNumber(1, 3)) {
+ case 1:
+ resetFrame = 8;
+ break;
+
+ case 2:
+ resetFrame = 9;
+ break;
+
+ case 3:
+ resetFrame = 11;
+ break;
+ }
+
+ if (_phantomStatus == 1)
+ resetFrame = 11;
+
+ break;
+
+ case 13:
+ case 24:
+ switch (_vm->getRandomNumber(1, 3)) {
+ case 1:
+ resetFrame = 12;
+ break;
+
+ case 2:
+ resetFrame = 13;
+ break;
+
+ case 3:
+ resetFrame = 16;
+ break;
+ }
+
+ if (_phantomStatus == 1)
+ resetFrame = 16;
+
+ break;
+
+ case 20:
+ if (_vm->getRandomNumber(1, 2) == 1)
+ resetFrame = 19;
+ else
+ resetFrame = 20;
+
+ if (_phantomStatus == 1)
+ resetFrame = 24;
+
+ break;
+
+ case 25:
+ _vm->_gameConv->release();
+ break;
+
+ case 47:
+ _fightStatus = 0;
+ break;
+
+ case 59:
+ if (_phantomStatus == 2)
+ resetFrame = 59;
+ else
+ resetFrame = 58;
+ break;
+
+ case 60:
+ _game._player._stepEnabled = false;
+ break;
+
+ case 80:
+ _game._objects.setRoom(OBJ_SWORD, NOWHERE);
+ break;
+
+ case 137:
+ _game._player._playerPos.x = 100;
+ _scene->_nextSceneId = 305;
+ break;
+
+ case 176:
+ _game._player._playerPos.x = 200;
+ _scene->_nextSceneId = 305;
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[1], resetFrame);
+ _phantomFrame = resetFrame;
+ }
+}
+
+void Scene304::handleFightAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[2]]->getCurrentFrame() == _fightFrame)
+ return;
+
+ _fightFrame = _scene->_animation[_globals._animationIndexes[2]]->getCurrentFrame();
+ int resetFrame = -1;
+
+ switch (_fightFrame) {
+ case 22:
+ _vm->_gameConv->release();
+ break;
+
+ case 23:
+ if (_fightStatus != 2)
+ resetFrame = 22;
+ break;
+
+ case 25:
+ case 26:
+ case 27:
+ if (_fightStatus == 2) {
+ resetFrame = _vm->getRandomNumber(24, 26);
+ ++_fightCount;
+ if (_fightCount > 17)
+ resetFrame = 24;
+ }
+ break;
+
+ case 28:
+ _fightStatus = 2;
+ break;
+
+ case 45:
+ _vm->_gameConv->release();
+ break;
+
+ case 46:
+ case 47:
+ case 48:
+ if (_fightStatus == 2) {
+ resetFrame = _vm->getRandomNumber(45, 47);
+ ++_fightCount;
+ if (_fightCount > 17)
+ resetFrame = 45;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[2], resetFrame);
+ _fightFrame = resetFrame;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene305::Scene305(MADSEngine *vm) : Scene3xx(vm) {
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _skipFl = false;
+ _unmaskFl = false;
+
+ _unmaskFrame = -1;
+}
+
+void Scene305::synchronize(Common::Serializer &s) {
+ Scene3xx::synchronize(s);
+
+ s.syncAsByte(_anim0ActvFl);
+ s.syncAsByte(_anim1ActvFl);
+ s.syncAsByte(_skipFl);
+ s.syncAsByte(_unmaskFl);
+
+ s.syncAsSint16LE(_unmaskFrame);
+}
+
+void Scene305::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene305::enter() {
+ _unmaskFl = false;
+ _skipFl = false;
+ _game._player._visible = false;
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+
+ _scene->_userInterface.setup(kInputLimitedSentences);
+ _scene->loadSpeech(5);
+ _game.loadQuoteSet(0x64, 0x65, 0);
+
+ if (_game._player._playerPos.x == 100) {
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('r', 1), 60);
+ _scene->_hotspots.activate(NOUN_MASK, false);
+ _anim1ActvFl = true;
+ } else if (_game._player._playerPos.x == 200) {
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('u', 1), 0);
+ _anim0ActvFl = true;
+ _scene->_hotspots.activate(NOUN_CANE, false);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene305::step() {
+ if (_anim0ActvFl)
+ handle_animation_unmask ();
+
+ if (_anim1ActvFl) {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == 53)
+ _game._player._stepEnabled = false;
+
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == 54 && !_skipFl) {
+ _scene->playSpeech(5);
+ _skipFl = true;
+ }
+ }
+
+ if (_game._trigger == 60) {
+ _globals[kPlayerScore] -= 10;
+ _scene->_userInterface.noInventoryAnim();
+ // CHECKME: Not sure about the next function call
+ _scene->_userInterface.refresh();
+ _scene->_nextSceneId = 303;
+ }
+}
+
+void Scene305::actions() {
+ if (_action.isAction(VERB_PUSH, NOUN_CANE)) {
+ _scene->_nextSceneId = 304;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_MASK)) {
+ _unmaskFl = true;
+ _game._player._stepEnabled = false;
+ _action._inProgress = false;
+ }
+}
+
+void Scene305::preActions() {
+}
+
+void Scene305::handle_animation_unmask() {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == _unmaskFrame)
+ return;
+
+ _unmaskFrame = _scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame();
+ int resetFrame = -1;
+
+ switch (_unmaskFrame) {
+ case 25:
+ if (!_unmaskFl)
+ resetFrame = 0;
+
+ break;
+
+ case 60:
+ _scene->playSpeech(10);
+ _scene->_kernelMessages.add(Common::Point(176, 53), 0x1110, 0, 0, 360, _game.getQuote(0x64));
+ _scene->_kernelMessages.add(Common::Point(176, 68), 0x1110, 0, 0, 360, _game.getQuote(0x65));
+ break;
+
+ case 95:
+ _scene->_nextSceneId = 306;
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[0], resetFrame);
+ _unmaskFrame = resetFrame;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene306::Scene306(MADSEngine *vm) : Scene3xx(vm) {
+ _speechDoneFl = false;
+}
+
+void Scene306::synchronize(Common::Serializer &s) {
+ Scene3xx::synchronize(s);
+
+ s.syncAsByte(_speechDoneFl);
+}
+
+void Scene306::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene306::enter() {
+ _scene->loadSpeech(6);
+ _speechDoneFl = false;
+
+ warning("TODO: Switch to letter box view. See definition of MADS_MENU_Y");
+
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('a', 1), 60);
+
+ sceneEntrySound();
+}
+
+void Scene306::step() {
+ if (_game._trigger == 60) {
+ if (_vm->_sound->_preferRoland)
+ _scene->_sequences.addTimer(120, 61);
+ else
+ _scene->_sequences.addTimer(300, 61);
+ }
+
+ if (!_speechDoneFl && (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == 3)) {
+ _scene->playSpeech(6);
+ _speechDoneFl = true;
+ }
+
+ if (_game._trigger == 61) {
+ _vm->_sound->command(1);
+ _vm->_sound->command(66);
+ _scene->_sequences.addTimer(120, 62);
+ }
+
+ if (_game._trigger == 62)
+ _scene->_nextSceneId = 150;
+}
+
+void Scene306::actions() {
+}
+
+void Scene306::preActions() {
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene307::Scene307(MADSEngine *vm) : Scene3xx(vm) {
+}
+
+void Scene307::synchronize(Common::Serializer &s) {
+ Scene3xx::synchronize(s);
+}
+
+void Scene307::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene307::enter() {
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('p', 0));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites("*RRD_9");
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites("*RDR_9");
+
+ if (_globals[kRightDoorIsOpen504])
+ _scene->_hotspots.activate(NOUN_DOOR, true);
+ else
+ _scene->_hotspots.activate(NOUN_DOOR, false);
+
+ if (_game._objects.isInRoom(OBJ_GREEN_FRAME) && (_game._difficulty == DIFFICULTY_EASY)) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+ } else
+ _scene->_hotspots.activate(NOUN_GREEN_FRAME, false);
+
+ if (_scene->_priorSceneId == 308) {
+ _game._player._playerPos = Common::Point(18, 134);
+ _game._player._facing = FACING_SOUTHEAST;
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, -2);
+ if (!(_globals[kPlayerScoreFlags] & 16)) {
+ _globals[kPlayerScoreFlags] |= 16;
+ _globals[kPlayerScore] += 5;
+ }
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 4);
+ _game._player.walk(Common::Point(41, 137), FACING_EAST);
+ _game._player.setWalkTrigger(60);
+ } else if ((_scene->_priorSceneId == 303) || (_scene->_priorSceneId != RETURNING_FROM_LOADING))
+ _game._player.firstWalk(Common::Point(340, 137), FACING_WEST, Common::Point(304, 137), FACING_WEST, true);
+
+ sceneEntrySound();
+}
+
+void Scene307::step() {
+ switch (_game._trigger) {
+ case 60:
+ _scene->deleteSequence(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[3], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 10);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 61);
+ break;
+
+ case 61:
+ _vm->_sound->command(25);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene307::actions() {
+ if (_action.isAction(VERB_TAKE, NOUN_GREEN_FRAME) && (_game._objects.isInRoom(OBJ_GREEN_FRAME) || _game._trigger)) {
+ switch (_game._trigger) {
+ case (0):
+ if (_globals[kCurrentYear] == 1881) {
+ int count = 0;
+ if (_game._objects.isInInventory(OBJ_YELLOW_FRAME))
+ ++count;
+ if (_game._objects.isInInventory(OBJ_RED_FRAME))
+ ++count;
+ if (_game._objects.isInInventory(OBJ_BLUE_FRAME))
+ ++count;
+
+ if (count < 3)
+ _globals[kPlayerScore] += 5;
+ }
+
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[1] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[1], false, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 5);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[1], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _scene->_hotspots.activate(NOUN_GREEN_FRAME, false);
+ _game._objects.addToInventory(OBJ_GREEN_FRAME);
+ _vm->_sound->command(26);
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[1]);
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(20, 3);
+ break;
+
+ case 3:
+ if (_globals[kCurrentYear] == 1881)
+ _vm->_dialogs->showItem(OBJ_GREEN_FRAME, 845, 0);
+ else
+ _vm->_dialogs->showItem(OBJ_GREEN_FRAME, 819, 0);
+
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR) || _action.isAction(VERB_OPEN, NOUN_DOOR)) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[4] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[4], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[4], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_SPRITE, 4, 70);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 72);
+ break;
+
+ case 70:
+ _vm->_sound->command(24);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ break;
+
+ case 71: {
+ int idx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, -2);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[3], SYNC_SEQ, idx);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
+ _scene->_sequences.addTimer(10, 73);
+ }
+ break;
+
+ case 72:
+ _game._player._visible = true;
+ break;
+
+ case 73:
+ _scene->_nextSceneId = 308;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(30710);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_COLUMN)) {
+ if (_globals[kRightDoorIsOpen504])
+ _vm->_dialogs->show(30725);
+ else
+ _vm->_dialogs->show(30711);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CATWALK)) {
+ _vm->_dialogs->show(30712);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_GRID)) {
+ _vm->_dialogs->show(30713);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_GIRDER)) {
+ _vm->_dialogs->show(30714);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_GRIDWORK)) {
+ _vm->_dialogs->show(30715);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_HEMP)) {
+ _vm->_dialogs->show(30716);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BACK_WALL)) {
+ _vm->_dialogs->show(30717);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DUCTWORK)) {
+ _vm->_dialogs->show(30718);
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isObject(NOUN_GREEN_FRAME)) && (_game._objects.isInRoom(OBJ_GREEN_FRAME))) {
+ if (_globals[kCurrentYear] == 1993)
+ _vm->_dialogs->show(30719);
+ else
+ _vm->_dialogs->show(30720);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_ALCOVE)) {
+ _vm->_dialogs->show(30721);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RAILING)) {
+ _vm->_dialogs->show(30722);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DOOR)) {
+ _vm->_dialogs->show(30726);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_HEMP)) {
+ _vm->_dialogs->show(30723);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_PULL, NOUN_HEMP)) {
+ _vm->_dialogs->show(30141);
+ _action._inProgress = false;
+ }
+}
+
+void Scene307::preActions() {
+ if (_action.isAction(VERB_EXIT_TO, NOUN_ALCOVE))
+ _game._player._walkOffScreenSceneId = 303;
+
+ if (_action.isAction(VERB_OPEN, NOUN_DOOR))
+ _game._player.walk(Common::Point(28, 137), FACING_NORTHWEST);
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene308::Scene308(MADSEngine *vm) : Scene3xx(vm) {
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _anim2ActvFl = false;
+ _anim3ActvFl = false;
+ _skip1Fl = false;
+ _skip2Fl = false;
+
+ _currentFloor = -1;
+}
+
+void Scene308::synchronize(Common::Serializer &s) {
+ Scene3xx::synchronize(s);
+
+ s.syncAsByte(_anim0ActvFl);
+ s.syncAsByte(_anim1ActvFl);
+ s.syncAsByte(_anim2ActvFl);
+ s.syncAsByte(_anim3ActvFl);
+ s.syncAsByte(_skip1Fl);
+ s.syncAsByte(_skip2Fl);
+
+ s.syncAsSint16LE(_currentFloor);
+}
+
+void Scene308::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene308::enter() {
+ _scene->loadSpeech(4);
+
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _anim2ActvFl = false;
+ _anim3ActvFl = false;
+ }
+
+ _skip1Fl = false;
+ _skip2Fl = false;
+
+ _vm->_gameConv->load(26);
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('a', 0));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('b', 0));
+ _scene->_userInterface.setup(kInputLimitedSentences);
+ _game._player._visible = false;
+
+ if (_scene->_priorSceneId == RETURNING_FROM_LOADING) {
+ switch (_currentFloor) {
+ case 1:
+ if (_globals[kRightDoorIsOpen504]) {
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 10);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[0], Common::Point(160, 104));
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 10);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(161, 124));
+ } else {
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 10);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[0], Common::Point(160, 127));
+ }
+ break;
+
+ case 2:
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 10);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[0], Common::Point(160, 76));
+ break;
+
+ case 3:
+ if (_globals[kRightDoorIsOpen504] && !_globals[kKnockedOverHead]) {
+ _anim0ActvFl = true;
+ _skip1Fl = true;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('b', 2), 2);
+ _scene->setAnimFrame(_globals._animationIndexes[0], 76);
+ } else {
+ _anim0ActvFl = true;
+ _skip1Fl = true;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('u', 2), 2);
+ _scene->setAnimFrame(_globals._animationIndexes[0], 96);
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else if (_scene->_priorSceneId == 309) {
+ _currentFloor = 1;
+ if (_globals[kRightDoorIsOpen504]) {
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 10);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[0], Common::Point(160, 104));
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 10);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(161, 124));
+ } else {
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 10);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[0], Common::Point(160, 127));
+ }
+ } else if (_scene->_priorSceneId == 206) {
+ _currentFloor = 2;
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 10);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[0], Common::Point(160, 76));
+ } else if (_scene->_priorSceneId == 307) {
+ _currentFloor = 3;
+ _anim0ActvFl = true;
+ _skip1Fl = true;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('u', 2), 2);
+ _scene->setAnimFrame(_globals._animationIndexes[0], 96);
+ }
+
+ if (!_game._visitedScenes._sceneRevisited) {
+ _globals[kPlayerScore] += 5;
+ _scene->_sequences.addTimer(1, 60);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene308::step() {
+ if (_game._trigger == 60)
+ _vm->_dialogs->show(30810);
+
+ if (_anim2ActvFl) {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == 77) {
+ _scene->setAnimFrame(_globals._animationIndexes[0], 76);
+ if (!_skip1Fl) {
+ _game._player._stepEnabled = true;
+ _vm->_dialogs->show(30811);
+ _skip1Fl = true;
+ }
+ }
+ }
+
+ if (_anim0ActvFl) {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == 97) {
+ if (_globals[kTopFloorLocked]) {
+ _scene->setAnimFrame(_globals._animationIndexes[0], 96);
+ if (!_skip1Fl) {
+ _game._player._stepEnabled = true;
+ _vm->_dialogs->show(30811);
+ _skip1Fl = true;
+ }
+ }
+ } else if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == 116) {
+ _globals[kTopFloorLocked] = true;
+ _scene->_nextSceneId = 307;
+ }
+ }
+
+ if (_anim1ActvFl) {
+ if ((_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == 51) && _globals[kTopFloorLocked]) {
+ _scene->setAnimFrame(_globals._animationIndexes[0], 50);
+ if (!_skip1Fl) {
+ _game._player._stepEnabled = true;
+ _vm->_dialogs->show(30811);
+ _skip1Fl = true;
+ }
+ }
+ }
+}
+
+void Scene308::actions() {
+ switch (_game._trigger) {
+ case 1:
+ _scene->_nextSceneId = 206;
+ _action._inProgress = false;
+ return;
+
+ case 2:
+ _scene->_nextSceneId = 307;
+ _action._inProgress = false;
+ return;
+
+ case 3:
+ _scene->_nextSceneId = 309;
+ _action._inProgress = false;
+ return;
+
+ default:
+ break;
+ }
+
+ if (_action.isAction(VERB_EXIT_TO, NOUN_MIDDLE_LEVEL)) {
+ switch (_currentFloor) {
+ case 1:
+ if (_globals[kRightDoorIsOpen504]) {
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('b', 1), 1);
+ _scene->deleteSequence(_globals._sequenceIndexes[0]);
+ _scene->deleteSequence(_globals._sequenceIndexes[1]);
+ _game._player._stepEnabled = false;
+ } else {
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('u', 1), 1);
+ _scene->deleteSequence(_globals._sequenceIndexes[0]);
+ _game._player._stepEnabled = false;
+ }
+ _action._inProgress = false;
+ return;
+
+ case 2:
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('m', 1), 1);
+ _scene->deleteSequence(_globals._sequenceIndexes[0]);
+ _game._player._stepEnabled = false;
+ _action._inProgress = false;
+ return;
+
+ case 3:
+ if (_globals[kRightDoorIsOpen504] && !_globals[kKnockedOverHead]) {
+ _scene->freeAnimation(_globals._animationIndexes[0]);
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('b', 4), 1);
+ _game._player._stepEnabled = false;
+ _anim2ActvFl = false;
+
+ } else {
+ _scene->freeAnimation(_globals._animationIndexes[0]);
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('x', 1), 1);
+ _game._player._stepEnabled = false;
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ }
+ _action._inProgress = false;
+ return;
+
+ default:
+ break;
+ }
+ }
+
+ if (_action.isAction(VERB_EXIT_TO, NOUN_UPPER_LEVEL)) {
+ switch (_currentFloor) {
+ case 1:
+ if (_globals[kRightDoorIsOpen504]) {
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('b', 2), 1);
+ _scene->deleteSequence(_globals._sequenceIndexes[0]);
+ _scene->deleteSequence(_globals._sequenceIndexes[1]);
+ _game._player._stepEnabled = false;
+ _anim2ActvFl = true;
+ _currentFloor = 3;
+ } else {
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('u', 2), 2);
+ _scene->deleteSequence(_globals._sequenceIndexes[0]);
+ _game._player._stepEnabled = false;
+ _anim0ActvFl = true;
+ _currentFloor = 3;
+ }
+ _action._inProgress = false;
+ return;
+
+ case 2:
+ if (_globals[kRightDoorIsOpen504]) {
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('u', 3), 2);
+ _scene->deleteSequence(_globals._sequenceIndexes[0]);
+ _game._player._stepEnabled = false;
+ } else {
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('u', 3), 2);
+ _scene->deleteSequence(_globals._sequenceIndexes[0]);
+ _game._player._stepEnabled = false;
+ _anim1ActvFl = true;
+ _currentFloor = 3;
+ }
+ _action._inProgress = false;
+ return;
+
+ case 3:
+ if (_globals[kRightDoorIsOpen504])
+ _globals[kTopFloorLocked] = false;
+ else {
+ _skip2Fl = false;
+ _skip1Fl = false;
+ }
+ _action._inProgress = false;
+ return;
+
+ default:
+ break;
+ }
+ }
+
+ if (_action.isAction(VERB_EXIT_TO, NOUN_LOWER_LEVEL)) {
+ switch (_currentFloor) {
+ case 1:
+ if (_globals[kRightDoorIsOpen504]) {
+ _vm->_gameConv->run(26);
+ _vm->_gameConv->exportValue(1);
+ } else {
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('l', 1), 3);
+ _scene->deleteSequence(_globals._sequenceIndexes[0]);
+ _game._player._stepEnabled = false;
+ }
+ _action._inProgress = false;
+ return;
+
+ case 2:
+ if (_globals[kRightDoorIsOpen504]) {
+ if (_vm->_sound->_preferRoland)
+ _vm->_sound->command(74);
+ else
+ _scene->playSpeech(1);
+
+ _vm->_gameConv->run(26);
+ _vm->_gameConv->exportValue(6);
+
+ } else {
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('d', 1), 3);
+ _scene->deleteSequence(_globals._sequenceIndexes[0]);
+ _game._player._stepEnabled = false;
+ }
+ _action._inProgress = false;
+ return;
+
+ case 3:
+ if (_globals[kRightDoorIsOpen504] && !_globals[kKnockedOverHead]) {
+ _vm->_gameConv->run(26);
+ _vm->_gameConv->exportValue(5);
+ } else if (_globals[kRightDoorIsOpen504] && _globals[kKnockedOverHead]) {
+ if (_vm->_sound->_preferRoland)
+ _vm->_sound->command(74);
+ else
+ _scene->playSpeech(1);
+
+ _vm->_gameConv->run(26);
+ _vm->_gameConv->exportValue(6);
+ } else {
+ _scene->freeAnimation(_globals._animationIndexes[0]);
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('x', 2), 3);
+ _game._player._stepEnabled = false;
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ }
+ _action._inProgress = false;
+ return;
+
+ default:
+ break;
+ }
+ }
+}
+
+void Scene308::preActions() {
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene309::Scene309(MADSEngine *vm) : Scene3xx(vm) {
+ _anim0ActvFl = false;
+
+ _boatStatus = -1;
+ _boatFrame = -1;
+ _talkCount = -1;
+}
+
+void Scene309::synchronize(Common::Serializer &s) {
+ Scene3xx::synchronize(s);
+
+ s.syncAsByte(_anim0ActvFl);
+
+ s.syncAsSint16LE(_boatStatus);
+ s.syncAsSint16LE(_boatFrame);
+ s.syncAsSint16LE(_talkCount);
+}
+
+void Scene309::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ if (_globals[kRightDoorIsOpen504])
+ _scene->_variant = 1;
+}
+
+void Scene309::enter() {
+ _scene->_hotspots.activate(NOUN_CHRISTINE, false);
+ _scene->_hotspots.activate(NOUN_BOAT, false);
+
+ _anim0ActvFl = false;
+ _boatStatus = 1;
+ _vm->_gameConv->load(26);
+
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites("*RDR_9");
+
+ if (_scene->_priorSceneId == RETURNING_FROM_LOADING) {
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 10);
+
+ if (_game._visitedScenes.exists(310)) {
+ _anim0ActvFl = true;
+
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('b', 1), 70);
+ _scene->setAnimFrame(_globals._animationIndexes[0], 184);
+ int id = _scene->_dynamicHotspots.add(NOUN_CHRISTINE, VERB_WALK_TO, SYNTAX_SINGULAR_FEM, EXT_NONE, Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(id, Common::Point(62, 146), FACING_NORTHWEST);
+ _scene->_dynamicHotspots[id]._articleNumber = PREP_ON;
+
+ _scene->setDynamicAnim(id, _globals._animationIndexes[0], 10);
+ _scene->setDynamicAnim(id, _globals._animationIndexes[0], 11);
+ _scene->setDynamicAnim(id, _globals._animationIndexes[0], 12);
+ _scene->setDynamicAnim(id, _globals._animationIndexes[0], 13);
+ _scene->setDynamicAnim(id, _globals._animationIndexes[0], 14);
+ _scene->setDynamicAnim(id, _globals._animationIndexes[0], 15);
+ _scene->setDynamicAnim(id, _globals._animationIndexes[0], 16);
+ _scene->setDynamicAnim(id, _globals._animationIndexes[0], 17);
+ _scene->setDynamicAnim(id, _globals._animationIndexes[0], 18);
+ _scene->_hotspots.activate(NOUN_CHRISTINE, true);
+ _scene->_hotspots.activate(NOUN_BOAT, true);
+ }
+ }
+
+ if (_scene->_priorSceneId == 404) {
+ _game._player._playerPos = Common::Point(319, 136);
+ _game._player._facing = FACING_SOUTHWEST;
+ _game._player.walk(Common::Point(281, 148), FACING_SOUTHWEST);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 10);
+ } else if (_scene->_priorSceneId == 310) {
+ _game._player._playerPos = Common::Point(209, 144);
+ _game._player._facing = FACING_SOUTH;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _anim0ActvFl = true;
+
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('b', 1), 70);
+ int id = _scene->_dynamicHotspots.add(NOUN_CHRISTINE, VERB_WALK_TO, SYNTAX_SINGULAR_FEM, EXT_NONE, Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(id, Common::Point(63, 146), FACING_NORTHWEST);
+ _scene->_dynamicHotspots[id]._articleNumber = PREP_ON;
+
+ _scene->setDynamicAnim(id, _globals._animationIndexes[0], 10);
+ _scene->setDynamicAnim(id, _globals._animationIndexes[0], 11);
+ _scene->setDynamicAnim(id, _globals._animationIndexes[0], 12);
+ _scene->setDynamicAnim(id, _globals._animationIndexes[0], 13);
+ _scene->setDynamicAnim(id, _globals._animationIndexes[0], 14);
+ _scene->setDynamicAnim(id, _globals._animationIndexes[0], 15);
+ _scene->setDynamicAnim(id, _globals._animationIndexes[0], 16);
+ _scene->setDynamicAnim(id, _globals._animationIndexes[0], 17);
+ _scene->setDynamicAnim(id, _globals._animationIndexes[0], 18);
+ _scene->_hotspots.activate(NOUN_CHRISTINE, true);
+ _scene->_hotspots.activate(NOUN_BOAT, true);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 10);
+ } else if ((_scene->_priorSceneId == 308) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
+ _game._player._playerPos = Common::Point(0, 121);
+ _game._player._facing = FACING_SOUTHEAST;
+ _game._player.walk(Common::Point(28, 142), FACING_SOUTHEAST);
+ _game._player.setWalkTrigger(65);
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 10);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene309::step() {
+ if (_anim0ActvFl)
+ handleBoatAnimation ();
+
+ switch (_game._trigger) {
+ case 65:
+ _scene->deleteSequence(_globals._sequenceIndexes[0]);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[0], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 10);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 66);
+ break;
+
+ case 66:
+ _vm->_sound->command(25);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 10);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene309::actions() {
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_STONE_ARCHWAY)) {
+ if (_globals[kRightDoorIsOpen504]) {
+ _vm->_gameConv->run(26);
+ _vm->_gameConv->exportValue(1);
+ _boatStatus = 0;
+ _talkCount = 0;
+ } else if (_globals[kLanternStatus] == 1)
+ _game.enterCatacombs(false);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TALK_TO, NOUN_CHRISTINE)) {
+ _vm->_gameConv->run(26);
+ _vm->_gameConv->exportValue(1);
+ _boatStatus = 0;
+ _talkCount = 0;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR) || _action.isAction(VERB_OPEN, NOUN_DOOR)) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[1] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[1], false, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[1], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_SPRITE, 4, 60);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 62);
+ break;
+
+ case 60:
+ _scene->deleteSequence(_globals._sequenceIndexes[0]);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 61);
+ _vm->_sound->command(24);
+ break;
+
+ case 61: {
+ int idx = _globals._sequenceIndexes[0];
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 5);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[0], SYNC_SEQ, idx);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ _game._player.walk(Common::Point(0, 121), FACING_NORTHWEST);
+ _game._player.setWalkTrigger(63);
+ }
+ break;
+
+ case 62:
+ _game._player._visible = true;
+ break;
+
+ case 63:
+ if (!_globals[kRightDoorIsOpen504]) {
+ _scene->deleteSequence(_globals._sequenceIndexes[0]);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[0], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 64);
+ _vm->_sound->command(25);
+ } else
+ _scene->setAnimFrame(_globals._animationIndexes[0], 186);
+
+ break;
+
+ case 64:
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 5);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 1);
+ _scene->_nextSceneId = 308;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(30910);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_STONE_WALL)) {
+ _vm->_dialogs->show(30911);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LAKE)) {
+ _vm->_dialogs->show(30912);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_STONE_COLUMN)) {
+ _vm->_dialogs->show(30913);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DOORWAY)) {
+ _vm->_dialogs->show(30914);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_STONE_ARCHWAY)) {
+ _vm->_dialogs->show(30915);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_STONE_FLOOR)) {
+ _vm->_dialogs->show(30916);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CATACOMBS)) {
+ _vm->_dialogs->show(30917);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CHRISTINE)) {
+ _vm->_dialogs->show(30919);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BOAT)) {
+ _vm->_dialogs->show(30921);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_CLIMB_INTO, NOUN_BOAT)) {
+ _vm->_dialogs->show(30920);
+ _action._inProgress = false;
+ }
+}
+
+void Scene309::preActions() {
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_STONE_ARCHWAY) && (_globals[kLanternStatus] == 0)) {
+ _game._player._needToWalk = false;
+ _vm->_dialogs->show(30918);
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_STONE_ARCHWAY) && _globals[kRightDoorIsOpen504])
+ _game._player.walk(Common::Point(285, 147), FACING_NORTHEAST);
+
+ if (_action.isAction(VERB_OPEN, NOUN_DOOR))
+ _game._player.walk(Common::Point(16, 139), FACING_NORTHEAST);
+}
+
+void Scene309::handleBoatAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == _boatFrame)
+ return;
+
+ _boatFrame = _scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame();
+ int resetFrame = -1;
+
+ switch (_boatFrame) {
+ case 72:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[0]);
+ _game._player._visible = true;
+ break;
+
+ case 130:
+ _game._player._stepEnabled = true;
+ break;
+
+ case 185:
+ if (_boatStatus == 0)
+ resetFrame = 244;
+ else
+ resetFrame = 184;
+
+ break;
+
+ case 244:
+ _scene->_nextSceneId = 308;
+ break;
+
+ case 245:
+ case 246:
+ case 247:
+ resetFrame = _vm->getRandomNumber(244, 246);
+ ++_talkCount;
+ if (_talkCount > 10) {
+ resetFrame = 184;
+ _boatStatus = 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[0], resetFrame);
+ _boatFrame = resetFrame;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene310::Scene310(MADSEngine *vm) : Scene3xx(vm) {
+ _raoulMessageColor = -1;
+ _chrisMessageColor = -1;
+ _lakeFrame = -1;
+ for (int i = 0; i < 4; i++)
+ _multiplanePosX[i] = -1;
+}
+
+void Scene310::synchronize(Common::Serializer &s) {
+ Scene3xx::synchronize(s);
+
+ s.syncAsSint16LE(_raoulMessageColor);
+ s.syncAsSint16LE(_chrisMessageColor);
+ s.syncAsSint16LE(_lakeFrame);
+ for (int i = 0; i < 4; i++)
+ s.syncAsSint16LE(_multiplanePosX[i]);
+}
+
+void Scene310::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene310::enter() {
+ warning("TODO: Switch to letter box view. See definition of MADS_MENU_Y");
+
+ for (int i = 0; i < 4; i++) {
+ _globals._spriteIndexes[i] = _scene->_sprites.addSprites(formAnimName('f', i));
+ _globals._sequenceIndexes[i] = -1;
+ }
+
+ _multiplanePosX[0] = 100;
+ _multiplanePosX[1] = 210;
+ _multiplanePosX[2] = 320;
+ _multiplanePosX[3] = 472;
+
+ _game.loadQuoteSet(0x66, 0x67, 0x69, 0x6A, 0x6C, 0x6D, 0x6E, 0x6F, 0x71, 0x72, 0x74, 0x70, 0x68, 0x73, 0x6B, 0);
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('l', 1), 80);
+ _scene->_animation[_globals._animationIndexes[0]]->_canChangeView = true;
+ _game._camX._manualFl = true;
+
+ _raoulMessageColor = 0x102;
+ _chrisMessageColor = 0x1110;
+
+ _scene->_userInterface.emptyConversationList();
+ _scene->_userInterface.setup(kInputConversation);
+
+ sceneEntrySound();
+}
+
+void Scene310::step() {
+ handleLakeAnimation();
+
+ if (_game._trigger == 80)
+ _scene->_nextSceneId = 309;
+
+ bool positionsSetFl = false;
+
+ if (_globals._animationIndexes[0] >= 0) {
+ MADS::Animation *anim = _scene->_animation[_globals._animationIndexes[0]];
+ int curFrame = anim->getCurrentFrame();
+ uint32 clock = anim->getNextFrameTimer();
+ if ((curFrame > 0) && (_scene->_frameStartTime >= clock)) {
+ Common::Point pos = anim->getFramePosAdjust(curFrame);
+ if (pos.x != _scene->_posAdjust.x) {
+ setMultiplanePos(pos.x);
+ positionsSetFl = true;
+ }
+ }
+ }
+
+ if (!positionsSetFl && (_game._fx != kTransitionNone))
+ setMultiplanePos(320);
+}
+
+void Scene310::actions() {
+}
+
+void Scene310::preActions() {
+}
+
+void Scene310::setMultiplanePos(int x_new) {
+ int center = x_new + 160;
+
+ for (int i = 0; i < 4; i++) {
+ if (_globals._sequenceIndexes[i] >= 0)
+ _scene->deleteSequence(_globals._sequenceIndexes[i]);
+
+ int difference = center - _multiplanePosX[i];
+
+ int direction = 0;
+ if (difference < 0)
+ direction = 1;
+ else if (difference > 0)
+ direction = -1;
+
+ int displace = abs(difference);
+ if (direction < 0)
+ displace = -displace;
+
+ int x = _multiplanePosX[i] + displace - 1;
+ int y = _scene->_sprites[_globals._spriteIndexes[i]]->getFrameWidth(0) + 29;
+ int halfWidth = 1 + (_scene->_sprites[_globals._spriteIndexes[i]]->getFrameHeight(0) / 2);
+
+ if (((x - halfWidth) >= (x_new + 320)) || ((x + halfWidth) < x_new))
+ _globals._sequenceIndexes[i] = -1;
+ else {
+ _globals._sequenceIndexes[i] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[i], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[i], Common::Point(x, y));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[i], 1);
+ }
+ }
+}
+
+void Scene310::handleLakeAnimation() {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == _lakeFrame)
+ return;
+
+ _lakeFrame = _scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame();
+ int id;
+
+ switch (_lakeFrame) {
+ case 60:
+ id = _scene->_kernelMessages.add(Common::Point(-142, 0), _chrisMessageColor, 0, 61, 600, _game.getQuote(0x66));
+ _scene->_kernelMessages.setAnim(id, _globals._animationIndexes[0], 0);
+ id = _scene->_kernelMessages.add(Common::Point(-142, 15), _chrisMessageColor, 0, 0, 600, _game.getQuote(0x67));
+ _scene->_kernelMessages.setAnim(id, _globals._animationIndexes[0], 0);
+ id = _scene->_kernelMessages.add(Common::Point(-142, 30), _chrisMessageColor, 0, 0, 600, _game.getQuote(0x68));
+ _scene->_kernelMessages.setAnim(id, _globals._animationIndexes[0], 0);
+ break;
+
+ case 120:
+ _scene->_kernelMessages.reset();
+ break;
+
+ case 140:
+ id = _scene->_kernelMessages.add(Common::Point(-120, 0), _chrisMessageColor, 0, 63, 360, _game.getQuote(0x69));
+ _scene->_kernelMessages.setAnim(id, _globals._animationIndexes[0], 0);
+ id = _scene->_kernelMessages.add(Common::Point(-120, 15), _chrisMessageColor, 0, 0, 360, _game.getQuote(0x6A));
+ _scene->_kernelMessages.setAnim(id, _globals._animationIndexes[0], 0);
+ id = _scene->_kernelMessages.add(Common::Point(-120, 30), _chrisMessageColor, 0, 0, 360, _game.getQuote(0x6B));
+ _scene->_kernelMessages.setAnim(id, _globals._animationIndexes[0], 0);
+ break;
+
+ case 200:
+ _scene->_kernelMessages.reset();
+ break;
+
+ case 220:
+ id = _scene->_kernelMessages.add(Common::Point(-32, 30), _chrisMessageColor, 0, 65, 240, _game.getQuote(0x6C));
+ _scene->_kernelMessages.setAnim(id, _globals._animationIndexes[0], 0);
+ id = _scene->_kernelMessages.add(Common::Point(-32, 45), _chrisMessageColor, 0, 0, 240, _game.getQuote(0x6D));
+ _scene->_kernelMessages.setAnim(id, _globals._animationIndexes[0], 0);
+ break;
+
+ case 280:
+ _scene->_kernelMessages.reset();
+ break;
+
+ case 300:
+ id = _scene->_kernelMessages.add(Common::Point(101, 0), _raoulMessageColor, 0, 67, 360, _game.getQuote(0x6E));
+ _scene->_kernelMessages.setAnim(id, _globals._animationIndexes[0], 0);
+ id = _scene->_kernelMessages.add(Common::Point(101, 15), _raoulMessageColor, 0, 0, 360, _game.getQuote(0x6F));
+ _scene->_kernelMessages.setAnim(id, _globals._animationIndexes[0], 0);
+ id = _scene->_kernelMessages.add(Common::Point(101, 30), _raoulMessageColor, 0, 0, 360, _game.getQuote(0x70));
+ _scene->_kernelMessages.setAnim(id, _globals._animationIndexes[0], 0);
+ break;
+
+ case 360:
+ _scene->_kernelMessages.reset();
+ break;
+
+ case 380:
+ id = _scene->_kernelMessages.add(Common::Point(107, 0), _chrisMessageColor, 0, 69, 360, _game.getQuote(0x71));
+ _scene->_kernelMessages.setAnim(id, _globals._animationIndexes[0], 0);
+ id = _scene->_kernelMessages.add(Common::Point(107, 15), _chrisMessageColor, 0, 0, 360, _game.getQuote(0x72));
+ _scene->_kernelMessages.setAnim(id, _globals._animationIndexes[0], 0);
+ id = _scene->_kernelMessages.add(Common::Point(107, 30), _chrisMessageColor, 0, 0, 360, _game.getQuote(0x73));
+ _scene->_kernelMessages.setAnim(id, _globals._animationIndexes[0], 0);
+ break;
+
+ case 440:
+ _scene->_kernelMessages.reset();
+ break;
+
+ case 460:
+ id = _scene->_kernelMessages.add(Common::Point(107, 7), _chrisMessageColor, 0, 0, 180, _game.getQuote(0x74));
+ _scene->_kernelMessages.setAnim(id, _globals._animationIndexes[0], 0);
+ break;
+
+ case 510:
+ _scene->_kernelMessages.reset();
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+} // End of namespace Phantom
+} // End of namespace MADS
diff --git a/engines/mads/phantom/phantom_scenes3.h b/engines/mads/phantom/phantom_scenes3.h
new file mode 100644
index 0000000000..9f58ad12bf
--- /dev/null
+++ b/engines/mads/phantom/phantom_scenes3.h
@@ -0,0 +1,248 @@
+/* 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 MADS_PHANTOM_SCENES3_H
+#define MADS_PHANTOM_SCENES3_H
+
+#include "common/scummsys.h"
+#include "common/serializer.h"
+#include "mads/game.h"
+#include "mads/scene.h"
+#include "mads/phantom/phantom_scenes.h"
+
+namespace MADS {
+
+namespace Phantom {
+
+class Scene3xx : public PhantomScene {
+protected:
+ /**
+ * Plays an appropriate sound when entering a scene
+ */
+ void sceneEntrySound();
+
+ /**
+ *Sets the AA file to use for the scene
+ */
+ void setAAName();
+
+ /**
+ * Updates the prefix used for getting player sprites for the scene
+ */
+ void setPlayerSpritesPrefix();
+public:
+ Scene3xx(MADSEngine *vm) : PhantomScene(vm) {}
+};
+
+class Scene301 : public Scene3xx {
+private:
+ bool _anim0ActvFl;
+ bool _skip1Fl;
+ bool _skip2Fl;
+
+ int _lightingHotspotId;
+ int _sandbagHotspotId;
+
+public:
+ Scene301(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene302 : public Scene3xx {
+public:
+ Scene302(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene303 : public Scene3xx {
+private:
+ bool _anim0ActvFl;
+ int _hempHotspotId;
+ int _skipFrameCheckFl;
+public:
+ Scene303(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene304 : public Scene3xx {
+private:
+ bool _anim0ActvFl;
+ bool _anim1ActvFl;
+ bool _anim2ActvFl;
+
+ int _raoulFrame;
+ int _raoulStatus;
+ int _fightFrame;
+ int _fightStatus;
+ int _fightCount;
+ int _phantomFrame;
+ int _phantomStatus;
+
+ void handleConversation23();
+ void handleRaoulAnimation();
+ void handlePhantomAnimation();
+ void handleFightAnimation();
+
+public:
+ Scene304(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene305 : public Scene3xx {
+private:
+ bool _anim0ActvFl;
+ bool _anim1ActvFl;
+ bool _skipFl;
+ bool _unmaskFl;
+
+ int _unmaskFrame;
+
+ void handle_animation_unmask();
+
+public:
+ Scene305(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene306 : public Scene3xx {
+private:
+ bool _speechDoneFl;
+
+public:
+ Scene306(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene307 : public Scene3xx {
+public:
+ Scene307(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene308 : public Scene3xx {
+private:
+ bool _anim0ActvFl;
+ bool _anim1ActvFl;
+ bool _anim2ActvFl;
+ bool _anim3ActvFl;
+ bool _skip1Fl;
+ bool _skip2Fl;
+ int _currentFloor;
+
+public:
+ Scene308(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene309 : public Scene3xx {
+private:
+ bool _anim0ActvFl;
+
+ int _boatStatus;
+ int _boatFrame;
+ int _talkCount;
+
+ void handleBoatAnimation();
+
+public:
+ Scene309(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene310 : public Scene3xx {
+private:
+ int _raoulMessageColor;
+ int _chrisMessageColor;
+ int _multiplanePosX[4];
+ int _lakeFrame;
+
+ void setMultiplanePos(int x_new);
+ void handleLakeAnimation();
+
+public:
+ Scene310(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+} // End of namespace Phantom
+} // End of namespace MADS
+
+#endif /* MADS_PHANTOM_SCENES3_H */
diff --git a/engines/mads/phantom/phantom_scenes4.cpp b/engines/mads/phantom/phantom_scenes4.cpp
new file mode 100644
index 0000000000..da6d62e727
--- /dev/null
+++ b/engines/mads/phantom/phantom_scenes4.cpp
@@ -0,0 +1,4975 @@
+/* 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 "mads/mads.h"
+#include "mads/conversations.h"
+#include "mads/scene.h"
+#include "mads/phantom/phantom_scenes.h"
+#include "mads/phantom/phantom_scenes4.h"
+
+namespace MADS {
+
+namespace Phantom {
+
+void Scene4xx::setAAName() {
+ _game._aaName = Resources::formatAAName(1);
+ _vm->_palette->setEntry(254, 43, 47, 51);
+}
+
+void Scene4xx::sceneEntrySound() {
+ if (!_vm->_musicFlag)
+ return;
+
+ _vm->_sound->command(16);
+}
+
+void Scene4xx::setPlayerSpritesPrefix() {
+ _vm->_sound->command(5);
+
+ Common::String oldName = _game._player._spritesPrefix;
+ if (!_game._player._forcePrefix)
+ _game._player._spritesPrefix = "RAL";
+ if (oldName != _game._player._spritesPrefix)
+ _game._player._spritesChanged = true;
+
+ _game._player._scalingVelocity = true;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene401::Scene401(MADSEngine *vm) : Scene4xx(vm) {
+ _anim0ActvFl = false;
+ _frameInRoomFl = false;
+ _takingFrameInRoomFl = false;
+
+ _redFrameHotspotId = -1;
+ _greenFrameHostpotId = -1;
+ _blueFrameHotspotId = -1;
+ _yellowFrameHotspotId = -1;
+}
+
+void Scene401::synchronize(Common::Serializer &s) {
+ Scene4xx::synchronize(s);
+
+ s.syncAsByte(_anim0ActvFl);
+ s.syncAsByte(_frameInRoomFl);
+ s.syncAsByte(_takingFrameInRoomFl);
+
+ s.syncAsSint16LE(_redFrameHotspotId);
+ s.syncAsSint16LE(_greenFrameHostpotId);
+ s.syncAsSint16LE(_blueFrameHotspotId);
+ s.syncAsSint16LE(_yellowFrameHotspotId);
+}
+
+void Scene401::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_PUDDLE)
+ _scene->_variant = 1;
+
+ _scene->addActiveVocab(NOUN_RED_FRAME);
+ _scene->addActiveVocab(NOUN_YELLOW_FRAME);
+ _scene->addActiveVocab(NOUN_BLUE_FRAME);
+ _scene->addActiveVocab(NOUN_GREEN_FRAME);
+}
+
+void Scene401::enter() {
+ _game.initCatacombs();
+ _anim0ActvFl = false;
+
+ _scene->_hotspots.activate(NOUN_PUDDLE, false);
+ _scene->_hotspots.activate(NOUN_RATS_NEST, false);
+ _scene->_hotspots.activate(NOUN_SKULL, false);
+ _scene->_hotspots.activate(NOUN_POT, false);
+
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites("*RRD_9");
+ _globals._spriteIndexes[9] = _scene->_sprites.addSprites(formAnimName('f', 0));
+ _globals._spriteIndexes[10] = _scene->_sprites.addSprites(formAnimName('f', 1));
+ _globals._spriteIndexes[11] = _scene->_sprites.addSprites(formAnimName('f', 2));
+ _globals._spriteIndexes[12] = _scene->_sprites.addSprites(formAnimName('f', 3));
+
+ if (_game.exitCatacombs(0) == -1) {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('c', 1));
+ _scene->drawToBackground(_globals._spriteIndexes[1], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_ARCHWAY_TO_NORTH, false);
+ }
+
+ if (_game.exitCatacombs(3) == -1) {
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('c', 0));
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_ARCHWAY_TO_WEST, false);
+ }
+
+ if (_game.exitCatacombs(1) == -1) {
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('c', 2));
+ _scene->drawToBackground(_globals._spriteIndexes[2], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_ARCHWAY_TO_EAST, false);
+ }
+
+ if (_game.exitCatacombs(2) == -1)
+ _scene->_hotspots.activate(NOUN_MORE_CATACOMBS, false);
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_RAT_NEST) {
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('c', 4));
+ _scene->drawToBackground(_globals._spriteIndexes[4], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_RATS_NEST, true);
+ }
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_SKULL) {
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('c', 5));
+ _scene->drawToBackground(_globals._spriteIndexes[5], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_SKULL, true);
+ }
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_POT) {
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('c', 6));
+ _scene->drawToBackground(_globals._spriteIndexes[6], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_POT, true);
+ }
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_BRICK) {
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('c', 7));
+ _scene->drawToBackground(_globals._spriteIndexes[7], 1, Common::Point(-32000, -32000), 0, 100);
+ }
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_PUDDLE) {
+ _scene->_hotspots.activate(NOUN_PUDDLE, true);
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('d', 1), 0);
+ _anim0ActvFl = true;
+ }
+
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ switch (_globals[kCatacombsFrom]) {
+ case 0:
+ _game._player._playerPos = Common::Point(128, 78);
+ _game._player._facing = FACING_SOUTH;
+ _game._player.walk(Common::Point(128, 91), FACING_SOUTH);
+ break;
+
+ case 1:
+ _game._player._playerPos = Common::Point(311, 115);
+ _game._player._facing = FACING_WEST;
+ _game._player.walk(Common::Point(271, 123), FACING_WEST);
+ break;
+
+ case 2:
+ _game._player._playerPos = Common::Point(142, 146);
+ _game._player._facing = FACING_NORTH;
+ break;
+
+ case 3:
+ _game._player._playerPos = Common::Point(4, 113);
+ _game._player._facing = FACING_SOUTH;
+ _game._player.walk(Common::Point(48, 113), FACING_EAST);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (_game._objects[OBJ_RED_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[9] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[9], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _redFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_RED_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_redFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_game._objects[OBJ_GREEN_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[10] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[10], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _greenFrameHostpotId = _scene->_dynamicHotspots.add(NOUN_GREEN_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_greenFrameHostpotId , Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_game._objects[OBJ_BLUE_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[11] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[11], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[11], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _blueFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_BLUE_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_blueFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_game._objects[OBJ_YELLOW_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[12] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[12], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[12], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _yellowFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_YELLOW_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_yellowFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene401::step() {
+ if (_anim0ActvFl) {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == 20)
+ _scene->setAnimFrame(_globals._animationIndexes[0], 0);
+ }
+}
+
+void Scene401::actions() {
+ if (_action.isAction(VERB_PUT) && _action.isTarget(NOUN_FLOOR)) {
+ if (_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_BLUE_FRAME) || _action.isObject(NOUN_YELLOW_FRAME) || _action.isObject(NOUN_GREEN_FRAME)) {
+ if (_frameInRoomFl)
+ _vm->_dialogs->show(29);
+ else {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[8] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[8], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[8], 1, 5);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[8], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (_action.isObject(NOUN_RED_FRAME)) {
+ _game._objects.setRoom(OBJ_RED_FRAME, NOWHERE);
+ _game._objects[OBJ_RED_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[9] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[9], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _redFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_RED_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_redFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_action.isObject(NOUN_GREEN_FRAME)) {
+ _game._objects.setRoom(OBJ_GREEN_FRAME, NOWHERE);
+ _game._objects[OBJ_GREEN_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[10] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[10], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _greenFrameHostpotId = _scene->_dynamicHotspots.add(NOUN_GREEN_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_greenFrameHostpotId , Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME)) {
+ _game._objects.setRoom(OBJ_BLUE_FRAME, NOWHERE);
+ _game._objects[OBJ_BLUE_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[11] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[11], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[11], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _blueFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_BLUE_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_blueFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME)) {
+ _game._objects.setRoom(OBJ_YELLOW_FRAME, NOWHERE);
+ _game._objects[OBJ_YELLOW_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[12] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[12], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[12], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _yellowFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_YELLOW_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_yellowFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[8]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE)) {
+ if (_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_GREEN_FRAME) || _action.isObject(NOUN_BLUE_FRAME) || _action.isObject(NOUN_YELLOW_FRAME)) {
+ if ((_takingFrameInRoomFl || _game._trigger)) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[8] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[8], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[8], 1, 5);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[8], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (_action.isObject(NOUN_RED_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[9]);
+ _scene->_dynamicHotspots.remove(_redFrameHotspotId);
+ _game._objects.addToInventory(OBJ_RED_FRAME);
+ }
+
+ if (_action.isObject(NOUN_GREEN_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[10]);
+ _scene->_dynamicHotspots.remove(_greenFrameHostpotId );
+ _game._objects.addToInventory(OBJ_GREEN_FRAME);
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[11]);
+ _scene->_dynamicHotspots.remove(_blueFrameHotspotId);
+ _game._objects.addToInventory(OBJ_BLUE_FRAME);
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[12]);
+ _scene->_dynamicHotspots.remove(_yellowFrameHotspotId);
+ _game._objects.addToInventory(OBJ_YELLOW_FRAME);
+ }
+
+ _vm->_sound->command(26);
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[8]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+ }
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_ARCHWAY_TO_NORTH)) {
+ _game.moveCatacombs(0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_ARCHWAY_TO_WEST)) {
+ _game.moveCatacombs(3);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_EXIT_TO, NOUN_MORE_CATACOMBS)) {
+ _game.moveCatacombs(2);
+ if ((_game._difficulty == DIFFICULTY_HARD) && (_globals[kCatacombsRoom] == 31))
+ _globals[kPriestPistonPuke] = true;
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_ARCHWAY_TO_EAST)) {
+ _game.moveCatacombs(1);
+ if ((_game._difficulty == DIFFICULTY_EASY) && (_globals[kCatacombsRoom] == 24))
+ _globals[kPriestPistonPuke] = true;
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(40110);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(40111);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(40112);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_ARCHWAY)) {
+ _vm->_dialogs->show(40113);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_EXPOSED_BRICK)) {
+ _vm->_dialogs->show(40114);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_MORE_CATACOMBS)) {
+ _vm->_dialogs->show(40115);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BLOCKED_ARCHWAY)) {
+ _vm->_dialogs->show(40116);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PUDDLE)) {
+ _vm->_dialogs->show(40117);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RATS_NEST)) {
+ _vm->_dialogs->show(40118);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SKULL)) {
+ _vm->_dialogs->show(40120);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RED_FRAME) && !_game._objects.isInInventory(OBJ_RED_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_RED_FRAME, 802, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_GREEN_FRAME) && !_game._objects.isInInventory(OBJ_GREEN_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_GREEN_FRAME, 819, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME) && !_game._objects.isInInventory(OBJ_BLUE_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_BLUE_FRAME, 817, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME) && !_game._objects.isInInventory(OBJ_YELLOW_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_YELLOW_FRAME, 804, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+
+ if (_action.isObject(NOUN_BROKEN_POT)) {
+ _vm->_dialogs->show(40122);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_RATS_NEST)) {
+ _vm->_dialogs->show(40119);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_SKULL)) {
+ _vm->_dialogs->show(40121);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_BROKEN_POT)) {
+ _vm->_dialogs->show(40123);
+ _action._inProgress = false;
+ }
+}
+
+void Scene401::preActions() {
+ _frameInRoomFl = false;
+ _takingFrameInRoomFl = false;
+
+ if (_game._objects[OBJ_RED_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_RED_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_game._objects[OBJ_YELLOW_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_YELLOW_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_game._objects[OBJ_BLUE_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_BLUE_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_game._objects[OBJ_GREEN_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_GREEN_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_action.isAction(VERB_PUT) && _action.isTarget(NOUN_FLOOR)
+ && (_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_BLUE_FRAME)
+ || _action.isObject(NOUN_YELLOW_FRAME) || _action.isObject(NOUN_GREEN_FRAME))) {
+ if (_frameInRoomFl)
+ _game._player._needToWalk = false;
+ else {
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _game._player.walk(Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene403::Scene403(MADSEngine *vm) : Scene4xx(vm) {
+ _frameInRoomFl = false;
+ _takingFrameInRoomFl = false;
+
+ _redFrameHotspotId = -1;
+ _greenFrameHostpotId = -1;
+ _blueFrameHotspotId = -1;
+ _yellowFrameHotspotId = -1;
+}
+
+void Scene403::synchronize(Common::Serializer &s) {
+ Scene4xx::synchronize(s);
+
+ s.syncAsByte(_frameInRoomFl);
+ s.syncAsByte(_takingFrameInRoomFl);
+
+ s.syncAsSint16LE(_redFrameHotspotId);
+ s.syncAsSint16LE(_greenFrameHostpotId);
+ s.syncAsSint16LE(_blueFrameHotspotId);
+ s.syncAsSint16LE(_yellowFrameHotspotId);
+}
+
+void Scene403::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_HOLE)
+ _scene->_variant = 1;
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_PLANK)
+ _scene->_variant = 2;
+
+ _scene->addActiveVocab(NOUN_RED_FRAME);
+ _scene->addActiveVocab(NOUN_YELLOW_FRAME);
+ _scene->addActiveVocab(NOUN_BLUE_FRAME);
+ _scene->addActiveVocab(NOUN_GREEN_FRAME);
+}
+
+void Scene403::enter() {
+ _game.initCatacombs();
+
+ _scene->_hotspots.activate(NOUN_HOLE, false);
+ _scene->_hotspots.activate(NOUN_WEB, false);
+ _scene->_hotspots.activate(NOUN_RATS_NEST, false);
+ _scene->_hotspots.activate(NOUN_SKULL, false);
+ _scene->_hotspots.activate(NOUN_PLANK, false);
+ _scene->_hotspots.activate(NOUN_GATE, false);
+
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites("*RRD_9");
+ _globals._spriteIndexes[9] = _scene->_sprites.addSprites(formAnimName('f', 0));
+ _globals._spriteIndexes[10] = _scene->_sprites.addSprites(formAnimName('f', 1));
+ _globals._spriteIndexes[11] = _scene->_sprites.addSprites(formAnimName('f', 2));
+ _globals._spriteIndexes[12] = _scene->_sprites.addSprites(formAnimName('f', 3));
+
+ if (_game.exitCatacombs(0) == -1) {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('c', 1));
+ _scene->drawToBackground(_globals._spriteIndexes[1], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_ARCHWAY_TO_NORTH, false);
+ }
+
+ if (_game.exitCatacombs(3) == -1) {
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('c', 0));
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_ARCHWAY_TO_WEST, false);
+ }
+
+ if (_game.exitCatacombs(1) == -1) {
+ _scene->_hotspots.activate(NOUN_MORE_CATACOMBS, false);
+ _scene->_hotspots.activate(NOUN_GATE, true);
+ _globals._spriteIndexes[13] = _scene->_sprites.addSprites(formAnimName('c', 9));
+ _scene->drawToBackground(_globals._spriteIndexes[13], 1, Common::Point(-32000, -32000), 0, 100);
+ }
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_HOLE) {
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('c', 3));
+ _scene->drawToBackground(_globals._spriteIndexes[2], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_HOLE, true);
+ }
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_WEB) {
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('c', 4));
+ _scene->drawToBackground(_globals._spriteIndexes[3], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_WEB, true);
+ }
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_BRICK) {
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('c', 5));
+ _scene->drawToBackground(_globals._spriteIndexes[4], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activateAtPos(NOUN_EXPOSED_BRICK, false, Common::Point(178, 35));
+ }
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_RAT_NEST) {
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('c', 6));
+ _scene->drawToBackground(_globals._spriteIndexes[5], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_RATS_NEST, true);
+ }
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_SKULL) {
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('c', 7));
+ _scene->drawToBackground(_globals._spriteIndexes[6], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_SKULL, true);
+ }
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_PLANK) {
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('c', 8));
+ _scene->drawToBackground(_globals._spriteIndexes[7], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_PLANK, true);
+ }
+
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ switch (_globals[kCatacombsFrom]) {
+ case 0:
+ _game._player._playerPos = Common::Point(212, 86);
+ _game._player._facing = FACING_SOUTH;
+ _game._player.walk(Common::Point(212, 100), FACING_SOUTH);
+ break;
+
+ case 1:
+ _game._player.firstWalk(Common::Point(330, 126), FACING_EAST, Common::Point(305, 126), FACING_WEST, true);
+ break;
+
+ case 3:
+ _game._player._playerPos = Common::Point(3, 128);
+ _game._player._facing = FACING_SOUTH;
+ _game._player.walk(Common::Point(40, 128), FACING_EAST);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (_game._objects[OBJ_RED_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[9] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[9], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _redFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_RED_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_redFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_game._objects[OBJ_GREEN_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[10] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[10], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _greenFrameHostpotId = _scene->_dynamicHotspots.add(NOUN_GREEN_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_greenFrameHostpotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_game._objects[OBJ_BLUE_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[11] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[11], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[11], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _blueFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_BLUE_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_blueFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_game._objects[OBJ_YELLOW_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[12] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[12], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[12], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _yellowFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_YELLOW_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_yellowFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if ((_game._difficulty == DIFFICULTY_EASY) && (_globals[kCatacombsRoom] == 19))
+ _scene->_sequences.addTimer(120, 60);
+
+ sceneEntrySound();
+}
+
+void Scene403::step() {
+ if (_game._trigger == 60)
+ _vm->_dialogs->show(31);
+}
+
+void Scene403::actions() {
+ if (_action.isAction(VERB_PUT) && _action.isTarget(NOUN_FLOOR)
+ && (_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_BLUE_FRAME) || _action.isObject(NOUN_YELLOW_FRAME) || _action.isObject(NOUN_GREEN_FRAME))) {
+ if (_frameInRoomFl)
+ _vm->_dialogs->show(29);
+ else {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[8] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[8], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[8], 1, 5);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[8], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (_action.isObject(NOUN_RED_FRAME)) {
+ _game._objects.setRoom(OBJ_RED_FRAME, NOWHERE);
+ _game._objects[OBJ_RED_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[9] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[9], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _redFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_RED_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_redFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_action.isObject(NOUN_GREEN_FRAME)) {
+ _game._objects.setRoom(OBJ_GREEN_FRAME, NOWHERE);
+ _game._objects[OBJ_GREEN_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[10] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[10], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _greenFrameHostpotId = _scene->_dynamicHotspots.add(NOUN_GREEN_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_greenFrameHostpotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME)) {
+ _game._objects.setRoom(OBJ_BLUE_FRAME, NOWHERE);
+ _game._objects[OBJ_BLUE_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[11] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[11], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[11], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _blueFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_BLUE_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_blueFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME)) {
+ _game._objects.setRoom(OBJ_YELLOW_FRAME, NOWHERE);
+ _game._objects[OBJ_YELLOW_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[12] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[12], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[12], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _yellowFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_YELLOW_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_yellowFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[8]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE)
+ && (_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_GREEN_FRAME) || _action.isObject(NOUN_BLUE_FRAME) || _action.isObject(NOUN_YELLOW_FRAME))) {
+ if ((_takingFrameInRoomFl || _game._trigger)) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[8] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[8], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[8], 1, 5);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[8], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (_action.isObject(NOUN_RED_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[9]);
+ _scene->_dynamicHotspots.remove(_redFrameHotspotId);
+ _game._objects.addToInventory(OBJ_RED_FRAME);
+ }
+
+ if (_action.isObject(NOUN_GREEN_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[10]);
+ _scene->_dynamicHotspots.remove(_greenFrameHostpotId);
+ _game._objects.addToInventory(OBJ_GREEN_FRAME);
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[11]);
+ _scene->_dynamicHotspots.remove(_blueFrameHotspotId);
+ _game._objects.addToInventory(OBJ_BLUE_FRAME);
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[12]);
+ _scene->_dynamicHotspots.remove(_yellowFrameHotspotId);
+ _game._objects.addToInventory(OBJ_YELLOW_FRAME);
+ }
+
+ _vm->_sound->command(26);
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[8]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_ARCHWAY_TO_NORTH)) {
+ _game.moveCatacombs(0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_ARCHWAY_TO_WEST)) {
+ _game.moveCatacombs(3);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(40310);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(40311);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(40312);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_ARCHWAY)) {
+ _vm->_dialogs->show(40313);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_EXPOSED_BRICK)) {
+ _vm->_dialogs->show(40314);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_MORE_CATACOMBS)) {
+ _vm->_dialogs->show(40315);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BLOCKED_ARCHWAY)) {
+ _vm->_dialogs->show(40316);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RATS_NEST)) {
+ _vm->_dialogs->show(40318);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SKULL)) {
+ _vm->_dialogs->show(40320);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_HOLE)) {
+ _vm->_dialogs->show(40323);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WEB)) {
+ _vm->_dialogs->show(40324);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RED_FRAME) && !_game._objects.isInInventory(OBJ_RED_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_RED_FRAME, 802, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_GREEN_FRAME) && !_game._objects.isInInventory(OBJ_GREEN_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_GREEN_FRAME, 819, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME) && !_game._objects.isInInventory(OBJ_BLUE_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_BLUE_FRAME, 817, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME) && !_game._objects.isInInventory(OBJ_YELLOW_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_YELLOW_FRAME, 804, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_GATE)) {
+ _vm->_dialogs->show(45330);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PLANK)) {
+ _vm->_dialogs->show(40325);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_GATE)) {
+ _vm->_dialogs->show(45331);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_RATS_NEST)) {
+ _vm->_dialogs->show(40319);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_SKULL)) {
+ _vm->_dialogs->show(40321);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_PLANK)) {
+ _vm->_dialogs->show(40326);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene403::preActions() {
+ if (_action.isAction(VERB_EXIT_TO, NOUN_MORE_CATACOMBS))
+ _game.moveCatacombs(1);
+
+ _frameInRoomFl = false;
+ _takingFrameInRoomFl = false;
+
+ if (_game._objects[OBJ_RED_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_RED_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_game._objects[OBJ_YELLOW_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_YELLOW_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_game._objects[OBJ_BLUE_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_BLUE_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_game._objects[OBJ_GREEN_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_GREEN_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_action.isAction(VERB_PUT) && _action.isTarget(NOUN_FLOOR)
+ && (_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_BLUE_FRAME) || _action.isObject(NOUN_YELLOW_FRAME) || _action.isObject(NOUN_GREEN_FRAME))) {
+ if (_frameInRoomFl)
+ _game._player._needToWalk = false;
+ else {
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _game._player.walk(Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene404::Scene404(MADSEngine *vm) : Scene4xx(vm) {
+ _frameInRoomFl = false;
+ _takingFrameInRoomFl = false;
+ _anim0ActvFl = false;
+
+ _redFrameHotspotId = -1;
+ _greenFrameHostpotId = -1;
+ _blueFrameHotspotId = -1;
+ _yellowFrameHotspotId = -1;
+}
+
+void Scene404::synchronize(Common::Serializer &s) {
+ Scene4xx::synchronize(s);
+
+ s.syncAsByte(_frameInRoomFl);
+ s.syncAsByte(_takingFrameInRoomFl);
+ s.syncAsByte(_anim0ActvFl);
+
+ s.syncAsSint16LE(_redFrameHotspotId);
+ s.syncAsSint16LE(_greenFrameHostpotId);
+ s.syncAsSint16LE(_blueFrameHotspotId);
+ s.syncAsSint16LE(_yellowFrameHotspotId);
+}
+
+void Scene404::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_BLOCK)
+ _scene->_variant = 1;
+
+ _scene->addActiveVocab(NOUN_RED_FRAME);
+ _scene->addActiveVocab(NOUN_YELLOW_FRAME);
+ _scene->addActiveVocab(NOUN_BLUE_FRAME);
+ _scene->addActiveVocab(NOUN_GREEN_FRAME);
+}
+
+void Scene404::enter() {
+ _game.initCatacombs();
+
+ _scene->_hotspots.activate(NOUN_RATS_NEST, false);
+ _scene->_hotspots.activate(NOUN_WEB, false);
+ _scene->_hotspots.activate(NOUN_BROKEN_POT, false);
+ _scene->_hotspots.activate(NOUN_BLOCK, false);
+ _scene->_hotspots.activate(NOUN_PUDDLE, false);
+
+ _anim0ActvFl = false;
+
+ _globals._spriteIndexes[9] = _scene->_sprites.addSprites("*RRD_9");
+ _globals._spriteIndexes[10] = _scene->_sprites.addSprites(formAnimName('f', 0));
+ _globals._spriteIndexes[11] = _scene->_sprites.addSprites(formAnimName('f', 1));
+ _globals._spriteIndexes[12] = _scene->_sprites.addSprites(formAnimName('f', 2));
+ _globals._spriteIndexes[13] = _scene->_sprites.addSprites(formAnimName('f', 3));
+
+
+ if (_game.exitCatacombs(0) == -1) {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('c', 1));
+ _scene->drawToBackground(_globals._spriteIndexes[1], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_ARCHWAY_TO_NORTH, false);
+ }
+
+ if (_game.exitCatacombs(3) == -1) {
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('c', 0));
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_ARCHWAY_TO_WEST, false);
+ }
+
+ if (_game.exitCatacombs(1) == -1) {
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('c', 2));
+ _scene->drawToBackground(_globals._spriteIndexes[2], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_ARCHWAY_TO_EAST, false);
+ }
+
+ if (_game.exitCatacombs(2) == -1)
+ _scene->_hotspots.activate(NOUN_MORE_CATACOMBS, false);
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_RAT_NEST) {
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('c', 3));
+ _scene->drawToBackground(_globals._spriteIndexes[3], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_RATS_NEST, true);
+ }
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_WEB) {
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('c', 4));
+ _scene->drawToBackground(_globals._spriteIndexes[4], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_WEB, true);
+ }
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_POT) {
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('c', 5));
+ _scene->drawToBackground(_globals._spriteIndexes[5], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_BROKEN_POT, true);
+ }
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_BLOCK) {
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('c', 7));
+ _scene->drawToBackground(_globals._spriteIndexes[7], 1, Common::Point(-32000, -32000), 0, 100);
+ }
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_FALLEN_BLOCK) {
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('c', 8));
+ _scene->drawToBackground(_globals._spriteIndexes[8], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_BLOCK, true);
+ }
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_PUDDLE) {
+ _scene->_hotspots.activate(NOUN_PUDDLE, true);
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('d', 1), 0);
+ _anim0ActvFl = true;
+ }
+
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ switch (_globals[kCatacombsFrom]) {
+ case 0:
+ _game._player._playerPos = Common::Point(156, 98);
+ _game._player._facing = FACING_SOUTH;
+ _game._player.walk(Common::Point(156, 117), FACING_SOUTH);
+ break;
+
+ case 1:
+ _game._player._playerPos = Common::Point(319, 135);
+ _game._player._facing = FACING_WEST;
+ _game._player.walk(Common::Point(279, 135), FACING_WEST);
+ break;
+
+ case 2:
+ _game._player._playerPos = Common::Point(175, 147);
+ _game._player._facing = FACING_NORTH;
+ break;
+
+ case 3:
+ _game._player._playerPos = Common::Point(17, 131);
+ _game._player._facing = FACING_SOUTH;
+ _game._player.walk(Common::Point(60, 131), FACING_EAST);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (_game._objects[OBJ_RED_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[10] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[10], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 14);
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[10]]->getFramePos(0);
+ _redFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_RED_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_redFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_game._objects[OBJ_GREEN_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[11] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[11], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[11], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[10]]->getFramePos(0);
+ _greenFrameHostpotId = _scene->_dynamicHotspots.add(NOUN_GREEN_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_greenFrameHostpotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_game._objects[OBJ_BLUE_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[12] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[12], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[12], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[10]]->getFramePos(0);
+ _blueFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_BLUE_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_blueFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_game._objects[OBJ_YELLOW_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[13] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[13], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[10]]->getFramePos(0);
+ _yellowFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_YELLOW_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_yellowFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_globals[kPriestPistonPuke])
+ _scene->_sequences.addTimer(120, 60);
+
+ sceneEntrySound();
+}
+
+void Scene404::step() {
+ if (_anim0ActvFl) {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == 20)
+ _scene->setAnimFrame(_globals._animationIndexes[0], 0);
+ }
+
+ if (_game._trigger == 60) {
+ _vm->_dialogs->show(30);
+ _globals[kPriestPistonPuke] = false;
+ }
+}
+
+void Scene404::actions() {
+ if (_action.isAction(VERB_PUT) && _action.isTarget(NOUN_FLOOR)
+ && (_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_BLUE_FRAME) || _action.isObject(NOUN_YELLOW_FRAME) || _action.isObject(NOUN_GREEN_FRAME))) {
+ if (_frameInRoomFl)
+ _vm->_dialogs->show(29);
+ else {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[9] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[9], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[9], 1, 5);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[9], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[9], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[9], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (_action.isObject(NOUN_RED_FRAME)) {
+ _game._objects.setRoom(OBJ_RED_FRAME, NOWHERE);
+ _game._objects[OBJ_RED_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[10] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[10], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[10]]->getFramePos(0);
+ _redFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_RED_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_redFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_action.isObject(NOUN_GREEN_FRAME)) {
+ _game._objects.setRoom(OBJ_GREEN_FRAME, NOWHERE);
+ _game._objects[OBJ_GREEN_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[11] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[11], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[11], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[10]]->getFramePos(0);
+ _greenFrameHostpotId = _scene->_dynamicHotspots.add(NOUN_GREEN_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_greenFrameHostpotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME)) {
+ _game._objects.setRoom(OBJ_BLUE_FRAME, NOWHERE);
+ _game._objects[OBJ_BLUE_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[12] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[12], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[12], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[10]]->getFramePos(0);
+ _blueFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_BLUE_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_blueFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME)) {
+ _game._objects.setRoom(OBJ_YELLOW_FRAME, NOWHERE);
+ _game._objects[OBJ_YELLOW_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[13] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[13], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[10]]->getFramePos(0);
+ _yellowFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_YELLOW_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_yellowFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[9]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE)) {
+ if ((_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_GREEN_FRAME) || _action.isObject(NOUN_BLUE_FRAME) || _action.isObject(NOUN_YELLOW_FRAME)) && (_takingFrameInRoomFl || _game._trigger)) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[9] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[9], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[9], 1, 5);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[9], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[9], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[9], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (_action.isObject(NOUN_RED_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[10]);
+ _scene->_dynamicHotspots.remove(_redFrameHotspotId);
+ _game._objects.addToInventory(OBJ_RED_FRAME);
+ }
+
+ if (_action.isObject(NOUN_GREEN_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[11]);
+ _scene->_dynamicHotspots.remove(_greenFrameHostpotId);
+ _game._objects.addToInventory(OBJ_GREEN_FRAME);
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[12]);
+ _scene->_dynamicHotspots.remove(_blueFrameHotspotId);
+ _game._objects.addToInventory(OBJ_BLUE_FRAME);
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[13]);
+ _scene->_dynamicHotspots.remove(_yellowFrameHotspotId);
+ _game._objects.addToInventory(OBJ_YELLOW_FRAME);
+ }
+
+ _vm->_sound->command(26);
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[9]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_ARCHWAY_TO_NORTH)) {
+ _game.moveCatacombs(0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_ARCHWAY_TO_WEST)) {
+ _game.moveCatacombs(3);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_EXIT_TO, NOUN_MORE_CATACOMBS)) {
+ _game.moveCatacombs(2);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_ARCHWAY_TO_EAST)) {
+ _game.moveCatacombs(1);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(40410);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(40411);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(40412);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_ARCHWAY)) {
+ _vm->_dialogs->show(40413);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_EXPOSED_BRICK)) {
+ _vm->_dialogs->show(40414);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_MORE_CATACOMBS)) {
+ _vm->_dialogs->show(40415);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PUDDLE)) {
+ _vm->_dialogs->show(40417);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RATS_NEST)) {
+ _vm->_dialogs->show(40418);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BROKEN_POT)) {
+ _vm->_dialogs->show(40421);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WEB)) {
+ _vm->_dialogs->show(40424);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RED_FRAME) && !_game._objects.isInInventory(OBJ_RED_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_RED_FRAME, 802, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_GREEN_FRAME) && !_game._objects.isInInventory(OBJ_GREEN_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_GREEN_FRAME, 819, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME) && !_game._objects.isInInventory(OBJ_BLUE_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_BLUE_FRAME, 817, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME) && !_game._objects.isInInventory(OBJ_YELLOW_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_YELLOW_FRAME, 804, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BLOCK)) {
+ _vm->_dialogs->show(40430);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_RATS_NEST)) {
+ _vm->_dialogs->show(40419);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_BROKEN_POT)) {
+ _vm->_dialogs->show(40422);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_BLOCK)) {
+ _vm->_dialogs->show(40431);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene404::preActions() {
+ _frameInRoomFl = false;
+ _takingFrameInRoomFl = false;
+
+ if (_game._objects[OBJ_RED_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_RED_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_game._objects[OBJ_YELLOW_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_YELLOW_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_game._objects[OBJ_BLUE_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_BLUE_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_game._objects[OBJ_GREEN_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_GREEN_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_action.isAction(VERB_PUT) && _action.isTarget(NOUN_FLOOR)
+ && (_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_BLUE_FRAME) || _action.isObject(NOUN_YELLOW_FRAME) || _action.isObject(NOUN_GREEN_FRAME))) {
+ if (_frameInRoomFl)
+ _game._player._needToWalk = false;
+ else {
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[10]]->getFramePos(0);
+ _game._player.walk(Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene406::Scene406(MADSEngine *vm) : Scene4xx(vm) {
+ _frameInRoomFl = false;
+ _takingFrameInRoomFl = false;
+
+ _redFrameHotspotId = -1;
+ _greenFrameHostpotId = -1;
+ _blueFrameHotspotId = -1;
+ _yellowFrameHotspotId = -1;
+}
+
+void Scene406::synchronize(Common::Serializer &s) {
+ Scene4xx::synchronize(s);
+
+ s.syncAsByte(_frameInRoomFl);
+ s.syncAsByte(_takingFrameInRoomFl);
+
+ s.syncAsSint16LE(_redFrameHotspotId);
+ s.syncAsSint16LE(_greenFrameHostpotId);
+ s.syncAsSint16LE(_blueFrameHotspotId);
+ s.syncAsSint16LE(_yellowFrameHotspotId);
+}
+
+void Scene406::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ _scene->addActiveVocab(NOUN_RED_FRAME);
+ _scene->addActiveVocab(NOUN_YELLOW_FRAME);
+ _scene->addActiveVocab(NOUN_BLUE_FRAME);
+ _scene->addActiveVocab(NOUN_GREEN_FRAME);
+}
+
+void Scene406::enter() {
+ _game.initCatacombs();
+
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites("*RRD_9");
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('f', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('f', 1));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('f', 2));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('f', 3));
+
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ switch (_globals[kCatacombsFrom]) {
+ case 1:
+ _game._player._playerPos = Common::Point(310, 118);
+ _game._player._facing = FACING_WEST;
+ _game._player.walk(Common::Point(271, 118), FACING_WEST);
+ break;
+
+ case 3:
+ _game._player._playerPos = Common::Point(20, 122);
+ _game._player._facing = FACING_SOUTH;
+ _game._player.walk(Common::Point(66, 122), FACING_EAST);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (_game._objects[OBJ_RED_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[1]]->getFramePos(0);
+ _redFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_RED_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_redFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_game._objects[OBJ_GREEN_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[1]]->getFramePos(0);
+ _greenFrameHostpotId = _scene->_dynamicHotspots.add(NOUN_GREEN_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_greenFrameHostpotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_game._objects[OBJ_BLUE_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[1]]->getFramePos(0);
+ _blueFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_BLUE_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_blueFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_game._objects[OBJ_YELLOW_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[4] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[4], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[1]]->getFramePos(0);
+ _yellowFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_YELLOW_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_yellowFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene406::step() {
+}
+
+void Scene406::actions() {
+ if (_action.isAction(VERB_PUT) && _action.isTarget(NOUN_FLOOR)
+ && (_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_BLUE_FRAME) || _action.isObject(NOUN_YELLOW_FRAME) || _action.isObject(NOUN_GREEN_FRAME))) {
+ if (_frameInRoomFl)
+ _vm->_dialogs->show(29);
+ else {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[0] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[0], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], 1, 5);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[0], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (_action.isObject(NOUN_RED_FRAME)) {
+ _game._objects.setRoom(OBJ_RED_FRAME, NOWHERE);
+ _game._objects[OBJ_RED_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[1]]->getFramePos(0);
+ _redFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_RED_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_redFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_action.isObject(NOUN_GREEN_FRAME)) {
+ _game._objects.setRoom(OBJ_GREEN_FRAME, NOWHERE);
+ _game._objects[OBJ_GREEN_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[1]]->getFramePos(0);
+ _greenFrameHostpotId = _scene->_dynamicHotspots.add(NOUN_GREEN_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_greenFrameHostpotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME)) {
+ _game._objects.setRoom(OBJ_BLUE_FRAME, NOWHERE);
+ _game._objects[OBJ_BLUE_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[1]]->getFramePos(0);
+ _blueFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_BLUE_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_blueFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME)) {
+ _game._objects.setRoom(OBJ_YELLOW_FRAME, NOWHERE);
+ _game._objects[OBJ_YELLOW_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[4] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[4], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[1]]->getFramePos(0);
+ _yellowFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_YELLOW_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_yellowFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[0]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE)
+ && (_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_GREEN_FRAME) || _action.isObject(NOUN_BLUE_FRAME) || _action.isObject(NOUN_YELLOW_FRAME))) {
+ if ((_takingFrameInRoomFl || _game._trigger)) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[0] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[0], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], 1, 5);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[0], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (_action.isObject(NOUN_RED_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[1]);
+ _scene->_dynamicHotspots.remove(_redFrameHotspotId);
+ _game._objects.addToInventory(OBJ_RED_FRAME);
+ }
+
+ if (_action.isObject(NOUN_GREEN_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _scene->_dynamicHotspots.remove(_greenFrameHostpotId);
+ _game._objects.addToInventory(OBJ_GREEN_FRAME);
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[3]);
+ _scene->_dynamicHotspots.remove(_blueFrameHotspotId);
+ _game._objects.addToInventory(OBJ_BLUE_FRAME);
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[4]);
+ _scene->_dynamicHotspots.remove(_yellowFrameHotspotId);
+ _game._objects.addToInventory(OBJ_YELLOW_FRAME);
+ }
+
+ _vm->_sound->command(26);
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[0]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_ARCHWAY_TO_WEST)) {
+ _game.moveCatacombs(3);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_ARCHWAY_TO_EAST)) {
+ _game.moveCatacombs(1);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(40610);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(40611);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(40612);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_ARCHWAY)) {
+ _vm->_dialogs->show(40613);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_EXPOSED_BRICK)) {
+ _vm->_dialogs->show(40614);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_MORE_CATACOMBS)) {
+ _vm->_dialogs->show(40615);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BLOCKED_ARCHWAY)) {
+ _vm->_dialogs->show(40616);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RED_FRAME) && !_game._objects.isInInventory(OBJ_RED_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_RED_FRAME, 802, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_GREEN_FRAME) && !_game._objects.isInInventory(OBJ_GREEN_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_GREEN_FRAME, 819, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME) && !_game._objects.isInInventory(OBJ_BLUE_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_BLUE_FRAME, 817, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME) && !_game._objects.isInInventory(OBJ_YELLOW_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_YELLOW_FRAME, 804, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_GRATE)) {
+ _vm->_dialogs->show(40617);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_GRATE) || _action.isAction(VERB_PUSH, NOUN_GRATE) || _action.isAction(VERB_PULL, NOUN_GRATE)) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], true, 5, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], -1, -2);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[0], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 2:
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], true, -2);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[0], true);
+ _scene->_sequences.addTimer(30, 3);
+ break;
+
+ case 3:
+ _scene->deleteSequence(_globals._sequenceIndexes[0]);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[0], true, 5, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], -1, -2);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[0], false);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 4);
+ break;
+
+ case 4:
+ _game._player._visible = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[0]);
+ _scene->_sequences.addTimer(6, 5);
+ break;
+
+ case 5:
+ _game._player._stepEnabled = true;
+ _vm->_dialogs->show(40618);
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ }
+}
+
+void Scene406::preActions() {
+ _frameInRoomFl = false;
+ _takingFrameInRoomFl = false;
+
+ if (_game._objects[OBJ_RED_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_RED_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_game._objects[OBJ_YELLOW_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_YELLOW_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_game._objects[OBJ_BLUE_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_BLUE_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_game._objects[OBJ_GREEN_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_GREEN_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_action.isAction(VERB_PUT) && _action.isTarget(NOUN_FLOOR)
+ && (_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_BLUE_FRAME) || _action.isObject(NOUN_YELLOW_FRAME) || _action.isObject(NOUN_GREEN_FRAME))) {
+ if (_frameInRoomFl)
+ _game._player._needToWalk = false;
+ else {
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[1]]->getFramePos(0);
+ pos.x += 12;
+ _game._player.walk(pos, FACING_NORTHWEST);
+ }
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene407::Scene407(MADSEngine *vm) : Scene4xx(vm) {
+ _frameInRoomFl = false;
+ _takingFrameInRoomFl = false;
+
+ _redFrameHotspotId = -1;
+ _greenFrameHotspotId = -1;
+ _blueFrameHotspotId = -1;
+ _yellowFrameHotspotId = -1;
+}
+
+void Scene407::synchronize(Common::Serializer &s) {
+ Scene4xx::synchronize(s);
+
+ s.syncAsByte(_frameInRoomFl);
+ s.syncAsByte(_takingFrameInRoomFl);
+
+ s.syncAsSint16LE(_redFrameHotspotId);
+ s.syncAsSint16LE(_greenFrameHotspotId);
+ s.syncAsSint16LE(_blueFrameHotspotId);
+ s.syncAsSint16LE(_yellowFrameHotspotId);
+}
+
+void Scene407::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ _scene->addActiveVocab(NOUN_RED_FRAME);
+ _scene->addActiveVocab(NOUN_YELLOW_FRAME);
+ _scene->addActiveVocab(NOUN_BLUE_FRAME);
+ _scene->addActiveVocab(NOUN_GREEN_FRAME);
+}
+
+void Scene407::enter() {
+ _game.initCatacombs();
+
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites("*RRD_9");
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('f', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('f', 1));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('f', 2));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('f', 3));
+
+ if (_game.exitCatacombs(3) == -1) {
+ _scene->_hotspots.activateAtPos(NOUN_MORE_CATACOMBS, false, Common::Point(9, 46));
+ _scene->_hotspots.activateAtPos(NOUN_MORE_CATACOMBS, false, Common::Point(8, 138));
+ _scene->_hotspots.activateAtPos(NOUN_MORE_CATACOMBS, false, Common::Point(12, 149));
+ _scene->_hotspots.activateAtPos(NOUN_MORE_CATACOMBS, false, Common::Point(0, 151));
+ }
+
+ if (_game.exitCatacombs(1) == -1) {
+ _scene->_hotspots.activateAtPos(NOUN_MORE_CATACOMBS, false, Common::Point(310, 107));
+ _scene->_hotspots.activateAtPos(NOUN_MORE_CATACOMBS, false, Common::Point(308, 175));
+ _scene->_hotspots.activateAtPos(NOUN_MORE_CATACOMBS, false, Common::Point(308, 146));
+ _scene->_hotspots.activateAtPos(NOUN_MORE_CATACOMBS, false, Common::Point(309, 152));
+ }
+
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ switch (_globals[kCatacombsFrom]) {
+ case 0:
+ _game._player._playerPos = Common::Point(197, 14);
+ _game._player._facing = FACING_WEST;
+ _game._player.walk(Common::Point(181, 14), FACING_WEST);
+ break;
+
+ case 1:
+ _game._player.firstWalk(Common::Point(330, 146), FACING_WEST, Common::Point(298, 146), FACING_WEST, true);
+ break;
+
+ case 2:
+ _game._player._playerPos = Common::Point(147, 14);
+ _game._player._facing = FACING_EAST;
+ _game._player.walk(Common::Point(165, 14), FACING_EAST);
+ break;
+
+ case 3:
+ _game._player.firstWalk(Common::Point(-20, 143), FACING_WEST, Common::Point(20, 143), FACING_WEST, true);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (_game._objects[OBJ_RED_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[1]]->getFramePos(0);
+ _redFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_RED_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_redFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_game._objects[OBJ_GREEN_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[1]]->getFramePos(0);
+ _greenFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_GREEN_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_greenFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_game._objects[OBJ_BLUE_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[1]]->getFramePos(0);
+ _blueFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_BLUE_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_blueFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_game._objects[OBJ_YELLOW_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[4] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[4], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[1]]->getFramePos(0);
+ _yellowFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_YELLOW_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_yellowFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene407::step() {
+}
+
+void Scene407::actions() {
+ if (_action.isAction(VERB_WALK_TO, NOUN_WALL) && (_game._player._playerPos.y > 30) && (_scene->_customDest.x > 160) && (_scene->_customDest.x < 190)) {
+ _vm->_dialogs->show(40718);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_TO) && (_scene->_customDest.x < 130) && (_game._player._playerPos.y < 30)) {
+ _vm->_dialogs->show(40718);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_TO) && (_scene->_customDest.x > 203) && (_game._player._playerPos.y < 30)) {
+ _vm->_dialogs->show(40718);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_TO, NOUN_FLOOR)) {
+ if ((_game._player._playerPos.y < 30) && (_scene->_customDest.y > 29)) {
+ _vm->_dialogs->show(40718);
+ _action._inProgress = false;
+ return;
+ } else if ((_game._player._playerPos.y > 29) && (_scene->_customDest.y < 30)) {
+ _vm->_dialogs->show(40718);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_PUT) && _action.isTarget(NOUN_FLOOR)) {
+ if (_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_BLUE_FRAME) || _action.isObject(NOUN_YELLOW_FRAME) || _action.isObject(NOUN_GREEN_FRAME)) {
+ if ((_game._player._playerPos.y < 30) && (_scene->_customDest.y < 30))
+ _vm->_dialogs->show(40717);
+ else if ((_game._player._playerPos.y < 30) && (_scene->_customDest.y > 29))
+ _vm->_dialogs->show(40718);
+ else if (_frameInRoomFl)
+ _vm->_dialogs->show(29);
+ else {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[0] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[0], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], 1, 5);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[0], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (_action.isObject(NOUN_RED_FRAME)) {
+ _game._objects.setRoom(OBJ_RED_FRAME, NOWHERE);
+ _game._objects[OBJ_RED_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[1]]->getFramePos(0);
+ _redFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_RED_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_redFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_action.isObject(NOUN_GREEN_FRAME)) {
+ _game._objects.setRoom(OBJ_GREEN_FRAME, NOWHERE);
+ _game._objects[OBJ_GREEN_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[1]]->getFramePos(0);
+ _greenFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_GREEN_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_greenFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME)) {
+ _game._objects.setRoom(OBJ_BLUE_FRAME, NOWHERE);
+ _game._objects[OBJ_BLUE_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[1]]->getFramePos(0);
+ _blueFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_BLUE_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_blueFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME)) {
+ _game._objects.setRoom(OBJ_YELLOW_FRAME, NOWHERE);
+ _game._objects[OBJ_YELLOW_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[4] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[4], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[1]]->getFramePos(0);
+ _yellowFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_YELLOW_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_yellowFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[0]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE)) {
+ if (_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_GREEN_FRAME) || _action.isObject(NOUN_BLUE_FRAME) || _action.isObject(NOUN_YELLOW_FRAME)) {
+ if ((_takingFrameInRoomFl || _game._trigger)) {
+ if (_game._player._playerPos.y < 30)
+ _vm->_dialogs->show(40718);
+ else {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[0] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[0], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], 1, 5);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[0], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (_action.isObject(NOUN_RED_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[1]);
+ _scene->_dynamicHotspots.remove(_redFrameHotspotId);
+ _game._objects.addToInventory(OBJ_RED_FRAME);
+ }
+
+ if (_action.isObject(NOUN_GREEN_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _scene->_dynamicHotspots.remove(_greenFrameHotspotId);
+ _game._objects.addToInventory(OBJ_GREEN_FRAME);
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[3]);
+ _scene->_dynamicHotspots.remove(_blueFrameHotspotId);
+ _game._objects.addToInventory(OBJ_BLUE_FRAME);
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[4]);
+ _scene->_dynamicHotspots.remove(_yellowFrameHotspotId);
+ _game._objects.addToInventory(OBJ_YELLOW_FRAME);
+ }
+
+ _vm->_sound->command(26);
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[0]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ _action._inProgress = false;
+ return;
+ }
+ }
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_ARCHWAY_TO_WEST)) {
+ if (_game._player._playerPos.y < 30)
+ _game.moveCatacombs(2);
+ else
+ _vm->_dialogs->show(40718);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_ARCHWAY_TO_EAST)) {
+ if (_game._player._playerPos.y < 30)
+ _game.moveCatacombs(0);
+ else
+ _vm->_dialogs->show(40718);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_EXIT_TO, NOUN_MORE_CATACOMBS) && (_game._player._playerPos.y < 30)) {
+ _vm->_dialogs->show(40718);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(40710);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(40711);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(40712);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_ARCHWAY)) {
+ _vm->_dialogs->show(40713);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_MORE_CATACOMBS)) {
+ _vm->_dialogs->show(40714);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_COLUMN)) {
+ _vm->_dialogs->show(40715);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RED_FRAME) && !_game._objects.isInInventory(OBJ_RED_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_RED_FRAME, 802, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_GREEN_FRAME) && !_game._objects.isInInventory(OBJ_GREEN_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_GREEN_FRAME, 818, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME) && !_game._objects.isInInventory(OBJ_BLUE_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_BLUE_FRAME, 817, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME) && !_game._objects.isInInventory(OBJ_YELLOW_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_YELLOW_FRAME, 804, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LAKE)) {
+ _vm->_dialogs->show(40716);
+ _action._inProgress = false;
+ }
+ }
+}
+
+void Scene407::preActions() {
+ if (_action.isAction(VERB_EXIT_TO, NOUN_MORE_CATACOMBS)) {
+ if (_game._player._playerPos.y > 30) {
+ if (_scene->_customDest.x < 100)
+ _game.moveCatacombs(3);
+ else
+ _game.moveCatacombs(1);
+ } else
+ _game._player._needToWalk = false;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH) && (_game._player._playerPos.y > 30))
+ _game._player._needToWalk = false;
+
+ _frameInRoomFl = false;
+ _takingFrameInRoomFl = false;
+
+ if (_game._objects[OBJ_RED_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_RED_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_game._objects[OBJ_YELLOW_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_YELLOW_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_game._objects[OBJ_BLUE_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_BLUE_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_game._objects[OBJ_GREEN_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_GREEN_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_action.isAction(VERB_PUT) && _action.isTarget(NOUN_FLOOR)
+ && (_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_BLUE_FRAME) || _action.isObject(NOUN_YELLOW_FRAME) || _action.isObject(NOUN_GREEN_FRAME))) {
+ if ((_frameInRoomFl) || (_game._player._playerPos.y < 30) || (_scene->_customDest.y < 30))
+ _game._player._needToWalk = false;
+ else {
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[1]]->getFramePos(0);
+ _game._player.walk(Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE)
+ && (_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_GREEN_FRAME) || _action.isObject(NOUN_BLUE_FRAME) || _action.isObject(NOUN_YELLOW_FRAME))) {
+ if (_takingFrameInRoomFl && (_game._player._playerPos.y < 30))
+ _game._player._needToWalk = false;
+ }
+
+ if (_action.isAction(VERB_WALK_ACROSS, NOUN_FLOOR) && (_game._player._playerPos.y < 30) && (_scene->_customDest.y > 29))
+ _game._player._needToWalk = false;
+
+ if (_action.isAction(VERB_WALK_TO, NOUN_LAKE) && (_game._player._playerPos.y < 30))
+ _game._player.walk(Common::Point(172, 18), FACING_SOUTH);
+
+ if (_action.isAction(VERB_WALK_TO) && (_scene->_customDest.x < 130) && (_game._player._playerPos.y < 30))
+ _game._player._needToWalk = false;
+
+ if (_action.isAction(VERB_WALK_TO) && (_scene->_customDest.x > 203) && (_game._player._playerPos.y < 30))
+ _game._player._needToWalk = false;
+
+ if (_action.isAction(VERB_WALK_TO, NOUN_WALL) && (_game._player._playerPos.y > 30) && (_scene->_customDest.x > 160) && (_scene->_customDest.x < 190))
+ _game._player._needToWalk = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene408::Scene408(MADSEngine *vm) : Scene4xx(vm) {
+ _frameInRoomFl = false;
+ _takingFrameInRoomFl = false;
+
+ _redFrameHotspotId = -1;
+ _greenFrameHotspotId = -1;
+ _blueFrameHotspotId = -1;
+ _yellowFrameHotspotId = -1;
+}
+
+void Scene408::synchronize(Common::Serializer &s) {
+ Scene4xx::synchronize(s);
+
+ s.syncAsByte(_frameInRoomFl);
+ s.syncAsByte(_takingFrameInRoomFl);
+
+ s.syncAsSint16LE(_redFrameHotspotId);
+ s.syncAsSint16LE(_greenFrameHotspotId);
+ s.syncAsSint16LE(_blueFrameHotspotId);
+ s.syncAsSint16LE(_yellowFrameHotspotId);
+}
+
+void Scene408::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ if ((_globals[kCatacombsMisc] & MAZE_EVENT_WEB) && (!_globals[kCobwebIsCut]))
+ _scene->_variant = 1;
+
+ _scene->addActiveVocab(NOUN_RED_FRAME);
+ _scene->addActiveVocab(NOUN_YELLOW_FRAME);
+ _scene->addActiveVocab(NOUN_BLUE_FRAME);
+ _scene->addActiveVocab(NOUN_GREEN_FRAME);
+}
+
+void Scene408::enter() {
+ _game.initCatacombs();
+ _scene->_hotspots.activate(NOUN_COBWEB, false);
+
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('c', 0));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites("*RRD_9");
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('f', 0));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('f', 1));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('f', 2));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('f', 3));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('c', 1));
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('c', 2));
+
+ if (_game.exitCatacombs(0) == -1) {
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_ARCHWAY_TO_NORTH, false);
+ _scene->_hotspots.activateAtPos(NOUN_FLOOR, false, Common::Point(147, 121));
+ _scene->_hotspots.activateAtPos(NOUN_FLOOR, false, Common::Point(153, 121));
+ _scene->_hotspots.activateAtPos(NOUN_FLOOR, false, Common::Point(154, 115));
+ _scene->_hotspots.activateAtPos(NOUN_FLOOR, false, Common::Point(161, 101));
+ _scene->_hotspots.activateAtPos(NOUN_FLOOR, false, Common::Point(162, 106));
+ _scene->_hotspots.activateAtPos(NOUN_FLOOR, false, Common::Point(187, 107));
+ _scene->_hotspots.activateAtPos(NOUN_FLOOR, false, Common::Point(185, 101));
+ _scene->_hotspots.activateAtPos(NOUN_FLOOR, false, Common::Point(192, 119));
+ _scene->_hotspots.activateAtPos(NOUN_WALL, false, Common::Point(147, 76));
+ _scene->_hotspots.activateAtPos(NOUN_WALL, false, Common::Point(159, 108));
+ _scene->_hotspots.activateAtPos(NOUN_WALL, false, Common::Point(185, 93));
+ _scene->_hotspots.activateAtPos(NOUN_WALL, false, Common::Point(199, 91));
+ _scene->changeVariant(1);
+ } else
+ _scene->_hotspots.activate(NOUN_GATE, false);
+
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ switch (_globals[kCatacombsFrom]) {
+ case 0:
+ _game._player._playerPos = Common::Point(174, 100);
+ _game._player._facing = FACING_SOUTH;
+ _game._player.walk(Common::Point(174, 106), FACING_SOUTH);
+ break;
+
+ case 2:
+ _game._player._playerPos = Common::Point(175, 145);
+ _game._player._facing = FACING_NORTH;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_WEB) {
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('x', -1));
+ if (!_globals[kCobwebIsCut]) {
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('c', 1));
+ _globals._sequenceIndexes[6] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[6], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 10);
+ _scene->_hotspots.activate(NOUN_COBWEB, true);
+ } else {
+ _globals._sequenceIndexes[8] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[8], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[8], 10);
+
+ int idx = _scene->_dynamicHotspots.add(NOUN_COBWEB, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(199, 112, 199 + 6, 112 + 12));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(194, 125), FACING_NORTHEAST);
+ idx = _scene->_dynamicHotspots.add(NOUN_COBWEB, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(202, 81, 202 + 5, 81 + 31));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(194, 125), FACING_NORTHEAST);
+
+ idx = _scene->_dynamicHotspots.add(NOUN_COBWEB, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(138, 74, 138 + 7, 74 + 33));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(154, 124), FACING_NORTHWEST);
+ idx = _scene->_dynamicHotspots.add(NOUN_COBWEB, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(143, 107, 143 + 6, 107 + 15));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(154, 124), FACING_NORTHWEST);
+ }
+ }
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_BRICK) {
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('c', 2));
+ _scene->drawToBackground(_globals._spriteIndexes[7], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_EXPOSED_BRICK, false);
+ }
+
+ if (_game._objects[OBJ_RED_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _redFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_RED_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_redFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_game._objects[OBJ_GREEN_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _greenFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_GREEN_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_greenFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_game._objects[OBJ_BLUE_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[4] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[4], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _blueFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_BLUE_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_blueFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_game._objects[OBJ_YELLOW_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _yellowFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_YELLOW_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_yellowFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if ((_game._difficulty == DIFFICULTY_HARD) && (_globals[kCatacombsRoom] == 52))
+ _scene->_sequences.addTimer(120, 60);
+
+ sceneEntrySound();
+}
+
+void Scene408::step() {
+ if (_game._trigger == 60)
+ _vm->_dialogs->show(31);
+}
+
+void Scene408::actions() {
+ if (_action.isAction(VERB_PUT) && _action.isTarget(NOUN_FLOOR)
+ && (_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_BLUE_FRAME) || _action.isObject(NOUN_YELLOW_FRAME) || _action.isObject(NOUN_GREEN_FRAME))) {
+ if (_frameInRoomFl)
+ _vm->_dialogs->show(29);
+ else {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[1] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[1], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 5);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[1], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (_action.isObject(NOUN_RED_FRAME)) {
+ _game._objects.setRoom(OBJ_RED_FRAME, NOWHERE);
+ _game._objects[OBJ_RED_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[2]]->getFramePos(0);
+ _redFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_RED_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_redFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_action.isObject(NOUN_GREEN_FRAME)) {
+ _game._objects.setRoom(OBJ_GREEN_FRAME, NOWHERE);
+ _game._objects[OBJ_GREEN_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _greenFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_GREEN_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_greenFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME)) {
+ _game._objects.setRoom(OBJ_BLUE_FRAME, NOWHERE);
+ _game._objects[OBJ_BLUE_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[4] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[4], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _blueFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_BLUE_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_blueFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME)) {
+ _game._objects.setRoom(OBJ_YELLOW_FRAME, NOWHERE);
+ _game._objects[OBJ_YELLOW_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _yellowFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_YELLOW_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_yellowFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[1]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+
+ if (_action.isAction(VERB_TAKE)
+ && (_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_GREEN_FRAME) || _action.isObject(NOUN_BLUE_FRAME) || _action.isObject(NOUN_YELLOW_FRAME))) {
+ if ((_takingFrameInRoomFl || _game._trigger)) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[1] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[1], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 5);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[1], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (_action.isObject(NOUN_RED_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _scene->_dynamicHotspots.remove(_redFrameHotspotId);
+ _game._objects.addToInventory(OBJ_RED_FRAME);
+ }
+
+ if (_action.isObject(NOUN_GREEN_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[3]);
+ _scene->_dynamicHotspots.remove(_greenFrameHotspotId);
+ _game._objects.addToInventory(OBJ_GREEN_FRAME);
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[4]);
+ _scene->_dynamicHotspots.remove(_blueFrameHotspotId);
+ _game._objects.addToInventory(OBJ_BLUE_FRAME);
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[5]);
+ _scene->_dynamicHotspots.remove(_yellowFrameHotspotId);
+ _game._objects.addToInventory(OBJ_YELLOW_FRAME);
+ }
+
+ _vm->_sound->command(26);
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[1]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_ARCHWAY_TO_NORTH)) {
+ _game.moveCatacombs(0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_EXIT_TO, NOUN_MORE_CATACOMBS)) {
+ _game.moveCatacombs(2);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(40810);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(40811);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(40812);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_ARCHWAY)) {
+ _vm->_dialogs->show(40813);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_EXPOSED_BRICK)) {
+ _vm->_dialogs->show(40814);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_MORE_CATACOMBS)) {
+ _vm->_dialogs->show(40815);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CEILING)) {
+ _vm->_dialogs->show(40816);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RED_FRAME) && !_game._objects.isInInventory(OBJ_RED_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_RED_FRAME, 802, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_GREEN_FRAME) && !_game._objects.isInInventory(OBJ_GREEN_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_GREEN_FRAME, 819, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME) && !_game._objects.isInInventory(OBJ_BLUE_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_BLUE_FRAME, 817, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME) && !_game._objects.isInInventory(OBJ_YELLOW_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_YELLOW_FRAME, 804, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_GATE)) {
+ _vm->_dialogs->show(40817);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_COBWEB)) {
+ if (_globals[kCobwebIsCut])
+ _vm->_dialogs->show(40820);
+ else
+ _vm->_dialogs->show(40819);
+
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if ((_action.isAction(VERB_ATTACK, NOUN_COBWEB) && !_globals[kCobwebIsCut])) {
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('W', 1), 70);
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _globals[kCobwebIsCut] = true;
+ _scene->deleteSequence(_globals._sequenceIndexes[6]);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_game._trigger == 70) {
+ _globals._sequenceIndexes[8] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[8], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[8], 14);
+ _scene->changeVariant(0);
+ _scene->_hotspots.activate(NOUN_COBWEB, false);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+
+ int idx = _scene->_dynamicHotspots.add(NOUN_COBWEB, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(199, 112, 199 + 6, 112 + 12));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(194, 125), FACING_NORTHEAST);
+ idx = _scene->_dynamicHotspots.add(NOUN_COBWEB, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(202, 81, 202 + 5, 81 + 31));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(194, 125), FACING_NORTHEAST);
+
+ idx = _scene->_dynamicHotspots.add(NOUN_COBWEB, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(138, 74, 138 + 7, 74 + 33));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(154, 124), FACING_NORTHWEST);
+ idx = _scene->_dynamicHotspots.add(NOUN_COBWEB, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(143, 107, 143 + 6, 107 + 15));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(154, 124), FACING_NORTHWEST);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_GATE)) {
+ _vm->_dialogs->show(40818);
+ _action._inProgress = false;
+ }
+}
+
+void Scene408::preActions() {
+ _frameInRoomFl = false;
+ _takingFrameInRoomFl = false;
+
+ if (_game._objects[OBJ_RED_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_RED_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_game._objects[OBJ_YELLOW_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_YELLOW_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_game._objects[OBJ_BLUE_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_BLUE_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_game._objects[OBJ_GREEN_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_GREEN_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_action.isAction(VERB_PUT) && _action.isTarget(NOUN_FLOOR)
+ && (_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_BLUE_FRAME) || _action.isObject(NOUN_YELLOW_FRAME) || _action.isObject(NOUN_GREEN_FRAME))) {
+ if (_frameInRoomFl)
+ _game._player._needToWalk = false;
+ else {
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _game._player.walk(Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene409::Scene409(MADSEngine *vm) : Scene4xx(vm) {
+ _frameInRoomFl = false;
+ _takingFrameInRoomFl = false;
+
+ _redFrameHotspotId = -1;
+ _greenFrameHotspotId = -1;
+ _blueFrameHotspotId = -1;
+ _yellowFrameHotspotId = -1;
+}
+
+void Scene409::synchronize(Common::Serializer &s) {
+ Scene4xx::synchronize(s);
+
+ s.syncAsByte(_frameInRoomFl);
+ s.syncAsByte(_takingFrameInRoomFl);
+
+ s.syncAsSint16LE(_redFrameHotspotId);
+ s.syncAsSint16LE(_greenFrameHotspotId);
+ s.syncAsSint16LE(_blueFrameHotspotId);
+ s.syncAsSint16LE(_yellowFrameHotspotId);
+}
+
+void Scene409::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ _scene->addActiveVocab(NOUN_RED_FRAME);
+ _scene->addActiveVocab(NOUN_YELLOW_FRAME);
+ _scene->addActiveVocab(NOUN_BLUE_FRAME);
+ _scene->addActiveVocab(NOUN_GREEN_FRAME);
+}
+
+void Scene409::enter() {
+ _game.initCatacombs();
+
+ _scene->loadSpeech(3);
+ _scene->_hotspots.activate(NOUN_SWORD, false);
+
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites("*RDR_9");
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites("*RRD_9");
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('f', 0));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('f', 1));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('f', 2));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('f', 3));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('a', 0));
+
+ if (_game._objects.isInRoom(OBJ_SWORD)) {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('p', 0));
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites("*RRD_9");
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ _scene->_hotspots.activate(NOUN_SWORD, true);
+ }
+
+ if (!_globals[kDoorIn409IsOpen]) {
+ _globals._sequenceIndexes[6] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[6], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 14);
+ _scene->_hotspots.activate(NOUN_ARCHWAY_TO_NORTH, false);
+ } else
+ _scene->_hotspots.activate(NOUN_DOOR, false);
+
+ if (_scene->_priorSceneId == 410) {
+ _game._player._facing = FACING_NORTH;
+ _game._player._playerPos = Common::Point(229, 106);
+
+ if (_globals[kFlickedLever1] && _globals[kFlickedLever2] && _globals[kFlickedLever3] && _globals[kFlickedLever4]) {
+ if ((_globals[kFlickedLever1] == 5) && (_globals[kFlickedLever2] == 18) && (_globals[kFlickedLever3] == 9) && (_globals[kFlickedLever4] == 11)) {
+ if (!_globals[kDoorIn409IsOpen]) {
+ _globals[kPlayerScore] += 5;
+ _vm->_sound->command(24);
+ _scene->deleteSequence(_globals._sequenceIndexes[6]);
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[6] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[6], false, 7, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[6], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 65);
+ }
+ } else {
+ _globals[kFlickedLever1] = 0;
+ _globals[kFlickedLever2] = 0;
+ _globals[kFlickedLever3] = 0;
+ _globals[kFlickedLever4] = 0;
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[7] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[7], false, 9, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[7], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_SPRITE, 15, 60);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_EXPIRE, 0, 61);
+ _vm->_sound->command(68);
+ }
+ } else {
+ _globals[kFlickedLever1] = 0;
+ _globals[kFlickedLever2] = 0;
+ _globals[kFlickedLever3] = 0;
+ _globals[kFlickedLever4] = 0;
+ }
+ } else if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ switch (_globals[kCatacombsFrom]) {
+ case 0:
+ _game._player._playerPos = Common::Point(195, 92);
+ _game._player._facing = FACING_SOUTH;
+ _game._player.walk(Common::Point(195, 107), FACING_SOUTH);
+ break;
+
+ case 2:
+ _game._player._playerPos = Common::Point(184, 45);
+ _game._player._facing = FACING_NORTH;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (_game._objects[OBJ_RED_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[2]]->getFramePos(0);
+ _redFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_RED_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_redFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_game._objects[OBJ_GREEN_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[2]]->getFramePos(0);
+ _greenFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_GREEN_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_greenFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_game._objects[OBJ_BLUE_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[4] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[4], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[2]]->getFramePos(0);
+ _blueFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_BLUE_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_blueFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_game._objects[OBJ_YELLOW_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[2]]->getFramePos(0);
+ _yellowFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_YELLOW_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_yellowFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene409::step() {
+ if (_game._trigger == 60) {
+ _game._player._visible = false;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[7]);
+ _scene->playSpeech(3);
+ }
+
+ if (_game._trigger == 61) {
+ _globals._sequenceIndexes[7] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[7], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 1);
+ _scene->_sequences.addTimer(60, 62);
+ _vm->_sound->command(27);
+ }
+
+ if (_game._trigger == 62)
+ _scene->_reloadSceneFlag = true;
+
+ if (_game._trigger == 65) {
+ _game._player._stepEnabled = true;
+ _globals[kDoorIn409IsOpen] = true;
+ _scene->_hotspots.activate(NOUN_DOOR, false);
+ _scene->_hotspots.activate(NOUN_ARCHWAY_TO_NORTH, true);
+ }
+}
+
+void Scene409::actions() {
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR) || _action.isAction(VERB_OPEN, NOUN_DOOR)) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[8] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[8], false, 5, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[8], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[8], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_SPRITE, 4, 4);
+ _action._inProgress = false;
+ return;
+
+ case 1: {
+ int syncIdx = _globals._sequenceIndexes[8];
+ _globals._sequenceIndexes[8] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[8], false, 4);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[8], SYNC_SEQ, syncIdx);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[8], false);
+ _scene->_sequences.addTimer(30, 2);
+ _action._inProgress = false;
+ }
+ return;
+
+ case 2:
+ _scene->deleteSequence(_globals._sequenceIndexes[8]);
+ _globals._sequenceIndexes[8] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[8], false, 5, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[8], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[8], false);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ _action._inProgress = false;
+ return;
+
+ case 3:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[8]);
+ _game._player._visible = true;
+ _vm->_dialogs->show(40923);
+ _game._player._stepEnabled = true;
+ _action._inProgress = false;
+ return;
+
+ case 4:
+ _vm->_sound->command(70);
+ _action._inProgress = false;
+ return;
+
+ default:
+ break;
+ }
+ }
+
+ if (_action.isAction(VERB_PUT) && _action.isTarget(NOUN_FLOOR)) {
+ if (_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_BLUE_FRAME) || _action.isObject(NOUN_YELLOW_FRAME) || _action.isObject(NOUN_GREEN_FRAME)) {
+ if (_frameInRoomFl) {
+ _vm->_dialogs->show(29);
+ } else {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[0] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[0], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], 1, 5);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[0], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (_action.isObject(NOUN_RED_FRAME)) {
+ _game._objects.setRoom(OBJ_RED_FRAME, NOWHERE);
+ _game._objects[OBJ_RED_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[2]]->getFramePos(0);
+ _redFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_RED_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_redFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_action.isObject(NOUN_GREEN_FRAME)) {
+ _game._objects.setRoom(OBJ_GREEN_FRAME, NOWHERE);
+ _game._objects[OBJ_GREEN_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[2]]->getFramePos(0);
+ _greenFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_GREEN_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_greenFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME)) {
+ _game._objects.setRoom(OBJ_BLUE_FRAME, NOWHERE);
+ _game._objects[OBJ_BLUE_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[4] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[4], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[2]]->getFramePos(0);
+ _blueFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_BLUE_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_blueFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME)) {
+ _game._objects.setRoom(OBJ_YELLOW_FRAME, NOWHERE);
+ _game._objects[OBJ_YELLOW_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[2]]->getFramePos(0);
+ _yellowFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_YELLOW_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_yellowFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[0]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE)) {
+ if ((_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_GREEN_FRAME) || _action.isObject(NOUN_BLUE_FRAME) || _action.isObject(NOUN_YELLOW_FRAME))
+ && (_takingFrameInRoomFl || _game._trigger)) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[0] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[0], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], 1, 5);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[0], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (_action.isObject(NOUN_RED_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _scene->_dynamicHotspots.remove(_redFrameHotspotId);
+ _game._objects.addToInventory(OBJ_RED_FRAME);
+ }
+
+ if (_action.isObject(NOUN_GREEN_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[3]);
+ _scene->_dynamicHotspots.remove(_greenFrameHotspotId);
+ _game._objects.addToInventory(OBJ_GREEN_FRAME);
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[4]);
+ _scene->_dynamicHotspots.remove(_blueFrameHotspotId);
+ _game._objects.addToInventory(OBJ_BLUE_FRAME);
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[5]);
+ _scene->_dynamicHotspots.remove(_yellowFrameHotspotId);
+ _game._objects.addToInventory(OBJ_YELLOW_FRAME);
+ }
+
+ _vm->_sound->command(26);
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[0]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_ARCHWAY_TO_NORTH)) {
+ _game.enterCatacombs(true);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_EXIT_TO, NOUN_MORE_CATACOMBS)) {
+ _game.enterCatacombs(false);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(40910);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_SWORD) && (_game._objects.isInRoom(OBJ_SWORD) || _game._trigger)) {
+ switch (_game._trigger) {
+ case (0):
+ _globals[kPlayerScore] += 5;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[0] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[0], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], 1, 5);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[0], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _scene->deleteSequence(_globals._sequenceIndexes[1]);
+ _scene->_hotspots.activate(NOUN_SWORD, false);
+ _game._objects.addToInventory(OBJ_SWORD);
+ _vm->_sound->command(26);
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[0]);
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(20, 3);
+ break;
+
+ case 3:
+ _vm->_dialogs->showItem(OBJ_SWORD, 808, 0);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(40911);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(40912);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_ARCHWAY)) {
+ _vm->_dialogs->show(40913);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_EXPOSED_BRICK)) {
+ _vm->_dialogs->show(40914);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_MORE_CATACOMBS)) {
+ _vm->_dialogs->show(40915);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BLOCKED_ARCHWAY)) {
+ _vm->_dialogs->show(40916);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_GRATE)) {
+ _vm->_dialogs->show(40917);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_UNLUCKY_ADVENTURER)) {
+ _vm->_dialogs->show(40920);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RED_FRAME) && !_game._objects.isInInventory(OBJ_RED_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_RED_FRAME, 802, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_GREEN_FRAME) && !_game._objects.isInInventory(OBJ_GREEN_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_GREEN_FRAME, 819, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME) && !_game._objects.isInInventory(OBJ_BLUE_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_BLUE_FRAME, 817, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME) && !_game._objects.isInInventory(OBJ_YELLOW_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_YELLOW_FRAME, 804, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SWORD) && _game._objects.isInRoom(OBJ_SWORD)) {
+ _vm->_dialogs->show(40921);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_SWITCH_PANEL)) {
+ _vm->_dialogs->show(40919);
+ _scene->_nextSceneId = 410;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_TO, NOUN_SWITCH_PANEL)) {
+ _scene->_nextSceneId = 410;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_GRATE) || _action.isAction(VERB_PUSH, NOUN_GRATE) || _action.isAction(VERB_PULL, NOUN_GRATE)) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 5, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], -1, -2);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[0], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 2:
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, -2);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[0], true);
+ _scene->_sequences.addTimer(30, 3);
+ break;
+
+ case 3:
+ _scene->deleteSequence(_globals._sequenceIndexes[0]);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[0], false, 5, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], -1, -2);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[0], false);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 4);
+ break;
+
+ case 4:
+ _game._player._visible = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[0]);
+ _scene->_sequences.addTimer(6, 5);
+ break;
+
+ case 5:
+ _game._player._stepEnabled = true;
+ _vm->_dialogs->show(40918);
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TALK_TO, NOUN_UNLUCKY_ADVENTURER)) {
+ _vm->_dialogs->show(40924);
+ _action._inProgress = false;
+ }
+}
+
+void Scene409::preActions() {
+ _frameInRoomFl = false;
+ _takingFrameInRoomFl = false;
+
+ if (_game._objects[OBJ_RED_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_RED_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_game._objects[OBJ_YELLOW_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_YELLOW_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_game._objects[OBJ_BLUE_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_BLUE_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_game._objects[OBJ_GREEN_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_GREEN_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_action.isAction(VERB_PUT) && _action.isTarget(NOUN_FLOOR)
+ && (_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_BLUE_FRAME) || _action.isObject(NOUN_YELLOW_FRAME) || _action.isObject(NOUN_GREEN_FRAME))) {
+ if (_frameInRoomFl)
+ _game._player._needToWalk = false;
+ else {
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[2]]->getFramePos(0);
+ _game._player.walk(Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_SWITCH_PANEL))
+ _game._player.walk(Common::Point(229, 106), FACING_NORTH);
+
+ if (_action.isAction(VERB_OPEN, NOUN_DOOR))
+ _game._player.walk(Common::Point(191, 104), FACING_NORTHEAST);
+
+ if (_action.isAction(VERB_OPEN, NOUN_GRATE))
+ _game._player._needToWalk = true;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene410::Scene410(MADSEngine *vm) : Scene4xx(vm) {
+ for (int i = 0; i < 26; i++)
+ _skullSequence[i] = 0;
+}
+
+void Scene410::synchronize(Common::Serializer &s) {
+ Scene4xx::synchronize(s);
+
+ for (int i = 0; i < 26; i++)
+ s.syncAsSint16LE(_skullSequence[i]);
+}
+
+void Scene410::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene410::enter() {
+ _game._player._visible = false;
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('l', 0));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('l', 1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('l', 2));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('a', 0));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('f', 0));
+
+ for (int i = 1; i < 27; i++) {
+ Common::Point pos;
+ int type;
+
+ getLeverInfo(&pos, &type, i, NULL);
+ int stampType = -1;
+
+ switch (type) {
+ case 1:
+ stampType = _globals._spriteIndexes[0];
+ break;
+
+ case 2:
+ stampType = _globals._spriteIndexes[1];
+ break;
+
+ case 3:
+ stampType = _globals._spriteIndexes[2];
+ break;
+
+ default:
+ break;
+ }
+
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(stampType, false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[0], pos);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 2);
+ _skullSequence[i - 1] = _globals._sequenceIndexes[0];
+ }
+
+ if (_globals[kFlickedLever1]) {
+ Common::Point pos;
+ int type;
+
+ getLeverInfo(&pos, &type, _globals[kFlickedLever1], NULL);
+ int stampType = -1;
+
+ switch (type) {
+ case 1:
+ stampType = _globals._spriteIndexes[0];
+ break;
+
+ case 2:
+ stampType = _globals._spriteIndexes[1];
+ break;
+
+ case 3:
+ stampType = _globals._spriteIndexes[2];
+ break;
+
+ default:
+ break;
+ }
+ _scene->deleteSequence(_skullSequence[_globals[kFlickedLever1] - 1]);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(stampType, false, -2);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[0], pos);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 2);
+ }
+
+ if (_globals[kFlickedLever2]) {
+ Common::Point pos;
+ int type;
+
+ getLeverInfo(&pos, &type, _globals[kFlickedLever2], NULL);
+ int stampType = -1;
+ switch (type) {
+ case 1:
+ stampType = _globals._spriteIndexes[0];
+ break;
+
+ case 2:
+ stampType = _globals._spriteIndexes[1];
+ break;
+
+ case 3:
+ stampType = _globals._spriteIndexes[2];
+ break;
+
+ default:
+ break;
+ }
+ _scene->deleteSequence(_skullSequence[_globals[kFlickedLever2] - 1]);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(stampType, false, -2);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[0], pos);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 2);
+ }
+
+ if (_globals[kFlickedLever3]) {
+ Common::Point pos;
+ int type;
+
+ getLeverInfo(&pos, &type, _globals[kFlickedLever3], NULL);
+ int stampType = -1;
+ switch (type) {
+ case 1:
+ stampType = _globals._spriteIndexes[0];
+ break;
+
+ case 2:
+ stampType = _globals._spriteIndexes[1];
+ break;
+
+ case 3:
+ stampType = _globals._spriteIndexes[2];
+ break;
+
+ default:
+ break;
+ }
+ _scene->deleteSequence(_skullSequence[_globals[kFlickedLever3] - 1]);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(stampType, false, -2);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[0], pos);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 2);
+ }
+
+ if (_globals[kFlickedLever4]) {
+ Common::Point pos;
+ int type;
+
+ getLeverInfo(&pos, &type, _globals[kFlickedLever4], NULL);
+ int stampType = -1;
+ switch (type) {
+ case 1:
+ stampType = _globals._spriteIndexes[0];
+ break;
+
+ case 2:
+ stampType = _globals._spriteIndexes[1];
+ break;
+
+ case 3:
+ stampType = _globals._spriteIndexes[2];
+ break;
+
+ default:
+ break;
+ }
+ _scene->deleteSequence(_skullSequence[_globals[kFlickedLever4] - 1]);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(stampType, false, -2);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[0], pos);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 2);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene410::step() {
+}
+
+void Scene410::actions() {
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(41013);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_PUSH) || _action.isAction(VERB_PULL)) {
+ if (_globals[kDoorIn409IsOpen])
+ _vm->_dialogs->show(41014);
+ else {
+ Common::Point pos;
+ int type;
+ int number;
+
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ getLeverInfo(&pos, &type, 0, &number);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[3], false, 4, 2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], -1, -2);
+ if (pos.y == 46)
+ pos.y = 48;
+
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(pos.x + 4, pos.y + 107));
+ if (!_globals[kDoorIn409IsOpen])
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_SPRITE, 16, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ getLeverInfo(&pos, &type, 0, &number);
+
+ if ((_globals[kFlickedLever1] != number) && (_globals[kFlickedLever2] != number) && (_globals[kFlickedLever3] != number) && (_globals[kFlickedLever4] != number)) {
+ _vm->_sound->command(65);
+
+ if (!_globals[kFlickedLever1]) {
+ _globals[kFlickedLever1] = number;
+ if (_globals[kFlickedLever1] == 5)
+ _vm->_sound->command(66);
+ } else if (!_globals[kFlickedLever2]) {
+ _globals[kFlickedLever2] = number;
+ if ((_globals[kFlickedLever1] == 5) && (_globals[kFlickedLever2] == 18))
+ _vm->_sound->command(66);
+ } else if (!_globals[kFlickedLever3]) {
+ _globals[kFlickedLever3] = number;
+ if ((_globals[kFlickedLever1] == 5) && (_globals[kFlickedLever2] == 18) && (_globals[kFlickedLever3] == 9))
+ _vm->_sound->command(66);
+ } else if (!_globals[kFlickedLever4]) {
+ _globals[kFlickedLever4] = number;
+ if ((_globals[kFlickedLever1] == 5) && (_globals[kFlickedLever2] == 18) && (_globals[kFlickedLever3] == 9) && (_globals[kFlickedLever4] == 11))
+ _vm->_sound->command(66);
+ }
+
+ if (_game._difficulty == DIFFICULTY_EASY)
+ _scene->drawToBackground(_globals._spriteIndexes[4], number, Common::Point(-32000, -32000), 0, 100);
+
+ switch (type) {
+ case 1:
+ _scene->deleteSequence(_skullSequence[number - 1]);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 4, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 4);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[0], pos);
+ break;
+
+ case 2:
+ _scene->deleteSequence(_skullSequence[number - 1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 4, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 4);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], pos);
+ break;
+
+ case 3:
+ _scene->deleteSequence(_skullSequence[number - 1]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 4, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 4);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], pos);
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case 2:
+ _game._player._stepEnabled = true;
+
+ if ((_globals[kFlickedLever1] == 5) && (_globals[kFlickedLever2] == 18) && (_globals[kFlickedLever3] == 9) && (_globals[kFlickedLever4] == 11) && !_globals[kDoorIn409IsOpen])
+ _vm->_sound->command(67);
+
+ if (_globals[kFlickedLever1] && _globals[kFlickedLever2] && _globals[kFlickedLever3] && _globals[kFlickedLever4])
+ _scene->_nextSceneId = 409;
+
+ break;
+
+ case 4:
+ getLeverInfo(&pos, &type, 0, &number);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 2);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[0], pos);
+ break;
+
+ case 5:
+ getLeverInfo(&pos, &type, 0, &number);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 2);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], pos);
+ break;
+
+ case 6:
+ getLeverInfo(&pos, &type, 0, &number);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 2);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], pos);
+ break;
+
+ default:
+ break;
+ }
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(41011);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SWITCH_PANEL)) {
+ _vm->_dialogs->show(41011);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CATACOMB_ROOM)) {
+ _vm->_dialogs->show(41015);
+ _action._inProgress = false;
+ return;
+ }
+
+ switch (_action._activeAction._objectNameId) {
+ case NOUN_SKULL_SWITCH_1:
+ case NOUN_SKULL_SWITCH_2:
+ case NOUN_SKULL_SWITCH_3:
+ case NOUN_SKULL_SWITCH_4:
+ case NOUN_SKULL_SWITCH_5:
+ case NOUN_SKULL_SWITCH_6:
+ case NOUN_SKULL_SWITCH_7:
+ case NOUN_SKULL_SWITCH_8:
+ case NOUN_SKULL_SWITCH_9:
+ case NOUN_SKULL_SWITCH_10:
+ case NOUN_SKULL_SWITCH_11:
+ case NOUN_SKULL_SWITCH_12:
+ case NOUN_SKULL_SWITCH_13:
+ case NOUN_SKULL_SWITCH_14:
+ case NOUN_SKULL_SWITCH_15:
+ case NOUN_SKULL_SWITCH_16:
+ case NOUN_SKULL_SWITCH_17:
+ case NOUN_SKULL_SWITCH_18:
+ case NOUN_SKULL_SWITCH_19:
+ case NOUN_SKULL_SWITCH_20:
+ case NOUN_SKULL_SWITCH_21:
+ case NOUN_SKULL_SWITCH_22:
+ case NOUN_SKULL_SWITCH_23:
+ case NOUN_SKULL_SWITCH_24:
+ case NOUN_SKULL_SWITCH_25:
+ case NOUN_SKULL_SWITCH_26:
+ _vm->_dialogs->show(41012);
+ _action._inProgress = false;
+ return;
+ break;
+ }
+ }
+
+ if (_action.isAction(VERB_EXIT_TO, NOUN_CATACOMB_ROOM)) {
+ _scene->_nextSceneId = 409;
+ _action._inProgress = false;
+ }
+}
+
+void Scene410::preActions() {
+}
+
+void Scene410::getLeverInfo(Common::Point *pos, int *type, int lever, int *noun) {
+ if (noun != NULL) {
+ switch (_action._activeAction._objectNameId) {
+ case NOUN_SKULL_SWITCH_1:
+ lever = 1;
+ break;
+
+ case NOUN_SKULL_SWITCH_2:
+ lever = 2;
+ break;
+
+ case NOUN_SKULL_SWITCH_3:
+ lever = 3;
+ break;
+
+ case NOUN_SKULL_SWITCH_4:
+ lever = 4;
+ break;
+
+ case NOUN_SKULL_SWITCH_5:
+ lever = 5;
+ break;
+
+ case NOUN_SKULL_SWITCH_6:
+ lever = 6;
+ break;
+
+ case NOUN_SKULL_SWITCH_7:
+ lever = 7;
+ break;
+
+ case NOUN_SKULL_SWITCH_8:
+ lever = 8;
+ break;
+
+ case NOUN_SKULL_SWITCH_9:
+ lever = 9;
+ break;
+
+ case NOUN_SKULL_SWITCH_10:
+ lever = 10;
+ break;
+
+ case NOUN_SKULL_SWITCH_11:
+ lever = 11;
+ break;
+
+ case NOUN_SKULL_SWITCH_12:
+ lever = 12;
+ break;
+
+ case NOUN_SKULL_SWITCH_13:
+ lever = 13;
+ break;
+
+ case NOUN_SKULL_SWITCH_14:
+ lever = 14;
+ break;
+
+ case NOUN_SKULL_SWITCH_15:
+ lever = 15;
+ break;
+
+ case NOUN_SKULL_SWITCH_16:
+ lever = 16;
+ break;
+
+ case NOUN_SKULL_SWITCH_17:
+ lever = 17;
+ break;
+
+ case NOUN_SKULL_SWITCH_18:
+ lever = 18;
+ break;
+
+ case NOUN_SKULL_SWITCH_19:
+ lever = 19;
+ break;
+
+ case NOUN_SKULL_SWITCH_20:
+ lever = 20;
+ break;
+
+ case NOUN_SKULL_SWITCH_21:
+ lever = 21;
+ break;
+
+ case NOUN_SKULL_SWITCH_22:
+ lever = 22;
+ break;
+
+ case NOUN_SKULL_SWITCH_23:
+ lever = 23;
+ break;
+
+ case NOUN_SKULL_SWITCH_24:
+ lever = 24;
+ break;
+
+ case NOUN_SKULL_SWITCH_25:
+ lever = 25;
+ break;
+
+ case NOUN_SKULL_SWITCH_26:
+ lever = 26;
+ break;
+
+ default:
+ break;
+ }
+ *noun = lever;
+ }
+
+ switch (lever) {
+ case 1:
+ *pos = Common::Point(124, 46);
+ *type = 3;
+ break;
+
+ case 2:
+ *pos = Common::Point(143, 46);
+ *type = 2;
+ break;
+
+ case 3:
+ *pos = Common::Point(162, 46);
+ *type = 1;
+ break;
+
+ case 4:
+ *pos = Common::Point(181, 46);
+ *type = 3;
+ break;
+
+ case 5:
+ *pos = Common::Point(200, 46);
+ *type = 1;
+ break;
+
+ case 6:
+ *pos = Common::Point(219, 46);
+ *type = 2;
+ break;
+
+ case 7:
+ *pos = Common::Point(238, 46);
+ *type = 1;
+ break;
+
+ case 8:
+ *pos = Common::Point(133, 71);
+ *type = 3;
+ break;
+
+ case 9:
+ *pos = Common::Point(152, 71);
+ *type = 2;
+ break;
+
+ case 10:
+ *pos = Common::Point(171, 71);
+ *type = 1;
+ break;
+
+ case 11:
+ *pos = Common::Point(190, 71);
+ *type = 3;
+ break;
+
+ case 12:
+ *pos = Common::Point(209, 71);
+ *type = 2;
+ break;
+
+ case 13:
+ *pos = Common::Point(228, 71);
+ *type = 1;
+ break;
+
+ case 14:
+ *pos = Common::Point(124, 98);
+ *type = 1;
+ break;
+
+ case 15:
+ *pos = Common::Point(143, 98);
+ *type = 3;
+ break;
+
+ case 16:
+ *pos = Common::Point(162, 98);
+ *type = 2;
+ break;
+
+ case 17:
+ *pos = Common::Point(181, 98);
+ *type = 1;
+ break;
+
+ case 18:
+ *pos = Common::Point(200, 98);
+ *type = 1;
+ break;
+
+ case 19:
+ *pos = Common::Point(219, 98);
+ *type = 2;
+ break;
+
+ case 20:
+ *pos = Common::Point(238, 98);
+ *type = 1;
+ break;
+
+ case 21:
+ *pos = Common::Point(133, 125);
+ *type = 3;
+ break;
+
+ case 22:
+ *pos = Common::Point(152, 125);
+ *type = 1;
+ break;
+
+ case 23:
+ *pos = Common::Point(171, 125);
+ *type = 3;
+ break;
+
+ case 24:
+ *pos = Common::Point(190, 125);
+ *type = 2;
+ break;
+
+ case 25:
+ *pos = Common::Point(209, 125);
+ *type = 1;
+ break;
+
+ case 26:
+ *pos = Common::Point(228, 125);
+ *type = 2;
+ break;
+
+ default:
+ *pos = Common::Point(-1, -1);
+ *type = -1;
+ break;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene453::Scene453(MADSEngine *vm) : Scene4xx(vm) {
+ _frameInRoomFl = false;
+ _takingFrameInRoomFl = false;
+
+ _redFrameHotspotId = -1;
+ _greenFrameHotspotId = -1;
+ _blueFrameHotspotId = -1;
+ _yellowFrameHotspotId = -1;
+}
+
+void Scene453::synchronize(Common::Serializer &s) {
+ Scene4xx::synchronize(s);
+
+ s.syncAsByte(_frameInRoomFl);
+ s.syncAsByte(_takingFrameInRoomFl);
+
+ s.syncAsSint16LE(_redFrameHotspotId);
+ s.syncAsSint16LE(_greenFrameHotspotId);
+ s.syncAsSint16LE(_blueFrameHotspotId);
+ s.syncAsSint16LE(_yellowFrameHotspotId);
+}
+
+void Scene453::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_STONE)
+ _scene->_variant = 1;
+
+ _scene->addActiveVocab(NOUN_RED_FRAME);
+ _scene->addActiveVocab(NOUN_YELLOW_FRAME);
+ _scene->addActiveVocab(NOUN_BLUE_FRAME);
+ _scene->addActiveVocab(NOUN_GREEN_FRAME);
+}
+
+void Scene453::enter() {
+ _game.initCatacombs();
+
+ _scene->_hotspots.activate(NOUN_SKULL, false);
+ _scene->_hotspots.activate(NOUN_DRAIN, false);
+ _scene->_hotspots.activate(NOUN_RATS_NEST, false);
+ _scene->_hotspots.activate(NOUN_WEB, false);
+ _scene->_hotspots.activate(NOUN_STONE, false);
+ _scene->_hotspots.activate(NOUN_HOLE, false);
+ _scene->_hotspots.activate(NOUN_GATE, false);
+
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites("*RRD_9");
+ _globals._spriteIndexes[9] = _scene->_sprites.addSprites(formAnimName('f', 0));
+ _globals._spriteIndexes[10] = _scene->_sprites.addSprites(formAnimName('f', 1));
+ _globals._spriteIndexes[11] = _scene->_sprites.addSprites(formAnimName('f', 2));
+ _globals._spriteIndexes[12] = _scene->_sprites.addSprites(formAnimName('f', 3));
+
+
+ if (_game.exitCatacombs(0) == -1) {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('c', 1));
+ _scene->drawToBackground(_globals._spriteIndexes[1], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_ARCHWAY_TO_NORTH, false);
+ }
+
+ if (_game.exitCatacombs(3) == -1) {
+ _globals._spriteIndexes[13] = _scene->_sprites.addSprites(formAnimName('c', 8));
+ _scene->drawToBackground(_globals._spriteIndexes[13], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_MORE_CATACOMBS, false);
+ _scene->_hotspots.activate(NOUN_GATE, true);
+ }
+
+ if (_game.exitCatacombs(1) == -1) {
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('c', 2));
+ _scene->drawToBackground(_globals._spriteIndexes[2], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_ARCHWAY_TO_EAST, false);
+ }
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_DRAIN) {
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('c', 3));
+ _scene->drawToBackground(_globals._spriteIndexes[3], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_DRAIN, true);
+ }
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_RAT_NEST) {
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('c', 4));
+ _scene->drawToBackground(_globals._spriteIndexes[4], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_SKULL, true);
+ _scene->_hotspots.activate(NOUN_RATS_NEST, true);
+ }
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_WEB) {
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('c', 5));
+ _scene->drawToBackground(_globals._spriteIndexes[5], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_WEB, true);
+ }
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_BRICK) {
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('c', 6));
+ _scene->drawToBackground(_globals._spriteIndexes[6], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activateAtPos(NOUN_EXPOSED_BRICK, false, Common::Point(138, 35));
+ _scene->_hotspots.activateAtPos(NOUN_EXPOSED_BRICK, false, Common::Point(84, 27));
+ }
+
+ if (_globals[kCatacombsMisc] & MAZE_EVENT_STONE) {
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('c', 7));
+ _scene->drawToBackground(_globals._spriteIndexes[7], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_HOLE, true);
+ _scene->_hotspots.activate(NOUN_STONE, true);
+ }
+
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ switch (_globals[kCatacombsFrom]) {
+ case 0:
+ _game._player._playerPos = Common::Point(107, 87);
+ _game._player._facing = FACING_SOUTH;
+ _game._player.walk(Common::Point(107, 98), FACING_SOUTH);
+ break;
+
+ case 1:
+ _game._player._playerPos = Common::Point(316, 129);
+ _game._player._facing = FACING_WEST;
+ _game._player.walk(Common::Point(277, 129), FACING_WEST);
+ break;
+
+ case 3:
+ _game._player.firstWalk(Common::Point(-20, 128), FACING_EAST, Common::Point(19, 128), FACING_EAST, true);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (_game._objects[OBJ_RED_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[9] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[9], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _redFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_RED_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_redFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_game._objects[OBJ_GREEN_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[10] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[10], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _greenFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_GREEN_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_greenFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_game._objects[OBJ_BLUE_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[11] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[11], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[11], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _blueFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_BLUE_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_blueFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_game._objects[OBJ_YELLOW_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[12] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[12], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[12], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _yellowFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_YELLOW_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_yellowFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene453::step() {
+}
+
+void Scene453::actions() {
+ if (_action.isAction(VERB_PUT) && _action.isTarget(NOUN_FLOOR)) {
+ if (_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_BLUE_FRAME) || _action.isObject(NOUN_YELLOW_FRAME) || _action.isObject(NOUN_GREEN_FRAME)) {
+ if (_frameInRoomFl)
+ _vm->_dialogs->show(29);
+ else {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[8] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[8], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[8], 1, 5);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[8], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (_action.isObject(NOUN_RED_FRAME)) {
+ _game._objects.setRoom(OBJ_RED_FRAME, NOWHERE);
+ _game._objects[OBJ_RED_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[9] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[9], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _redFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_RED_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_redFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_action.isObject(NOUN_GREEN_FRAME)) {
+ _game._objects.setRoom(OBJ_GREEN_FRAME, NOWHERE);
+ _game._objects[OBJ_GREEN_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[10] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[10], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _greenFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_GREEN_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_greenFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME)) {
+ _game._objects.setRoom(OBJ_BLUE_FRAME, NOWHERE);
+ _game._objects[OBJ_BLUE_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[11] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[11], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[11], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _blueFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_BLUE_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_blueFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME)) {
+ _game._objects.setRoom(OBJ_YELLOW_FRAME, NOWHERE);
+ _game._objects[OBJ_YELLOW_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[12] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[12], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[12], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _yellowFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_YELLOW_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_yellowFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[8]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE)) {
+ if (_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_GREEN_FRAME) || _action.isObject(NOUN_BLUE_FRAME) || _action.isObject(NOUN_YELLOW_FRAME)) {
+ if ((_takingFrameInRoomFl || _game._trigger)) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[8] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[8], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[8], 1, 5);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[8], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (_action.isObject(NOUN_RED_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[9]);
+ _scene->_dynamicHotspots.remove(_redFrameHotspotId);
+ _game._objects.addToInventory(OBJ_RED_FRAME);
+ }
+
+ if (_action.isObject(NOUN_GREEN_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[10]);
+ _scene->_dynamicHotspots.remove(_greenFrameHotspotId);
+ _game._objects.addToInventory(OBJ_GREEN_FRAME);
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[11]);
+ _scene->_dynamicHotspots.remove(_blueFrameHotspotId);
+ _game._objects.addToInventory(OBJ_BLUE_FRAME);
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[12]);
+ _scene->_dynamicHotspots.remove(_yellowFrameHotspotId);
+ _game._objects.addToInventory(OBJ_YELLOW_FRAME);
+ }
+
+ _vm->_sound->command(26);
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[8]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+ }
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_ARCHWAY_TO_NORTH)) {
+ _game.moveCatacombs(0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_ARCHWAY_TO_EAST)) {
+ _game.moveCatacombs(1);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(45310);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(45311);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(45312);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_ARCHWAY)) {
+ _vm->_dialogs->show(45313);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_EXPOSED_BRICK)) {
+ _vm->_dialogs->show(45314);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_HOLE)) {
+ _vm->_dialogs->show(45317);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SKULL)) {
+ _vm->_dialogs->show(45318);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WEB)) {
+ _vm->_dialogs->show(45324);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RATS_NEST)) {
+ _vm->_dialogs->show(45325);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DRAIN)) {
+ _vm->_dialogs->show(45327);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_STONE)) {
+ _vm->_dialogs->show(45328);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RED_FRAME) && !_game._objects.isInInventory(OBJ_RED_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_RED_FRAME, 802, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_GREEN_FRAME) && !_game._objects.isInInventory(OBJ_GREEN_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_GREEN_FRAME, 819, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME) && !_game._objects.isInInventory(OBJ_BLUE_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_BLUE_FRAME, 817, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME) && !_game._objects.isInInventory(OBJ_YELLOW_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_YELLOW_FRAME, 804, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_MORE_CATACOMBS)) {
+ _vm->_dialogs->show(45315);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_GATE)) {
+ _vm->_dialogs->show(45330);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_SKULL)) {
+ _vm->_dialogs->show(45319);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_GATE)) {
+ _vm->_dialogs->show(45331);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_RATS_NEST)) {
+ _vm->_dialogs->show(45326);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_STONE)) {
+ _vm->_dialogs->show(45329);
+ _action._inProgress = false;
+ }
+}
+
+void Scene453::preActions() {
+ if (_action.isAction(VERB_EXIT_TO, NOUN_MORE_CATACOMBS))
+ _game.moveCatacombs(3);
+
+ _frameInRoomFl = false;
+ _takingFrameInRoomFl = false;
+
+ if (_game._objects[OBJ_RED_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_RED_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_game._objects[OBJ_YELLOW_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_YELLOW_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_game._objects[OBJ_BLUE_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_BLUE_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_game._objects[OBJ_GREEN_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_GREEN_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_action.isAction(VERB_PUT) && _action.isTarget(NOUN_FLOOR) && (_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_BLUE_FRAME) || _action.isObject(NOUN_YELLOW_FRAME) || _action.isObject(NOUN_GREEN_FRAME))) {
+ if (_frameInRoomFl)
+ _game._player._needToWalk = false;
+ else {
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[9]]->getFramePos(0);
+ _game._player.walk(Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene456::Scene456(MADSEngine *vm) : Scene4xx(vm) {
+ _frameInRoomFl = false;
+ _takingFrameInRoomFl = false;
+
+ _redFrameHotspotId = -1;
+ _greenFrameHotspotId = -1;
+ _blueFrameHotspotId = -1;
+ _yellowFrameHotspotId = -1;
+}
+
+void Scene456::synchronize(Common::Serializer &s) {
+ Scene4xx::synchronize(s);
+
+ s.syncAsByte(_frameInRoomFl);
+ s.syncAsByte(_takingFrameInRoomFl);
+
+ s.syncAsSint16LE(_redFrameHotspotId);
+ s.syncAsSint16LE(_greenFrameHotspotId);
+ s.syncAsSint16LE(_blueFrameHotspotId);
+ s.syncAsSint16LE(_yellowFrameHotspotId);
+}
+
+void Scene456::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ _scene->addActiveVocab(NOUN_RED_FRAME);
+ _scene->addActiveVocab(NOUN_YELLOW_FRAME);
+ _scene->addActiveVocab(NOUN_BLUE_FRAME);
+ _scene->addActiveVocab(NOUN_GREEN_FRAME);
+}
+
+void Scene456::enter() {
+ _game.initCatacombs();
+
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('c', 1));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites("*RRD_9");
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('f', 0));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('f', 1));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('f', 2));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('f', 3));
+
+ if (_game.exitCatacombs(1) == -1) {
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_hotspots.activate(NOUN_ARCHWAY_TO_EAST, false);
+ }
+
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ switch (_globals[kCatacombsFrom]) {
+ case 1:
+ _game._player._playerPos = Common::Point(298, 123);
+ _game._player._facing = FACING_WEST;
+ _game._player.walk(Common::Point(254, 123), FACING_WEST);
+ break;
+
+ case 3:
+ _game._player._playerPos = Common::Point(14, 117);
+ _game._player._facing = FACING_SOUTH;
+ _game._player.walk(Common::Point(46, 117), FACING_EAST);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (_game._objects[OBJ_RED_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[2]]->getFramePos(0);
+ _redFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_RED_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_redFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_game._objects[OBJ_GREEN_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[2]]->getFramePos(0);
+ _greenFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_GREEN_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_greenFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_game._objects[OBJ_BLUE_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[4] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[4], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[2]]->getFramePos(0);
+ _blueFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_BLUE_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_blueFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_game._objects[OBJ_YELLOW_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[2]]->getFramePos(0);
+ _yellowFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_YELLOW_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_yellowFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene456::step() {
+}
+
+void Scene456::actions() {
+ if (_action.isAction(VERB_PUT) && _action.isTarget(NOUN_FLOOR)) {
+ if (_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_BLUE_FRAME) || _action.isObject(NOUN_YELLOW_FRAME) || _action.isObject(NOUN_GREEN_FRAME)) {
+ if (_frameInRoomFl) {
+ _vm->_dialogs->show(29);
+ } else {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[1] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[1], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 5);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[1], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (_action.isObject(NOUN_RED_FRAME)) {
+ _game._objects.setRoom(OBJ_RED_FRAME, NOWHERE);
+ _game._objects[OBJ_RED_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[2]]->getFramePos(0);
+ _redFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_RED_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_redFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_action.isObject(NOUN_GREEN_FRAME)) {
+ _game._objects.setRoom(OBJ_GREEN_FRAME, NOWHERE);
+ _game._objects[OBJ_GREEN_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[2]]->getFramePos(0);
+ _greenFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_GREEN_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_greenFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME)) {
+ _game._objects.setRoom(OBJ_BLUE_FRAME, NOWHERE);
+ _game._objects[OBJ_BLUE_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[4] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[4], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[2]]->getFramePos(0);
+ _blueFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_BLUE_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_blueFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME)) {
+ _game._objects.setRoom(OBJ_YELLOW_FRAME, NOWHERE);
+ _game._objects[OBJ_YELLOW_FRAME]._roomNumber = _globals[kCatacombsRoom] + 600;
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 14);
+
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[2]]->getFramePos(0);
+ _yellowFrameHotspotId = _scene->_dynamicHotspots.add(NOUN_YELLOW_FRAME, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(pos.x - 5, pos.y - 5, pos.x + 5, pos.y + 1));
+ _scene->_dynamicHotspots.setPosition(_yellowFrameHotspotId, Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[1]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+
+ if (_action.isAction(VERB_TAKE)
+ && (_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_GREEN_FRAME) || _action.isObject(NOUN_BLUE_FRAME) || _action.isObject(NOUN_YELLOW_FRAME))) {
+ if ((_takingFrameInRoomFl || _game._trigger)) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[1] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[1], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 5);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[1], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (_action.isObject(NOUN_RED_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _scene->_dynamicHotspots.remove(_redFrameHotspotId);
+ _game._objects.addToInventory(OBJ_RED_FRAME);
+ }
+
+ if (_action.isObject(NOUN_GREEN_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[3]);
+ _scene->_dynamicHotspots.remove(_greenFrameHotspotId);
+ _game._objects.addToInventory(OBJ_GREEN_FRAME);
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[4]);
+ _scene->_dynamicHotspots.remove(_blueFrameHotspotId);
+ _game._objects.addToInventory(OBJ_BLUE_FRAME);
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME)) {
+ _scene->deleteSequence(_globals._sequenceIndexes[5]);
+ _scene->_dynamicHotspots.remove(_yellowFrameHotspotId);
+ _game._objects.addToInventory(OBJ_YELLOW_FRAME);
+ }
+
+ _vm->_sound->command(26);
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[1]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_ARCHWAY_TO_WEST)) {
+ _game.moveCatacombs(3);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_ARCHWAY_TO_EAST)) {
+ _game.moveCatacombs(1);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(45610);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(45611);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(45612);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_ARCHWAY)) {
+ _vm->_dialogs->show(45613);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_EXPOSED_BRICK)) {
+ _vm->_dialogs->show(45614);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RED_FRAME) && !_game._objects.isInInventory(OBJ_RED_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_RED_FRAME, 802, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_GREEN_FRAME) && !_game._objects.isInInventory(OBJ_GREEN_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_GREEN_FRAME, 819, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BLUE_FRAME) && !_game._objects.isInInventory(OBJ_BLUE_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_BLUE_FRAME, 817, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_YELLOW_FRAME) && !_game._objects.isInInventory(OBJ_YELLOW_FRAME)) {
+ _vm->_dialogs->showItem(OBJ_YELLOW_FRAME, 804, 0);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_MORE_CATACOMBS)) {
+ _vm->_dialogs->show(45615);
+ _action._inProgress = false;
+ }
+ }
+}
+
+void Scene456::preActions() {
+ _frameInRoomFl = false;
+ _takingFrameInRoomFl = false;
+
+ if (_game._objects[OBJ_RED_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_RED_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_game._objects[OBJ_YELLOW_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_YELLOW_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_game._objects[OBJ_BLUE_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_BLUE_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_game._objects[OBJ_GREEN_FRAME]._roomNumber == _globals[kCatacombsRoom] + 600) {
+ _frameInRoomFl = true;
+ if (_action.isAction(VERB_TAKE, NOUN_GREEN_FRAME))
+ _takingFrameInRoomFl = true;
+ }
+
+ if (_action.isAction(VERB_PUT) && _action.isTarget(NOUN_FLOOR)
+ && (_action.isObject(NOUN_RED_FRAME) || _action.isObject(NOUN_BLUE_FRAME) || _action.isObject(NOUN_YELLOW_FRAME) || _action.isObject(NOUN_GREEN_FRAME))) {
+ if (_frameInRoomFl)
+ _game._player._needToWalk = false;
+ else {
+ Common::Point pos = _scene->_sprites[_globals._spriteIndexes[2]]->getFramePos(0);
+ _game._player.walk(Common::Point(pos.x + 12, pos.y), FACING_NORTHWEST);
+ }
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+} // End of namespace Phantom
+} // End of namespace MADS
diff --git a/engines/mads/phantom/phantom_scenes4.h b/engines/mads/phantom/phantom_scenes4.h
new file mode 100644
index 0000000000..5aece98cd6
--- /dev/null
+++ b/engines/mads/phantom/phantom_scenes4.h
@@ -0,0 +1,265 @@
+/* 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 MADS_PHANTOM_SCENES4_H
+#define MADS_PHANTOM_SCENES4_H
+
+#include "common/scummsys.h"
+#include "common/serializer.h"
+#include "mads/game.h"
+#include "mads/scene.h"
+#include "mads/phantom/phantom_scenes.h"
+
+namespace MADS {
+
+namespace Phantom {
+
+class Scene4xx : public PhantomScene {
+protected:
+ /**
+ * Plays an appropriate sound when entering a scene
+ */
+ void sceneEntrySound();
+
+ /**
+ *Sets the AA file to use for the scene
+ */
+ void setAAName();
+
+ /**
+ * Updates the prefix used for getting player sprites for the scene
+ */
+ void setPlayerSpritesPrefix();
+public:
+ Scene4xx(MADSEngine *vm) : PhantomScene(vm) {}
+};
+
+class Scene401 : public Scene4xx {
+private:
+ bool _anim0ActvFl;
+ bool _frameInRoomFl;
+ bool _takingFrameInRoomFl;
+
+ int _redFrameHotspotId;
+ int _greenFrameHostpotId;
+ int _blueFrameHotspotId;
+ int _yellowFrameHotspotId;
+
+public:
+ Scene401(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene403 : public Scene4xx {
+private:
+ bool _frameInRoomFl;
+ bool _takingFrameInRoomFl;
+
+ int _redFrameHotspotId;
+ int _greenFrameHostpotId;
+ int _blueFrameHotspotId;
+ int _yellowFrameHotspotId;
+
+public:
+ Scene403(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene404 : public Scene4xx {
+private:
+ bool _frameInRoomFl;
+ bool _takingFrameInRoomFl;
+ bool _anim0ActvFl;
+
+ int _redFrameHotspotId;
+ int _greenFrameHostpotId;
+ int _blueFrameHotspotId;
+ int _yellowFrameHotspotId;
+
+public:
+ Scene404(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene406 : public Scene4xx {
+private:
+ bool _frameInRoomFl;
+ bool _takingFrameInRoomFl;
+
+ int _redFrameHotspotId;
+ int _greenFrameHostpotId;
+ int _blueFrameHotspotId;
+ int _yellowFrameHotspotId;
+
+public:
+ Scene406(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene407 : public Scene4xx {
+private:
+ bool _frameInRoomFl;
+ bool _takingFrameInRoomFl;
+
+ int _redFrameHotspotId;
+ int _greenFrameHotspotId;
+ int _blueFrameHotspotId;
+ int _yellowFrameHotspotId;
+
+public:
+ Scene407(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene408 : public Scene4xx {
+private:
+ bool _frameInRoomFl;
+ bool _takingFrameInRoomFl;
+
+ int _redFrameHotspotId;
+ int _greenFrameHotspotId;
+ int _blueFrameHotspotId;
+ int _yellowFrameHotspotId;
+
+public:
+ Scene408(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene409 : public Scene4xx {
+private:
+ bool _frameInRoomFl;
+ bool _takingFrameInRoomFl;
+
+ int _redFrameHotspotId;
+ int _greenFrameHotspotId;
+ int _blueFrameHotspotId;
+ int _yellowFrameHotspotId;
+
+public:
+ Scene409(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene410 : public Scene4xx {
+private:
+ int _skullSequence[26];
+ void getLeverInfo(Common::Point *pos, int *type, int lever_number, int *noun);
+
+public:
+ Scene410(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene453 : public Scene4xx {
+private:
+ bool _frameInRoomFl;
+ bool _takingFrameInRoomFl;
+
+ int _redFrameHotspotId;
+ int _greenFrameHotspotId;
+ int _blueFrameHotspotId;
+ int _yellowFrameHotspotId;
+
+public:
+ Scene453(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene456 : public Scene4xx {
+private:
+ bool _frameInRoomFl;
+ bool _takingFrameInRoomFl;
+
+ int _redFrameHotspotId;
+ int _greenFrameHotspotId;
+ int _blueFrameHotspotId;
+ int _yellowFrameHotspotId;
+
+public:
+ Scene456(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+} // End of namespace Phantom
+} // End of namespace MADS
+
+#endif /* MADS_PHANTOM_SCENES4_H */
diff --git a/engines/mads/phantom/phantom_scenes5.cpp b/engines/mads/phantom/phantom_scenes5.cpp
new file mode 100644
index 0000000000..12d064becb
--- /dev/null
+++ b/engines/mads/phantom/phantom_scenes5.cpp
@@ -0,0 +1,4308 @@
+/* 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 "mads/mads.h"
+#include "mads/conversations.h"
+#include "mads/scene.h"
+#include "mads/phantom/phantom_scenes.h"
+#include "mads/phantom/phantom_scenes5.h"
+
+namespace MADS {
+
+namespace Phantom {
+
+void Scene5xx::setAAName() {
+ _game._aaName = Resources::formatAAName(1);
+ _vm->_palette->setEntry(254, 43, 47, 51);
+}
+
+void Scene5xx::sceneEntrySound() {
+ if (!_vm->_musicFlag)
+ return;
+
+ if ((_globals[kCoffinStatus] == 2) && !_game._visitedScenes.exists(506) && (_globals[kFightStatus] == 0) && (_scene->_currentSceneId == 504))
+ _vm->_sound->command(33);
+ else if (_scene->_currentSceneId == 505)
+ _vm->_sound->command((_vm->_gameConv->restoreRunning() == 20) ? 39 : 16);
+ else
+ _vm->_sound->command(16);
+}
+
+void Scene5xx::setPlayerSpritesPrefix() {
+ _vm->_sound->command(5);
+
+ Common::String oldName = _game._player._spritesPrefix;
+ if (!_game._player._forcePrefix)
+ _game._player._spritesPrefix = "RAL";
+ if (oldName != _game._player._spritesPrefix)
+ _game._player._spritesChanged = true;
+
+ _game._player._scalingVelocity = true;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene501::Scene501(MADSEngine *vm) : Scene5xx(vm) {
+ _anim0ActvFl = false;
+ _skipFl = false;
+}
+
+void Scene501::synchronize(Common::Serializer &s) {
+ Scene5xx::synchronize(s);
+
+ s.syncAsByte(_anim0ActvFl);
+ s.syncAsByte(_skipFl);
+}
+
+void Scene501::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ _scene->addActiveVocab(NOUN_CHRISTINE);
+ _scene->addActiveVocab(VERB_LOOK_AT);
+ _scene->addActiveVocab(VERB_WALK_TO);
+}
+
+void Scene501::enter() {
+ _scene->_hotspots.activate(NOUN_CHRISTINE, false);
+ _scene->_hotspots.activate(NOUN_BOAT, false);
+
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ _anim0ActvFl = false;
+ _skipFl = false;
+ }
+
+ _vm->_gameConv->load(26);
+
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 2));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('a', 1));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('a', 0));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*CHR_6", PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*CHR_9", PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*CHR_8", PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites("*RDRR_6");
+
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 6);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], -1, -2);
+
+ if (_scene->_priorSceneId == RETURNING_FROM_LOADING) {
+ if (_globals[kChristineIsInBoat]) {
+ _anim0ActvFl = true;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('b', 1), 100);
+ _scene->setAnimFrame(_globals._animationIndexes[0], 124);
+ _scene->_hotspots.activateAtPos(NOUN_CHRISTINE, true, Common::Point(113, 93));
+ _scene->_hotspots.activate(NOUN_BOAT, true);
+ }
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 4);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 4);
+ }
+
+ if (_scene->_priorSceneId == 506) {
+ _game._player._playerPos = Common::Point(305, 112);
+ _game._player._facing = FACING_WEST;
+ _game._player._stepEnabled = false;
+
+ if (_globals[kChristineIsInBoat]) {
+ _anim0ActvFl = true;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('b', 1), 100);
+ _scene->setAnimFrame(_globals._animationIndexes[0], 124);
+ _scene->_hotspots.activateAtPos(NOUN_CHRISTINE, true, Common::Point(113, 93));
+ _scene->_hotspots.activate(NOUN_BOAT, true);
+ _game._player.walk(Common::Point(260, 112), FACING_SOUTHWEST);
+ _game._player.setWalkTrigger(80);
+ _game._player.setWalkTrigger(55);
+ } else {
+ _anim0ActvFl = true;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('b', 1), 100);
+ _globals[kChristineIsInBoat] = true;
+ _scene->_hotspots.activate(NOUN_BOAT, true);
+ _game._player.walk(Common::Point(260, 112), FACING_SOUTHWEST);
+ _game._player.setWalkTrigger(80);
+ }
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 4);
+
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ } else if ((_scene->_priorSceneId == 401) || (_scene->_priorSceneId == 408) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
+ _game._player.firstWalk(Common::Point(-20, 109), FACING_EAST, Common::Point(24, 109), FACING_EAST, true);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 4);
+
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 4);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene501::step() {
+ switch (_game._trigger) {
+ case 55:
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[2], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 10);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 56);
+ break;
+
+ case 56:
+ _vm->_sound->command(25);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 10);
+ if (!_globals[kChrisWillTakeSeat])
+ _game._player._stepEnabled = true;
+
+ _globals[kChrisWillTakeSeat] = false;
+ break;
+
+ default:
+ break;
+ }
+
+
+ switch (_game._trigger) {
+ case 60:
+ _globals._sequenceIndexes[1] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[1], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 4);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 61);
+ break;
+
+ case 61:
+ _vm->_sound->command(25);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 4);
+ _game._player._stepEnabled = true;
+ break;
+
+ case 80: {
+ _game._player.walk(Common::Point(255, 118), FACING_NORTHWEST);
+ _scene->setAnimFrame(_globals._animationIndexes[0], 2);
+ int idx = _scene->_dynamicHotspots.add(NOUN_CHRISTINE, VERB_WALK_TO, SYNTAX_SINGULAR_FEM, EXT_NONE, Common::Rect(0, 0, 0, 0));
+ _scene->setDynamicAnim(idx, _globals._animationIndexes[0], 0);
+ _scene->setDynamicAnim(idx, _globals._animationIndexes[0], 1);
+ _scene->setDynamicAnim(idx, _globals._animationIndexes[0], 2);
+ _scene->setDynamicAnim(idx, _globals._animationIndexes[0], 3);
+ }
+ break;
+
+ case 90:
+ _globals[kPlayerScore] += 5;
+ _scene->_nextSceneId = 310;
+ break;
+
+ case 100:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 9, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 90);
+ break;
+
+ default:
+ break;
+ }
+
+ if (_anim0ActvFl) {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == 103)
+ _scene->_hotspots.activateAtPos(NOUN_CHRISTINE, true, Common::Point(125, 94));
+
+ if ((_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == 28) && !_skipFl) {
+ _skipFl = true;
+ _scene->_sequences.addTimer(1, 55);
+ }
+
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == 124) {
+ _scene->_hotspots.activateAtPos(NOUN_CHRISTINE, false, Common::Point(125, 94));
+ _scene->_hotspots.activateAtPos(NOUN_CHRISTINE, true , Common::Point(113, 93));
+ }
+
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == 125)
+ _scene->setAnimFrame(_globals._animationIndexes[0], 124);
+
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == 1)
+ _scene->setAnimFrame(_globals._animationIndexes[0], 0);
+
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == 84)
+ _game._player._stepEnabled = true;
+ }
+}
+
+void Scene501::actions() {
+ if (_vm->_gameConv->activeConvId() == 26) {
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_ARCHWAY_TO_WEST) && (_globals[kChristineIsInBoat])) {
+ _vm->_gameConv->run(26);
+ _vm->_gameConv->exportValue(3);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TALK_TO, NOUN_CHRISTINE)) {
+ _vm->_gameConv->run(26);
+ _vm->_gameConv->exportValue(1);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLIMB_INTO, NOUN_BOAT)) {
+ if (_game._objects.isInInventory(OBJ_OAR))
+ _anim0ActvFl = false;
+ else
+ _vm->_dialogs->show(50123);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_UNLOCK, NOUN_DOOR) || _action.isAction(VERB_LOCK, NOUN_DOOR)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 5, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[3], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1: {
+ int idx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 4);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[3], SYNC_SEQ, idx);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[3], false);
+ _scene->_sequences.addTimer(15, 2);
+ _vm->_sound->command(74);
+ }
+ break;
+
+ case 2:
+ _scene->deleteSequence(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[3], false, 5, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[3], false);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[3]);
+ _game._player._visible = true;
+ _vm->_dialogs->show(50122);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR) || _action.isAction(VERB_OPEN, NOUN_DOOR)) {
+ if (_scene->_customDest.x < 287) {
+ if (!_globals[kChristineIsInBoat]) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 5, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[3], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1: {
+ int idx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 4);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[3], SYNC_SEQ, idx);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[3], false);
+ _scene->_sequences.addTimer(15, 2);
+ _vm->_sound->command(74);
+ }
+ break;
+
+ case 2:
+ _scene->deleteSequence(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[3], false, 5, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[3], false);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[3]);
+ _game._player._visible = true;
+ _vm->_dialogs->show(50120);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[3] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[3], false, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[3], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_SPRITE, 4, 65);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 67);
+ break;
+
+ case 65:
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 4);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 66);
+ _vm->_sound->command(24);
+ break;
+
+ case 66:
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _game._player.walk(Common::Point(305, 112), FACING_EAST);
+ _game._player.setWalkTrigger(68);
+ break;
+
+ case 67:
+ _game._player._visible = true;
+ break;
+
+ case 68:
+ _vm->_gameConv->stop();
+ _scene->_nextSceneId = 506;
+ break;
+ }
+ }
+ } else {
+ if (!_globals[kChristineIsInBoat]) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[3] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[3], false, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[3], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_SPRITE, 4, 65);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 67);
+ break;
+
+ case 65: {
+ int idx = _globals._sequenceIndexes[1];
+ _scene->deleteSequence(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 8, 1);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[1], SYNC_SEQ, idx);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 4);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 66);
+ _vm->_sound->command(24);
+ }
+ break;
+
+ case 66:
+ _game._player.walk(Common::Point(319, 116), FACING_NORTHWEST);
+ _game._player.setWalkTrigger(68);
+ break;
+
+ case 67:
+ _game._player._visible = true;
+ break;
+
+ case 68:
+ _globals._sequenceIndexes[1] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[1], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 69);
+ _vm->_sound->command(25);
+ break;
+
+ case 69:
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 5);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ _scene->_nextSceneId = 502;
+ break;
+ }
+ } else {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 5, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[3], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1: {
+ int idx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 4);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[3], SYNC_SEQ, idx);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[3], false);
+ _scene->_sequences.addTimer(15, 2);
+ _vm->_sound->command(73);
+ }
+ break;
+
+ case 2:
+ _scene->deleteSequence(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[3], false, 5, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[3], false);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[3]);
+ _game._player._visible = true;
+ _vm->_dialogs->show(50120);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(50110);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(50111);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(50112);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CEILING)) {
+ _vm->_dialogs->show(50113);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LAKE)) {
+ _vm->_dialogs->show(50114);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_BOAT)) {
+ _vm->_dialogs->show(50126);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_TORCH)) {
+ _vm->_dialogs->show(50117);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_ARCHWAY_TO_WEST)) {
+ _vm->_dialogs->show(50118);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DOOR)) {
+ if (_scene->_customDest.x < 287) {
+ if (_game._visitedScenes.exists(506))
+ _vm->_dialogs->show(50127);
+ else
+ _vm->_dialogs->show(50119);
+ } else {
+ if (_game._visitedScenes.exists(506))
+ _vm->_dialogs->show(50128);
+ else
+ _vm->_dialogs->show(50119);
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_COLUMN)) {
+ _vm->_dialogs->show(50121);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CHRISTINE)) {
+ _vm->_dialogs->show(50124);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_TORCH)) {
+ _vm->_dialogs->show(50125);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_CHRISTINE)) {
+ _vm->_dialogs->show(50129);
+ _action._inProgress = false;
+ }
+}
+
+void Scene501::preActions() {
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_ARCHWAY_TO_WEST)) {
+ if (_globals[kLanternStatus] == 0) {
+ _game._player._needToWalk = false;
+ _vm->_dialogs->show(30918);
+ _game._player.cancelCommand();
+ } else if (!_globals[kChristineIsInBoat])
+ _game.enterCatacombs(0);
+ }
+
+ if ((_action.isObject(NOUN_DOOR)) && (_action.isAction(VERB_LOCK) || _action.isAction(VERB_UNLOCK) || _action.isAction(VERB_OPEN))) {
+ if (_scene->_customDest.x < 287)
+ _game._player.walk(Common::Point(266, 112), FACING_EAST);
+ else
+ _game._player.walk(Common::Point(287, 118), FACING_EAST);
+ }
+
+ if ((_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR) || _action.isAction(VERB_OPEN, NOUN_DOOR)) && _game._visitedScenes.exists(506) && _scene->_customDest.x < 287) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._readyToWalk = false;
+ _game._player._needToWalk = false;
+ _game._player._stepEnabled = false;
+ _vm->_gameConv->run(26);
+ _vm->_gameConv->exportValue(2);
+ _scene->_sequences.addTimer(6, 1);
+ break;
+
+ case 1:
+ if (_vm->_gameConv->activeConvId() >= 0)
+ _scene->_sequences.addTimer(6, 1);
+ else {
+ _game._player._stepEnabled = true;
+ _action._inProgress = true;
+ _game._player._needToWalk = true;
+ _game._player._readyToWalk = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_ARCHWAY_TO_WEST) && _globals[kLanternStatus] && _globals[kRightDoorIsOpen504])
+ _game._player.walk(Common::Point(24, 110), FACING_WEST);
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene502::Scene502(MADSEngine *vm) : Scene5xx(vm) {
+ _fire1ActiveFl = false;
+ _fire2ActiveFl = false;
+ _fire3ActiveFl = false;
+ _fire4ActiveFl = false;
+ _panelTurningFl = false;
+ _trapDoorHotspotEnabled = false;
+ _acceleratedFireActivationFl = false;
+
+ for (int i = 0; i < 16; i++) {
+ _puzzlePictures[i] = -1;
+ _puzzleSprites[i] = -1;
+ _puzzleSequences[i] = -1;
+ }
+
+ _panelPushedNum = -1;
+ _messageLevel = -1;
+ _cycleStage = -1;
+
+ _nextPos = Common::Point(-1, -1);
+
+ _lastFrameTime = 0;
+ _timer = 0;
+ _deathTimer = 0;
+
+ _cyclePointer = nullptr;
+}
+
+Scene502::~Scene502() {
+ if (_cyclePointer)
+ delete(_cyclePointer);
+}
+
+void Scene502::synchronize(Common::Serializer &s) {
+ Scene5xx::synchronize(s);
+
+ s.syncAsByte(_fire1ActiveFl);
+ s.syncAsByte(_fire2ActiveFl);
+ s.syncAsByte(_fire3ActiveFl);
+ s.syncAsByte(_fire4ActiveFl);
+ s.syncAsByte(_panelTurningFl);
+ s.syncAsByte(_trapDoorHotspotEnabled);
+ s.syncAsByte(_acceleratedFireActivationFl);
+
+ for (int i = 0; i < 16; i++) {
+ s.syncAsSint16LE(_puzzlePictures[i]);
+ s.syncAsSint16LE(_puzzleSprites[i]);
+ s.syncAsSint16LE(_puzzleSequences[i]);
+ }
+
+ s.syncAsSint16LE(_panelPushedNum);
+ s.syncAsSint16LE(_messageLevel);
+ s.syncAsSint16LE(_cycleStage);
+
+ s.syncAsSint16LE(_nextPos.x);
+ s.syncAsSint16LE(_nextPos.y);
+
+ s.syncAsUint32LE(_lastFrameTime);
+ s.syncAsUint32LE(_timer);
+ s.syncAsUint32LE(_deathTimer);
+
+ warning("more syncing required");
+}
+
+void Scene502::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene502::enter() {
+ loadCyclingInfo();
+ _scene->loadSpeech(7);
+
+ _panelPushedNum = -1;
+ _panelTurningFl = false;
+ _fire1ActiveFl = false;
+ _fire2ActiveFl = false;
+ _fire3ActiveFl = false;
+ _fire4ActiveFl = false;
+
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ _lastFrameTime = _scene->_frameStartTime;
+ _cycleStage = 0;
+ _timer = 0;
+ _deathTimer = 0;
+ _messageLevel = 1;
+ _acceleratedFireActivationFl = true;
+ _trapDoorHotspotEnabled = false;
+ }
+
+ _scene->_hotspots.activate(NOUN_ROPE, false);
+ _scene->_hotspots.activateAtPos(NOUN_TRAP_DOOR, false, Common::Point(225, 28));
+
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('x', 2));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 3));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 4));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('x', 5));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('a', 2));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('a', 1));
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('a', 3));
+ _globals._spriteIndexes[9] = _scene->_sprites.addSprites(formAnimName('x', 6));
+ _globals._spriteIndexes[10] = _scene->_sprites.addSprites(formAnimName('a', 0));
+ _globals._spriteIndexes[11] = _scene->_sprites.addSprites(formAnimName('j', 0));
+ _globals._spriteIndexes[12] = _scene->_sprites.addSprites(formAnimName('k', 0));
+ _globals._spriteIndexes[13] = _scene->_sprites.addSprites(formAnimName('l', 0));
+ _globals._spriteIndexes[14] = _scene->_sprites.addSprites(formAnimName('m', 0));
+ _globals._spriteIndexes[16] = _scene->_sprites.addSprites(formAnimName('h', 0));
+
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 14);
+ } else
+ _scene->drawToBackground(_globals._spriteIndexes[5], -2, Common::Point(-32000, -32000), 0, 100);
+
+ if ((_scene->_priorSceneId == 501) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
+ if (!_game._visitedScenes._sceneRevisited) {
+ if (_game._objects.isInInventory(OBJ_ROPE))
+ _globals[kCableHookWasSeparate] = true;
+ else
+ _globals[kCableHookWasSeparate] = false;
+ } else if (_globals[kCableHookWasSeparate]) {
+ _game._objects.addToInventory(OBJ_ROPE);
+ _game._objects.addToInventory(OBJ_CABLE_HOOK);
+ _game._objects.setRoom(OBJ_ROPE_WITH_HOOK, NOWHERE);
+ } else {
+ _game._objects.setRoom(OBJ_ROPE, NOWHERE);
+ _game._objects.setRoom(OBJ_CABLE_HOOK, NOWHERE);
+ _game._objects.addToInventory(OBJ_ROPE_WITH_HOOK);
+ }
+
+ _game._player._playerPos = Common::Point(43, 154);
+ _game._player._facing = FACING_EAST;
+ _game._player._stepEnabled = false;
+ _game._player.walk(Common::Point(87, 153), FACING_EAST);
+ _game._player.setWalkTrigger(77);
+ }
+
+ room_502_initialize_panels();
+
+ if (_trapDoorHotspotEnabled) {
+ _globals._sequenceIndexes[6] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[6], false, 6);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 1);
+ _scene->_hotspots.activate(NOUN_TRAP_DOOR, false);
+ _scene->_hotspots.activateAtPos(NOUN_TRAP_DOOR, true, Common::Point(225, 28));
+ if (!_game._objects.isInInventory(OBJ_ROPE_WITH_HOOK) && !_game._objects.isInInventory(OBJ_CABLE_HOOK)) {
+ _globals._sequenceIndexes[9] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[9], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 12);
+ _scene->_hotspots.activate(NOUN_ROPE, true);
+ }
+ } else {
+ _globals._sequenceIndexes[6] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[6], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 14);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene502::step() {
+ if (_acceleratedFireActivationFl) {
+ int32 diff = _scene->_frameStartTime - _lastFrameTime;
+ if ((diff >= 0) && (diff <= 4)) {
+ _timer += diff;
+ _deathTimer += diff;
+ } else {
+ _timer += 1;
+ _deathTimer += 1;
+ }
+ _lastFrameTime = _scene->_frameStartTime;
+
+ if (_timer >= 300) {
+ _timer = 0;
+ if (_cycleStage < 8)
+ ++_cycleStage;
+ }
+ }
+
+ if ((_deathTimer >= 7200) && !_panelTurningFl) {
+ _vm->_dialogs->show(50215);
+ _game._player.walk(Common::Point(160, 148), FACING_NORTH);
+ _game._player.setWalkTrigger(71);
+ _game._player._stepEnabled = false;
+ _panelTurningFl = true;
+ _deathTimer = 0;
+ }
+
+ if ((_deathTimer > 900) && (_messageLevel == 1) && !_panelTurningFl) {
+ _messageLevel = 2;
+ _vm->_dialogs->show(50212);
+ }
+
+ if ((_deathTimer > 3600) && (_messageLevel == 2) && !_panelTurningFl) {
+ _messageLevel = 3;
+ _vm->_dialogs->show(50213);
+ }
+
+ if ((_deathTimer > 5400) && (_messageLevel == 3) && !_panelTurningFl) {
+ _messageLevel = 4;
+ _vm->_dialogs->show(50214);
+ }
+
+ switch (_game._trigger) {
+ case 71:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 7, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 72);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_SPRITE, 44, 73);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_SPRITE, 51, 74);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_SPRITE, 32, 75);
+ break;
+
+ case 72:
+ _globals._sequenceIndexes[4] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[4], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 1);
+ _scene->_userInterface.noInventoryAnim();
+ // CHECKME: Not sure about the next function call
+ _scene->_userInterface.refresh();
+ _scene->_sequences.addTimer(120, 76);
+ break;
+
+ case 73:
+ _vm->_sound->command(1);
+ _vm->_sound->command(67);
+ break;
+
+ case 74:
+ _vm->_sound->command(27);
+ break;
+
+ case 75:
+ _scene->playSpeech(7);
+ break;
+
+ case 76:
+ _scene->_reloadSceneFlag = true;
+ break;
+
+ case 77:
+ _scene->deleteSequence(_globals._sequenceIndexes[5]);
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 7, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 78);
+ break;
+
+ case 78:
+ _vm->_dialogs->show(50211);
+ _scene->drawToBackground(_globals._spriteIndexes[5], -2, Common::Point(-32000, -32000), 0, 100);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+
+ if (!_trapDoorHotspotEnabled)
+ animateFireBursts();
+
+ setPaletteCycle();
+}
+
+void Scene502::actions() {
+ if (_game._trigger >= 110) {
+ handlePanelAnimation();
+ _action._inProgress = false;
+ return;
+ }
+
+ switch (_game._trigger) {
+ case 80:
+ _globals._sequenceIndexes[6] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[6], false, 6);
+ _scene->_hotspots.activateAtPos(NOUN_ROPE, true, Common::Point(225, 28));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 1);
+ _scene->_hotspots.activate(NOUN_TRAP_DOOR, false);
+ _scene->_hotspots.activateAtPos(NOUN_TRAP_DOOR, true, Common::Point(225, 28));
+ if (!_panelTurningFl)
+ _vm->_dialogs->show(50216);
+
+ _action._inProgress = false;
+ return;
+
+ case 90:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[10] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[10], false, 7, 2);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[10], true);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[10], 14, 18);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[10], SEQUENCE_TRIGGER_EXPIRE, 0, 91);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[10], SEQUENCE_TRIGGER_SPRITE, 18, 110);
+ _action._inProgress = false;
+ return;
+
+ case 91:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[10]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ _scene->_sequences.addTimer(5, 102);
+ _action._inProgress = false;
+ return;
+
+ case 95:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[10] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[10], false, 7, 2);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[10], true);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[10], 8, 13);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[10], SEQUENCE_TRIGGER_EXPIRE, 0, 96);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[10], SEQUENCE_TRIGGER_SPRITE, 13, 110);
+ _action._inProgress = false;
+ return;
+
+ case 96:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[10]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ _scene->_sequences.addTimer(5, 102);
+ _action._inProgress = false;
+ return;
+
+ case 100:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[10] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[10], false, 9, 2);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[10], true);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[10], 5, 7);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[10], SEQUENCE_TRIGGER_EXPIRE, 0, 101);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[10], SEQUENCE_TRIGGER_SPRITE, 7, 110);
+ _action._inProgress = false;
+ return;
+
+ case 101:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[10]);
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(5, 102);
+ _action._inProgress = false;
+ return;
+
+ case 102:
+ _panelTurningFl = false;
+ _game._player._stepEnabled = true;
+ _action._inProgress = false;
+ return;
+
+ case 105:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[10] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[10], false, 8, 2);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[10], true);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[10], 1, 4);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[10], SEQUENCE_TRIGGER_EXPIRE, 0, 106);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[10], SEQUENCE_TRIGGER_SPRITE, 4, 110);
+ _action._inProgress = false;
+ return;
+
+ case 106:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[10]);
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(5, 102);
+ _action._inProgress = false;
+ return;
+
+ default:
+ break;
+ }
+
+ if (_action.isAction(VERB_PUSH, NOUN_PANEL)) {
+ if (_panelTurningFl) {
+ _action._inProgress = false;
+ return;
+ }
+
+ Common::Point walkToPos;
+ getPanelInfo(&walkToPos, &_panelPushedNum, _scene->_customDest, &_nextPos);
+ _panelTurningFl = true;
+
+ switch (_panelPushedNum) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ _scene->_sequences.addTimer(1, 90);
+ break;
+
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ _scene->_sequences.addTimer(1, 95);
+ break;
+
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ _scene->_sequences.addTimer(1, 100);
+ break;
+
+ default:
+ _scene->_sequences.addTimer(1, 105);
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_THROW, NOUN_ROPE_WITH_HOOK, NOUN_TRAP_DOOR) || _action.isAction(VERB_GRAPPLE, NOUN_TRAP_DOOR)) {
+ if (_trapDoorHotspotEnabled) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _panelTurningFl = true;
+ _globals._sequenceIndexes[7] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[7], false, 6, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 13);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[7], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_EXPIRE, 0, 82);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_SPRITE, 10, 83);
+ _game._objects.setRoom(OBJ_ROPE_WITH_HOOK, NOWHERE);
+ break;
+
+ case 82:
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ _panelTurningFl = false;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[7]);
+ _globals._sequenceIndexes[9] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[9], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 13);
+ _scene->_hotspots.activate(NOUN_ROPE, true);
+ break;
+
+ case 83:
+ _vm->_sound->command(69);
+ break;
+
+ default:
+ break;
+ }
+ } else
+ _vm->_dialogs->show(50229);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLIMB_THROUGH, NOUN_TRAP_DOOR)
+ && (_game._objects.isInInventory(OBJ_ROPE_WITH_HOOK) || _game._objects.isInInventory(OBJ_CABLE_HOOK))) {
+ _vm->_dialogs->show(50228);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_THROW, NOUN_ROPE, NOUN_TRAP_DOOR)) {
+ _vm->_dialogs->show(50226);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_THROW, NOUN_CABLE_HOOK, NOUN_TRAP_DOOR)) {
+ _vm->_dialogs->show(50227);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLIMB, NOUN_ROPE) || _action.isAction(VERB_CLIMB_THROUGH, NOUN_TRAP_DOOR)) {
+ switch (_game._trigger) {
+ case 0:
+ _globals[kPlayerScore] += 5;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _panelTurningFl = true;
+ _globals._sequenceIndexes[8] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[8], false, 6, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[8], 10);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[8], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 82);
+ break;
+
+ case 82:
+ _scene->_nextSceneId = 504;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(50210);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(50217);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_TRAP_DOOR)) {
+ _vm->_dialogs->show(_trapDoorHotspotEnabled ? 50220 : 50225);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(50219);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DOOR)) {
+ _vm->_dialogs->show(50221);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PANELS)) {
+ _vm->_dialogs->show(50222);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PANEL)) {
+ _vm->_dialogs->show(50223);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CEILING)) {
+ _vm->_dialogs->show(50224);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_ROPE) && !_game._objects.isInInventory(OBJ_ROPE)
+ && !_game._objects.isInInventory(OBJ_CABLE_HOOK) && !_game._objects.isInInventory(OBJ_ROPE_WITH_HOOK)) {
+ _vm->_dialogs->show(50233);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_TRAP_DOOR)) {
+ _vm->_dialogs->show(_trapDoorHotspotEnabled ? 50230 : 50228);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLOSE, NOUN_TRAP_DOOR)) {
+ _vm->_dialogs->show(_trapDoorHotspotEnabled ? 50228 : 50231);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_ROPE) && !_game._objects.isInInventory(OBJ_ROPE)
+ && !_game._objects.isInInventory(OBJ_CABLE_HOOK) && !_game._objects.isInInventory(OBJ_ROPE_WITH_HOOK)) {
+ _vm->_dialogs->show(50234);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LASSO, NOUN_TRAP_DOOR)) {
+ _vm->_dialogs->show(50232);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene502::preActions() {
+ int panel;
+
+ if (_action.isAction(VERB_PUSH, NOUN_PANEL)) {
+ Common::Point walkToPos;
+ Common::Point tmpPos;
+ getPanelInfo(&walkToPos, &panel, _scene->_customDest, &tmpPos);
+ _game._player.walk(walkToPos, FACING_NORTH);
+ }
+
+ if (_trapDoorHotspotEnabled && (_action.isAction(VERB_CLIMB, NOUN_ROPE) || _action.isAction(VERB_CLIMB_THROUGH, NOUN_TRAP_DOOR)))
+ _game._player.walk(Common::Point(211, 149), FACING_NORTH);
+
+ if (_trapDoorHotspotEnabled && (_action.isAction(VERB_THROW, NOUN_ROPE_WITH_HOOK, NOUN_TRAP_DOOR) || _action.isAction(VERB_GRAPPLE, NOUN_TRAP_DOOR)))
+ _game._player.walk(Common::Point(200, 149), FACING_NORTH);
+}
+
+void Scene502::room_502_initialize_panels() {
+ for (int i = 0, curPuzzleSprite = 2, count = 1; i < 16; i++) {
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING)
+ _puzzlePictures[i] = _vm->getRandomNumber(1, 4);
+
+ curPuzzleSprite += (_puzzlePictures[i] * 3) - 3;
+ _puzzleSprites[i] = curPuzzleSprite;
+
+ int sprIdx;
+
+ switch (i) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ sprIdx = _globals._spriteIndexes[11];
+ break;
+
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ sprIdx = _globals._spriteIndexes[12];
+ break;
+
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ sprIdx = _globals._spriteIndexes[13];
+ break;
+
+ default:
+ sprIdx = _globals._spriteIndexes[14];
+ break;
+ }
+
+ _globals._sequenceIndexes[15] = _scene->_sequences.addStampCycle(sprIdx, false, curPuzzleSprite);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[15], 14);
+ _puzzleSequences[i] = _globals._sequenceIndexes[15];
+
+ ++count;
+ if (count >= 5)
+ count = 1;
+
+ switch (count) {
+ case 1:
+ curPuzzleSprite = 2;
+ break;
+
+ case 2:
+ curPuzzleSprite = 14;
+ break;
+
+ case 3:
+ curPuzzleSprite = 26;
+ break;
+
+ case 4:
+ curPuzzleSprite = 38;
+ break;
+ }
+ }
+}
+
+void Scene502::loadCyclingInfo() {
+ warning("TODO: loadCyclingInfo");
+}
+
+void Scene502::animateFireBursts() {
+ int rndTrigger;
+
+ if (_acceleratedFireActivationFl)
+ rndTrigger = _vm->getRandomNumber(1, 50);
+ else
+ rndTrigger = _vm->getRandomNumber(1, 400);
+
+ if (rndTrigger == 1) {
+ rndTrigger = _vm->getRandomNumber(1, 4);
+
+ switch (rndTrigger) {
+ case 1:
+ if (!_fire1ActiveFl) {
+ _scene->_sequences.addTimer(_vm->getRandomNumber(300, 600), 60);
+ _fire1ActiveFl = true;
+ }
+ break;
+
+ case 2:
+ if (!_fire2ActiveFl) {
+ _scene->_sequences.addTimer(_vm->getRandomNumber(300, 600), 63);
+ _fire2ActiveFl = true;
+ }
+ break;
+
+ case 3:
+ if (!_fire3ActiveFl) {
+ _scene->_sequences.addTimer(_vm->getRandomNumber(300, 600), 66);
+ _fire3ActiveFl = true;
+ }
+ break;
+
+ case 4:
+ if (!_fire4ActiveFl) {
+ _scene->_sequences.addTimer(_vm->getRandomNumber(300, 600), 69);
+ _fire4ActiveFl = true;
+ }
+ break;
+ }
+ }
+
+ switch (_game._trigger) {
+ case 60:
+ if ((_game._player._playerPos.x < 198) || (_game._player._playerPos.y > 150)) {
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 5, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], 1, 10);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 61);
+ }
+ break;
+
+ case 61:
+ _fire1ActiveFl = false;
+ break;
+
+ case 63:
+ if ((_game._player._playerPos.x > 127) || (_game._player._playerPos.y < 150)) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 5, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 10);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 64);
+ }
+ break;
+
+ case 64:
+ _fire2ActiveFl = false;
+ break;
+
+ case 66:
+ if (_game._player._playerPos.x < 198) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 5, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 10);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 67);
+ }
+ break;
+
+ case 67:
+ _fire3ActiveFl = false;
+ break;
+
+ case 69:
+ if ((_game._player._playerPos.x > 110) || (_game._player._playerPos.y > 150)) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 5, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 10);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 70);
+ }
+ break;
+
+ case 70:
+ _fire4ActiveFl = false;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene502::setPaletteCycle() {
+ warning("TODO: setPaletteCycle");
+}
+
+void Scene502::getPanelInfo(Common::Point *walkToPos, int *panel, Common::Point mousePos, Common::Point *interimPos) {
+ walkToPos->y = 148;
+
+ if ((mousePos.x < 120) || (mousePos.y < 75) || (mousePos.y > 137))
+ return;
+
+ if (mousePos.x <= 139) {
+ interimPos->x = 129;
+ if (mousePos.y <= 90) {
+ *panel = 0;
+ interimPos->y = 90;
+ walkToPos->x = 107;
+ } else if (mousePos.y <= 106) {
+ *panel = 4;
+ interimPos->y = 106;
+ walkToPos->x = 107;
+ } else if (mousePos.y <= 122) {
+ *panel = 8;
+ interimPos->y = 122;
+ walkToPos->x = 107;
+ } else {
+ *panel = 12;
+ interimPos->y = 138;
+ walkToPos->x = 107;
+ }
+ } else if (mousePos.x <= 159) {
+ interimPos->x = 149;
+ if (mousePos.y <= 90) {
+ *panel = 1;
+ interimPos->y = 90;
+ walkToPos->x = 127;
+ } else if (mousePos.y <= 106) {
+ *panel = 5;
+ interimPos->y = 106;
+ walkToPos->x = 127;
+ } else if (mousePos.y <= 122) {
+ *panel = 9;
+ interimPos->y = 122;
+ walkToPos->x = 127;
+ } else {
+ *panel = 13;
+ interimPos->y = 138;
+ walkToPos->x = 127;
+ }
+ } else if (mousePos.x <= 179) {
+ interimPos->x = 169;
+ if (mousePos.y <= 90) {
+ *panel = 2;
+ interimPos->y = 90;
+ walkToPos->x = 147;
+ } else if (mousePos.y <= 106) {
+ *panel = 6;
+ interimPos->y = 106;
+ walkToPos->x = 147;
+ } else if (mousePos.y <= 122) {
+ *panel = 10;
+ interimPos->y = 122;
+ walkToPos->x = 147;
+ } else {
+ *panel = 14;
+ interimPos->y = 138;
+ walkToPos->x = 147;
+ }
+ } else if (mousePos.x <= 199) {
+ interimPos->x = 189;
+ if (mousePos.y <= 90) {
+ *panel = 3;
+ interimPos->y = 90;
+ walkToPos->x = 167;
+ } else if (mousePos.y <= 106) {
+ *panel = 7;
+ interimPos->y = 106;
+ walkToPos->x = 167;
+ } else if (mousePos.y <= 122) {
+ *panel = 11;
+ interimPos->y = 122;
+ walkToPos->x = 167;
+ } else {
+ *panel = 15;
+ interimPos->y = 138;
+ walkToPos->x = 167;
+ }
+ }
+}
+
+void Scene502::handlePanelAnimation() {
+ switch (_game._trigger) {
+ case 110:
+ _vm->_sound->command(65);
+ _scene->deleteSequence(_puzzleSequences[_panelPushedNum]);
+ switch (_panelPushedNum) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ _globals._sequenceIndexes[11] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[11], false, _puzzleSprites[_panelPushedNum] - 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[11], 14);
+ _scene->_sequences.addTimer(5, 111);
+ break;
+
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ _globals._sequenceIndexes[12] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[12], false, _puzzleSprites[_panelPushedNum] - 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[12], 14);
+ _scene->_sequences.addTimer(5, 111);
+ break;
+
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ _globals._sequenceIndexes[13] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[13], false, _puzzleSprites[_panelPushedNum] - 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 14);
+ _scene->_sequences.addTimer(5, 111);
+ break;
+
+ default:
+ _globals._sequenceIndexes[14] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[14], false, _puzzleSprites[_panelPushedNum] - 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[14], 14);
+ _scene->_sequences.addTimer(5, 111);
+ break;
+ }
+ break;
+
+ case 111:
+ switch (_panelPushedNum) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ _scene->deleteSequence(_globals._sequenceIndexes[11]);
+ break;
+
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ _scene->deleteSequence(_globals._sequenceIndexes[12]);
+ break;
+
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ _scene->deleteSequence(_globals._sequenceIndexes[13]);
+ break;
+
+ default:
+ _scene->deleteSequence(_globals._sequenceIndexes[14]);
+ break;
+ }
+
+ _globals._sequenceIndexes[16] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[16], false, 5, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[16], 14);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[16], _nextPos);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[16], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[16], SEQUENCE_TRIGGER_EXPIRE, 0, 112);
+ break;
+
+ case 112: {
+ int idx = _globals._sequenceIndexes[16];
+ int newSprId = _puzzleSprites[_panelPushedNum] + 4;
+
+ switch (_panelPushedNum) {
+ case 0:
+ case 4:
+ case 8:
+ case 12:
+ if (newSprId > 12)
+ newSprId = 3;
+ break;
+
+ case 1:
+ case 5:
+ case 9:
+ case 13:
+ if (newSprId > 24)
+ newSprId = 15;
+ break;
+
+ case 2:
+ case 6:
+ case 10:
+ case 14:
+ if (newSprId > 36)
+ newSprId = 27;
+ break;
+
+ default:
+ if (newSprId > 48)
+ newSprId = 39;
+ break;
+ }
+
+ switch (_panelPushedNum) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ _globals._sequenceIndexes[11] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[11], false, newSprId);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[11], 14);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[11], SYNC_SEQ, idx);
+ _scene->_sequences.addTimer(5, 113);
+ break;
+
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ _globals._sequenceIndexes[12] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[12], false, newSprId);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[12], 14);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[12], SYNC_SEQ, idx);
+ _scene->_sequences.addTimer(5, 113);
+ break;
+
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ _globals._sequenceIndexes[13] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[13], false, newSprId);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 14);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[13], SYNC_SEQ, idx);
+ _scene->_sequences.addTimer(5, 113);
+ break;
+
+ default:
+ _globals._sequenceIndexes[14] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[14], false, newSprId);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[14], 14);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[14], SYNC_SEQ, idx);
+ _scene->_sequences.addTimer(5, 113);
+ break;
+ }
+ }
+ break;
+
+ case 113: {
+ switch (_panelPushedNum) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ _scene->deleteSequence(_globals._sequenceIndexes[11]);
+ break;
+
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ _scene->deleteSequence(_globals._sequenceIndexes[12]);
+ break;
+
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ _scene->deleteSequence(_globals._sequenceIndexes[13]);
+ break;
+
+ default:
+ _scene->deleteSequence(_globals._sequenceIndexes[14]);
+ break;
+ }
+
+ int newSprId = _puzzleSprites[_panelPushedNum] + 3;
+
+ switch (_panelPushedNum) {
+ case 0:
+ case 4:
+ case 8:
+ case 12:
+ if (newSprId > 12)
+ newSprId = 2;
+ break;
+
+ case 1:
+ case 5:
+ case 9:
+ case 13:
+ if (newSprId > 24)
+ newSprId = 14;
+ break;
+
+ case 2:
+ case 6:
+ case 10:
+ case 14:
+ if (newSprId > 36)
+ newSprId = 26;
+ break;
+
+ default:
+ if (newSprId > 48)
+ newSprId = 38;
+ break;
+ }
+ _puzzleSprites[_panelPushedNum] = newSprId;
+ ++_puzzlePictures[_panelPushedNum];
+ if (_puzzlePictures[_panelPushedNum] >= 5)
+ _puzzlePictures[_panelPushedNum] = 1;
+
+ switch (_panelPushedNum) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ _globals._sequenceIndexes[11] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[11], false, newSprId);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[11], 14);
+ _puzzleSequences[_panelPushedNum] = _globals._sequenceIndexes[11];
+ break;
+
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ _globals._sequenceIndexes[12] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[12], false, newSprId);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[12], 14);
+ _puzzleSequences[_panelPushedNum] = _globals._sequenceIndexes[12];
+ break;
+
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ _globals._sequenceIndexes[13] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[13], false, newSprId);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 14);
+ _puzzleSequences[_panelPushedNum] = _globals._sequenceIndexes[13];
+ break;
+
+ default:
+ _globals._sequenceIndexes[14] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[14], false, newSprId);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[14], 14);
+ _puzzleSequences[_panelPushedNum] = _globals._sequenceIndexes[14];
+ break;
+ }
+
+ int puzzleSolvedFl = true;
+ for (int i = 0; i < 16; i++) {
+ if (_puzzlePictures[i] != 1)
+ puzzleSolvedFl = false;
+ }
+
+ if (puzzleSolvedFl && !_trapDoorHotspotEnabled) {
+ _trapDoorHotspotEnabled = true;
+ _scene->deleteSequence(_globals._sequenceIndexes[6]);
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('t', 1), 80);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene504::Scene504(MADSEngine *vm) : Scene5xx(vm) {
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _anim2ActvFl = false;
+ _anim3ActvFl = false;
+ _anim4ActvFl = false;
+ _anim5ActvFl = false;
+ _playingMusicFl = false;
+ _chairDialogDoneFl = false;
+ _fireBreathFl = false;
+
+ _songNum = -1;
+ _input3Count = -1;
+ _playCount = -1;
+ _listenStatus = -1;
+ _listenFrame = -1;
+ _chairStatus = -1;
+ _chairFrame = -1;
+ _playStatus = -1;
+ _playFrame = -1;
+ _phantomStatus = -1;
+ _phantomFrame = -1;
+ _christineTalkCount = -1;
+ _deathCounter = -1;
+}
+
+void Scene504::synchronize(Common::Serializer &s) {
+ Scene5xx::synchronize(s);
+
+ s.syncAsByte(_anim0ActvFl);
+ s.syncAsByte(_anim1ActvFl);
+ s.syncAsByte(_anim2ActvFl);
+ s.syncAsByte(_anim3ActvFl);
+ s.syncAsByte(_anim4ActvFl);
+ s.syncAsByte(_anim5ActvFl);
+ s.syncAsByte(_playingMusicFl);
+ s.syncAsByte(_chairDialogDoneFl);
+ s.syncAsByte(_fireBreathFl);
+
+ s.syncAsSint16LE(_songNum);
+ s.syncAsSint16LE(_input3Count);
+ s.syncAsSint16LE(_playCount);
+ s.syncAsSint16LE(_listenStatus);
+ s.syncAsSint16LE(_listenFrame);
+ s.syncAsSint16LE(_chairStatus);
+ s.syncAsSint16LE(_chairFrame);
+ s.syncAsSint16LE(_playStatus);
+ s.syncAsSint16LE(_playFrame);
+ s.syncAsSint16LE(_phantomStatus);
+ s.syncAsSint16LE(_phantomFrame);
+ s.syncAsSint16LE(_christineTalkCount);
+ s.syncAsSint16LE(_deathCounter);
+}
+
+void Scene504::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ _scene->addActiveVocab(NOUN_PHANTOM);
+ _scene->addActiveVocab(NOUN_CHRISTINE);
+}
+
+void Scene504::enter() {
+ _vm->_disableFastwalk = true;
+
+ _input3Count = 0;
+ _deathCounter = 0;
+ _anim2ActvFl = false;
+
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ _playCount = 0;
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _anim3ActvFl = false;
+ _anim4ActvFl = false;
+ _anim5ActvFl = false;
+ _playingMusicFl = false;
+ _fireBreathFl = false;
+ _chairDialogDoneFl = false;
+ _songNum = 0;
+ _phantomStatus = 0;
+ }
+
+ _scene->_hotspots.activate(NOUN_CHRISTINE, false);
+
+ if (!_globals[kRightDoorIsOpen504]) {
+ _vm->_gameConv->load(19);
+ _vm->_gameConv->load(27);
+ } else
+ _vm->_gameConv->load(21);
+
+ _vm->_gameConv->load(26);
+
+ _globals._spriteIndexes[14] = _scene->_sprites.addSprites("*RDR_9");
+ _globals._spriteIndexes[15] = _scene->_sprites.addSprites(formAnimName('x', 8));
+
+ if (!_game._objects.isInRoom(OBJ_MUSIC_SCORE)) {
+ _globals._sequenceIndexes[15] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[15], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[15], 14);
+ _scene->_hotspots.activate(NOUN_MUSIC_SCORE, false);
+ }
+
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('x', 2));
+ _globals._spriteIndexes[13] = _scene->_sprites.addSprites(formAnimName('x', 7), PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+
+ if (_globals[kFightStatus] == 0)
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 1));
+
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('x', 3));
+
+ if ((_scene->_priorSceneId == 505) || ((_scene->_priorSceneId == 504) && _globals[kRightDoorIsOpen504])) {
+ if ((_globals[kFightStatus] == 0) && (_globals[kCoffinStatus] == 2)) {
+ _scene->_hotspots.activate(NOUN_CHRISTINE, true);
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+
+ _globals._spriteIndexes[13] = _scene->_sprites.addSprites(formAnimName('x', 7), PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('b', 0));
+
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*CHR_6", PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*FACERAL", PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*FACEXDFR", PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*FACEPHN", PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+
+ _globals._spriteIndexes[11] = _scene->_sprites.addSprites(formAnimName('a', 5));
+ _globals._spriteIndexes[10] = _scene->_sprites.addSprites(formAnimName('a', 3), PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('a', 6), PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('a', 7), PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[9] = _scene->_sprites.addSprites(formAnimName('a', 0), PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+
+ _globals._animationIndexes[3] = _scene->loadAnimation(formAnimName('p', 1), 0);
+ int hotspotIdx = _scene->_dynamicHotspots.add(NOUN_PHANTOM, VERB_LOOK_AT, SYNTAX_MASC_NOT_PROPER, EXT_NONE, Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots[hotspotIdx]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(hotspotIdx, Common::Point(-2, -2), FACING_NONE);
+
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[3], 4);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[3], 8);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[3], 13);
+
+ _phantomStatus = 0;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _anim3ActvFl = true;
+ } else {
+ if (_globals[kFightStatus])
+ _scene->drawToBackground(_globals._spriteIndexes[13], 1, Common::Point(-32000, -32000), 0, 100);
+
+ if (_globals[kCoffinStatus] != 2) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ }
+
+ _game._player._playerPos = Common::Point(317, 115);
+ _game._player._facing = FACING_SOUTHWEST;
+ _game._player.walk(Common::Point(279, 121), FACING_SOUTHWEST);
+
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+
+ if (!_game._visitedScenes.exists(506) && (_globals[kCoffinStatus] == 2)) {
+ _scene->changeVariant(1);
+
+ _scene->drawToBackground(_globals._spriteIndexes[13], 1, Common::Point(-32000, -32000), 0, 100);
+ _anim5ActvFl = true;
+
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*CHR_2");
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*FACERAL", PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*FACEXDFR",PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*FACEPHN", PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+
+ _globals._animationIndexes[3] = _scene->loadAnimation(formAnimName('p', 3), 0);
+ int hotspotIdx = _scene->_dynamicHotspots.add(NOUN_CHRISTINE, VERB_WALK_TO, SYNTAX_SINGULAR_FEM, EXT_NONE, Common::Rect(0, 0, 0, 0));
+ _phantomStatus = 5;
+ _scene->_dynamicHotspots[hotspotIdx]._articleNumber = PREP_ON;
+ _scene->setAnimFrame(_globals._animationIndexes[3], 79);
+ _scene->_dynamicHotspots.setPosition(hotspotIdx, Common::Point(66, 119), FACING_NORTHWEST);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[3], 0);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[3], 1);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[3], 2);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[3], 3);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[3], 4);
+ }
+ }
+ } else if (_scene->_priorSceneId == 506) {
+ _game._player._playerPos = Common::Point(0, 109);
+ _game._player._facing = FACING_SOUTHEAST;
+ _game._player.walk(Common::Point(39, 118), FACING_SOUTHEAST);
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->drawToBackground(_globals._spriteIndexes[13], 1, Common::Point(-32000, -32000), 0, 100);
+ } else if (_scene->_priorSceneId == 504) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+
+ _game._player._playerPos = Common::Point(147, 131);
+ _game._player._facing = FACING_EAST;
+ } else if ((_scene->_priorSceneId == 502) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('t', 1), 60);
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _game._player._playerPos = Common::Point(147, 131);
+ _game._player._facing = FACING_EAST;
+ }
+
+ if (_scene->_priorSceneId == RETURNING_FROM_LOADING) {
+ if (!_globals[kRightDoorIsOpen504]) {
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+ }
+
+ if (_vm->_gameConv->restoreRunning() == 19) {
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('l', 1), 67);
+ _anim0ActvFl = true;
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _game._player._playerPos = Common::Point(286, 120);
+ _game._player._facing = FACING_EAST;
+ _listenStatus = 0;
+ _scene->setAnimFrame(_globals._animationIndexes[0], 8);
+ _vm->_gameConv->run(19);
+ _vm->_gameConv->exportValue(_game._difficulty);
+ } else if (_vm->_gameConv->restoreRunning() == 27) {
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('x', 4), PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('x', 5), PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('o', 1), 100);
+
+ _scene->setAnimFrame(_globals._animationIndexes[1], 22);
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _playingMusicFl = false;
+ _anim1ActvFl = true;
+ _playStatus = 0;
+ _vm->_gameConv->run(27);
+ } else if ((_globals[kFightStatus] <= 1) && (_globals[kCoffinStatus] == 2)) {
+ if ((_phantomStatus == 1) || (_phantomStatus == 2)) {
+ _scene->_hotspots.activate(NOUN_CHRISTINE, true);
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('b', 0));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*CHR_6", PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*FACERAL", PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*FACEXDFR", PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*FACEPHN", PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+
+ _globals._spriteIndexes[11] = _scene->_sprites.addSprites(formAnimName('a', 5));
+ _globals._spriteIndexes[10] = _scene->_sprites.addSprites(formAnimName('a', 3), PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('a', 6), PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('a', 7), PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[9] = _scene->_sprites.addSprites(formAnimName('a', 0), PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+
+ _globals._animationIndexes[3] = _scene->loadAnimation(formAnimName('p', 1), 0);
+ int hotspotIdx = _scene->_dynamicHotspots.add(NOUN_PHANTOM, VERB_LOOK_AT, SYNTAX_MASC_NOT_PROPER, EXT_NONE, Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots[hotspotIdx]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(hotspotIdx, Common::Point(-2, -2), FACING_NONE);
+
+ if (_phantomStatus == 1)
+ _scene->setAnimFrame(_globals._animationIndexes[3], _vm->getRandomNumber(109, 112));
+ else if (_phantomStatus == 2) {
+ _scene->setAnimFrame(_globals._animationIndexes[3], _vm->getRandomNumber(148, 150));
+ _scene->drawToBackground(_globals._spriteIndexes[13], 1, Common::Point(-32000, -32000), 0, 100);
+ }
+
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[3], 4);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[3], 8);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[3], 13);
+
+ _game._player._visible = false;
+ _anim3ActvFl = true;
+
+ if (_vm->_gameConv->restoreRunning() == 21) {
+ _game._player._stepEnabled = false;
+ _vm->_gameConv->run(21);
+ _vm->_gameConv->exportValue(_game._objects.isInInventory(OBJ_MUSIC_SCORE));
+ }
+ } else if (_phantomStatus == 4) {
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->drawToBackground(_globals._spriteIndexes[13], 1, Common::Point(-32000, -32000), 0, 100);
+
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*CHR_3");
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*FACERAL", PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*FACEXDFR", PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*FACEPHN", PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[12] = _scene->_sprites.addSprites(formAnimName('a', 8), PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+
+ _globals._animationIndexes[3] = _scene->loadAnimation(formAnimName('p', 2), 130);
+ _scene->setAnimFrame(_globals._animationIndexes[3], 159);
+
+ _game._player._playerPos = Common::Point(130, 135);
+ _game._player._facing = FACING_NORTHEAST;
+ _game._player._visible = true;
+ _anim4ActvFl = true;
+
+ _game._player._stepEnabled = false;
+ _vm->_gameConv->run(21);
+ _vm->_gameConv->exportValue(_game._objects.isInInventory(OBJ_MUSIC_SCORE));
+ }
+ } else if (_globals[kFightStatus] == 2) {
+ if (!_game._visitedScenes.exists(506)) {
+ _scene->changeVariant(1);
+
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->drawToBackground(_globals._spriteIndexes[13], 1, Common::Point(-32000, -32000), 0, 100);
+ _anim5ActvFl = true;
+
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*CHR_3");
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*FACERAL", PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*FACEXDFR",PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*FACEPHN", PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+
+ _globals._animationIndexes[3] = _scene->loadAnimation(formAnimName('p', 3), 0);
+ int hotspotIdx = _scene->_dynamicHotspots.add(NOUN_CHRISTINE, VERB_WALK_TO, SYNTAX_SINGULAR_FEM, EXT_NONE, Common::Rect(0, 0, 0, 0));
+ _phantomStatus = 5;
+ _scene->_dynamicHotspots[hotspotIdx]._articleNumber = PREP_ON;
+ _scene->setAnimFrame(_globals._animationIndexes[3], 79);
+ _scene->_dynamicHotspots.setPosition(hotspotIdx, Common::Point(66, 119), FACING_NORTHWEST);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[3], 0);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[3], 1);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[3], 2);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[3], 3);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[3], 4);
+ } else {
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->drawToBackground(_globals._spriteIndexes[13], 1, Common::Point(-32000, -32000), 0, 100);
+ }
+ } else {
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ if (!_globals[kHeListened])
+ _scene->_sequences.addTimer(30, 62);
+ }
+ }
+
+ sceneEntrySound();
+}
+
+void Scene504::step() {
+ if (_anim0ActvFl)
+ handleListenAnimation();
+
+ if (_anim1ActvFl)
+ handleOrganAnimation();
+
+ if (_anim2ActvFl)
+ handleChairAnimation();
+
+ if (_anim3ActvFl)
+ handlePhantomAnimation1();
+
+ if (_anim4ActvFl)
+ handlePhantomAnimation2();
+
+ if (_anim5ActvFl)
+ handlePhantomAnimation3();
+
+ if (_game._trigger == 120) {
+ _game._player._stepEnabled = false;
+ _vm->_gameConv->run(21);
+ _vm->_gameConv->exportValue(_game._objects.isInInventory(OBJ_MUSIC_SCORE));
+ _vm->_gameConv->exportValue(1);
+ _globals[kFightStatus] = 1;
+ }
+
+ if (_game._trigger == 60) {
+ _game._player._visible = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[0]);
+ _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
+ _scene->_sequences.addTimer(30, 61);
+ }
+
+ if (_game._trigger == 61) {
+ _game._player._stepEnabled = true;
+ _scene->_sequences.addTimer(60, 62);
+ }
+
+ if (_game._trigger == 62) {
+ _globals[kHeListened] = true;
+ _game._player._stepEnabled = false;
+ _vm->_gameConv->run(19);
+ _vm->_gameConv->exportValue(_game._difficulty);
+ }
+
+ if (_game._trigger == 80) {
+ _vm->_sound->command(73);
+ _globals[kRightDoorIsOpen504] = true;
+ _scene->deleteSequence(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 6, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], -1, -2);
+
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 6, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 90);
+ }
+
+ if (_game._trigger == 90) {
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 6, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 91);
+ }
+
+ if (_game._trigger == 91) {
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 6, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 92);
+ }
+
+ if (_game._trigger == 92)
+ _fireBreathFl = true;
+
+ if (_fireBreathFl) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 6, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], -1, -2);
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 6, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], -1, -2);
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 6, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], -1, -2);
+ _fireBreathFl = false;
+ }
+
+ if (_game._trigger == 130) {
+ _scene->freeAnimation(_globals._animationIndexes[3]);
+ _scene->_sprites.remove(_globals._spriteIndexes[12]);
+
+ _anim4ActvFl = false;
+ _anim5ActvFl = true;
+
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*CHR_2", PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*CHR_3", PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+
+ _scene->changeVariant(1);
+
+ _globals._animationIndexes[3] = _scene->loadAnimation(formAnimName('p', 3), 0);
+ int hotspotIdx = _scene->_dynamicHotspots.add(NOUN_CHRISTINE, VERB_WALK_TO, SYNTAX_SINGULAR_FEM, EXT_NONE, Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots[hotspotIdx]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(hotspotIdx, Common::Point(66, 119), FACING_NORTHWEST);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[3], 0);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[3], 1);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[3], 2);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[3], 3);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[3], 4);
+ }
+
+ if (_game._trigger == 67) {
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ _anim0ActvFl = false;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[0]);
+ }
+
+ if (_game._trigger == 136)
+ _scene->_nextSceneId = 506;
+
+ if (_game._trigger == 100) {
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[1]);
+ _game._player._playerPos = Common::Point(156, 114);
+ _game._player._visible = true;
+ _anim1ActvFl = false;
+ _game._player.resetFacing(FACING_EAST);
+ _scene->_sequences.addTimer(10, 101);
+ }
+
+ if (_game._trigger == 101) {
+ _game._player._stepEnabled = true;
+ _scene->_sprites.remove(_globals._spriteIndexes[5]);
+ _scene->_sprites.remove(_globals._spriteIndexes[4]);
+ }
+}
+
+void Scene504::actions() {
+ if (_vm->_gameConv->activeConvId() == 26) {
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_SIT_IN, NOUN_LARGE_CHAIR)) {
+ if (!_anim2ActvFl) {
+ _chairStatus = 0;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _anim2ActvFl = true;
+ _globals._animationIndexes[2] = _scene->loadAnimation(formAnimName('c', 1), 0);
+ _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[0], SYNC_PLAYER, 0);
+ } else
+ _vm->_dialogs->show(50436);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_game._trigger == 95) {
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('l', 1), 67);
+ _listenStatus = 0;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _anim0ActvFl = true;
+ _globals[kHeListened] = true;
+ _vm->_gameConv->run(19);
+ _vm->_gameConv->exportValue(_game._difficulty);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_game._trigger == 67) {
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ _anim0ActvFl = false;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[0]);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_vm->_gameConv->activeConvId() == 19) {
+ handleListenConversation();
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_vm->_gameConv->activeConvId() == 27) {
+ handlePlayConversation();
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_vm->_gameConv->activeConvId() == 21) {
+ handleFightConversation();
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_game._trigger == 100) {
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[1]);
+ _game._player._playerPos = Common::Point(156, 114);
+ _game._player._visible = true;
+ _anim1ActvFl = false;
+ _game._player.resetFacing(FACING_EAST);
+ _scene->_sequences.addTimer(10, 101);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_game._trigger == 101) {
+ _game._player._stepEnabled = true;
+ _scene->_sprites.remove(_globals._spriteIndexes[5]);
+ _scene->_sprites.remove(_globals._spriteIndexes[4]);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_SIT_ON, NOUN_ORGAN_BENCH)) {
+ if (_globals[kRightDoorIsOpen504])
+ _vm->_dialogs->show(50427);
+ else {
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('x', 4), PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('x', 5), PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('o', 1), 100);
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _playingMusicFl = false;
+ _anim1ActvFl = true;
+ _playStatus = 0;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_RIGHT_DOOR) || _action.isAction(VERB_OPEN, NOUN_RIGHT_DOOR)) {
+ if (_globals[kRightDoorIsOpen504]) {
+ if (_vm->_gameConv->activeConvId() == 26)
+ _vm->_gameConv->stop();
+
+ _scene->_nextSceneId = 505;
+ } else
+ _vm->_dialogs->show(50418);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_LEFT_DOOR) || _action.isAction(VERB_OPEN, NOUN_LEFT_DOOR)) {
+ if (_globals[kFightStatus]) {
+ if (_game._visitedScenes.exists(506))
+ _scene->_nextSceneId = 506;
+ else if (!_game._objects.isInInventory(OBJ_MUSIC_SCORE))
+ _vm->_dialogs->show(50425);
+ else {
+ _phantomStatus = 6;
+ _game._player._stepEnabled = false;
+ }
+ } else
+ _vm->_dialogs->show(50418);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_MUSIC_SCORE)) {
+ switch (_game._trigger) {
+ case (0):
+ if (_game._objects.isInRoom(OBJ_MUSIC_SCORE)) {
+ _globals[kPlayerScore] += 5;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[14] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[14], false, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[14], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[14], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[14], SEQUENCE_TRIGGER_SPRITE, 4, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[14], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ _action._inProgress = false;
+ return;
+ }
+ break;
+
+ case 1:
+ _globals._sequenceIndexes[15] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[15], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[15], 14);
+ _scene->_hotspots.activate(NOUN_MUSIC_SCORE, false);
+ _game._objects.addToInventory(OBJ_MUSIC_SCORE);
+ _vm->_sound->command(26);
+ _action._inProgress = false;
+ return;
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[14]);
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(20, 3);
+ _action._inProgress = false;
+ return;
+ break;
+
+ case 3:
+ _vm->_dialogs->showItem(OBJ_MUSIC_SCORE, 820, 0);
+ _game._player._stepEnabled = true;
+ _action._inProgress = false;
+ return;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(50410);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(50411);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(50412);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_ORGAN)) {
+ _vm->_dialogs->show(50413);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_ORGAN_BENCH)) {
+ _vm->_dialogs->show(50414);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_MUSIC_SCORE) && _game._objects.isInRoom(OBJ_MUSIC_SCORE)) {
+ _vm->_dialogs->show(50415);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LEFT_DOOR)) {
+ _vm->_dialogs->show(50416);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RIGHT_DOOR)) {
+ _vm->_dialogs->show(_globals[kRightDoorIsOpen504] ? 50434 : 50417);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_TABLE)) {
+ _vm->_dialogs->show(50419);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_TRAP_DOOR)) {
+ _vm->_dialogs->show(50420);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LARGE_CHAIR)) {
+ _vm->_dialogs->show(50422);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CHRISTINE)) {
+ _vm->_dialogs->show(_globals[kFightStatus] ? 50426 : 50429);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_PHANTOM)) {
+ _vm->_dialogs->show(50428);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_TRAP_DOOR)) {
+ _vm->_dialogs->show(50421);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLOSE) && _action.isObject(NOUN_RIGHT_DOOR) && !_globals[kRightDoorIsOpen504]) {
+ _vm->_dialogs->show(50433);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLOSE) && _action.isObject(NOUN_LEFT_DOOR) && !_globals[kFightStatus] && !_game._visitedScenes.exists(506)) {
+ _vm->_dialogs->show(50433);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_anim3ActvFl && (_action.isAction(VERB_TAKE, NOUN_SWORD) || _action.isAction(VERB_ATTACK, NOUN_PHANTOM))) {
+ _game._player._stepEnabled = false;
+ _input3Count = 0;
+ _phantomStatus = 4;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TALK_TO, NOUN_CHRISTINE)) {
+ _vm->_gameConv->run(21);
+ _vm->_gameConv->exportValue(_game._objects.isInInventory(OBJ_MUSIC_SCORE));
+ _vm->_gameConv->exportValue(0);
+ _phantomStatus = 7;
+ _christineTalkCount = 0;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TALK_TO, NOUN_PHANTOM)) {
+ _vm->_dialogs->show(50431);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_CHRISTINE)) {
+ _vm->_dialogs->show(50435);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+void Scene504::preActions() {
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_RIGHT_DOOR) || _action.isAction(VERB_OPEN, NOUN_RIGHT_DOOR)) {
+ if (_globals[kRightDoorIsOpen504]) {
+ if ((_globals[kFightStatus] == 2) && !_game._visitedScenes.exists(506)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player.walk(Common::Point(317, 115), FACING_NORTHEAST);
+ _game._player._readyToWalk = false;
+ _game._player._needToWalk = false;
+ _game._player._stepEnabled = false;
+ _vm->_gameConv->run(26);
+ _vm->_gameConv->exportValue(2);
+ _scene->_sequences.addTimer(6, 1);
+ break;
+
+ case 1:
+ if (_vm->_gameConv->activeConvId() >= 0)
+ _scene->_sequences.addTimer(6, 1);
+ else {
+ _game._player._stepEnabled = true;
+ _action._inProgress = true;
+ _game._player._needToWalk = true;
+ _game._player._readyToWalk = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else
+ _game._player.walk(Common::Point(317, 115), FACING_NORTHEAST);
+ } else if (_globals[kHeListened] || (_globals[kFightStatus] == 0))
+ _game._player.walk(Common::Point(286, 120), FACING_NORTHEAST);
+ }
+
+ if (_anim2ActvFl && !_action.isAction(VERB_SIT_IN) && _game._player._needToWalk) {
+ _chairStatus = 1;
+ _game._player._stepEnabled = false;
+ _game._player._readyToWalk = false;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_LEFT_DOOR) || _action.isAction(VERB_OPEN, NOUN_LEFT_DOOR)) {
+ if ((_globals[kFightStatus] == 0) && (_globals[kCoffinStatus] == 2) && !_game._visitedScenes.exists(506)) {
+ _vm->_dialogs->show(50432);
+ _game._player.cancelCommand();
+ return;
+ } else if (_game._visitedScenes.exists(506))
+ _game._player.walk(Common::Point(0, 109), FACING_NORTHWEST);
+ else if (!_game._objects.isInInventory(OBJ_MUSIC_SCORE) || (_globals[kFightStatus] == 0))
+ _game._player.walk(Common::Point(33, 116), FACING_NORTHWEST);
+ }
+
+ if ((_globals[kFightStatus] == 0) && (_globals[kCoffinStatus] == 2) && !_game._visitedScenes.exists(506)
+ && !_action.isAction(VERB_LOOK) && !_action.isAction(VERB_LOOK_AT) && !_action.isAction(VERB_ATTACK)
+ && !_action.isAction(VERB_TAKE, NOUN_SWORD) && !_action.isAction(VERB_TALK_TO, NOUN_PHANTOM)) {
+ _vm->_dialogs->show(50430);
+ _game._player.cancelCommand();
+ }
+}
+
+void Scene504::handleListenAnimation() {
+ int curFrame = _scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame();
+ if (curFrame == _listenFrame)
+ return;
+
+ _listenFrame = curFrame;
+ int resetFrame = -1;
+
+ switch (_listenFrame) {
+ case 8:
+ _vm->_gameConv->release();
+ break;
+
+ case 9:
+ resetFrame = (_listenStatus == 0) ? 8 : 9;
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[0], resetFrame);
+ _listenFrame = resetFrame;
+ }
+}
+
+void Scene504::handleOrganAnimation() {
+ int curFrame = _scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame();
+ if (curFrame == _playFrame)
+ return;
+
+ _playFrame = curFrame;
+ int resetFrame = -1;
+
+ switch (_playFrame) {
+ case 22:
+ _game._player._stepEnabled = true;
+ _vm->_gameConv->run(27);
+ break;
+
+ case 23:
+ if (_playStatus == 0)
+ resetFrame = 22;
+ else {
+ _game._player._stepEnabled = false;
+ if (_songNum == 5) {
+ _playingMusicFl = false;
+ _fireBreathFl = false;
+ resetFrame = 104;
+ }
+ }
+ break;
+
+ case 28:
+ if (!_playingMusicFl) {
+ _playingMusicFl = true;
+ _fireBreathFl = true;
+ _game._player._stepEnabled = false;
+
+ switch (_songNum) {
+ case 1:
+ _vm->_sound->command(34);
+ break;
+
+ case 2:
+ _vm->_sound->command(37);
+ break;
+
+ case 3:
+ _vm->_sound->command(35);
+ break;
+
+ case 4:
+ _vm->_sound->command(36);
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case 69:
+ if ((_globals[kRightDoorIsOpen504]) && (_playCount >= 2)) {
+ _playCount = 0;
+ resetFrame = 102;
+ _vm->_sound->command(2);
+ _vm->_sound->command(16);
+ } else if (_songNum != _globals[kMusicSelected]) {
+ _vm->_sound->command(2);
+ _fireBreathFl = true;
+ resetFrame = 75;
+ } else {
+ resetFrame = 25;
+ ++_playCount;
+ if (!_globals[kRightDoorIsOpen504]) {
+ _scene->_sequences.addTimer(1, 80);
+ _globals[kPlayerScore] += 5;
+ }
+ }
+ break;
+
+ case 76:
+ _scene->playSpeech(7);
+ break;
+
+ case 90:
+ _vm->_sound->command(27);
+ break;
+
+ case 102:
+ ++_deathCounter;
+ if (_deathCounter >= 17)
+ _scene->_reloadSceneFlag = true;
+ else
+ resetFrame = 101;
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[1], resetFrame);
+ _playFrame = resetFrame;
+ }
+}
+
+void Scene504::handlePhantomAnimation1() {
+ int curFrame = _scene->_animation[_globals._animationIndexes[3]]->getCurrentFrame();
+ if (curFrame == _phantomFrame)
+ return;
+
+ _phantomFrame = curFrame;
+ int resetFrame = -1;
+
+ switch (_phantomFrame) {
+ case 41:
+ _vm->_gameConv->run(21);
+ _vm->_gameConv->exportValue(_game._objects.isInInventory(OBJ_MUSIC_SCORE));
+ _vm->_gameConv->exportValue(0);
+ break;
+
+ case 52:
+ case 53:
+ case 54:
+ case 55:
+ resetFrame = (_phantomStatus == 0) ? _vm->getRandomNumber(51, 54) : 55;
+ break;
+
+ case 78:
+ _vm->_gameConv->release();
+ break;
+
+ case 110:
+ case 111:
+ case 112:
+ case 113:
+ resetFrame = (_phantomStatus == 1) ? _vm->getRandomNumber(109, 112) : 113;
+ break;
+
+ case 142:
+ _scene->drawToBackground(_globals._spriteIndexes[13], 1, Common::Point(-32000, -32000), 0, 100);
+ break;
+
+ case 143:
+ _game._player._stepEnabled = true;
+ break;
+
+ case 149:
+ case 150:
+ case 151:
+ ++_input3Count;
+
+ if (_phantomStatus == 4) {
+ _game._player._stepEnabled = false;
+ resetFrame = 200;
+ } else if (_input3Count >= 9) {
+ _game._player._stepEnabled = false;
+ resetFrame = 151;
+ } else if (_phantomStatus == 2)
+ resetFrame = _vm->getRandomNumber(148, 150);
+ break;
+
+ case 169:
+ _vm->_sound->command(1);
+ _scene->playSpeech(7);
+ break;
+
+ case 180:
+ _vm->_sound->command(27);
+ break;
+
+ case 187:
+ _deathCounter = 0;
+ break;
+
+ case 189:
+ ++_deathCounter;
+ if (_deathCounter >= 29)
+ _scene->_reloadSceneFlag = true;
+ else
+ resetFrame = 188;
+ break;
+
+ case 227:
+
+ _scene->freeAnimation(_globals._animationIndexes[3]);
+ _scene->_sprites.remove(_globals._spriteIndexes[9]);
+ _scene->_sprites.remove(_globals._spriteIndexes[8]);
+ _scene->_sprites.remove(_globals._spriteIndexes[7]);
+ _scene->_sprites.remove(_globals._spriteIndexes[10]);
+ _scene->_sprites.remove(_globals._spriteIndexes[11]);
+
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*CHR_3", PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[12] = _scene->_sprites.addSprites(formAnimName('a', 8), PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._animationIndexes[3] = _scene->loadAnimation(formAnimName('p', 2), 130);
+
+ _scene->setAnimFrame(_globals._animationIndexes[3], 27);
+ resetFrame = -1;
+ _anim3ActvFl = false;
+ _anim4ActvFl = true;
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[3], resetFrame);
+ _phantomFrame = resetFrame;
+ }
+}
+
+void Scene504::handlePhantomAnimation2() {
+ int curFrame = _scene->_animation[_globals._animationIndexes[3]]->getCurrentFrame();
+ if (curFrame == _phantomFrame)
+ return;
+
+ _phantomFrame = curFrame;
+ int resetFrame = -1;
+
+ switch (_phantomFrame) {
+ case 78:
+ _scene->playSpeech(9);
+ break;
+
+ case 119:
+ _game._player._playerPos = Common::Point(114, 137);
+ _game._player._facing = FACING_WEST;
+ _game._player._visible = true;
+ _globals[kPlayerScore] += 5;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[3]);
+ _game._player.walk(Common::Point(130, 135), FACING_NORTHEAST);
+ _scene->_hotspots.activate(NOUN_CHRISTINE, false);
+ _game._player.setWalkTrigger(120);
+ _vm->_sound->command(1);
+ break;
+
+ case 150:
+ _vm->_sound->command(16);
+ break;
+
+ case 160:
+ switch (_playStatus) {
+ case 5:
+ resetFrame = 164;
+ break;
+
+ case 7:
+ resetFrame = 160;
+ break;
+
+ default:
+ resetFrame = 159;
+ break;
+ }
+ break;
+
+ case 161:
+ case 162:
+ case 163:
+ case 164:
+ resetFrame = (_phantomStatus == 5) ? 159 : _vm->getRandomNumber(160, 162);
+
+ ++_christineTalkCount;
+ if (_christineTalkCount > 10) {
+ resetFrame = 159;
+ if (_phantomStatus != 5)
+ _phantomStatus = 4;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[3], resetFrame);
+ _phantomFrame = resetFrame;
+ }
+}
+
+void Scene504::handlePhantomAnimation3() {
+ int curFrame = _scene->_animation[_globals._animationIndexes[3]]->getCurrentFrame();
+ if (curFrame == _phantomFrame)
+ return;
+
+ _phantomFrame = curFrame;
+ int resetFrame = -1;
+
+ switch (_phantomFrame) {
+ case 58:
+ _game._player._stepEnabled = true;
+ break;
+
+ case 80:
+ if (_phantomStatus == 7)
+ resetFrame = 116;
+ else if (_phantomStatus != 6)
+ resetFrame = 79;
+ break;
+
+ case 115:
+ _game._player.walk(Common::Point(0, 109), FACING_NORTHWEST);
+ _game._player.setWalkTrigger(136);
+ break;
+
+ case 116:
+ resetFrame = 115;
+ break;
+
+ case 117:
+ case 118:
+ case 119:
+ resetFrame = _vm->getRandomNumber(116, 118);
+ ++_christineTalkCount;
+ if (_christineTalkCount > 10) {
+ resetFrame = 79;
+ if (_phantomStatus != 6)
+ _phantomStatus = 5;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[3], resetFrame);
+ _phantomFrame = resetFrame;
+ }
+}
+
+void Scene504::handleChairAnimation() {
+ int curFrame = _scene->_animation[_globals._animationIndexes[2]]->getCurrentFrame();
+ if (curFrame == _chairFrame)
+ return;
+
+ _chairFrame = curFrame;
+ int resetFrame = -1;
+
+ switch (_chairFrame) {
+ case 24:
+ _game._player._stepEnabled = true;
+ break;
+
+ case 25:
+ case 26:
+ case 30:
+ case 31:
+ if (!_chairDialogDoneFl) {
+ _chairDialogDoneFl = true;
+ _vm->_dialogs->show(50424);
+ }
+
+ if (_chairStatus == 0) {
+ if (_vm->getRandomNumber(1,5) == 1)
+ resetFrame = _vm->getRandomNumber(24, 30);
+ else
+ resetFrame = _chairFrame - 1;
+ } else
+ resetFrame = 31;
+ break;
+
+ case 47:
+ resetFrame = -1;
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ _game._player._readyToWalk = true;
+ _anim2ActvFl = false;
+ _chairDialogDoneFl = false;
+ _scene->freeAnimation(_globals._animationIndexes[2]);
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[2], resetFrame);
+ _chairFrame = resetFrame;
+ }
+}
+
+void Scene504::handleListenConversation() {
+ if ((_action._activeAction._verbId == 2) && !_game._trigger) {
+ _game._player.walk(Common::Point(286, 120), FACING_EAST);
+ _game._player.setWalkTrigger(95);
+ }
+
+ if (_action._activeAction._verbId == 12)
+ _listenStatus = 1;
+}
+
+void Scene504::handlePlayConversation() {
+ switch (_action._activeAction._verbId) {
+ case 2:
+ _vm->_gameConv->setStartNode(1);
+ _vm->_gameConv->stop();
+ _playStatus = 1;
+ _songNum = 1;
+ break;
+
+ case 3:
+ _vm->_gameConv->setStartNode(1);
+ _vm->_gameConv->stop();
+ _playStatus = 1;
+ _songNum = 2;
+ break;
+
+ case 4:
+ _vm->_gameConv->setStartNode(1);
+ _vm->_gameConv->stop();
+ _playStatus = 1;
+ _songNum = 3;
+ break;
+
+ case 5:
+ _vm->_gameConv->setStartNode(1);
+ _vm->_gameConv->stop();
+ _playStatus = 1;
+ _songNum = 4;
+ break;
+
+ case 6:
+ _vm->_gameConv->setStartNode(1);
+ _vm->_gameConv->stop();
+ _playStatus = 1;
+ _songNum = 5;
+ break;
+
+ case 8:
+ _vm->_gameConv->setStartNode(1);
+ _vm->_gameConv->stop();
+ _playStatus = 1;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene504::handleFightConversation() {
+ switch (_action._activeAction._verbId) {
+ case 3:
+ _vm->_gameConv->hold();
+ _phantomStatus = 1;
+ break;
+
+ case 8:
+ _phantomStatus = 2;
+ break;
+
+ case 10:
+ case 11:
+ case 12:
+ case 15:
+ _vm->_gameConv->setInterlocutorTrigger(145);
+ break;
+
+ case 14:
+ case 17:
+ _phantomStatus = 5;
+ _globals[kFightStatus] = 2;
+ break;
+
+ default:
+ break;
+ }
+
+ if ((_game._trigger == 145) && (_phantomStatus != 5)) {
+ _phantomStatus = 7;
+ _christineTalkCount = 0;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene505::Scene505(MADSEngine *vm) : Scene5xx(vm) {
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _anim2ActvFl = false;
+ _checkFrame106 = false;
+ _leaveRoomFl = false;
+ _partedFl = false;
+
+ _raoulStatus = -1;
+ _raoulFrame = -1;
+ _raoulCount = -1;
+ _bothStatus = -1;
+ _bothFrame = -1;
+ _bothCount = -1;
+ _partStatus = -1;
+ _partFrame = -1;
+ _partCount = -1;
+}
+
+void Scene505::synchronize(Common::Serializer &s) {
+ Scene5xx::synchronize(s);
+
+ s.syncAsByte(_anim0ActvFl);
+ s.syncAsByte(_anim1ActvFl);
+ s.syncAsByte(_anim2ActvFl);
+ s.syncAsByte(_checkFrame106);
+ s.syncAsByte(_leaveRoomFl);
+ s.syncAsByte(_partedFl);
+
+ s.syncAsSint16LE(_raoulStatus);
+ s.syncAsSint16LE(_raoulFrame);
+ s.syncAsSint16LE(_raoulCount);
+ s.syncAsSint16LE(_bothStatus);
+ s.syncAsSint16LE(_bothFrame);
+ s.syncAsSint16LE(_bothCount);
+ s.syncAsSint16LE(_partStatus);
+ s.syncAsSint16LE(_partFrame);
+ s.syncAsSint16LE(_partCount);
+}
+
+void Scene505::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ if ((_globals[kCoffinStatus] == 2) && (!_globals[kChrisLeft505]))
+ _scene->_variant = 1;
+
+ _scene->addActiveVocab(NOUN_CHRISTINE);
+}
+
+void Scene505::enter() {
+ _vm->_disableFastwalk = true;
+
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ _partedFl = false;
+ _leaveRoomFl = false;
+ _anim0ActvFl = false;
+ _anim1ActvFl = false;
+ _anim2ActvFl = false;
+ _checkFrame106 = false;
+ }
+
+ _vm->_gameConv->load(20);
+ _scene->_hotspots.activateAtPos(NOUN_LID, false, Common::Point(216, 44));
+ _scene->_hotspots.activate(NOUN_CHRISTINE, false);
+
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('x', 6));
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('a', 1));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('x', 2));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('x', 3));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('x', 4));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('x', 5));
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('a', 4));
+
+ if (_scene->_priorSceneId == RETURNING_FROM_LOADING) {
+ if (_vm->_gameConv->restoreRunning() == 20) {
+ _scene->_hotspots.activate(NOUN_LID, false);
+ _scene->_hotspots.activateAtPos(NOUN_LID, true, Common::Point(216, 44));
+ _globals._sequenceIndexes[7] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[7], false, 12);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 1);
+
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('c', 1), 65);
+ _scene->setAnimFrame(_globals._animationIndexes[1], 109);
+ _anim1ActvFl = true;
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _bothStatus = 3;
+
+ _vm->_gameConv->run(20);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ } else if (_partedFl && (_globals[kFightStatus] == 0)) {
+ _scene->_hotspots.activate(NOUN_LID, false);
+ _scene->_hotspots.activateAtPos(NOUN_LID, true, Common::Point(216, 44));
+ _globals._sequenceIndexes[7] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[7], false, 12);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 1);
+
+ _anim2ActvFl = true;
+ _bothStatus = 3;
+ _globals._animationIndexes[2] = _scene->loadAnimation(formAnimName('b', 1), 0);
+ int hotspotIdx = _scene->_dynamicHotspots.add(NOUN_CHRISTINE, VERB_WALK_TO, SYNTAX_SINGULAR_FEM, EXT_NONE, Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots[hotspotIdx]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(hotspotIdx, Common::Point(91, 108), FACING_NORTHWEST);
+ _scene->setAnimFrame(_globals._animationIndexes[2], 89);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[2], 3);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[2], 4);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[2], 5);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[2], 6);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[2], 7);
+ } else if (_globals[kFightStatus]) {
+ _scene->_hotspots.activate(NOUN_LID, false);
+ _scene->_hotspots.activateAtPos(NOUN_LID, true, Common::Point(216, 44));
+ _globals._sequenceIndexes[7] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[7], false, 12);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 1);
+ } else {
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('c', 1), 65);
+ _anim1ActvFl = true;
+ _bothStatus = 0;
+ _scene->_hotspots.activate(NOUN_CHRISTINE, true);
+ }
+ }
+
+ if ((_scene->_priorSceneId == 504) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
+ _game._player._playerPos = Common::Point(5, 87);
+ _game._player._facing = FACING_EAST;
+ _game._player._stepEnabled = false;
+ _game._player.walk(Common::Point(58, 104), FACING_SOUTHEAST);
+ if (_globals[kCoffinStatus] != 2) {
+ _game._player.setWalkTrigger(70);
+ _anim1ActvFl = true;
+ _bothStatus = 0;
+ _scene->_hotspots.activate(NOUN_CHRISTINE, true);
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('c', 1), 65);
+ } else {
+ _scene->_hotspots.activate(NOUN_LID, false);
+ _scene->_hotspots.activateAtPos(NOUN_LID, true, Common::Point(216, 44));
+ _globals._sequenceIndexes[7] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[7], false, 12);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 1);
+ _game._player._stepEnabled = true;
+ }
+ }
+
+ sceneEntrySound();
+}
+
+void Scene505::step() {
+ if (_anim0ActvFl)
+ handleRaoulAnimation();
+
+ if (_anim1ActvFl)
+ handleBothanimation();
+
+ if (_anim2ActvFl)
+ handlePartedAnimation();
+
+ if (_game._trigger == 65) {
+ _scene->freeAnimation(_globals._animationIndexes[1]);
+ _vm->_sound->command(1);
+ _partedFl = true;
+ _anim2ActvFl = true;
+ _anim1ActvFl = false;
+ _globals._animationIndexes[2] = _scene->loadAnimation(formAnimName('b', 1), 0);
+
+ int hotspotIDx = _scene->_dynamicHotspots.add(NOUN_CHRISTINE, VERB_WALK_TO, SYNTAX_SINGULAR_FEM, EXT_NONE, Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(hotspotIDx, Common::Point(91, 108), FACING_NORTHWEST);
+ _scene->_dynamicHotspots[hotspotIDx]._articleNumber = PREP_ON;
+ _scene->setDynamicAnim(hotspotIDx, _globals._animationIndexes[2], 3);
+ _scene->setDynamicAnim(hotspotIDx, _globals._animationIndexes[2], 4);
+ _scene->setDynamicAnim(hotspotIDx, _globals._animationIndexes[2], 5);
+ _scene->setDynamicAnim(hotspotIDx, _globals._animationIndexes[2], 6);
+ _scene->setDynamicAnim(hotspotIDx, _globals._animationIndexes[2], 7);
+ }
+
+ if (_game._trigger == 70) {
+ _game._player._stepEnabled = true;
+ if (!_game._visitedScenes._sceneRevisited) {
+ _vm->_gameConv->run(20);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ }
+ }
+}
+
+void Scene505::actions() {
+ if (_game._trigger == 80) {
+ _bothStatus = 2;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_vm->_gameConv->activeConvId() == 20) {
+ handleCoffinDialog();
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TALK_TO, NOUN_CHRISTINE)) {
+ if (_globals[kCoffinStatus] != 2)
+ _vm->_dialogs->show(50536);
+ else {
+ _vm->_gameConv->run(20);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ _partStatus = 10;
+ _partCount = 0;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isAction(VERB_UNLOCK, NOUN_SARCOPHAGUS) || _action.isAction(VERB_UNLOCK, NOUN_LID)) && !_globals[kLookedAtSkullFace]) {
+ _vm->_dialogs->show(50539);
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isAction(VERB_UNLOCK, NOUN_SKULL_FACE) || _action.isAction(VERB_PUT, NOUN_KEY, NOUN_SKULL_FACE)) || ((_action.isAction(VERB_UNLOCK, NOUN_SARCOPHAGUS) || _action.isAction(VERB_UNLOCK, NOUN_LID)) && _globals[kLookedAtSkullFace])) {
+ if (_globals[kCoffinStatus] == 0) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[8] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[8], false, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[8], -1, -2);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[8], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_SPRITE, 9, 95);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 96);
+ _action._inProgress = false;
+ return;
+
+ case 95:
+ _vm->_sound->command(76);
+ _vm->_dialogs->show(50528);
+ _action._inProgress = false;
+ return;
+
+ case 96:
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ _globals[kCoffinStatus] = 1;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[8]);
+ _action._inProgress = false;
+ return;
+
+ default:
+ break;
+ }
+ } else {
+ _vm->_dialogs->show(50534);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_PUSH, NOUN_SKULL) && (_scene->_customDest.x >= 19)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[0] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[0], false, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], -1, -2);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[0], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_SPRITE, 6, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1: {
+ int sprIdx;
+ _vm->_sound->command(77);
+ if (_scene->_customDest.x <= 44)
+ sprIdx = _globals._spriteIndexes[4];
+ else if (_scene->_customDest.x <= 58)
+ sprIdx = _globals._spriteIndexes[3];
+ else if (_scene->_customDest.x <= 71)
+ sprIdx = _globals._spriteIndexes[2];
+ else if (_scene->_customDest.x <= 84) {
+ sprIdx = _globals._spriteIndexes[1];
+ if (_globals[kCoffinStatus] == 1) {
+ _bothStatus = 1;
+ _scene->_hotspots.activate(NOUN_LID, false);
+ _scene->_hotspots.activate(NOUN_CHRISTINE, false);
+ _scene->_hotspots.activateAtPos(NOUN_LID, true, Common::Point(216, 44));
+ _scene->changeVariant(1);
+ }
+ } else if (_scene->_customDest.x <= 100)
+ sprIdx = _globals._spriteIndexes[5];
+ else
+ sprIdx = _globals._spriteIndexes[6];
+
+ int skullSeqIdx = _scene->_sequences.startPingPongCycle(sprIdx, false, 5, 2);
+ _scene->_sequences.setAnimRange(skullSeqIdx, -1, -2);
+ _scene->_sequences.setDepth(skullSeqIdx, 1);
+ }
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[0]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ if (_bothStatus == 1) {
+ _game._player.walk(Common::Point(136, 126), FACING_EAST);
+ _game._player.setWalkTrigger(80);
+ _game._player._stepEnabled = false;
+ }
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR)) {
+ if (_anim2ActvFl) {
+ _leaveRoomFl = true;
+ _game._player._stepEnabled = false;
+ } else {
+ _globals[kChrisLeft505] = true;
+ _scene->_nextSceneId = 504;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(50510);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(50511);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(50512);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SARCOPHAGUS)) {
+ _vm->_dialogs->show((_globals[kCoffinStatus] <= 1) ? 50513 : 50514);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SKULL_FACE)) {
+ _globals[kLookedAtSkullFace] = true;
+ _vm->_dialogs->show(50529);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DOOR)) {
+ _vm->_dialogs->show(50519);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SKULL)) {
+ _vm->_dialogs->show((_scene->_customDest.x < 19) ? 50521 : 50520);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_SKULLS)) {
+ _vm->_dialogs->show(50521);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_TOTEM)) {
+ _vm->_dialogs->show(50522);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DESK)) {
+ _vm->_dialogs->show(50523);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_POLE)) {
+ _vm->_dialogs->show(50524);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CURTAIN)) {
+ _vm->_dialogs->show(50525);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CHRISTINE)) {
+ _vm->_dialogs->show((_globals[kCoffinStatus] == 2) ? 50530 : 50537);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_LID)) {
+ _vm->_dialogs->show((_globals[kCoffinStatus] == 2) ? 50531 : 50532);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_LOCK, NOUN_SARCOPHAGUS) || _action.isAction(VERB_LOCK, NOUN_LID) || _action.isAction(VERB_LOCK, NOUN_SKULL_FACE)) {
+ _vm->_dialogs->show(50535);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_SARCOPHAGUS) || _action.isAction(VERB_OPEN, NOUN_LID)) {
+ if (_globals[kCoffinStatus] == 2)
+ _vm->_dialogs->show(50533);
+ else if (_globals[kCoffinStatus] == 1)
+ _vm->_dialogs->show(50518);
+ else
+ _vm->_dialogs->show(50515);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_CHRISTINE) && (_globals[kCoffinStatus] != 2)) {
+ _vm->_dialogs->show(50538);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_CHRISTINE)) {
+ _vm->_dialogs->show((_globals[kCoffinStatus] <= 1) ? 50538 : 50540);
+ _action._inProgress = false;
+ }
+}
+
+void Scene505::preActions() {
+ if ((_globals[kCoffinStatus] == 0) && (_action.isAction(VERB_UNLOCK, NOUN_SKULL_FACE) || _action.isAction(VERB_UNLOCK, NOUN_SARCOPHAGUS) || _action.isAction(VERB_PUT, NOUN_KEY, NOUN_SKULL_FACE) || _action.isAction(VERB_UNLOCK, NOUN_LID))) {
+ if (_action.isObject(NOUN_SKULL_FACE) || _globals[kLookedAtSkullFace])
+ _game._player.walk(Common::Point(279, 150), FACING_SOUTHWEST);
+ }
+
+ if (_action.isObject(NOUN_SKULL_FACE) && (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)))
+ _game._player.walk(Common::Point(279, 150), FACING_SOUTHWEST);
+
+ if (_action.isObject(NOUN_CURTAIN) && (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)))
+ _game._player._needToWalk = true;
+
+ if (_action.isObject(NOUN_SKULL) && (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)))
+ _game._player._needToWalk = true;
+}
+
+void Scene505::handleCoffinDialog() {
+ int interlocutorFl = false;
+ int heroFl = false;
+
+ switch (_action._activeAction._verbId) {
+ case 8:
+ heroFl = true;
+ interlocutorFl = true;
+ _bothStatus = 6;
+ break;
+
+ case 14:
+ heroFl = true;
+ interlocutorFl = true;
+ if (!_checkFrame106)
+ _vm->_gameConv->hold();
+ break;
+
+ case 17:
+ heroFl = true;
+ interlocutorFl = true;
+ if (!_game._trigger) {
+ _vm->_gameConv->hold();
+ _raoulStatus = 2;
+ }
+ break;
+
+ case 20:
+ heroFl = true;
+ interlocutorFl = true;
+ if (!_game._trigger) {
+ _vm->_gameConv->hold();
+ _game._player.walk(Common::Point(244, 130), FACING_SOUTHWEST);
+ _game._player.setWalkTrigger(71);
+ }
+ break;
+
+ case 22:
+ heroFl = true;
+ interlocutorFl = true;
+ if (!_game._trigger) {
+ _vm->_gameConv->hold();
+ _bothStatus = 7;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 70:
+ case 76:
+ _vm->_gameConv->release();
+ break;
+
+ case 71:
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('r', 1), 75);
+ _anim0ActvFl = true;
+ _raoulStatus = 0;
+ _raoulCount = 0;
+ _game._player._visible = false;
+ break;
+
+ case 75:
+ _game._player._visible = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[0]);
+ _scene->_sequences.addTimer(10, 76);
+ break;
+
+ case 85:
+ if ((_bothStatus != 6) && (_bothStatus != 0))
+ _bothStatus = 5;
+ break;
+
+ case 90:
+ if ((_bothStatus != 6) && (_bothStatus != 0))
+ _bothStatus = 4;
+ break;
+
+ default:
+ break;
+ }
+
+ if (!heroFl)
+ _vm->_gameConv->setHeroTrigger(85);
+
+ if (!interlocutorFl)
+ _vm->_gameConv->setInterlocutorTrigger(90);
+
+ _bothCount = 0;
+}
+
+void Scene505::handleRaoulAnimation() {
+ int curFrame = _scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame();
+ if (curFrame == _raoulFrame)
+ return;
+
+ _raoulFrame = curFrame;
+ int resetFrame = -1;
+
+ switch (_raoulFrame) {
+ case 3:
+ _vm->_gameConv->release();
+ break;
+
+ case 4:
+ case 5:
+ case 6:
+ if (_raoulStatus == 0) {
+ resetFrame = _vm->getRandomNumber(3, 5);
+ ++_raoulCount;
+ if (_raoulCount > 20) {
+ _raoulStatus = 1;
+ resetFrame = 3;
+ }
+ break;
+ }
+
+ if (_raoulStatus == 1)
+ resetFrame = 3;
+
+ if (_raoulStatus == 2)
+ resetFrame = 6;
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[0], resetFrame);
+ _raoulFrame = resetFrame;
+ }
+}
+
+void Scene505::handleBothanimation() {
+ int curFrame = _scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame();
+ if (curFrame == _bothFrame)
+ return;
+
+ _bothFrame = curFrame;
+ int resetFrame = -1;
+
+ switch (_bothFrame) {
+ case 1:
+ case 20:
+ case 39:
+ if (_bothStatus == 0) {
+ if (_vm->getRandomNumber(1, 35) == 1) {
+ if (_vm->getRandomNumber(1, 2) == 1)
+ resetFrame = 1;
+ else
+ resetFrame = 20;
+ } else
+ resetFrame = 0;
+ } else if (_bothStatus == 1)
+ resetFrame = 39;
+ else
+ resetFrame = 0;
+ break;
+
+ case 14:
+ if (_vm->getRandomNumber(1, 3) == 1)
+ resetFrame = 8;
+ break;
+
+ case 32:
+ if (_vm->getRandomNumber(1, 2) == 1)
+ resetFrame = 28;
+ break;
+
+ case 41:
+ _vm->_sound->command(39);
+ break;
+
+ case 51:
+ _globals._sequenceIndexes[7] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[7], false, 12);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 1);
+ _globals[kCoffinStatus] = 2;
+ break;
+
+ case 66:
+ _game._player._stepEnabled = false;
+ _vm->_gameConv->run(20);
+ _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
+ break;
+
+ case 67:
+ if (_bothStatus == 1)
+ resetFrame = 66;
+ break;
+
+ case 68:
+ _game._player._visible = false;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[1]);
+ break;
+
+ case 106:
+ _checkFrame106 = true;
+ _vm->_gameConv->release();
+ break;
+
+ case 109:
+ case 130:
+ _vm->_gameConv->release();
+ break;
+
+ case 110:
+ case 111:
+ case 112:
+ case 113:
+ case 114:
+ case 115:
+ case 131:
+ switch (_bothStatus) {
+ case 4:
+ resetFrame = _vm->getRandomNumber(112, 114);
+ ++_bothCount;
+ if (_bothCount > 20) {
+ _bothStatus = 3;
+ resetFrame = 109;
+ }
+ break;
+
+ case 5:
+ resetFrame = _vm->getRandomNumber(109, 111);
+ ++_bothCount;
+ if (_bothCount > 20) {
+ _bothStatus = 3;
+ resetFrame = 109;
+ }
+ break;
+
+ case 6:
+ resetFrame = 131;
+ _bothStatus = 8;
+ _game._player._stepEnabled = false;
+ break;
+
+ case 7:
+ resetFrame = 115;
+ _bothStatus = 3;
+ break;
+
+ default:
+ resetFrame = 109;
+ break;
+ }
+ break;
+
+ case 127:
+ _vm->_sound->command(26);
+ _game._objects.addToInventory(OBJ_WEDDING_RING);
+ _vm->_dialogs->showItem(OBJ_WEDDING_RING, 821, 0);
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[1], resetFrame);
+ _bothFrame = resetFrame;
+ }
+}
+
+void Scene505::handlePartedAnimation() {
+ int curFrame = _scene->_animation[_globals._animationIndexes[2]]->getCurrentFrame();
+ if (curFrame == _partFrame)
+ return;
+
+ _partFrame = curFrame;
+ int resetFrame = -1;
+
+ switch (_partFrame) {
+ case 20:
+ _vm->_sound->command(16);
+ break;
+
+ case 25:
+ _game._player._playerPos = Common::Point(93, 133);
+ _game._player.resetFacing(FACING_WEST);
+ _game._player._visible = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[2]);
+ break;
+
+ case 70:
+ _game._player._stepEnabled = true;
+ break;
+
+ case 90:
+ if (_partStatus == 10)
+ resetFrame = 146;
+ else if (!_leaveRoomFl)
+ resetFrame = 89;
+ break;
+
+ case 145:
+ _scene->_nextSceneId = 504;
+ break;
+
+ case 147:
+ case 148:
+ case 149:
+ resetFrame = _vm->getRandomNumber(146, 148);
+ ++_partCount;
+ if (_partCount > 10) {
+ resetFrame = 89;
+ _partStatus = 8;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (resetFrame >= 0) {
+ _scene->setAnimFrame(_globals._animationIndexes[2], resetFrame);
+ _partFrame = resetFrame;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene506::Scene506(MADSEngine *vm) : Scene5xx(vm) {
+ _anim0ActvFl = false;
+ _skipFl = false;
+ _ascendingFl = false;
+}
+
+void Scene506::synchronize(Common::Serializer &s) {
+ Scene5xx::synchronize(s);
+
+ s.syncAsByte(_anim0ActvFl);
+ s.syncAsByte(_skipFl);
+ s.syncAsByte(_ascendingFl);
+}
+
+void Scene506::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ _scene->addActiveVocab(NOUN_CHRISTINE);
+ _scene->addActiveVocab(VERB_LOOK_AT);
+
+ if (!_globals[kChristineIsInBoat])
+ _scene->_variant = 1;
+}
+
+void Scene506::enter() {
+ _vm->_disableFastwalk = true;
+
+ if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
+ _anim0ActvFl = false;
+ _skipFl = false;
+ _ascendingFl = false;
+ }
+
+ _vm->_gameConv->load(26);
+
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 2));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('x', 3));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('p', 0));
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('a', 1));
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('a', 0));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('b', 0), PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites("*RDR_9");
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*CHR_6", PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*CHR_3", PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*CHR_2", PALFLAG_ALL_TO_CLOSEST | PALFLAG_ANY_TO_CLOSEST);
+
+ if (_game._objects.isInRoom(OBJ_OAR)) {
+ _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 14);
+ } else
+ _scene->_hotspots.activate(NOUN_OAR, false);
+
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 6, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], -1, -2);
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 6, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], -1, -2);
+
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 6, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], -1, -2);
+
+ if (_scene->_priorSceneId == RETURNING_FROM_LOADING) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
+ if (!_globals[kChristineIsInBoat]) {
+ _anim0ActvFl = true;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('r', 1), 0);
+ _scene->setAnimFrame(_globals._animationIndexes[0], 239);
+ int hotspotIdx = _scene->_dynamicHotspots.add(NOUN_CHRISTINE, VERB_WALK_TO, SYNTAX_SINGULAR_FEM, EXT_NONE, Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots[hotspotIdx]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(hotspotIdx, Common::Point(79, 133), FACING_SOUTHWEST);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[0], 6);
+ }
+ } else if (_scene->_priorSceneId == 504) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
+
+ if (_game._visitedScenes._sceneRevisited) {
+ _game._player._playerPos = Common::Point(189, 123);
+ _game._player._facing = FACING_SOUTHWEST;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+
+ if (!_globals[kChristineIsInBoat]) {
+ _anim0ActvFl = true;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('r', 1), 0);
+ _scene->setAnimFrame(_globals._animationIndexes[0], 239);
+ int hotspotIdx = _scene->_dynamicHotspots.add(NOUN_CHRISTINE, VERB_WALK_TO, SYNTAX_SINGULAR_FEM, EXT_NONE, Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots[hotspotIdx]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(hotspotIdx, Common::Point(79, 133), FACING_SOUTHWEST);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[0], 6);
+ }
+ _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('r', 2), 95);
+ } else {
+ _game._player._playerPos = Common::Point(186, 122);
+ _game._player._facing = FACING_SOUTHWEST;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _anim0ActvFl = true;
+ _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('r', 1), 0);
+ int hotspotIdx = _scene->_dynamicHotspots.add(NOUN_CHRISTINE, VERB_WALK_TO, SYNTAX_SINGULAR_FEM, EXT_NONE, Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots[hotspotIdx]._articleNumber = PREP_ON;
+ _scene->_dynamicHotspots.setPosition(hotspotIdx, Common::Point(79, 133), FACING_SOUTHWEST);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[0], 2);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[0], 3);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[0], 4);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[0], 5);
+ _scene->setDynamicAnim(hotspotIdx, _globals._animationIndexes[0], 6);
+ }
+ } else if ((_scene->_priorSceneId == 501) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
+ _game._player._playerPos = Common::Point(0, 142);
+ _game._player._facing = FACING_EAST;
+ _game._player._stepEnabled = false;
+ _game._player.walk(Common::Point(23, 145), FACING_EAST);
+ _game._player.setWalkTrigger(60);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene506::step() {
+ switch (_game._trigger) {
+ case 60:
+ _globals._sequenceIndexes[3] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[3], false, 6, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 61);
+ break;
+
+ case 61:
+ _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
+ _game._player._stepEnabled = true;
+ break;
+
+ case 95:
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[1]);
+ break;
+
+ default:
+ break;
+ }
+
+ if (_anim0ActvFl) {
+ int curFrame = _scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame();
+ if ((curFrame == 141) && !_skipFl) {
+ _game._player._visible = true;
+ _skipFl = true;
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[0]);
+ }
+
+ if (curFrame == 240)
+ _scene->setAnimFrame(_globals._animationIndexes[0], 239);
+
+ if (curFrame == 300)
+ _scene->setAnimFrame(_globals._animationIndexes[0], 239);
+
+ if (curFrame == 168)
+ _game._player._stepEnabled = true;
+
+ if (curFrame == 289)
+ _scene->_nextSceneId = 501;
+ }
+
+ if (_ascendingFl && (_vm->_gameConv->activeConvId() != 26)) {
+ _ascendingFl = false;
+ _game._player._stepEnabled = false;
+ }
+}
+
+void Scene506::actions() {
+ if (_action.isAction(VERB_TALK_TO, NOUN_CHRISTINE)) {
+ _vm->_gameConv->run(26);
+ _vm->_gameConv->exportValue(1);
+ _scene->setAnimFrame(_globals._animationIndexes[0], 290);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_OAR)) {
+ switch (_game._trigger) {
+ case (0):
+ if (_game._objects.isInRoom(OBJ_OAR)) {
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[4] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[4], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[4], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_SPRITE, 4, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ }
+ break;
+
+ case 1:
+ _scene->deleteSequence(_globals._sequenceIndexes[5]);
+ _scene->_hotspots.activate(NOUN_OAR, false);
+ _game._objects.addToInventory(OBJ_OAR);
+ _vm->_sound->command(26);
+ break;
+
+ case 2:
+ _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[4]);
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(20, 3);
+ break;
+
+ case 3:
+ _vm->_dialogs->showItem(OBJ_OAR, 824, 0);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR) || _action.isAction(VERB_OPEN, NOUN_DOOR)) {
+ if (_scene->_customDest.x < 150) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[4] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[4], true, 5, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 1, 4);
+ _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[4], true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_SPRITE, 4, 65);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 67);
+ break;
+
+ case 65:
+ _scene->deleteSequence(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 8, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 66);
+ _vm->_sound->command(24);
+ break;
+
+ case 66:
+ _game._player.walk(Common::Point(0, 142), FACING_WEST);
+ _game._player.setWalkTrigger(68);
+ break;
+
+ case 67:
+ _game._player._visible = true;
+ break;
+
+ case 68:
+ if (_globals[kChristineIsInBoat])
+ _scene->_nextSceneId = 501;
+ else
+ _scene->setAnimFrame(_globals._animationIndexes[0], 241);
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ switch (_game._trigger) {
+ case (0):
+ if (!_globals[kChristineIsInBoat]) {
+ _vm->_gameConv->run(26);
+ _vm->_gameConv->exportValue(2);
+ int curFrame = _scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame();
+ if (curFrame == 240 || curFrame == 239)
+ _scene->setAnimFrame(_globals._animationIndexes[0], 290);
+ _ascendingFl = true;
+ }
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[7] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[7], false, 5, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[7], -1, -2);
+ _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[7], SYNC_PLAYER, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_EXPIRE, 0, 90);
+ break;
+
+ case 90:
+ _vm->_gameConv->stop();
+ _scene->_nextSceneId = 504;
+ break;
+
+ default:
+ break;
+ }
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_vm->_gameConv->activeConvId() == 26) {
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(50610);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
+ if (_action.isObject(NOUN_FLOOR)) {
+ _vm->_dialogs->show(50611);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_WALL)) {
+ _vm->_dialogs->show(50612);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_TORCH)) {
+ _vm->_dialogs->show(50613);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_COLUMN)) {
+ _vm->_dialogs->show(50614);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CEILING)) {
+ _vm->_dialogs->show(50615);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_RAMP)) {
+ _vm->_dialogs->show(50616);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_DOOR)) {
+ if (_scene->_customDest.x < 150)
+ _vm->_dialogs->show(50617);
+ else
+ _vm->_dialogs->show(50618);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_OAR) && _game._objects.isInRoom(OBJ_OAR)) {
+ _vm->_dialogs->show(50619);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isObject(NOUN_CHRISTINE)) {
+ if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() < 235)
+ _vm->_dialogs->show(50621);
+ else
+ _vm->_dialogs->show(50620);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_TORCH)) {
+ _vm->_dialogs->show(50613);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_CHRISTINE)) {
+ _vm->_dialogs->show(50622);
+ _action._inProgress = false;
+ }
+}
+
+void Scene506::preActions() {
+ if (_action.isAction(VERB_UNLOCK, NOUN_DOOR) || _action.isAction(VERB_LOCK, NOUN_DOOR))
+ _game._player.walk(Common::Point(33, 142), FACING_NORTHWEST);
+
+ if (_action.isAction(VERB_OPEN, NOUN_DOOR)) {
+ if (_scene->_customDest.x < 150)
+ _game._player.walk(Common::Point(33, 142), FACING_NORTHWEST);
+ else
+ _game._player.walk(Common::Point(191, 118), FACING_EAST);
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+} // End of namespace Phantom
+} // End of namespace MADS
diff --git a/engines/mads/phantom/phantom_scenes5.h b/engines/mads/phantom/phantom_scenes5.h
new file mode 100644
index 0000000000..33478304f3
--- /dev/null
+++ b/engines/mads/phantom/phantom_scenes5.h
@@ -0,0 +1,219 @@
+/* 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 MADS_PHANTOM_SCENES5_H
+#define MADS_PHANTOM_SCENES5_H
+
+#include "common/scummsys.h"
+#include "common/serializer.h"
+#include "mads/game.h"
+#include "mads/scene.h"
+#include "mads/phantom/phantom_scenes.h"
+
+namespace MADS {
+
+namespace Phantom {
+
+class Scene5xx : public PhantomScene {
+protected:
+ /**
+ * Plays an appropriate sound when entering a scene
+ */
+ void sceneEntrySound();
+
+ /**
+ *Sets the AA file to use for the scene
+ */
+ void setAAName();
+
+ /**
+ * Updates the prefix used for getting player sprites for the scene
+ */
+ void setPlayerSpritesPrefix();
+public:
+ Scene5xx(MADSEngine *vm) : PhantomScene(vm) {}
+};
+
+class Scene501 : public Scene5xx {
+private:
+ bool _anim0ActvFl;
+ bool _skipFl;
+
+public:
+ Scene501(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene502 : public Scene5xx {
+private:
+ bool _fire1ActiveFl;
+ bool _fire2ActiveFl;
+ bool _fire3ActiveFl;
+ bool _fire4ActiveFl;
+ bool _panelTurningFl;
+ bool _trapDoorHotspotEnabled;
+ bool _acceleratedFireActivationFl;
+
+ int _panelPushedNum;
+ int _puzzlePictures[16];
+ int _puzzleSprites[16];
+ int _puzzleSequences[16];
+ int _messageLevel;
+ int _cycleStage;
+
+ Common::Point _nextPos;
+
+ uint32 _lastFrameTime;
+ uint32 _timer;
+ uint32 _deathTimer;
+
+ byte *_cyclePointer;
+
+ void room_502_initialize_panels();
+ void loadCyclingInfo();
+ void animateFireBursts();
+ void setPaletteCycle();
+ void handlePanelAnimation();
+ void getPanelInfo(Common::Point *walkToPos, int *panel, Common::Point mousePos, Common::Point *interimPos);
+
+public:
+ Scene502(MADSEngine *vm);
+ ~Scene502();
+
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene504 : public Scene5xx {
+private:
+ bool _anim0ActvFl;
+ bool _anim1ActvFl;
+ bool _anim2ActvFl;
+ bool _anim3ActvFl;
+ bool _anim4ActvFl;
+ bool _anim5ActvFl;
+ bool _playingMusicFl;
+ bool _chairDialogDoneFl;
+ bool _fireBreathFl;
+
+ int _songNum;
+ int _input3Count;
+ int _playCount;
+ int _listenStatus;
+ int _listenFrame;
+ int _chairStatus;
+ int _chairFrame;
+ int _playStatus;
+ int _playFrame;
+ int _phantomStatus;
+ int _phantomFrame;
+ int _christineTalkCount;
+ int _deathCounter;
+
+ void handleListenAnimation();
+ void handleOrganAnimation();
+ void handleChairAnimation();
+ void handlePhantomAnimation1();
+ void handlePhantomAnimation2();
+ void handlePhantomAnimation3();
+ void handleListenConversation();
+ void handlePlayConversation();
+ void handleFightConversation();
+
+public:
+ Scene504(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene505 : public Scene5xx {
+private:
+ bool _anim0ActvFl;
+ bool _anim1ActvFl;
+ bool _anim2ActvFl;
+ bool _checkFrame106;
+ bool _leaveRoomFl;
+ bool _partedFl;
+
+ int _raoulStatus;
+ int _raoulFrame;
+ int _raoulCount;
+ int _bothStatus;
+ int _bothFrame;
+ int _bothCount;
+ int _partStatus;
+ int _partFrame;
+ int _partCount;
+
+ void handleRaoulAnimation();
+ void handleBothanimation();
+ void handlePartedAnimation();
+ void handleCoffinDialog();
+
+public:
+ Scene505(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene506 : public Scene5xx {
+private:
+ bool _anim0ActvFl;
+ bool _skipFl;
+ bool _ascendingFl;
+
+public:
+ Scene506(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+} // End of namespace Phantom
+} // End of namespace MADS
+
+#endif /* MADS_PHANTOM_SCENES5_H */
diff --git a/engines/mads/player.cpp b/engines/mads/player.cpp
index bb747f4b52..0940e79562 100644
--- a/engines/mads/player.cpp
+++ b/engines/mads/player.cpp
@@ -32,6 +32,34 @@ const int Player::_directionListIndexes[32] = {
0, 7, 4, 3, 6, 0, 2, 5, 0, 1, 9, 4, 1, 2, 7, 9, 3, 8, 9, 6, 7, 2, 3, 6, 1, 7, 9, 4, 7, 8, 0, 0
};
+/*------------------------------------------------------------------------*/
+
+void StopWalkerEntry::synchronize(Common::Serializer &s) {
+ s.syncAsSint16LE(_stack);
+ s.syncAsSint16LE(_trigger);
+}
+
+/*------------------------------------------------------------------------*/
+
+void StopWalkers::synchronize(Common::Serializer &s) {
+ StopWalkerEntry rec;
+ int count = size();
+ s.syncAsUint16LE(count);
+
+ if (s.isLoading()) {
+ clear();
+ for (int idx = 0; idx < count; ++idx) {
+ rec.synchronize(s);
+ push(rec);
+ }
+ } else {
+ for (int idx = 0; idx < count; ++idx)
+ (*this)[idx].synchronize(s);
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
Player::Player(MADSEngine *vm)
: _vm(vm) {
_action = nullptr;
@@ -56,7 +84,6 @@ Player::Player(MADSEngine *vm)
_special = 0;
_ticksAmount = 0;
_priorTimer = 0;
- _trigger = 0;
_scalingVelocity = false;
_spritesChanged = false;
_forceRefresh = false;
@@ -70,7 +97,6 @@ Player::Player(MADSEngine *vm)
_upcomingTrigger = 0;
_trigger = 0;
_frameListIndex = 0;
- _stopWalkerIndex = 0;
_totalDistance = 0;
_distAccum = 0;
_pixelAccum = 0;
@@ -80,10 +106,17 @@ Player::Player(MADSEngine *vm)
_moving = false;
_walkOffScreen = 0;
_walkOffScreenSceneId = -1;
+ _forcePrefix = false;
+ _commandsAllowed = false;
+ _enableAtTarget = false;
- Common::fill(&_stopWalkerList[0], &_stopWalkerList[12], 0);
- Common::fill(&_stopWalkerTrigger[0], &_stopWalkerTrigger[12], 0);
Common::fill(&_spriteSetsPresent[0], &_spriteSetsPresent[PLAYER_SPRITES_FILE_COUNT], false);
+
+ _walkTrigger = 0;
+ _walkTriggerDest = SEQUENCE_TRIGGER_NONE;
+ _walkTriggerAction._verbId = VERB_NONE;
+ _walkTriggerAction._objectNameId = 0;
+ _walkTriggerAction._indirectObjectId = 0;
}
void Player::cancelWalk() {
@@ -186,8 +219,10 @@ void Player::changeFacing() {
(Facing)_directionListIndexes[_facing + 10];
selectSeries();
- if ((_facing == _turnToFacing) && !_moving)
+ if ((_facing == _turnToFacing) && !_moving) {
updateFrame();
+ activateTrigger();
+ }
_priorTimer += 1;
}
@@ -242,8 +277,8 @@ void Player::updateFrame() {
Scene &scene = _vm->_game->_scene;
assert(scene._sprites[idx] != nullptr);
SpriteAsset &spriteSet = *scene._sprites[idx];
-
- // WORKAROUND: Certain cutscenes set up player sprites that don't have any
+
+ // WORKAROUND: Certain cutscenes set up player sprites that don't have any
// character info. In such cases, simply ignore player updates
if (!spriteSet._charInfo)
return;
@@ -251,15 +286,16 @@ void Player::updateFrame() {
if (!spriteSet._charInfo->_numEntries) {
_frameNumber = 1;
} else {
- _frameListIndex = _stopWalkerList[_stopWalkerIndex];
+ _frameListIndex = _stopWalkers.empty() ? 0 : _stopWalkers.top()._stack;
if (!_visible) {
_upcomingTrigger = 0;
} else {
- _upcomingTrigger = _stopWalkerTrigger[_stopWalkerIndex];
-
- if (_stopWalkerIndex > 0)
- --_stopWalkerIndex;
+ if (_stopWalkers.empty()) {
+ _upcomingTrigger = 0;
+ } else {
+ _upcomingTrigger = _stopWalkers.pop()._trigger;
+ }
}
// Set the player frame number
@@ -278,6 +314,25 @@ void Player::updateFrame() {
_forceRefresh = true;
}
+void Player::activateTrigger() {
+ Game &game = *_vm->_game;
+ MADSAction &action = game._scene._action;
+
+ _commandsAllowed |= _enableAtTarget;
+ _enableAtTarget = false;
+
+ if (_walkTrigger) {
+ game._trigger = _walkTrigger;
+ game._triggerMode = SEQUENCE_TRIGGER_DAEMON;
+
+ if (game._triggerMode != SEQUENCE_TRIGGER_DAEMON) {
+ action._activeAction = _walkTriggerAction;
+ }
+
+ _walkTrigger = 0;
+ }
+}
+
void Player::update() {
Scene &scene = _vm->_game->_scene;
@@ -289,7 +344,7 @@ void Player::update() {
int newDepth = 1;
int yp = MIN(_playerPos.y, (int16)(MADS_SCENE_HEIGHT - 1));
- for (int idx = 1; idx < 15; ++idx) {
+ for (int idx = 1; idx < DEPTH_BANDS_SIZE; ++idx) {
if (scene._sceneInfo->_depthList[newDepth] >= yp)
newDepth = idx + 1;
}
@@ -361,9 +416,7 @@ void Player::update() {
}
void Player::clearStopList() {
- _stopWalkerList[0] = 0;
- _stopWalkerTrigger[0] = 0;
- _stopWalkerIndex = 0;
+ _stopWalkers.clear();
_upcomingTrigger = 0;
_trigger = 0;
}
@@ -441,10 +494,12 @@ void Player::move() {
if (newFacing && _moving)
startMovement();
- if (_turnToFacing != _facing)
+ if (_turnToFacing != _facing) {
changeFacing();
- else if (!_moving)
+ } else if (!_moving) {
updateFrame();
+ activateTrigger();
+ }
int velocity = _velocity;
if (_scalingVelocity && (_totalDistance > 0)) {
@@ -684,14 +739,10 @@ void Player::addWalker(int walker, int trigger) {
SpriteAsset &spriteSet = *scene._sprites[_spritesStart + _spritesIdx];
assert(spriteSet._charInfo);
- if (walker < spriteSet._charInfo->_numEntries && _stopWalkerIndex < 11) {
- ++_stopWalkerIndex;
- _stopWalkerList[_stopWalkerIndex] = walker;
- _stopWalkerTrigger[_stopWalkerIndex] = trigger;
- }
+ if (walker < spriteSet._charInfo->_numEntries)
+ _stopWalkers.push(StopWalkerEntry(walker, trigger));
}
-
/**
* Releases any sprites used by the player
*/
@@ -753,13 +804,10 @@ void Player::synchronize(Common::Serializer &s) {
s.syncAsSint16LE(_currentDepth);
s.syncAsSint16LE(_currentScale);
s.syncAsSint16LE(_frameListIndex);
+ _stopWalkers.synchronize(s);
+ _walkTriggerAction.synchronize(s);
+ s.syncAsUint16LE(_walkTriggerDest);
- for (int i = 0; i < 12; ++i) {
- s.syncAsSint16LE(_stopWalkerList[i]);
- s.syncAsSint16LE(_stopWalkerTrigger[i]);
- }
-
- s.syncAsSint16LE(_stopWalkerIndex);
s.syncAsSint16LE(_upcomingTrigger);
s.syncAsSint16LE(_trigger);
s.syncAsSint16LE(_scalingVelocity);
@@ -797,4 +845,28 @@ void Player::removePlayerSprites() {
_visible = false;
}
+void Player::firstWalk(Common::Point fromPos, Facing fromFacing, Common::Point destPos, Facing destFacing, bool enableFl) {
+ _playerPos = fromPos;
+ _facing = fromFacing;
+
+ walk(destPos, destFacing);
+ _walkAnywhere = true;
+
+ _commandsAllowed = false;
+ _enableAtTarget = enableFl;
+}
+
+void Player::setWalkTrigger(int val) {
+ Scene &scene = _vm->_game->_scene;
+ _walkTrigger = val;
+ _walkTriggerDest = _vm->_game->_triggerSetupMode;
+ _walkTriggerAction = scene._action._activeAction;
+}
+
+void Player::resetFacing(Facing facing) {
+ _facing = facing;
+ _turnToFacing = facing;
+ selectSeries();
+}
+
} // End of namespace MADS
diff --git a/engines/mads/player.h b/engines/mads/player.h
index e5765a9bca..04b86b76b4 100644
--- a/engines/mads/player.h
+++ b/engines/mads/player.h
@@ -45,6 +45,23 @@ enum Facing {
FACING_NONE = 5, FACING_DUMMY = 0
};
+struct StopWalkerEntry {
+ int _stack;
+ int _trigger;
+
+ StopWalkerEntry() : _stack(0), _trigger(0) {}
+ StopWalkerEntry(int stack, int trigger) : _stack(stack), _trigger(trigger) {}
+
+ void synchronize(Common::Serializer &s);
+};
+
+class StopWalkers : public Common::FixedStack<StopWalkerEntry, 12> {
+public:
+ StopWalkers() : Common::FixedStack<StopWalkerEntry, 12>() {}
+
+ void synchronize(Common::Serializer &s);
+};
+
class Player {
private:
static const int _directionListIndexes[32];
@@ -58,8 +75,6 @@ private:
int _distAccum;
int _pixelAccum;
int _deltaDistance;
- int _stopWalkerList[12];
- int _stopWalkerTrigger[12];
int _totalDistance;
void clearStopList();
@@ -95,6 +110,8 @@ private:
void startMovement();
void changeFacing();
+
+ void activateTrigger();
public:
MADSAction *_action;
@@ -131,13 +148,20 @@ public:
int _trigger;
bool _scalingVelocity;
bool _forceRefresh;
+ bool _forcePrefix;
bool _needToWalk;
bool _readyToWalk;
- int _stopWalkerIndex;
+ bool _commandsAllowed;
+ bool _enableAtTarget;
int _centerOfGravity;
int _currentDepth;
int _currentScale;
Common::String _spritesPrefix;
+
+ int _walkTrigger;
+ TriggerMode _walkTriggerDest;
+ ActionDetails _walkTriggerAction;
+ StopWalkers _stopWalkers;
public:
Player(MADSEngine *vm);
@@ -221,6 +245,13 @@ public:
}
void removePlayerSprites();
+
+ void firstWalk(Common::Point fromPos, Facing fromFacing, Common::Point destPos, Facing destFacing, bool enableFl);
+
+ void setWalkTrigger(int val);
+
+ void resetFacing(Facing facing);
+
};
} // End of namespace MADS
diff --git a/engines/mads/rails.cpp b/engines/mads/rails.cpp
index 9b2ec71de6..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
@@ -274,4 +274,18 @@ void Rails::synchronize(Common::Serializer &s) {
}
}
+void Rails::disableNode(int nodeIndex) {
+ _nodes[nodeIndex]._active = false;
+
+ for (uint16 i = 0; i < _nodes.size(); i++) {
+ if (i != nodeIndex)
+ disableLine(i, nodeIndex);
+ }
+}
+
+void Rails::disableLine(int from, int to) {
+ _nodes[from]._distances[to] = 0x3FFF;
+ _nodes[to]._distances[from] = 0x3FFF;
+}
+
} // End of namespace MADS
diff --git a/engines/mads/rails.h b/engines/mads/rails.h
index c95f5c47a6..ea12177038 100644
--- a/engines/mads/rails.h
+++ b/engines/mads/rails.h
@@ -127,6 +127,10 @@ public:
* Synchronize the data for the route
*/
void synchronize(Common::Serializer &s);
+
+ void disableNode(int idx);
+ void disableLine(int from, int to);
+
};
} // End of namespace MADS
diff --git a/engines/mads/resources.cpp b/engines/mads/resources.cpp
index d5352fb205..16019a4b07 100644
--- a/engines/mads/resources.cpp
+++ b/engines/mads/resources.cpp
@@ -79,7 +79,7 @@ private:
*/
ResourceType getResourceType(const Common::String &resourceName) const;
public:
- HagArchive(MADSEngine *vm);
+ explicit HagArchive(MADSEngine *vm);
virtual ~HagArchive();
// Archive implementation
@@ -151,7 +151,7 @@ void HagArchive::loadIndex(MADSEngine *vm) {
Common::File hagFile;
for (int sectionIndex = -1; sectionIndex < 11; ++sectionIndex) {
- if (sectionIndex == 0)
+ if (sectionIndex == 0 && !Common::File::exists("SECTION0.HAG"))
continue;
// Dragonsphere does not have some sections - skip them
@@ -239,7 +239,7 @@ Common::String HagArchive::getResourceFilename(const Common::String &resourceNam
int value = atoi(resourceName.c_str() + 2);
int hagFileNum = (resType == RESTYPE_ROOM) ? value / 100 : value;
- if (hagFileNum > 0)
+ if (hagFileNum >= 0)
outputFilename = Common::String::format("SECTION%d.HAG", hagFileNum);
}
diff --git a/engines/mads/scene.cpp b/engines/mads/scene.cpp
index ee5f1a5440..66f56f9407 100644
--- a/engines/mads/scene.cpp
+++ b/engines/mads/scene.cpp
@@ -24,6 +24,7 @@
#include "mads/scene.h"
#include "mads/compression.h"
#include "mads/mads.h"
+#include "mads/audio.h"
#include "mads/dragonsphere/dragonsphere_scenes.h"
#include "mads/nebular/nebular_scenes.h"
#include "mads/phantom/phantom_scenes.h"
@@ -49,7 +50,8 @@ Scene::Scene(MADSEngine *vm)
_reloadSceneFlag = false;
_freeAnimationFlag = false;
_animationData = nullptr;
- _activeAnimation = nullptr;
+ for (int i = 0; i < 10; i++)
+ _animation[i] = nullptr;
_textSpacing = -1;
_frameStartTime = 0;
_mode = SCREENMODE_VGA;
@@ -60,6 +62,8 @@ Scene::Scene(MADSEngine *vm)
_spritesCount = 0;
_variant = 0;
+ _speechReady = -1;
+
_paletteUsageF.push_back(PaletteUsage::UsageEntry(0xF));
// Set up a scene surface that maps to our physical screen drawing surface
@@ -85,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() {
@@ -150,6 +153,8 @@ void Scene::loadScene(int sceneId, const Common::String &prefix, bool palFlag) {
_sequences.clear();
_kernelMessages.clear();
_vm->_palette->_paletteUsage.load(&_scenePaletteUsage);
+ if (_vm->getGameID() != GType_RexNebular)
+ setCamera(Common::Point(0, 0));
int flags = SCENEFLAG_LOAD_SHADOW;
if (_vm->_dithering)
@@ -385,6 +390,7 @@ void Scene::doFrame() {
!_vm->_game->_fx);
}
+ _vm->_game->camUpdate();
if (_action._selectedAction && player._stepEnabled && !player._needToWalk &&
!_vm->_game->_trigger && !player._trigger) {
_action.startAction();
@@ -412,14 +418,24 @@ void Scene::doFrame() {
}
if (_currentSceneId != _nextSceneId) {
+ _vm->_gameConv->stop();
_freeAnimationFlag = true;
+ // TODO: Handle Phantom/Dragonsphere animation list free
} else {
doSceneStep();
checkKeyboard();
if (_currentSceneId != _nextSceneId) {
+ _vm->_gameConv->stop();
_freeAnimationFlag = true;
+ // TODO: Handle Phantom/Dragonsphere animation list free
} else {
+ // Handle conversation updates if one is active
+ if (!_vm->_game->_trigger && _vm->_gameConv->active() &&
+ !_vm->_game->_camX._activeFl && !_vm->_game->_camY._activeFl)
+ _vm->_gameConv->update(false);
+
+ // Update the player
player.nextFrame();
// Cursor update code
@@ -430,8 +446,7 @@ void Scene::doFrame() {
_sequences.tick();
// Handle any active animation
- if (_activeAnimation)
- _activeAnimation->update();
+ animations_tick();
}
// If the debugget flag is set, show the mouse position
@@ -480,8 +495,10 @@ void Scene::doFrame() {
_vm->_game->_fx = kTransitionNone;
// Handle freeing animation if necessary
- if (_activeAnimation && _activeAnimation->freeFlag())
- _freeAnimationFlag = true;
+ for (int i = 0; i < 10; i++) {
+ if (_animation[i] && _animation[i]->freeFlag())
+ _freeAnimationFlag = true;
+ }
if (_freeAnimationFlag)
freeAnimation();
}
@@ -496,8 +513,10 @@ void Scene::drawElements(ScreenTransition transitionType, bool surfaceFlag) {
// Merge any identified dirty areas
_dirtyAreas.merge(1, DIRTY_AREAS_SIZE);
+ 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();
@@ -508,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
@@ -538,13 +557,20 @@ void Scene::doPreactions() {
void Scene::doAction() {
bool flag = false;
+ // Don't allow the player to move if a conversation is active
+ if (_vm->_gameConv->active()) {
+ _vm->_game->_scene._action._savedFields._lookFlag = false;
+ if (_vm->_gameConv->currentMode() == CONVMODE_2 || _vm->_gameConv->currentMode() == CONVMODE_3)
+ _vm->_game->_player._stepEnabled = false;
+ }
+
_vm->_game->_triggerSetupMode = SEQUENCE_TRIGGER_PARSER;
if ((_action._inProgress || _vm->_game->_trigger) && !_action._savedFields._commandError) {
_sceneLogic->actions();
flag = !_action._inProgress;
}
- if (_vm->_game->_screenObjects._inputMode == kInputConversation) {
+ if (_vm->_gameConv->active() || _vm->_game->_screenObjects._inputMode == kInputConversation) {
_action._inProgress = false;
} else {
if ((_action._inProgress || _vm->_game->_trigger) ||
@@ -577,6 +603,10 @@ void Scene::doAction() {
_action._inProgress = false;
if (_vm->_game->_triggerMode == SEQUENCE_TRIGGER_PARSER)
_vm->_game->_trigger = 0;
+
+ if (_vm->_gameConv->active() && (_vm->_gameConv->currentMode() == CONVMODE_1 ||
+ _vm->_gameConv->currentMode() == CONVMODE_2))
+ _vm->_gameConv->update(true);
}
void Scene::doSceneStep() {
@@ -605,19 +635,29 @@ void Scene::checkKeyboard() {
}
}
-void Scene::loadAnimation(const Common::String &resName, int trigger) {
+int Scene::loadAnimation(const Common::String &resName, int trigger) {
// WORKAROUND: If there's already a previous active animation used by the
// scene, then free it before we create the new one
- if (_activeAnimation)
- freeAnimation();
+ if ((_vm->getGameID() == GType_RexNebular) && _animation[0])
+ freeAnimation(0);
DepthSurface depthSurface;
UserInterface interfaceSurface(_vm);
- _activeAnimation = Animation::init(_vm, this);
- _activeAnimation->load(interfaceSurface, depthSurface, resName,
- _vm->_dithering ? ANIMFLAG_DITHER : 0, nullptr, nullptr);
- _activeAnimation->startAnimation(trigger);
+ for (int i = 0; i < 10; i++) {
+ if (!_animation[i]) {
+ _animation[i] = Animation::init(_vm, this);
+ _animation[i]->load(interfaceSurface, depthSurface, resName,
+ _vm->_dithering ? ANIMFLAG_DITHER : 0, nullptr, nullptr);
+ _animation[i]->startAnimation(trigger);
+
+ return i;
+ }
+ }
+
+ error("Unable to find an available animation slot");
+
+ return -1;
}
void Scene::updateCursor() {
@@ -658,9 +698,12 @@ void Scene::freeCurrentScene() {
delete _animationData;
_animationData = nullptr;
}
- if (_activeAnimation) {
- delete _activeAnimation;
- _activeAnimation = nullptr;
+
+ for (int i = 0; i < 10; i++) {
+ if (_animation[i]) {
+ delete _animation[i];
+ _animation[i] = nullptr;
+ }
}
_vm->_palette->_paletteUsage.load(nullptr);
@@ -692,33 +735,40 @@ void Scene::resetScene() {
}
void Scene::freeAnimation() {
- if (_activeAnimation) {
- Player &player = _vm->_game->_player;
+ for (int j = 0; j < 10; j++)
+ freeAnimation(j);
- if (!_freeAnimationFlag) {
- _spriteSlots.fullRefresh(true);
- _sequences.scan();
- }
+ _freeAnimationFlag = false;
+}
+
+void Scene::freeAnimation(int idx) {
+ if (_animation[idx]) {
+ if (idx == 0) {
+ Player &player = _vm->_game->_player;
+
+ if (!_freeAnimationFlag) {
+ _spriteSlots.fullRefresh(true);
+ _sequences.scan();
+ }
- // Refresh the player
- if (player._visible) {
- player._forceRefresh = true;
- player.update();
+ // Refresh the player
+ if (player._visible) {
+ player._forceRefresh = true;
+ player.update();
+ }
}
// Remove any kernel messages in use by the animation
- for (uint i = 0; i < _activeAnimation->_messages.size(); ++i) {
- int msgIndex = _activeAnimation->_messages[i]._kernelMsgIndex;
+ for (uint i = 0; i < _animation[idx]->_messages.size(); ++i) {
+ int msgIndex = _animation[idx]->_messages[i]._kernelMsgIndex;
if (msgIndex >= 0)
_kernelMessages.remove(msgIndex);
}
// Delete the animation
- delete _activeAnimation;
- _activeAnimation = nullptr;
+ delete _animation[idx];
+ _animation[idx] = nullptr;
}
-
- _freeAnimationFlag = false;
}
void Scene::synchronize(Common::Serializer &s) {
@@ -729,7 +779,107 @@ void Scene::synchronize(Common::Serializer &s) {
s.syncAsByte(_roomChanged);
s.syncAsUint16LE(_nextSceneId);
s.syncAsUint16LE(_priorSceneId);
+ s.syncAsSint16LE(_variant);
_dynamicHotspots.synchronize(s);
}
+void Scene::setAnimFrame(int id, int val) {
+ if ((id >= 0) && _animation[id])
+ _animation[id]->setCurrentFrame(val);
+}
+
+int Scene::getAnimFrame(int id) {
+ if ((id >= 0) && _animation[id])
+ return _animation[id]->getCurrentFrame();
+
+ return -1;
+}
+
+void Scene::setDynamicAnim(int id, int anim_id, int segment) {
+ if (id >= 0 && id <= DYNAMIC_HOTSPOTS_SIZE && _animation[anim_id]) {
+ _animation[anim_id]->_dynamicHotspotIndex = id;
+ if (_dynamicHotspots[id]._animIndex < 0)
+ _dynamicHotspots[id]._active = false;
+ _dynamicHotspots[id]._animIndex = anim_id;
+
+ // TODO: Anim segments
+
+ // NOTE: Only remove the TODO below when _dynamicHotspotIndex
+ // in the Animation class is actually used in the engine!
+
+ warning("TODO: Scene::setDynamicAnim");
+ }
+}
+
+void Scene::setCamera(Common::Point pos) {
+ _posAdjust = pos;
+ warning("setCamera: Incomplete function");
+}
+
+void Scene::drawToBackground(int spriteId, int frameId, Common::Point pos, int depth, int scale) {
+ SpriteAsset &asset = *_sprites[spriteId];
+
+ if (pos.x == -32000)
+ pos.x = asset.getFramePos(frameId - 1).x;
+ if (pos.y == -32000)
+ pos.y = asset.getFramePos(frameId - 1).y;
+
+ int slotIndex = _spriteSlots.add();
+ SpriteSlot &slot = _spriteSlots[slotIndex];
+ slot._spritesIndex = spriteId;
+ slot._frameNumber = frameId;
+ slot._seqIndex = 1;
+ slot._position = pos;
+ slot._depth = depth;
+ slot._scale = scale;
+ slot._flags = IMG_DELTA;
+}
+
+void Scene::deleteSequence(int idx) {
+ if (_sequences[idx]._active && _sequences[idx]._dynamicHotspotIndex >= 0)
+ _dynamicHotspots.remove(_sequences[idx]._dynamicHotspotIndex);
+
+ _sequences[idx]._active = false;
+
+ if (!_sequences[idx]._doneFlag) {
+ warning("TODO: deleteSequence: Sequence %d not done", idx);
+ // TODO: This is wrong, and crashes Phantom at scene 102 when the door is opened
+ //doFrame(); // FIXME/CHECKME: Is this correct?
+ } else {
+ _sequences.remove(idx);
+ }
+}
+
+void Scene::loadSpeech(int idx) {
+ _vm->_audio->setDefaultSoundGroup();
+ // NOTE: The original actually preloads the speech sample here, but the samples
+ // are so small that it's not really worth it...
+
+ // TODO: As the speech samples aren't cached anymore, _speechReady should be remove
+ _speechReady = idx;
+}
+
+void Scene::playSpeech(int idx) {
+ _vm->_audio->stop();
+ _vm->_audio->playSound(idx - 1);
+}
+
+void Scene::sceneScale(int yFront, int maxScale, int yBack, int minScale) {
+ _sceneInfo->_yBandsEnd = yFront;
+ _sceneInfo->_maxScale = maxScale;
+ _sceneInfo->_yBandsStart = yBack;
+ _sceneInfo->_minScale = minScale;
+
+ _bandsRange = _sceneInfo->_yBandsEnd - _sceneInfo->_yBandsStart;
+ _scaleRange = _sceneInfo->_maxScale - _sceneInfo->_minScale;
+}
+
+void Scene::animations_tick() {
+ //warning("TODO: Implement _animations as an AnimationList and refactor (and check implementation)");
+ for (int i = 0; i < 10; i++) {
+ if (_animation[i])
+ _animation[i]->update();
+ }
+}
+
} // End of namespace MADS
diff --git a/engines/mads/scene.h b/engines/mads/scene.h
index c0784c3812..79e0fd4029 100644
--- a/engines/mads/scene.h
+++ b/engines/mads/scene.h
@@ -111,7 +111,7 @@ public:
Common::Array<PaletteCycle> _paletteCycles;
Common::StringArray _vocabStrings;
Animation *_animationData;
- Animation *_activeAnimation;
+ Animation *_animation[10];
bool _freeAnimationFlag;
int _depthStyle;
int _bandsRange;
@@ -128,7 +128,6 @@ public:
Common::Point _customDest;
Common::Array<PaletteUsage::UsageEntry> _paletteUsageF;
Common::Array<PaletteUsage::UsageEntry> _scenePaletteUsage;
-
/**
* Constructor
*/
@@ -214,7 +213,7 @@ public:
/**
* Load an animation
*/
- void loadAnimation(const Common::String &resName, int trigger = 0);
+ int loadAnimation(const Common::String &resName, int trigger = 0);
/**
* Returns a vocab entry
@@ -245,9 +244,28 @@ public:
void freeAnimation();
/**
+ * Frees any given active animation for the scene
+ */
+ void freeAnimation(int idx);
+
+ /**
* Synchronize the game
*/
void synchronize(Common::Serializer &s);
+
+ void setAnimFrame(int id, int val);
+ int getAnimFrame(int id);
+
+ void setDynamicAnim(int id, int anim_id, int segment);
+ void setCamera(Common::Point pos);
+ void drawToBackground(int spriteId, int frameId, Common::Point pos, int depth, int scale);
+ void deleteSequence(int idx);
+ void loadSpeech(int idx);
+ void playSpeech(int idx);
+ void sceneScale(int yFront, int maxScale, int yBack, int minScale);
+ void animations_tick();
+
+ int _speechReady;
};
} // End of namespace MADS
diff --git a/engines/mads/scene_data.cpp b/engines/mads/scene_data.cpp
index e48bcd8c6f..21fd4f9026 100644
--- a/engines/mads/scene_data.cpp
+++ b/engines/mads/scene_data.cpp
@@ -108,7 +108,7 @@ SceneInfo::SceneInfo(MADSEngine *vm) : _vm(vm) {
_minScale = 0;
_field4A = 0;
_usageIndex = 0;
- for (int i = 0; i < 15; ++i)
+ for (int i = 0; i < DEPTH_BANDS_SIZE; ++i)
_depthList[i] = 0;
}
@@ -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
@@ -145,6 +145,15 @@ void SceneInfo::load(int sceneId, int variant, const Common::String &resName,
// Read in basic data
Common::SeekableReadStream *infoStream = infoPack.getItemStream(0);
+
+ /*
+ byte *data = new byte[infoStream->size()];
+ infoStream->read(data, infoStream->size());
+ Common::hexdump(data, infoStream->size());
+ infoStream->seek(0);
+ delete[] data;
+ */
+
if (_vm->getGameID() == GType_RexNebular) {
_sceneId = infoStream->readUint16LE();
} else {
@@ -161,22 +170,28 @@ void SceneInfo::load(int sceneId, int variant, const Common::String &resName,
_height = infoStream->readUint16LE();
infoStream->skip(24);
-
- nodeCount = infoStream->readUint16LE();
- _yBandsEnd = infoStream->readUint16LE();
- _yBandsStart = infoStream->readUint16LE();
- _maxScale = infoStream->readUint16LE();
- _minScale = infoStream->readUint16LE();
- for (int i = 0; i < DEPTH_BANDS_SIZE; ++i)
- _depthList[i] = infoStream->readUint16LE();
- _field4A = infoStream->readUint16LE();
} else {
_artFileNum = sceneId;
_depthStyle = 0;
_width = 320;
_height = 156;
- infoStream->skip(140);
+ infoStream->skip(98);
+ }
+
+ nodeCount = infoStream->readUint16LE();
+ _yBandsEnd = infoStream->readUint16LE();
+ _yBandsStart = infoStream->readUint16LE();
+ _maxScale = infoStream->readUint16LE();
+ _minScale = infoStream->readUint16LE();
+ for (int i = 0; i < DEPTH_BANDS_SIZE; ++i)
+ _depthList[i] = infoStream->readUint16LE();
+ _field4A = infoStream->readUint16LE();
+
+ // HACK for V2 games
+ if (_vm->getGameID() != GType_RexNebular) {
+ _minScale = _maxScale = 100;
+ memset(_depthList, 0, DEPTH_BANDS_SIZE * sizeof(int));
}
// Load the scene's walk nodes
@@ -184,27 +199,29 @@ void SceneInfo::load(int sceneId, int variant, const Common::String &resName,
WalkNode node;
node.load(infoStream);
- if (i < nodeCount)
+ if (i < nodeCount) {
_nodes.push_back(node);
+ //debug("Node %d: %d,%d", i, node._walkPos.x, node._walkPos.y);
+ }
}
- int spriteSetsCount = infoStream->readUint16LE();
- int spriteInfoCount = infoStream->readUint16LE();
-
- // Load in sprite sets
Common::StringArray setNames;
- for (int i = 0; i < 10; ++i) {
- char name[64];
- infoStream->read(name, 64);
-
- if (i < spriteSetsCount)
- setNames.push_back(Common::String(name));
- }
-
- // Load in sprite draw information
Common::Array<SpriteInfo> spriteInfo;
- // TODO: The following isn't quite right for V2 games
+
if (_vm->getGameID() == GType_RexNebular) {
+ int spriteSetsCount = infoStream->readUint16LE();
+ int spriteInfoCount = infoStream->readUint16LE();
+
+ // Load in sprite sets
+ for (int i = 0; i < 10; ++i) {
+ char name[64];
+ infoStream->read(name, 64);
+
+ if (i < spriteSetsCount)
+ setNames.push_back(Common::String(name));
+ }
+
+ // Load in sprite draw information
for (int i = 0; i < 50; ++i) {
SpriteInfo info;
info.load(infoStream);
@@ -212,6 +229,12 @@ void SceneInfo::load(int sceneId, int variant, const Common::String &resName,
if (i < spriteInfoCount)
spriteInfo.push_back(info);
}
+ } else {
+ uint16 shadowColors = infoStream->readUint16LE();
+ uint16 shadowR = infoStream->readUint16LE();
+ uint16 shadowG = infoStream->readUint16LE();
+ uint16 shadowB = infoStream->readUint16LE();
+ debug("Shadow colors: %d (%d, %d, %d)", shadowColors, shadowR, shadowG, shadowB);
}
delete infoStream;
@@ -219,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);
@@ -265,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());
}
@@ -276,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);
@@ -328,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;
@@ -374,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);
@@ -422,6 +445,18 @@ void SceneInfo::loadMadsV2Background(int sceneId, const Common::String &resName,
assert(screenWidth == _width);
assert(screenHeight <= _height);
+ // Resize the background surface to hold all of the tiles
+ uint16 newWidth = bgSurface.w;
+ uint16 newHeight = bgSurface.h;
+
+ if (tileWidth < screenWidth && bgSurface.w != tileCount * tileWidth)
+ newWidth = tileCount * tileWidth;
+ if (tileHeight < screenHeight && bgSurface.h != tileCount * tileHeight)
+ newHeight = tileCount * tileHeight;
+
+ if (bgSurface.w != newWidth || bgSurface.h != newHeight)
+ bgSurface.create(newWidth, newHeight);
+
// --------------------------------------------------------------------------------
// Get tile data
@@ -442,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];
@@ -468,12 +503,15 @@ 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();
}
}
tileSet.clear();
tileDataFile.close();
+
+ delete[] tileMap;
}
/*------------------------------------------------------------------------*/
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 3c27001ae0..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;
-}
-
-void ScreenSurface::resetClipBounds() {
- setClipBounds(Common::Rect(0, 0, MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT));
+ // Reset clipping
+ markAllDirty();
+ setClipBounds(clipBounds);
}
-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;
@@ -687,7 +678,6 @@ void ScreenSurface::panTransition(MSurface &newScreen, byte *palData, int entryS
int y1, y2;
int startX = 0;
int deltaX;
- int xAt;
int loopStart;
// uint32 baseTicks, currentTicks;
byte paletteMap[256];
@@ -720,7 +710,7 @@ void ScreenSurface::panTransition(MSurface &newScreen, byte *palData, int entryS
loopStart = throughBlack == THROUGH_BLACK1 ? 0 : 1;
for (int loop = loopStart; loop < 2; ++loop) {
- xAt = startX;
+ int xAt = startX;
for (int xCtr = 0; xCtr < size.x; ++xCtr, xAt += deltaX) {
if (!loop) {
fillRect(Common::Rect(xAt + destPos.x, y1 + destPos.y,
@@ -732,12 +722,10 @@ void ScreenSurface::panTransition(MSurface &newScreen, byte *palData, int entryS
srcPos.x + xAt + 1, srcPos.y + size.y));
} else {
newScreen.copyRectToSurface(*this, xAt, destPos.y,
- Common::Rect(srcPos.x + xAt, srcPos.y,
+ Common::Rect(srcPos.x + xAt, srcPos.y,
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);
@@ -748,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];
@@ -776,10 +766,10 @@ 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),
+
+ copyRectTranslate(*this, oldMap, Common::Point(0, 0),
Common::Rect(0, 0, MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT));
palette.setFullPalette(oldPalette);
@@ -789,9 +779,9 @@ void ScreenSurface::swapForeground(byte newPalette[PALETTE_SIZE], byte *paletteM
/**
* Translates a given palette into a mapping table.
* Palettes consist of 128 RGB entries for the foreground and background
- * respectively, with the two interleaved together. So the start
+ * 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];
@@ -807,7 +797,7 @@ void ScreenSurface::swapPalette(const byte *palData, byte swapTable[PALETTE_COUN
// Handle the 128 palette entries for the foreground or background
for (int idx = 0; idx < (PALETTE_COUNT / 2); ++idx) {
if (start >= PALETTE_START && start <= PALETTE_END) {
- swapTable[start] = Palette::closestColor(dynamicList, staticList,
+ swapTable[start] = Palette::closestColor(dynamicList, staticList,
2 * RGB_SIZE, PALETTE_COUNT / 2) * 2 + staticStart;
}
@@ -816,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 e5bf1631c2..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
@@ -259,7 +259,7 @@ bool SequenceList::loadSprites(int seqIndex) {
}
if (seqEntry._flags & 2) {
- // Check for object having moved off-scren
+ // Check for object having moved off-screen
if ((pt.x + width) < 0 || (pt.x + width) >= MADS_SCREEN_WIDTH ||
pt.y < 0 || (pt.y - height) >= MADS_SCENE_HEIGHT) {
result = true;
@@ -550,4 +550,26 @@ void SequenceList::setMotion(int seqIndex, int flags, int deltaX, int deltaY) {
se._posAccum.x = se._posAccum.y = 0;
}
+int SequenceList::addStampCycle(int srcSpriteIdx, bool flipped, int sprite) {
+ int id;
+
+ id = addSpriteCycle(srcSpriteIdx, flipped, 32767, 0, 0, 0);
+ if (id >= 0) {
+ setAnimRange(id, sprite, sprite);
+ _entries[id]._animType = ANIMTYPE_STAMP;
+ }
+ return (id);
+}
+
+void SequenceList::setSeqPlayer(int idx, bool flag) {
+ Player &player = _vm->_game->_player;
+ int yp = player._playerPos.y + (player._centerOfGravity * player._currentScale) / 100;
+ setPosition(idx, Common::Point(player._playerPos.x, yp));
+ setDepth(idx, player._currentDepth);
+ setScale(idx, player._currentScale);
+
+ if (flag)
+ _vm->_game->syncTimers(SYNC_SEQ, idx, SYNC_PLAYER, 0);
+}
+
} // End of namespace
diff --git a/engines/mads/sequence.h b/engines/mads/sequence.h
index c3a277c5a5..05a7b616aa 100644
--- a/engines/mads/sequence.h
+++ b/engines/mads/sequence.h
@@ -38,7 +38,7 @@ enum SequenceTrigger {
SEQUENCE_TRIGGER_SPRITE = 2 // Trigger when sequence reaches specific sprite
};
-enum SpriteAnimType { ANIMTYPE_NONE = 0, ANIMTYPE_CYCLED = 1, ANIMTYPE_PING_PONG = 2 };
+enum SpriteAnimType { ANIMTYPE_NONE = 0, ANIMTYPE_CYCLED = 1, ANIMTYPE_PING_PONG = 2, ANIMTYPE_STAMP = 9 };
#define SEQUENCE_ENTRY_SUBSET_MAX 5
@@ -125,6 +125,9 @@ public:
void setMsgLayout(int seqIndex);
void setDone(int seqIndex);
void setMotion(int seqIndex, int flags, int deltaX, int deltaY);
+
+ int addStampCycle(int srcSpriteIdx, bool flipped, int sprite);
+ void setSeqPlayer(int idx, bool flag);
};
} // End of namespace MADS
diff --git a/engines/mads/sound.cpp b/engines/mads/sound.cpp
index 4a35edb80f..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) {
@@ -39,6 +41,8 @@ SoundManager::SoundManager(MADSEngine *vm, Audio::Mixer *mixer) {
_newSoundsPaused = false;
_masterVolume = 255;
+ _preferRoland = false;
+
_opl = OPL::Config::create();
_opl->init();
diff --git a/engines/mads/sound.h b/engines/mads/sound.h
index 9882f65e5a..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 {
@@ -48,6 +57,8 @@ public:
SoundManager(MADSEngine *vm, Audio::Mixer *mixer);
~SoundManager();
+ bool _preferRoland;
+
/**
* Initializes the sound driver for a given game section
*/
@@ -102,6 +113,7 @@ public:
* Some sort of random noise generation?
*/
void noise();
+
//@}
};
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 62fd036c03..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) {
@@ -733,7 +733,7 @@ void UserInterface::loadElements() {
_categoryIndexes[CAT_HOTSPOT - 1] = _vm->_game->_screenObjects.size() + 1;
for (int hotspotIdx = scene._hotspots.size() - 1; hotspotIdx >= 0; --hotspotIdx) {
Hotspot &hs = scene._hotspots[hotspotIdx];
- ScreenObject *so = _vm->_game->_screenObjects.add(hs._bounds, SCREENMODE_VGA,
+ ScreenObject *so = _vm->_game->_screenObjects.add(hs._bounds, SCREENMODE_VGA,
CAT_HOTSPOT, hotspotIdx);
so->_active = hs._active;
}
@@ -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 1366aa2c32..6c9485998a 100644
--- a/engines/mads/user_interface.h
+++ b/engines/mads/user_interface.h
@@ -190,10 +190,6 @@ private:
* Draw a UI textual element
*/
void writeVocab(ScrCategory category, int id);
-
- void refresh();
-
- void updateRect(const Common::Rect &bounds);
public:
MSurface _surface;
UISlots _uiSlots;
@@ -242,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);
/**
@@ -304,6 +300,8 @@ public:
* Synchronize the data
*/
void synchronize(Common::Serializer &s);
+
+ void refresh();
};
} // End of namespace MADS
diff --git a/engines/metaengine.h b/engines/metaengine.h
index 41f3ec4cba..e7bfebab71 100644
--- a/engines/metaengine.h
+++ b/engines/metaengine.h
@@ -96,6 +96,9 @@ public:
/**
* Return a list of all save states associated with the given target.
*
+ * The returned list is guaranteed to be sorted by slot numbers. That
+ * means smaller slot numbers are always stored before bigger slot numbers.
+ *
* The caller has to ensure that this (Meta)Engine is responsible
* for the specified target (by using findGame on it respectively
* on the associated gameid from the relevant ConfMan entry, if present).
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/console.cpp b/engines/mohawk/console.cpp
index 9b5bae78be..fd79e53b07 100644
--- a/engines/mohawk/console.cpp
+++ b/engines/mohawk/console.cpp
@@ -63,6 +63,8 @@ MystConsole::MystConsole(MohawkEngine_Myst *vm) : GUI::Debugger(), _vm(vm) {
registerCmd("disableInitOpcodes", WRAP_METHOD(MystConsole, Cmd_DisableInitOpcodes));
registerCmd("cache", WRAP_METHOD(MystConsole, Cmd_Cache));
registerCmd("resources", WRAP_METHOD(MystConsole, Cmd_Resources));
+ registerCmd("quickTest", WRAP_METHOD(MystConsole, Cmd_QuickTest));
+ registerVar("show_resource_rects", &_vm->_showResourceRects);
}
MystConsole::~MystConsole() {
@@ -119,7 +121,7 @@ static const uint16 default_start_card[12] = {
10000,
2000,
5038,
- 2, // TODO: Should be 1?
+ 1,
1,
6122,
4134,
@@ -329,6 +331,44 @@ bool MystConsole::Cmd_Resources(int argc, const char **argv) {
return true;
}
+bool MystConsole::Cmd_QuickTest(int argc, const char **argv) {
+ // Go through all the ages, all the views and click random stuff
+ for (uint i = 0; i < ARRAYSIZE(mystStackNames); i++) {
+ if (i == 2 || i == 5 || i == 9 || i == 10) continue;
+ debug("Loading stack %s", mystStackNames[i]);
+ _vm->changeToStack(i, default_start_card[i], 0, 0);
+
+ Common::Array<uint16> ids = _vm->getResourceIDList(ID_VIEW);
+ for (uint j = 0; j < ids.size(); j++) {
+ if (ids[j] == 4632) continue;
+
+ debug("Loading card %d", ids[j]);
+ _vm->changeToCard(ids[j], kTransitionCopy);
+
+ _vm->_video->updateMovies();
+ _vm->_scriptParser->runPersistentScripts();
+ _vm->_system->updateScreen();
+
+ int16 resIndex = _vm->_rnd->getRandomNumber(_vm->_resources.size()) - 1;
+ if (resIndex >= 0 && _vm->_resources[resIndex]->isEnabled()) {
+ _vm->_resources[resIndex]->handleMouseDown();
+ _vm->_resources[resIndex]->handleMouseUp();
+ }
+
+ _vm->_video->updateMovies();
+ _vm->_scriptParser->runPersistentScripts();
+ _vm->_system->updateScreen();
+
+ if (_vm->getCurStack() != i) {
+ // Clicking may have linked us to another age
+ _vm->changeToStack(i, default_start_card[i], 0, 0);
+ }
+ }
+ }
+
+ return true;
+}
+
#endif // ENABLE_MYST
#ifdef ENABLE_RIVEN
diff --git a/engines/mohawk/console.h b/engines/mohawk/console.h
index af01c0d1e0..dc40049a89 100644
--- a/engines/mohawk/console.h
+++ b/engines/mohawk/console.h
@@ -55,6 +55,7 @@ private:
bool Cmd_DisableInitOpcodes(int argc, const char **argv);
bool Cmd_Cache(int argc, const char **argv);
bool Cmd_Resources(int argc, const char **argv);
+ bool Cmd_QuickTest(int argc, const char **argv);
};
#endif
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 926c296257..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"
@@ -35,10 +36,12 @@
#ifdef ENABLE_MYST
#include "mohawk/myst.h"
+#include "mohawk/myst_state.h"
#endif
#ifdef ENABLE_RIVEN
#include "mohawk/riven.h"
+#include "mohawk/riven_saveload.h"
#endif
namespace Mohawk {
@@ -52,7 +55,7 @@ struct MohawkGameDescription {
};
const char* MohawkEngine::getGameId() const {
- return _gameDescription->desc.gameid;
+ return _gameDescription->desc.gameId;
}
uint32 MohawkEngine::getFeatures() const {
@@ -159,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;
}
@@ -182,45 +199,107 @@ 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;
};
bool MohawkMetaEngine::hasFeature(MetaEngineFeature f) const {
return
(f == kSupportsListSaves)
|| (f == kSupportsLoadingDuringStartup)
- || (f == kSupportsDeleteSave);
+ || (f == kSupportsDeleteSave)
+ || (f == kSavesSupportMetaInfo)
+ || (f == kSavesSupportThumbnail)
+ || (f == kSavesSupportCreationDate)
+ || (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 = g_system->getSavefileManager()->listSavefiles("*.mys");
-
- for (uint32 i = 0; i < filenames.size(); i++)
- saveList.push_back(SaveStateDescriptor(i, filenames[i]));
- } else if (strstr(target, "riven")) {
- filenames = g_system->getSavefileManager()->listSavefiles("*.rvn");
+ saveList = listSavesForPrefix("myst", "mys");
- 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::MystGameState::querySaveDescription(slot);
+ save->setDescription(description);
+ }
}
+#endif
+#ifdef ENABLE_RIVEN
+ if (strstr(target, "riven")) {
+ saveList = listSavesForPrefix("riven", "rvn");
+
+ 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 = g_system->getSavefileManager()->listSavefiles("*.mys");
- g_system->getSavefileManager()->removeSavefile(filenames[slot].c_str());
- } else if (strstr(target, "riven")) {
- Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles("*.rvn");
- g_system->getSavefileManager()->removeSavefile(filenames[slot].c_str());
+ Mohawk::MystGameState::deleteSave(slot);
+ }
+#endif
+#ifdef ENABLE_RIVEN
+ if (strstr(target, "riven")) {
+ Mohawk::RivenSaveLoad::deleteSave(slot);
+ }
+#endif
+}
+
+SaveStateDescriptor MohawkMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
+#ifdef ENABLE_MYST
+ if (strstr(target, "myst")) {
+ return Mohawk::MystGameState::querySaveMetaInfos(slot);
+ }
+#endif
+#ifdef ENABLE_RIVEN
+ if (strstr(target, "riven")) {
+ return Mohawk::RivenSaveLoad::querySaveMetaInfos(slot);
+ } else
+#endif
+ {
+ return SaveStateDescriptor();
}
}
diff --git a/engines/mohawk/detection_tables.h b/engines/mohawk/detection_tables.h
index 6bb836b5b8..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,26 @@ 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,
+ 0,
+ },
+
+ // Myst
+ // Italian Windows ?
+ // From goodoldgeorg in bug #6895
+ {
+ {
+ "myst",
+ "",
+ AD_ENTRY1("MYST.DAT", "a5795ce1751fc42525e4f9a1859181d5"),
+ Common::IT_ITA,
+ Common::kPlatformWindows,
+ ADGF_TESTING,
+ GUI_OPTIONS_MYST
},
GType_MYST,
0,
@@ -123,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,
@@ -141,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,
@@ -159,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,
@@ -177,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,
@@ -195,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,
@@ -213,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,
@@ -231,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,
@@ -249,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,
@@ -312,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
{
@@ -330,6 +373,40 @@ static const MohawkGameDescription gameDescriptions[] = {
},
// Riven: The Sequel to Myst
+ // Version 1.0.0 (5CD) - Russian, Fargus
+ {
+ {
+ "riven",
+ "",
+ AD_ENTRY1s("a_Data.MHK", "2a840ed74fe5dc3a388bced674d379d5", 12024358),
+ Common::RU_RUS,
+ Common::kPlatformWindows,
+ ADGF_UNSTABLE,
+ GUIO1(GUIO_NOASPECT)
+ },
+ GType_RIVEN,
+ 0,
+ 0,
+ },
+
+ // Riven: The Sequel to Myst
+ // Version 1.1 (5CD) - Russian, Fargus
+ {
+ {
+ "riven",
+ "",
+ AD_ENTRY1("a_Data.MHK", "59bd2e3ccbae2f1faa1b23a18dc316eb"),
+ Common::RU_RUS,
+ Common::kPlatformWindows,
+ ADGF_UNSTABLE,
+ GUIO1(GUIO_NOASPECT)
+ },
+ GType_RIVEN,
+ 0,
+ 0,
+ },
+
+ // Riven: The Sequel to Myst
// Version 1.? (DVD, From "Myst 10th Anniversary Edition")
// From Clone2727
{
@@ -366,14 +443,14 @@ static const MohawkGameDescription gameDescriptions[] = {
},
// Riven: The Sequel to Myst
- // Version ? (DVD, From "Myst: La Trilogie")
- // From gamin
+ // Version 1.02 (DVD, From "Myst: Antologia")
+ // From pykman
{
{
"riven",
"",
- AD_ENTRY1("a_Data.MHK", "aff2a384aaa9a0e0ec51010f708c5c04"),
- Common::FR_FRA,
+ AD_ENTRY1("a_Data.MHK", "733a710cf5f848b441ec72d988ab8a3d"),
+ Common::PL_POL,
Common::kPlatformWindows,
ADGF_UNSTABLE,
GUIO1(GUIO_NOASPECT)
@@ -384,14 +461,13 @@ static const MohawkGameDescription gameDescriptions[] = {
},
// Riven: The Sequel to Myst
- // Version 1.02 (DVD, From "Myst: Antologia")
- // From pykman
+ // Version 1.1 (DVD), Russan, Fargus
{
{
"riven",
- "",
- AD_ENTRY1("a_Data.MHK", "733a710cf5f848b441ec72d988ab8a3d"),
- Common::PL_POL,
+ "DVD",
+ AD_ENTRY1("a_Data.MHK", "b5f40e6e6b843bf3abea291faa0911f4"),
+ Common::RU_RUS,
Common::kPlatformWindows,
ADGF_UNSTABLE,
GUIO1(GUIO_NOASPECT)
@@ -1819,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
{
{
@@ -2041,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
{
{
@@ -2645,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,
@@ -2660,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,
@@ -2675,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 ffc455286f..8c11e3a5e9 100644
--- a/engines/mohawk/dialogs.cpp
+++ b/engines/mohawk/dialogs.cpp
@@ -24,7 +24,7 @@
#include "mohawk/dialogs.h"
#include "gui/gui-manager.h"
-#include "gui/ThemeEngine.h"
+#include "gui/saveload.h"
#include "gui/widget.h"
#include "common/system.h"
#include "common/translation.h"
@@ -82,39 +82,122 @@ enum {
kWaterCmd = 'WATR',
kDropCmd = 'DROP',
kMapCmd = 'SMAP',
- kMenuCmd = 'MENU'
+ kMenuCmd = 'MENU',
+ kSaveCmd = 'SAVE',
+ kLoadCmd = 'LOAD',
+ kQuitCmd = 'QUIT'
};
+#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);
+
+ 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);
+
+ _loadDialog = new GUI::SaveLoadChooser(_("Load game:"), _("Load"), false);
+ _saveDialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
+}
+
+MohawkOptionsDialog::~MohawkOptionsDialog() {
+ delete _loadDialog;
+ delete _saveDialog;
+}
+
+void MohawkOptionsDialog::open() {
+ GUI::Dialog::open();
+
+ _loadButton->setEnabled(_vm->canLoadGameStateCurrently());
+ _saveButton->setEnabled(_vm->canSaveGameStateCurrently());
+}
+
+
+void MohawkOptionsDialog::save() {
+ int slot = _saveDialog->runModalWithCurrentTarget();
+
+ if (slot >= 0) {
+ Common::String result(_saveDialog->getResultString());
+ if (result.empty()) {
+ // If the user was lazy and entered no save name, come up with a default name.
+ result = _saveDialog->createDefaultSaveDescription(slot);
+ }
+
+ _vm->saveGameState(slot, result);
+ close();
+ }
+}
+
+void MohawkOptionsDialog::load() {
+ int slot = _loadDialog->runModalWithCurrentTarget();
+
+ if (slot >= 0) {
+ _vm->loadGameState(slot);
+ close();
+ }
+}
+
+void MohawkOptionsDialog::reflowLayout() {
+ const int screenW = g_system->getOverlayWidth();
+ const int screenH = g_system->getOverlayHeight();
+
+ // Center the dialog
+ _x = (screenW - getWidth()) / 2;
+ _y = (screenH - getHeight()) / 2;
+
+ 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) : GUI::OptionsDialog("", 120, 120, 360, 200), _vm(vm) {
+MystOptionsDialog::MystOptionsDialog(MohawkEngine_Myst* vm) : MohawkOptionsDialog(vm), _vm(vm) {
// I18N: Option for fast scene switching
- _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 300, 15, _("~Z~ip Mode Activated"), 0, kZipCmd);
- _transitionsCheckbox = new GUI::CheckboxWidget(this, 15, 30, 300, 15, _("~T~ransitions Enabled"), 0, kTransCmd);
+ _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, _("~S~how Map"), 0, kMapCmd);
+ _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, _("~M~ain Menu"), 0, kMenuCmd);
+ _returnToMenuButton = new GUI::ButtonWidget(this, 15, 95, 100, 25, _("Main Men~u~"), 0, kMenuCmd);
else
_returnToMenuButton = 0;
-
- 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);
}
MystOptionsDialog::~MystOptionsDialog() {
}
void MystOptionsDialog::open() {
- Dialog::open();
+ MohawkOptionsDialog::open();
_dropPageButton->setEnabled(_vm->_gameState->_globals.heldPage != 0);
@@ -144,18 +227,30 @@ void MystOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, ui
case kMapCmd:
_vm->_needsShowMap = true;
close();
- break;
+ break;
case kMenuCmd:
_vm->_needsShowDemoMenu = true;
close();
- break;
+ break;
+ case kQuitCmd: {
+ if (_vm->getGameType() != GType_MAKINGOF) {
+ _vm->_needsShowCredits = true;
+ } else {
+ Common::Event eventQ;
+ eventQ.type = Common::EVENT_QUIT;
+ g_system->getEventManager()->pushEvent(eventQ);
+ }
+ close();
+ }
+ break;
case GUI::kOKCmd:
_vm->_gameState->_globals.zipMode = _zipModeCheckbox->getState();
_vm->_gameState->_globals.transitions = _transitionsCheckbox->getState();
- GUI::OptionsDialog::handleCommand(sender, cmd, data);
+ setResult(1);
+ close();
break;
default:
- GUI::OptionsDialog::handleCommand(sender, cmd, data);
+ MohawkOptionsDialog::handleCommand(sender, cmd, data);
}
}
@@ -163,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);
@@ -183,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 7470cd3acd..3cfb628f9d 100644
--- a/engines/mohawk/dialogs.h
+++ b/engines/mohawk/dialogs.h
@@ -28,9 +28,14 @@
#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 {
@@ -66,21 +71,50 @@ 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::OptionsDialog {
+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 handleCommand(GUI::CommandSender*, uint32, uint32);
private:
MohawkEngine_Myst *_vm;
+
GUI::CheckboxWidget *_zipModeCheckbox;
GUI::CheckboxWidget *_transitionsCheckbox;
+
GUI::ButtonWidget *_dropPageButton;
GUI::ButtonWidget *_showMapButton;
GUI::ButtonWidget *_returnToMenuButton;
@@ -92,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 b6a6c27329..633b67f7e9 100644
--- a/engines/mohawk/myst.cpp
+++ b/engines/mohawk/myst.cpp
@@ -66,38 +66,22 @@ 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;
_curCard = 0;
_needsUpdate = false;
+ _canSafelySaveLoad = false;
_curResource = -1;
- _hoverResource = 0;
- _dragResource = 0;
-
- _gfx = NULL;
- _console = NULL;
- _scriptParser = NULL;
- _gameState = NULL;
- _loadDialog = NULL;
- _optionsDialog = NULL;
-
- _cursorHintCount = 0;
- _cursorHints = NULL;
-
- _prevStack = NULL;
-
- _view.conditionalImageCount = 0;
- _view.conditionalImages = NULL;
- _view.soundList = NULL;
- _view.soundListVolume = NULL;
- _view.scriptResCount = 0;
- _view.scriptResources = NULL;
+ _hoverResource = nullptr;
+
+ _gfx = nullptr;
+ _console = nullptr;
+ _scriptParser = nullptr;
+ _gameState = nullptr;
+ _optionsDialog = nullptr;
+
+ _prevStack = nullptr;
}
MohawkEngine_Myst::~MohawkEngine_Myst() {
@@ -107,20 +91,12 @@ MohawkEngine_Myst::~MohawkEngine_Myst() {
delete _console;
delete _scriptParser;
delete _gameState;
- delete _loadDialog;
delete _optionsDialog;
delete _prevStack;
delete _rnd;
- delete[] _cursorHints;
-
- delete[] _view.conditionalImages;
- delete[] _view.scriptResources;
-
for (uint32 i = 0; i < _resources.size(); i++)
delete _resources[i];
-
- _resources.clear();
}
// Uses cached data objects in preference to disk access
@@ -138,7 +114,11 @@ Common::SeekableReadStream *MohawkEngine_Myst::getResource(uint32 tag, uint16 id
}
error("Could not find a \'%s\' resource with ID %04x", tag2str(tag), id);
- return NULL;
+ return nullptr;
+}
+
+Common::Array<uint16> MohawkEngine_Myst::getResourceIDList(uint32 type) const {
+ return _mhk[0]->getResourceIDList(type);
}
void MohawkEngine_Myst::cachePreload(uint32 tag, uint16 id) {
@@ -242,7 +222,6 @@ Common::Error MohawkEngine_Myst::run() {
_gfx = new MystGraphics(this);
_console = new MystConsole(this);
_gameState = new MystGameState(this, _saveFileMan);
- _loadDialog = new GUI::SaveLoadChooser(_("Load game:"), _("Load"), false);
_optionsDialog = new MystOptionsDialog(this);
_cursor = new MystCursorManager(this);
_rnd = new Common::RandomSource("myst");
@@ -251,12 +230,10 @@ Common::Error MohawkEngine_Myst::run() {
_cursor->showCursor();
// Load game from launcher/command line if requested
- if (ConfMan.hasKey("save_slot") && canLoadGameStateCurrently()) {
- uint32 gameToLoad = ConfMan.getInt("save_slot");
- Common::StringArray savedGamesList = _gameState->generateSaveGameList();
- if (gameToLoad > savedGamesList.size())
- error ("Could not find saved game");
- _gameState->load(savedGamesList[gameToLoad]);
+ if (ConfMan.hasKey("save_slot") && hasGameSaveSupport()) {
+ 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)
@@ -284,7 +261,7 @@ Common::Error MohawkEngine_Myst::run() {
_needsUpdate = _video->updateMovies();
_scriptParser->runPersistentScripts();
- while (_eventMan->pollEvent(event)) {
+ while (pollEvent(event)) {
switch (event.type) {
case Common::EVENT_MOUSEMOVE: {
_needsUpdate = true;
@@ -324,17 +301,15 @@ Common::Error MohawkEngine_Myst::run() {
case Common::KEYCODE_SPACE:
pauseGame();
break;
- case Common::KEYCODE_F4:
- _showResourceRects = !_showResourceRects;
- if (_showResourceRects)
- drawResourceRects();
- break;
case Common::KEYCODE_F5:
_needsPageDrop = false;
_needsShowMap = false;
_needsShowDemoMenu = false;
+ _needsShowCredits = false;
+ _canSafelySaveLoad = true;
runDialog(*_optionsDialog);
+ _canSafelySaveLoad = false;
if (_needsPageDrop) {
dropPage();
@@ -350,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;
@@ -372,6 +353,15 @@ Common::Error MohawkEngine_Myst::run() {
return Common::kNoError;
}
+bool MohawkEngine_Myst::pollEvent(Common::Event &event) {
+ // Saving / Loading is allowed from the GMM only when the main event loop is running
+ _canSafelySaveLoad = true;
+ bool eventReturned = _eventMan->pollEvent(event);
+ _canSafelySaveLoad = false;
+
+ return eventReturned;
+}
+
bool MohawkEngine_Myst::skippableWait(uint32 duration) {
uint32 end = _system->getMillis() + duration;
bool skipped = false;
@@ -413,6 +403,7 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS
// Fill screen with black and empty cursor
_cursor->setCursor(0);
+ _currentCursor = 0;
if (getFeatures() & GF_ME)
_system->fillScreen(_system->getScreenFormat().RGBToColor(0, 0, 0));
@@ -502,7 +493,7 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS
if (getFeatures() & GF_ME) {
// Play Flyby Entry Movie on Masterpiece Edition.
- const char *flyby = 0;
+ const char *flyby = nullptr;
switch (_curStack) {
case kSeleniticStack:
@@ -512,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:
@@ -539,12 +531,12 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS
uint16 MohawkEngine_Myst::getCardBackgroundId() {
uint16 imageToDraw = 0;
- if (_view.conditionalImageCount == 0)
+ if (_view.conditionalImages.size() == 0)
imageToDraw = _view.mainImage;
else {
- for (uint16 i = 0; i < _view.conditionalImageCount; i++) {
+ for (uint16 i = 0; i < _view.conditionalImages.size(); i++) {
uint16 varValue = _scriptParser->getVar(_view.conditionalImages[i].var);
- if (varValue < _view.conditionalImages[i].numStates)
+ if (varValue < _view.conditionalImages[i].values.size())
imageToDraw = _view.conditionalImages[i].values[varValue];
}
}
@@ -586,36 +578,7 @@ void MohawkEngine_Myst::changeToCard(uint16 card, TransitionType transition) {
drawCardBackground();
// Handle sound
- int16 soundAction = 0;
- uint16 soundActionVolume = 0;
-
- if (_view.sound == kMystSoundActionConditional) {
- uint16 soundVarValue = _scriptParser->getVar(_view.soundVar);
- if (soundVarValue >= _view.soundCount)
- warning("Conditional sound variable outside range");
- else {
- soundAction = _view.soundList[soundVarValue];
- soundActionVolume = _view.soundListVolume[soundVarValue];
- }
- } else {
- soundAction = _view.sound;
- soundActionVolume = _view.soundVolume;
- }
-
- if (soundAction == kMystSoundActionContinue)
- debug(2, "Continuing with current sound");
- else if (soundAction == kMystSoundActionChangeVolume) {
- debug(2, "Continuing with current sound, changing volume");
- _sound->changeBackgroundVolumeMyst(soundActionVolume);
- } else if (soundAction == kMystSoundActionStop) {
- debug(2, "Stopping sound");
- _sound->stopBackgroundMyst();
- } else if (soundAction > 0) {
- debug(2, "Playing new sound %d", soundAction);
- _sound->replaceBackgroundMyst(soundAction, soundActionVolume);
- } else {
- error("Unknown sound action %d", soundAction);
- }
+ applySoundBlock(_view.soundBlock);
if (_view.flags & kMystZipDestination)
_gameState->addZipDest(_curStack, card);
@@ -637,15 +600,17 @@ void MohawkEngine_Myst::changeToCard(uint16 card, TransitionType transition) {
// Make sure the screen is updated
if (transition != kNoTransition) {
- if (!_gameState->_globals.transitions)
- transition = kTransitionCopy;
-
- _gfx->runTransition(transition, Common::Rect(544, 333), 10, 0);
+ if (_gameState->_globals.transitions) {
+ _gfx->runTransition(transition, Common::Rect(544, 333), 10, 0);
+ } else {
+ _gfx->copyBackBufferToScreen(Common::Rect(544, 333));
+ _system->updateScreen();
+ _needsUpdate = false;
+ }
}
// Make sure we have the right cursor showing
- _dragResource = 0;
- _hoverResource = 0;
+ _hoverResource = nullptr;
_curResource = -1;
checkCurrentResource();
@@ -671,13 +636,13 @@ void MohawkEngine_Myst::checkCurrentResource() {
// Tell previous resource the mouse is no longer hovering it
if (_hoverResource && !_hoverResource->contains(mouse)) {
_hoverResource->handleMouseLeave();
- _hoverResource = 0;
+ _hoverResource = nullptr;
}
for (uint16 i = 0; i < _resources.size(); i++)
if (_resources[i]->contains(mouse)) {
- if (_hoverResource != _resources[i] && _resources[i]->type == kMystHoverArea) {
- _hoverResource = static_cast<MystResourceType13 *>(_resources[i]);
+ if (_hoverResource != _resources[i] && _resources[i]->type == kMystAreaHover) {
+ _hoverResource = static_cast<MystAreaHover *>(_resources[i]);
_hoverResource->handleMouseEnter();
}
@@ -694,17 +659,17 @@ void MohawkEngine_Myst::checkCurrentResource() {
checkCursorHints();
}
-MystResource *MohawkEngine_Myst::updateCurrentResource() {
+MystArea *MohawkEngine_Myst::updateCurrentResource() {
checkCurrentResource();
if (_curResource >= 0)
return _resources[_curResource];
else
- return 0;
+ return nullptr;
}
void MohawkEngine_Myst::loadCard() {
- debugC(kDebugView, "Loading Card View:");
+ debugC(kDebugView, "Loading Card View: %d", _curCard);
Common::SeekableReadStream *viewStream = getResource(ID_VIEW, _curCard);
@@ -713,21 +678,23 @@ void MohawkEngine_Myst::loadCard() {
debugC(kDebugView, "Flags: 0x%04X", _view.flags);
// The Image Block (Reminiscent of Riven PLST resources)
- _view.conditionalImageCount = viewStream->readUint16LE();
- debugC(kDebugView, "Conditional Image Count: %d", _view.conditionalImageCount);
- if (_view.conditionalImageCount != 0) {
- _view.conditionalImages = new MystCondition[_view.conditionalImageCount];
- for (uint16 i = 0; i < _view.conditionalImageCount; i++) {
+ uint16 conditionalImageCount = viewStream->readUint16LE();
+ debugC(kDebugView, "Conditional Image Count: %d", conditionalImageCount);
+ if (conditionalImageCount != 0) {
+ for (uint16 i = 0; i < conditionalImageCount; i++) {
+ MystCondition conditionalImage;
+
debugC(kDebugView, "\tImage %d:", i);
- _view.conditionalImages[i].var = viewStream->readUint16LE();
- debugC(kDebugView, "\t\tVar: %d", _view.conditionalImages[i].var);
- _view.conditionalImages[i].numStates = viewStream->readUint16LE();
- debugC(kDebugView, "\t\tNumber of States: %d", _view.conditionalImages[i].numStates);
- _view.conditionalImages[i].values = new uint16[_view.conditionalImages[i].numStates];
- for (uint16 j = 0; j < _view.conditionalImages[i].numStates; j++) {
- _view.conditionalImages[i].values[j] = viewStream->readUint16LE();
- debugC(kDebugView, "\t\tState %d -> Value %d", j, _view.conditionalImages[i].values[j]);
+ conditionalImage.var = viewStream->readUint16LE();
+ debugC(kDebugView, "\t\tVar: %d", conditionalImage.var);
+ uint16 numStates = viewStream->readUint16LE();
+ debugC(kDebugView, "\t\tNumber of States: %d", numStates);
+ for (uint16 j = 0; j < numStates; j++) {
+ conditionalImage.values.push_back(viewStream->readUint16LE());
+ debugC(kDebugView, "\t\tState %d -> Value %d", j, conditionalImage.values[j]);
}
+
+ _view.conditionalImages.push_back(conditionalImage);
}
_view.mainImage = 0;
} else {
@@ -736,87 +703,58 @@ void MohawkEngine_Myst::loadCard() {
}
// The Sound Block (Reminiscent of Riven SLST resources)
- _view.sound = viewStream->readSint16LE();
- debugCN(kDebugView, "Sound Control: %d = ", _view.sound);
- if (_view.sound > 0) {
- debugC(kDebugView, "Play new Sound, change volume");
- debugC(kDebugView, "\tSound: %d", _view.sound);
- _view.soundVolume = viewStream->readUint16LE();
- debugC(kDebugView, "\tVolume: %d", _view.soundVolume);
- } else if (_view.sound == kMystSoundActionContinue)
- debugC(kDebugView, "Continue current sound");
- else if (_view.sound == kMystSoundActionChangeVolume) {
- debugC(kDebugView, "Continue current sound, change volume");
- _view.soundVolume = viewStream->readUint16LE();
- debugC(kDebugView, "\tVolume: %d", _view.soundVolume);
- } else if (_view.sound == kMystSoundActionStop) {
- debugC(kDebugView, "Stop sound");
- } else if (_view.sound == kMystSoundActionConditional) {
- debugC(kDebugView, "Conditional sound list");
- _view.soundVar = viewStream->readUint16LE();
- debugC(kDebugView, "\tVar: %d", _view.soundVar);
- _view.soundCount = viewStream->readUint16LE();
- debugC(kDebugView, "\tCount: %d", _view.soundCount);
- _view.soundList = new int16[_view.soundCount];
- _view.soundListVolume = new uint16[_view.soundCount];
-
- for (uint16 i = 0; i < _view.soundCount; i++) {
- _view.soundList[i] = viewStream->readSint16LE();
- debugC(kDebugView, "\t\tCondition %d: Action %d", i, _view.soundList[i]);
- if (_view.soundList[i] == kMystSoundActionChangeVolume || _view.soundList[i] >= 0) {
- _view.soundListVolume[i] = viewStream->readUint16LE();
- debugC(kDebugView, "\t\tCondition %d: Volume %d", i, _view.soundListVolume[i]);
- }
- }
- } else {
- debugC(kDebugView, "Unknown");
- warning("Unknown sound control value in card");
- }
+ _view.soundBlock = readSoundBlock(viewStream);
// Resources that scripts can call upon
- _view.scriptResCount = viewStream->readUint16LE();
- debugC(kDebugView, "Script Resource Count: %d", _view.scriptResCount);
- if (_view.scriptResCount != 0) {
- _view.scriptResources = new MystView::ScriptResource[_view.scriptResCount];
- for (uint16 i = 0; i < _view.scriptResCount; i++) {
- debugC(kDebugView, "\tResource %d:", i);
- _view.scriptResources[i].type = viewStream->readUint16LE();
- debugC(kDebugView, "\t\t Type: %d", _view.scriptResources[i].type);
-
- switch (_view.scriptResources[i].type) {
- case 1:
- debugC(kDebugView, "\t\t\t\t= Image");
- break;
- case 2:
- debugC(kDebugView, "\t\t\t\t= Sound");
- break;
- case 3:
- debugC(kDebugView, "\t\t\t\t= Resource List");
- break;
- default:
- debugC(kDebugView, "\t\t\t\t= Unknown");
- break;
- }
+ uint16 scriptResCount = viewStream->readUint16LE();
+ debugC(kDebugView, "Script Resource Count: %d", scriptResCount);
+ for (uint16 i = 0; i < scriptResCount; i++) {
+ MystView::ScriptResource scriptResource;
+
+ debugC(kDebugView, "\tResource %d:", i);
+ scriptResource.type = (MystView::ScriptResourceType) viewStream->readUint16LE();
+ debugC(kDebugView, "\t\t Type: %d", scriptResource.type);
+
+ switch (scriptResource.type) {
+ case MystView::kResourceImage:
+ debugC(kDebugView, "\t\t\t\t= Image");
+ break;
+ case MystView::kResourceSound:
+ debugC(kDebugView, "\t\t\t\t= Sound");
+ break;
+ case MystView::kResourceSwitch:
+ debugC(kDebugView, "\t\t\t\t= Resource Switch");
+ break;
+ case MystView::kResourceImageNoCache:
+ debugC(kDebugView, "\t\t\t\t= Image - Caching disabled");
+ break;
+ case MystView::kResourceSoundNoCache:
+ debugC(kDebugView, "\t\t\t\t= Sound - Caching disabled");
+ break;
+ default:
+ debugC(kDebugView, "\t\t\t\t= Unknown");
+ warning("Unknown script resource type '%d' in card '%d'", scriptResource.type, _curCard);
+ break;
+ }
- if (_view.scriptResources[i].type == 3) {
- _view.scriptResources[i].var = viewStream->readUint16LE();
- debugC(kDebugView, "\t\t Var: %d", _view.scriptResources[i].var);
- _view.scriptResources[i].count = viewStream->readUint16LE();
- debugC(kDebugView, "\t\t Resource List Count: %d", _view.scriptResources[i].count);
- _view.scriptResources[i].u0 = viewStream->readUint16LE();
- debugC(kDebugView, "\t\t u0: %d", _view.scriptResources[i].u0);
- _view.scriptResources[i].resource_list = new int16[_view.scriptResources[i].count];
-
- for (uint16 j = 0; j < _view.scriptResources[i].count; j++) {
- _view.scriptResources[i].resource_list[j] = viewStream->readSint16LE();
- debugC(kDebugView, "\t\t Resource List %d: %d", j, _view.scriptResources[i].resource_list[j]);
- }
- } else {
- _view.scriptResources[i].resource_list = NULL;
- _view.scriptResources[i].id = viewStream->readUint16LE();
- debugC(kDebugView, "\t\t Id: %d", _view.scriptResources[i].id);
+ if (scriptResource.type == MystView::kResourceSwitch) {
+ scriptResource.switchVar = viewStream->readUint16LE();
+ debugC(kDebugView, "\t\t Var: %d", scriptResource.switchVar);
+ uint16 count = viewStream->readUint16LE();
+ debugC(kDebugView, "\t\t Resource List Count: %d", count);
+ scriptResource.switchResourceType = (MystView::ScriptResourceType) viewStream->readUint16LE();
+ debugC(kDebugView, "\t\t u0: %d", scriptResource.switchResourceType);
+
+ for (uint16 j = 0; j < count; j++) {
+ scriptResource.switchResourceIds.push_back(viewStream->readSint16LE());
+ debugC(kDebugView, "\t\t Resource List %d: %d", j, scriptResource.switchResourceIds[j]);
}
+ } else {
+ scriptResource.id = viewStream->readUint16LE();
+ debugC(kDebugView, "\t\t Id: %d", scriptResource.id);
}
+
+ _view.scriptResources.push_back(scriptResource);
}
// Identifiers for other resources. 0 if non existent. There is always an RLST.
@@ -831,7 +769,6 @@ void MohawkEngine_Myst::loadCard() {
delete viewStream;
// Precache Card Resources
- // TODO: Deal with Mac ME External Picture File
uint32 cacheImageType;
if (getFeatures() & GF_ME)
cacheImageType = ID_PICT;
@@ -839,63 +776,58 @@ void MohawkEngine_Myst::loadCard() {
cacheImageType = ID_WDIB;
// Precache Image Block data
- if (_view.conditionalImageCount != 0) {
- for (uint16 i = 0; i < _view.conditionalImageCount; i++)
- for (uint16 j = 0; j < _view.conditionalImages[i].numStates; j++)
- cachePreload(cacheImageType, _view.conditionalImages[i].values[j]);
- } else
+ if (_view.conditionalImages.size() != 0) {
+ for (uint16 i = 0; i < _view.conditionalImages.size(); i++) {
+ uint16 value = _scriptParser->getVar(_view.conditionalImages[i].var);
+ cachePreload(cacheImageType, _view.conditionalImages[i].values[value]);
+ }
+ } else {
cachePreload(cacheImageType, _view.mainImage);
+ }
// Precache Sound Block data
- if (_view.sound > 0)
- cachePreload(ID_MSND, _view.sound);
- else if (_view.sound == kMystSoundActionConditional) {
- for (uint16 i = 0; i < _view.soundCount; i++) {
- if (_view.soundList[i] > 0)
- cachePreload(ID_MSND, _view.soundList[i]);
+ if (_view.soundBlock.sound > 0)
+ cachePreload(ID_MSND, _view.soundBlock.sound);
+ else if (_view.soundBlock.sound == kMystSoundActionConditional) {
+ uint16 value = _scriptParser->getVar(_view.soundBlock.soundVar);
+ if (_view.soundBlock.soundList[value].action > 0) {
+ cachePreload(ID_MSND, _view.soundBlock.soundList[value].action);
}
}
// Precache Script Resources
- if (_view.scriptResCount != 0) {
- for (uint16 i = 0; i < _view.scriptResCount; i++) {
- switch (_view.scriptResources[i].type) {
- case 1:
- cachePreload(cacheImageType, _view.scriptResources[i].id);
- break;
- case 2:
- cachePreload(ID_MSND, _view.scriptResources[i].id);
- break;
- case 3:
- warning("TODO: Precaching of Script Resource List not supported");
- break;
- default:
- warning("Unknown Resource in Script Resource List Precaching");
- break;
- }
+ for (uint16 i = 0; i < _view.scriptResources.size(); i++) {
+ MystView::ScriptResourceType type;
+ int16 id;
+ if (_view.scriptResources[i].type == MystView::kResourceSwitch) {
+ type = _view.scriptResources[i].switchResourceType;
+ uint16 value = _scriptParser->getVar(_view.scriptResources[i].switchVar);
+ id = _view.scriptResources[i].switchResourceIds[value];
+ } else {
+ type = _view.scriptResources[i].type;
+ id = _view.scriptResources[i].id;
+ }
+
+ if (id < 0) continue;
+
+ switch (type) {
+ case MystView::kResourceImage:
+ cachePreload(cacheImageType, id);
+ break;
+ case MystView::kResourceSound:
+ cachePreload(ID_MSND, id);
+ break;
+ default:
+ // The other resource types should not be cached
+ break;
}
}
}
void MohawkEngine_Myst::unloadCard() {
- for (uint16 i = 0; i < _view.conditionalImageCount; i++)
- delete[] _view.conditionalImages[i].values;
-
- delete[] _view.conditionalImages;
- _view.conditionalImageCount = 0;
- _view.conditionalImages = NULL;
-
- delete[] _view.soundList;
- _view.soundList = NULL;
- delete[] _view.soundListVolume;
- _view.soundListVolume = NULL;
-
- for (uint16 i = 0; i < _view.scriptResCount; i++)
- delete[] _view.scriptResources[i].resource_list;
-
- delete[] _view.scriptResources;
- _view.scriptResources = NULL;
- _view.scriptResCount = 0;
+ _view.conditionalImages.clear();
+ _view.soundBlock.soundList.clear();
+ _view.scriptResources.clear();
}
void MohawkEngine_Myst::runInitScript() {
@@ -968,14 +900,12 @@ void MohawkEngine_Myst::loadHelp(uint16 id) {
debugC(kDebugHelp, "\thelpText: \"%s\"", helpText.c_str());
delete[] u0;
+
+ delete helpStream;
}
void MohawkEngine_Myst::loadCursorHints() {
- for (uint16 i = 0; i < _cursorHintCount; i++)
- delete[] _cursorHints[i].variableHint.values;
- _cursorHintCount = 0;
- delete[] _cursorHints;
- _cursorHints = NULL;
+ _cursorHints.clear();
if (!_view.hint) {
debugC(kDebugHint, "No HINT Present");
@@ -985,33 +915,33 @@ void MohawkEngine_Myst::loadCursorHints() {
debugC(kDebugHint, "Loading Cursor Hints:");
Common::SeekableReadStream *hintStream = getResource(ID_HINT, _curCard);
- _cursorHintCount = hintStream->readUint16LE();
- debugC(kDebugHint, "Cursor Hint Count: %d", _cursorHintCount);
- _cursorHints = new MystCursorHint[_cursorHintCount];
+ uint16 cursorHintCount = hintStream->readUint16LE();
+ debugC(kDebugHint, "Cursor Hint Count: %d", cursorHintCount);
+
+ for (uint16 i = 0; i < cursorHintCount; i++) {
+ MystCursorHint hint;
- for (uint16 i = 0; i < _cursorHintCount; i++) {
debugC(kDebugHint, "Cursor Hint %d:", i);
- _cursorHints[i].id = hintStream->readUint16LE();
- debugC(kDebugHint, "\tId: %d", _cursorHints[i].id);
- _cursorHints[i].cursor = hintStream->readSint16LE();
- debugC(kDebugHint, "\tCursor: %d", _cursorHints[i].cursor);
+ hint.id = hintStream->readUint16LE();
+ debugC(kDebugHint, "\tId: %d", hint.id);
+ hint.cursor = hintStream->readSint16LE();
+ debugC(kDebugHint, "\tCursor: %d", hint.cursor);
- if (_cursorHints[i].cursor == -1) {
+ if (hint.cursor == -1) {
debugC(kDebugHint, "\tConditional Cursor Hints:");
- _cursorHints[i].variableHint.var = hintStream->readUint16LE();
- debugC(kDebugHint, "\tVar: %d", _cursorHints[i].variableHint.var);
- _cursorHints[i].variableHint.numStates = hintStream->readUint16LE();
- debugC(kDebugHint, "\tNumber of States: %d", _cursorHints[i].variableHint.numStates);
- _cursorHints[i].variableHint.values = new uint16[_cursorHints[i].variableHint.numStates];
- for (uint16 j = 0; j < _cursorHints[i].variableHint.numStates; j++) {
- _cursorHints[i].variableHint.values[j] = hintStream->readUint16LE();
- debugC(kDebugHint, "\t\t State %d: Cursor %d", j, _cursorHints[i].variableHint.values[j]);
+ hint.variableHint.var = hintStream->readUint16LE();
+ debugC(kDebugHint, "\tVar: %d", hint.variableHint.var);
+ uint16 numStates = hintStream->readUint16LE();
+ debugC(kDebugHint, "\tNumber of States: %d", numStates);
+ for (uint16 j = 0; j < numStates; j++) {
+ hint.variableHint.values.push_back(hintStream->readUint16LE());
+ debugC(kDebugHint, "\t\t State %d: Cursor %d", j, hint.variableHint.values[j]);
}
} else {
- _cursorHints[i].variableHint.var = 0;
- _cursorHints[i].variableHint.numStates = 0;
- _cursorHints[i].variableHint.values = NULL;
+ hint.variableHint.var = 0;
}
+
+ _cursorHints.push_back(hint);
}
delete hintStream;
@@ -1033,12 +963,12 @@ void MohawkEngine_Myst::checkCursorHints() {
}
// Check all the cursor hints to see if we're in a hotspot that contains a hint.
- for (uint16 i = 0; i < _cursorHintCount; i++)
+ for (uint16 i = 0; i < _cursorHints.size(); i++)
if (_cursorHints[i].id == _curResource && _resources[_cursorHints[i].id]->isEnabled()) {
if (_cursorHints[i].cursor == -1) {
uint16 var_value = _scriptParser->getVar(_cursorHints[i].variableHint.var);
- if (var_value >= _cursorHints[i].variableHint.numStates)
+ if (var_value >= _cursorHints[i].variableHint.values.size())
warning("Variable %d Out of Range in variable HINT Resource %d", _cursorHints[i].variableHint.var, i);
else {
_currentCursor = _cursorHints[i].variableHint.values[var_value];
@@ -1076,50 +1006,50 @@ void MohawkEngine_Myst::drawResourceImages() {
_resources[i]->drawDataToScreen();
}
-void MohawkEngine_Myst::redrawResource(MystResourceType8 *resource, bool update) {
- resource->drawConditionalDataToScreen(_scriptParser->getVar(resource->getType8Var()), update);
+void MohawkEngine_Myst::redrawResource(MystAreaImageSwitch *resource, bool update) {
+ resource->drawConditionalDataToScreen(_scriptParser->getVar(resource->getImageSwitchVar()), update);
}
void MohawkEngine_Myst::redrawArea(uint16 var, bool update) {
for (uint16 i = 0; i < _resources.size(); i++)
- if (_resources[i]->type == kMystConditionalImage && _resources[i]->getType8Var() == var)
- redrawResource(static_cast<MystResourceType8 *>(_resources[i]), update);
+ if (_resources[i]->type == kMystAreaImageSwitch && _resources[i]->getImageSwitchVar() == var)
+ redrawResource(static_cast<MystAreaImageSwitch *>(_resources[i]), update);
}
-MystResource *MohawkEngine_Myst::loadResource(Common::SeekableReadStream *rlstStream, MystResource *parent) {
- MystResource *resource = 0;
+MystArea *MohawkEngine_Myst::loadResource(Common::SeekableReadStream *rlstStream, MystArea *parent) {
+ MystArea *resource = nullptr;
ResourceType type = static_cast<ResourceType>(rlstStream->readUint16LE());
debugC(kDebugResource, "\tType: %d", type);
- debugC(kDebugResource, "\tSub_Record: %d", (parent == NULL) ? 0 : 1);
+ debugC(kDebugResource, "\tSub_Record: %d", (parent == nullptr) ? 0 : 1);
switch (type) {
- case kMystAction:
- resource = new MystResourceType5(this, rlstStream, parent);
+ case kMystAreaAction:
+ resource = new MystAreaAction(this, rlstStream, parent);
break;
- case kMystVideo:
- resource = new MystResourceType6(this, rlstStream, parent);
+ case kMystAreaVideo:
+ resource = new MystAreaVideo(this, rlstStream, parent);
break;
- case kMystSwitch:
- resource = new MystResourceType7(this, rlstStream, parent);
+ case kMystAreaActionSwitch:
+ resource = new MystAreaActionSwitch(this, rlstStream, parent);
break;
- case kMystConditionalImage:
- resource = new MystResourceType8(this, rlstStream, parent);
+ case kMystAreaImageSwitch:
+ resource = new MystAreaImageSwitch(this, rlstStream, parent);
break;
- case kMystSlider:
- resource = new MystResourceType10(this, rlstStream, parent);
+ case kMystAreaSlider:
+ resource = new MystAreaSlider(this, rlstStream, parent);
break;
- case kMystDragArea:
- resource = new MystResourceType11(this, rlstStream, parent);
+ case kMystAreaDrag:
+ resource = new MystAreaDrag(this, rlstStream, parent);
break;
case kMystVideoInfo:
- resource = new MystResourceType12(this, rlstStream, parent);
+ resource = new MystVideoInfo(this, rlstStream, parent);
break;
- case kMystHoverArea:
- resource = new MystResourceType13(this, rlstStream, parent);
+ case kMystAreaHover:
+ resource = new MystAreaHover(this, rlstStream, parent);
break;
default:
- resource = new MystResource(this, rlstStream, parent);
+ resource = new MystArea(this, rlstStream, parent);
break;
}
@@ -1145,34 +1075,37 @@ void MohawkEngine_Myst::loadResources() {
for (uint16 i = 0; i < resourceCount; i++) {
debugC(kDebugResource, "Resource #%d:", i);
- _resources.push_back(loadResource(rlstStream, NULL));
+ _resources.push_back(loadResource(rlstStream, nullptr));
}
delete rlstStream;
}
Common::Error MohawkEngine_Myst::loadGameState(int slot) {
- if (_gameState->load(_gameState->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 = _gameState->generateSaveGameList();
-
- if ((uint)slot < saveList.size())
- _gameState->deleteSave(saveList[slot]);
+ return _gameState->save(slot, desc) ? Common::kNoError : Common::kUnknownError;
+}
- return _gameState->save(Common::String(desc)) ? Common::kNoError : Common::kUnknownError;
+bool MohawkEngine_Myst::hasGameSaveSupport() const {
+ return !(getFeatures() & GF_DEMO) && getGameType() != GType_MAKINGOF;
}
bool MohawkEngine_Myst::canLoadGameStateCurrently() {
// No loading in the demo/makingof
- return !(getFeatures() & GF_DEMO) && getGameType() != GType_MAKINGOF;
+ return _canSafelySaveLoad && hasGameSaveSupport();
}
bool MohawkEngine_Myst::canSaveGameStateCurrently() {
+ if (!_canSafelySaveLoad) {
+ return false;
+ }
+
// There's a limited number of stacks the game can save in
switch (_curStack) {
case kChannelwoodStack:
@@ -1225,4 +1158,82 @@ void MohawkEngine_Myst::dropPage() {
checkCursorHints();
}
+MystSoundBlock MohawkEngine_Myst::readSoundBlock(Common::ReadStream *stream) const {
+ MystSoundBlock soundBlock;
+ soundBlock.sound = stream->readSint16LE();
+ debugCN(kDebugView, "Sound Control: %d = ", soundBlock.sound);
+
+ if (soundBlock.sound > 0) {
+ debugC(kDebugView, "Play new Sound, change volume");
+ debugC(kDebugView, "\tSound: %d", soundBlock.sound);
+ soundBlock.soundVolume = stream->readUint16LE();
+ debugC(kDebugView, "\tVolume: %d", soundBlock.soundVolume);
+ } else if (soundBlock.sound == kMystSoundActionContinue)
+ debugC(kDebugView, "Continue current sound");
+ else if (soundBlock.sound == kMystSoundActionChangeVolume) {
+ debugC(kDebugView, "Continue current sound, change volume");
+ soundBlock.soundVolume = stream->readUint16LE();
+ debugC(kDebugView, "\tVolume: %d", soundBlock.soundVolume);
+ } else if (soundBlock.sound == kMystSoundActionStop) {
+ debugC(kDebugView, "Stop sound");
+ } else if (soundBlock.sound == kMystSoundActionConditional) {
+ debugC(kDebugView, "Conditional sound list");
+ soundBlock.soundVar = stream->readUint16LE();
+ debugC(kDebugView, "\tVar: %d", soundBlock.soundVar);
+ uint16 soundCount = stream->readUint16LE();
+ debugC(kDebugView, "\tCount: %d", soundCount);
+
+ for (uint16 i = 0; i < soundCount; i++) {
+ MystSoundBlock::SoundItem sound;
+
+ sound.action = stream->readSint16LE();
+ debugC(kDebugView, "\t\tCondition %d: Action %d", i, sound.action);
+ if (sound.action == kMystSoundActionChangeVolume || sound.action >= 0) {
+ sound.volume = stream->readUint16LE();
+ debugC(kDebugView, "\t\tCondition %d: Volume %d", i, sound.volume);
+ }
+
+ soundBlock.soundList.push_back(sound);
+ }
+ } else {
+ debugC(kDebugView, "Unknown");
+ warning("Unknown sound control value '%d' in card '%d'", soundBlock.sound, _curCard);
+ }
+
+ return soundBlock;
+}
+
+void MohawkEngine_Myst::applySoundBlock(const MystSoundBlock &block) {
+ int16 soundAction = 0;
+ uint16 soundActionVolume = 0;
+
+ if (block.sound == kMystSoundActionConditional) {
+ uint16 soundVarValue = _scriptParser->getVar(block.soundVar);
+ if (soundVarValue >= block.soundList.size())
+ warning("Conditional sound variable outside range");
+ else {
+ soundAction = block.soundList[soundVarValue].action;
+ soundActionVolume = block.soundList[soundVarValue].volume;
+ }
+ } else {
+ soundAction = block.sound;
+ soundActionVolume = block.soundVolume;
+ }
+
+ if (soundAction == kMystSoundActionContinue)
+ debug(2, "Continuing with current sound");
+ else if (soundAction == kMystSoundActionChangeVolume) {
+ debug(2, "Continuing with current sound, changing volume");
+ _sound->changeBackgroundVolumeMyst(soundActionVolume);
+ } else if (soundAction == kMystSoundActionStop) {
+ debug(2, "Stopping sound");
+ _sound->stopBackgroundMyst();
+ } else if (soundAction > 0) {
+ debug(2, "Playing new sound %d", soundAction);
+ _sound->replaceBackgroundMyst(soundAction, soundActionVolume);
+ } else {
+ error("Unknown sound action %d", soundAction);
+ }
+}
+
} // End of namespace Mohawk
diff --git a/engines/mohawk/myst.h b/engines/mohawk/myst.h
index 4d86642652..0b249e5499 100644
--- a/engines/mohawk/myst.h
+++ b/engines/mohawk/myst.h
@@ -28,10 +28,9 @@
#include "mohawk/resource_cache.h"
#include "mohawk/myst_scripts.h"
+#include "common/events.h"
#include "common/random.h"
-#include "gui/saveload.h"
-
namespace Mohawk {
class MohawkEngine_Myst;
@@ -41,9 +40,9 @@ class MystScriptParser;
class MystConsole;
class MystGameState;
class MystOptionsDialog;
-class MystResource;
-class MystResourceType8;
-class MystResourceType13;
+class MystArea;
+class MystAreaImageSwitch;
+class MystAreaHover;
// Engine Debug Flags
enum {
@@ -96,8 +95,19 @@ const uint16 kMasterpieceOnly = 0xFFFF;
struct MystCondition {
uint16 var;
- uint16 numStates;
- uint16 *values;
+ Common::Array<uint16> values;
+};
+
+struct MystSoundBlock {
+ struct SoundItem {
+ int16 action;
+ uint16 volume;
+ };
+
+ int16 sound;
+ uint16 soundVolume;
+ uint16 soundVar;
+ Common::Array<SoundItem> soundList;
};
// View Sound Action Type
@@ -118,29 +128,29 @@ struct MystView {
uint16 flags;
// Image Data
- uint16 conditionalImageCount;
- MystCondition *conditionalImages;
+ Common::Array<MystCondition> conditionalImages;
uint16 mainImage;
// Sound Data
- int16 sound;
- uint16 soundVolume;
- uint16 soundVar;
- uint16 soundCount;
- int16 *soundList;
- uint16 *soundListVolume;
+ MystSoundBlock soundBlock;
// Script Resources
- uint16 scriptResCount;
+ enum ScriptResourceType {
+ kResourceImage = 1,
+ kResourceSound = 2,
+ kResourceSwitch = 3,
+ kResourceImageNoCache = 4,
+ kResourceSoundNoCache = 5
+ };
+
struct ScriptResource {
- uint16 type;
- uint16 id; // Not used by type 3
- // TODO: Type 3 has more. Maybe use a union?
- uint16 var; // Used by type 3 only
- uint16 count; // Used by type 3 only
- uint16 u0; // Used by type 3 only
- int16 *resource_list; // Used by type 3 only
- } *scriptResources;
+ ScriptResourceType type;
+ uint16 id;
+ uint16 switchVar;
+ ScriptResourceType switchResourceType;
+ Common::Array<int16> switchResourceIds;
+ };
+ Common::Array<ScriptResource> scriptResources;
// Resource ID's
uint16 rlst;
@@ -158,18 +168,17 @@ struct MystCursorHint {
class MohawkEngine_Myst : public MohawkEngine {
protected:
- Common::Error run();
+ Common::Error run() override;
public:
MohawkEngine_Myst(OSystem *syst, const MohawkGameDescription *gamedesc);
virtual ~MohawkEngine_Myst();
- Common::SeekableReadStream *getResource(uint32 tag, uint16 id);
+ Common::SeekableReadStream *getResource(uint32 tag, uint16 id) override;
+ Common::Array<uint16> getResourceIDList(uint32 type) const;
Common::String wrapMovieFilename(const Common::String &movieName, uint16 stack);
- void reloadSaveList();
-
void changeToStack(uint16 stack, uint16 card, uint16 linkSrcSound, uint16 linkDstSound);
void changeToCard(uint16 card, TransitionType transition);
uint16 getCurCard() { return _curCard; }
@@ -177,46 +186,50 @@ public:
void setMainCursor(uint16 cursor);
uint16 getMainCursor() { return _mainCursor; }
void checkCursorHints();
- MystResource *updateCurrentResource();
+ MystArea *updateCurrentResource();
bool skippableWait(uint32 duration);
- bool _tweaksEnabled;
+ MystSoundBlock readSoundBlock(Common::ReadStream *stream) const;
+ void applySoundBlock(const MystSoundBlock &block);
+
bool _needsUpdate;
bool _needsPageDrop;
bool _needsShowMap;
bool _needsShowDemoMenu;
+ bool _needsShowCredits;
+
+ bool _showResourceRects;
- MystView _view;
MystGraphics *_gfx;
MystGameState *_gameState;
MystScriptParser *_scriptParser;
- Common::Array<MystResource *> _resources;
- MystResource *_dragResource;
+ Common::Array<MystArea *> _resources;
Common::RandomSource *_rnd;
- bool _showResourceRects;
- MystResource *loadResource(Common::SeekableReadStream *rlstStream, MystResource *parent);
+ MystArea *loadResource(Common::SeekableReadStream *rlstStream, MystArea *parent);
void setResourceEnabled(uint16 resourceId, bool enable);
void redrawArea(uint16 var, bool update = true);
- void redrawResource(MystResourceType8 *resource, bool update = true);
+ void redrawResource(MystAreaImageSwitch *resource, bool update = true);
void drawResourceImages();
void drawCardBackground();
uint16 getCardBackgroundId();
+ template<class T>
+ T *getViewResource(uint index);
+
void setCacheState(bool state) { _cache.enabled = state; }
bool getCacheState() { return _cache.enabled; }
- GUI::Debugger *getDebugger() { return _console; }
+ GUI::Debugger *getDebugger() override { return _console; }
- bool canLoadGameStateCurrently();
- bool canSaveGameStateCurrently();
- Common::Error loadGameState(int slot);
- Common::Error saveGameState(int slot, const Common::String &desc);
- bool hasFeature(EngineFeature f) const;
+ bool canLoadGameStateCurrently() override;
+ bool canSaveGameStateCurrently() override;
+ Common::Error loadGameState(int slot) override;
+ Common::Error saveGameState(int slot, const Common::String &desc) override;
+ bool hasFeature(EngineFeature f) const override;
private:
MystConsole *_console;
- GUI::SaveLoadChooser *_loadDialog;
MystOptionsDialog *_optionsDialog;
MystScriptParser *_prevStack;
ResourceCache _cache;
@@ -224,9 +237,18 @@ private:
uint16 _curStack;
uint16 _curCard;
+ MystView _view;
bool _runExitScript;
+ /**
+ * Saving / Loading is only allowed from the main event loop
+ */
+ bool _canSafelySaveLoad;
+ bool hasGameSaveSupport() const;
+
+ bool pollEvent(Common::Event &event);
+
void dropPage();
void loadCard();
@@ -240,15 +262,25 @@ private:
void drawResourceRects();
void checkCurrentResource();
int16 _curResource;
- MystResourceType13 *_hoverResource;
+ MystAreaHover *_hoverResource;
- uint16 _cursorHintCount;
- MystCursorHint *_cursorHints;
+ Common::Array<MystCursorHint> _cursorHints;
void loadCursorHints();
uint16 _currentCursor;
uint16 _mainCursor; // Also defines the current page being held (white, blue, red, or none)
};
+template<class T>
+T *MohawkEngine_Myst::getViewResource(uint index) {
+ T *resource = dynamic_cast<T *>(_resources[index]);
+
+ if (!resource) {
+ error("View resource '%d' has unexpected type", index);
+ }
+
+ return resource;
+}
+
} // End of namespace Mohawk
#endif
diff --git a/engines/mohawk/myst_areas.cpp b/engines/mohawk/myst_areas.cpp
index 7a9596d8e0..4b9cf546fa 100644
--- a/engines/mohawk/myst_areas.cpp
+++ b/engines/mohawk/myst_areas.cpp
@@ -32,11 +32,11 @@
namespace Mohawk {
-MystResource::MystResource(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) {
+MystArea::MystArea(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) {
_vm = vm;
_parent = parent;
- if (parent == NULL) {
+ if (parent == nullptr) {
_flags = rlstStream->readUint16LE();
_rect.left = rlstStream->readSint16LE();
_rect.top = rlstStream->readSint16LE();
@@ -66,10 +66,10 @@ MystResource::MystResource(MohawkEngine_Myst *vm, Common::SeekableReadStream *rl
debugC(kDebugResource, "\tdest: %d", _dest);
}
-MystResource::~MystResource() {
+MystArea::~MystArea() {
}
-void MystResource::handleMouseUp() {
+void MystArea::handleMouseUp() {
if (_dest == 0) {
warning("Movement type resource with null destination at position (%d, %d), (%d, %d)", _rect.left, _rect.top, _rect.right, _rect.bottom);
return;
@@ -78,13 +78,13 @@ void MystResource::handleMouseUp() {
uint16 opcode;
switch (type) {
- case kMystForwardArea:
+ case kMystAreaForward:
opcode = 6;
break;
- case kMystLeftArea:
+ case kMystAreaLeft:
opcode = 8;
break;
- case kMystRightArea:
+ case kMystAreaRight:
opcode = 7;
break;
default:
@@ -96,27 +96,27 @@ void MystResource::handleMouseUp() {
_vm->_scriptParser->runOpcode(opcode, 0);
}
-bool MystResource::canBecomeActive() {
+bool MystArea::canBecomeActive() {
return !unreachableZipDest() && (isEnabled() || (_flags & kMystUnknownFlag));
}
-bool MystResource::unreachableZipDest() {
+bool MystArea::unreachableZipDest() {
return (_flags & kMystZipModeEnableFlag)
&& !_vm->_gameState->isReachableZipDest(_vm->getCurStack() , _dest);
}
-bool MystResource::isEnabled() {
+bool MystArea::isEnabled() {
return _flags & kMystHotspotEnableFlag;
}
-void MystResource::setEnabled(bool enabled) {
+void MystArea::setEnabled(bool enabled) {
if (enabled)
_flags |= kMystHotspotEnableFlag;
else
_flags &= ~kMystHotspotEnableFlag;
}
-const Common::String MystResource::describe() {
+const Common::String MystArea::describe() {
Common::String desc = Common::String::format("type: %2d rect: (%3d %3d %3d %3d)",
type, _rect.left, _rect.top, _rect.width(), _rect.height());
@@ -126,7 +126,7 @@ const Common::String MystResource::describe() {
return desc;
}
-void MystResource::drawBoundingRect() {
+void MystArea::drawBoundingRect() {
if (_rect.isValidRect()) {
if (!canBecomeActive())
_vm->_gfx->drawRect(_rect, kRectUnreachable);
@@ -137,18 +137,19 @@ void MystResource::drawBoundingRect() {
}
}
-MystResourceType5::MystResourceType5(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) : MystResource(vm, rlstStream, parent) {
+MystAreaAction::MystAreaAction(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) :
+ MystArea(vm, rlstStream, parent) {
debugC(kDebugResource, "\tResource Type 5 Script:");
_script = vm->_scriptParser->readScript(rlstStream, kMystScriptNormal);
}
-void MystResourceType5::handleMouseUp() {
+void MystAreaAction::handleMouseUp() {
_vm->_scriptParser->runScript(_script, this);
}
-const Common::String MystResourceType5::describe() {
- Common::String desc = MystResource::describe();
+const Common::String MystAreaAction::describe() {
+ Common::String desc = MystArea::describe();
if (_script->size() != 0) {
desc += " ops:";
@@ -161,7 +162,7 @@ const Common::String MystResourceType5::describe() {
}
// In Myst/Making of Myst, the paths are hardcoded ala Windows style without extension. Convert them.
-Common::String MystResourceType6::convertMystVideoName(Common::String name) {
+Common::String MystAreaVideo::convertMystVideoName(Common::String name) {
Common::String temp;
for (uint32 i = 1; i < name.size(); i++) {
@@ -174,7 +175,8 @@ Common::String MystResourceType6::convertMystVideoName(Common::String name) {
return temp + ".mov";
}
-MystResourceType6::MystResourceType6(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) : MystResourceType5(vm, rlstStream, parent) {
+MystAreaVideo::MystAreaVideo(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) :
+ MystAreaAction(vm, rlstStream, parent) {
char c = 0;
do {
@@ -197,16 +199,7 @@ MystResourceType6::MystResourceType6(MohawkEngine_Myst *vm, Common::SeekableRead
_direction = rlstStream->readSint16LE();
_playBlocking = rlstStream->readUint16LE();
_loop = rlstStream->readUint16LE();
- _u3 = rlstStream->readUint16LE();
-
- // TODO: Out of bound values should clip the movie
- if (_left < 0)
- _left = 0;
- if (_top < 0)
- _top = 0;
-
- if (_u3 != 0)
- warning("Type 6 _u3 != 0");
+ _playRate = rlstStream->readUint16LE();
debugC(kDebugResource, "\tvideoFile: \"%s\"", _videoFile.c_str());
debugC(kDebugResource, "\tleft: %d", _left);
@@ -215,15 +208,15 @@ MystResourceType6::MystResourceType6(MohawkEngine_Myst *vm, Common::SeekableRead
debugC(kDebugResource, "\tdirection: %d", _direction);
debugC(kDebugResource, "\tplayBlocking: %d", _playBlocking);
debugC(kDebugResource, "\tplayOnCardChange: %d", _playOnCardChange);
- debugC(kDebugResource, "\tu3: %d", _u3);
+ debugC(kDebugResource, "\tplayRate: %d", _playRate);
}
-VideoHandle MystResourceType6::playMovie() {
+VideoHandle MystAreaVideo::playMovie() {
// Check if the video is already running
VideoHandle handle = _vm->_video->findVideoHandle(_videoFile);
// If the video is not running, play it
- if (!handle || handle->endOfVideo()) {
+ if (!handle) {
handle = _vm->_video->playMovie(_videoFile);
if (!handle)
error("Failed to open '%s'", _videoFile.c_str());
@@ -231,13 +224,23 @@ VideoHandle MystResourceType6::playMovie() {
handle->moveTo(_left, _top);
handle->setLooping(_loop != 0);
+ Common::Rational rate;
+ if (_playRate != 0) {
+ rate = Common::Rational(_playRate, 100);
+ } else {
+ rate = 1;
+ }
+
if (_direction == -1) {
+ rate = -rate;
handle->seek(handle->getDuration());
- handle->setRate(-1);
}
+
+ handle->setRate(rate);
} else {
// Resume the video
handle->pause(false);
+ handle->start();
}
if (_playBlocking) {
@@ -248,186 +251,156 @@ VideoHandle MystResourceType6::playMovie() {
return handle;
}
-void MystResourceType6::handleCardChange() {
+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();
}
-bool MystResourceType6::isPlaying() {
+bool MystAreaVideo::isPlaying() {
VideoHandle handle = _vm->_video->findVideoHandle(_videoFile);
return handle && !handle->endOfVideo();
}
-void MystResourceType6::pauseMovie(bool pause) {
+void MystAreaVideo::pauseMovie(bool pause) {
VideoHandle handle = _vm->_video->findVideoHandle(_videoFile);
if (handle && !handle->endOfVideo())
handle->pause(pause);
}
-MystResourceType7::MystResourceType7(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) : MystResource(vm, rlstStream, parent) {
- _var7 = rlstStream->readUint16LE();
- _numSubResources = rlstStream->readUint16LE();
- debugC(kDebugResource, "\tvar7: %d", _var7);
- debugC(kDebugResource, "\tnumSubResources: %d", _numSubResources);
+MystAreaActionSwitch::MystAreaActionSwitch(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) :
+ MystArea(vm, rlstStream, parent) {
+ _actionSwitchVar = rlstStream->readUint16LE();
+ uint16 numSubResources = rlstStream->readUint16LE();
+ debugC(kDebugResource, "\tactionSwitchVar: %d", _actionSwitchVar);
+ debugC(kDebugResource, "\tnumSubResources: %d", numSubResources);
- for (uint16 i = 0; i < _numSubResources; i++)
+ for (uint16 i = 0; i < numSubResources; i++)
_subResources.push_back(vm->loadResource(rlstStream, this));
}
-MystResourceType7::~MystResourceType7() {
+MystAreaActionSwitch::~MystAreaActionSwitch() {
for (uint32 i = 0; i < _subResources.size(); i++)
delete _subResources[i];
_subResources.clear();
}
-// TODO: All these functions to switch subresource are very similar.
-// Find way to share code (function pointer pass?)
-void MystResourceType7::drawDataToScreen() {
- if (_var7 == 0xFFFF) {
- if (_numSubResources == 1)
- _subResources[0]->drawDataToScreen();
- else if (_numSubResources != 0)
- warning("Type 7 Resource with _numSubResources of %d, but no control variable", _numSubResources);
+void MystAreaActionSwitch::doSwitch(AreaHandler handler) {
+ if (_actionSwitchVar == 0xFFFF) {
+ if (_subResources.size() == 1)
+ (_subResources[0]->*handler)();
+ else if (_subResources.size() != 0)
+ warning("Action switch resource with _numSubResources of %d, but no control variable", _subResources.size());
} else {
- uint16 varValue = _vm->_scriptParser->getVar(_var7);
+ uint16 varValue = _vm->_scriptParser->getVar(_actionSwitchVar);
- if (_numSubResources == 1 && varValue != 0)
- _subResources[0]->drawDataToScreen();
- else if (_numSubResources != 0) {
- if (varValue < _numSubResources)
- _subResources[varValue]->drawDataToScreen();
+ if (_subResources.size() == 1 && varValue != 0)
+ (_subResources[0]->*handler)();
+ else if (_subResources.size() != 0) {
+ if (varValue < _subResources.size())
+ (_subResources[varValue]->*handler)();
else
- warning("Type 7 Resource Var %d: %d exceeds number of sub resources %d", _var7, varValue, _numSubResources);
+ warning("Action switch resource Var %d: %d exceeds number of sub resources %d", _actionSwitchVar, varValue, _subResources.size());
}
}
}
-void MystResourceType7::handleCardChange() {
- if (_var7 == 0xFFFF) {
- if (_numSubResources == 1)
- _subResources[0]->handleCardChange();
- else if (_numSubResources != 0)
- warning("Type 7 Resource with _numSubResources of %d, but no control variable", _numSubResources);
- } else {
- uint16 varValue = _vm->_scriptParser->getVar(_var7);
-
- if (_numSubResources == 1 && varValue != 0)
- _subResources[0]->handleCardChange();
- else if (_numSubResources != 0) {
- if (varValue < _numSubResources)
- _subResources[varValue]->handleCardChange();
- else
- warning("Type 7 Resource Var %d: %d exceeds number of sub resources %d", _var7, varValue, _numSubResources);
- }
- }
+void MystAreaActionSwitch::drawDataToScreen() {
+ doSwitch(&MystArea::drawDataToScreen);
}
-void MystResourceType7::handleMouseUp() {
- if (_var7 == 0xFFFF) {
- if (_numSubResources == 1)
- _subResources[0]->handleMouseUp();
- else if (_numSubResources != 0)
- warning("Type 7 Resource with _numSubResources of %d, but no control variable", _numSubResources);
- } else {
- uint16 varValue = _vm->_scriptParser->getVar(_var7);
-
- if (_numSubResources == 1 && varValue != 0)
- _subResources[0]->handleMouseUp();
- else if (_numSubResources != 0) {
- if (varValue < _numSubResources)
- _subResources[varValue]->handleMouseUp();
- else
- warning("Type 7 Resource Var %d: %d exceeds number of sub resources %d", _var7, varValue, _numSubResources);
- }
- }
+void MystAreaActionSwitch::handleCardChange() {
+ doSwitch(&MystArea::handleCardChange);
}
-void MystResourceType7::handleMouseDown() {
- if (_var7 == 0xFFFF) {
- if (_numSubResources == 1)
- _subResources[0]->handleMouseDown();
- else if (_numSubResources != 0)
- warning("Type 7 Resource with _numSubResources of %d, but no control variable", _numSubResources);
- } else {
- uint16 varValue = _vm->_scriptParser->getVar(_var7);
-
- if (_numSubResources == 1 && varValue != 0)
- _subResources[0]->handleMouseDown();
- else if (_numSubResources != 0) {
- if (varValue < _numSubResources)
- _subResources[varValue]->handleMouseDown();
- else
- warning("Type 7 Resource Var %d: %d exceeds number of sub resources %d", _var7, varValue, _numSubResources);
- }
- }
+void MystAreaActionSwitch::handleMouseUp() {
+ doSwitch(&MystArea::handleMouseUp);
}
-MystResourceType8::MystResourceType8(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) : MystResourceType7(vm, rlstStream, parent) {
- _var8 = rlstStream->readUint16LE();
- _numSubImages = rlstStream->readUint16LE();
- debugC(kDebugResource, "\tvar8: %d", _var8);
- debugC(kDebugResource, "\tnumSubImages: %d", _numSubImages);
+void MystAreaActionSwitch::handleMouseDown() {
+ doSwitch(&MystArea::handleMouseDown);
+}
- _subImages = new MystResourceType8::SubImage[_numSubImages];
+MystAreaImageSwitch::MystAreaImageSwitch(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) :
+ MystAreaActionSwitch(vm, rlstStream, parent) {
+ _imageSwitchVar = rlstStream->readUint16LE();
+ uint16 numSubImages = rlstStream->readUint16LE();
+ debugC(kDebugResource, "\tvar8: %d", _imageSwitchVar);
+ debugC(kDebugResource, "\tnumSubImages: %d", numSubImages);
- for (uint16 i = 0; i < _numSubImages; i++) {
+ for (uint16 i = 0; i < numSubImages; i++) {
debugC(kDebugResource, "\tSubimage %d:", i);
- _subImages[i].wdib = rlstStream->readUint16LE();
- _subImages[i].rect.left = rlstStream->readSint16LE();
+ SubImage subImage;
+ subImage.wdib = rlstStream->readUint16LE();
+ subImage.rect.left = rlstStream->readSint16LE();
- if (_subImages[i].rect.left != -1) {
- _subImages[i].rect.top = rlstStream->readSint16LE();
- _subImages[i].rect.right = rlstStream->readSint16LE();
- _subImages[i].rect.bottom = rlstStream->readSint16LE();
+ if (subImage.rect.left != -1) {
+ subImage.rect.top = rlstStream->readSint16LE();
+ subImage.rect.right = rlstStream->readSint16LE();
+ subImage.rect.bottom = rlstStream->readSint16LE();
} else {
// Use the hotspot rect as the source rect since the subimage is fullscreen
// Convert to bitmap coordinates (upside down)
- _subImages[i].rect.left = _rect.left;
- _subImages[i].rect.top = 333 - _rect.bottom;
- _subImages[i].rect.right = _rect.right;
- _subImages[i].rect.bottom = 333 - _rect.top;
+ subImage.rect.left = _rect.left;
+ subImage.rect.top = 333 - _rect.bottom;
+ subImage.rect.right = _rect.right;
+ subImage.rect.bottom = 333 - _rect.top;
}
- debugC(kDebugResource, "\twdib: %d", _subImages[i].wdib);
- debugC(kDebugResource, "\tleft: %d", _subImages[i].rect.left);
- debugC(kDebugResource, "\ttop: %d", _subImages[i].rect.top);
- debugC(kDebugResource, "\tright: %d", _subImages[i].rect.right);
- debugC(kDebugResource, "\tbottom: %d", _subImages[i].rect.bottom);
+ debugC(kDebugResource, "\twdib: %d", subImage.wdib);
+ debugC(kDebugResource, "\tleft: %d", subImage.rect.left);
+ debugC(kDebugResource, "\ttop: %d", subImage.rect.top);
+ debugC(kDebugResource, "\tright: %d", subImage.rect.right);
+ debugC(kDebugResource, "\tbottom: %d", subImage.rect.bottom);
+
+ _subImages.push_back(subImage);
}
}
-MystResourceType8::~MystResourceType8() {
- delete[] _subImages;
+MystAreaImageSwitch::~MystAreaImageSwitch() {
}
-void MystResourceType8::drawDataToScreen() {
- // Need to call overidden Type 7 function to ensure
+void MystAreaImageSwitch::drawDataToScreen() {
+ // Need to call overridden function to ensure
// switch section is processed correctly.
- MystResourceType7::drawDataToScreen();
+ MystAreaActionSwitch::drawDataToScreen();
bool drawSubImage = false;
int16 subImageId = 0;
- if (_var8 == 0xFFFF) {
- if (_numSubImages == 1) {
+ if (_imageSwitchVar == 0xFFFF) {
+ if (_subImages.size() == 1) {
subImageId = 0;
drawSubImage = true;
- } else if (_numSubImages != 0)
- warning("Type 8 Resource with _numSubImages of %d, but no control variable", _numSubImages);
+ } else if (_subImages.size() != 0)
+ warning("Image Switch resource with _numSubImages of %d, but no control variable", _subImages.size());
} else {
- uint16 varValue = _vm->_scriptParser->getVar(_var8);
+ uint16 varValue = _vm->_scriptParser->getVar(_imageSwitchVar);
- if (_numSubImages == 1 && varValue != 0) {
+ if (_subImages.size() == 1 && varValue != 0) {
subImageId = 0;
drawSubImage = true;
- } else if (_numSubImages != 0) {
- if (varValue < _numSubImages) {
+ } else if (_subImages.size() != 0) {
+ if (varValue < _subImages.size()) {
subImageId = varValue;
drawSubImage = true;
} else
- warning("Type 8 Image Var %d: %d exceeds number of subImages %d", _var8, varValue, _numSubImages);
+ warning("Image Switch Var %d: %d exceeds number of subImages %d", _imageSwitchVar, varValue, _subImages.size());
}
}
@@ -442,20 +415,21 @@ void MystResourceType8::drawDataToScreen() {
}
}
-void MystResourceType8::drawConditionalDataToScreen(uint16 state, bool update) {
+//TODO: Merge with the method above?
+void MystAreaImageSwitch::drawConditionalDataToScreen(uint16 state, bool update) {
bool drawSubImage = false;
int16 subImageId = 0;
- if (_numSubImages == 1 && state != 0) {
+ if (_subImages.size() == 1 && state != 0) {
subImageId = 0;
drawSubImage = true;
- } else if (_numSubImages != 0) {
- if (state < _numSubImages) {
+ } else if (_subImages.size() != 0) {
+ if (state < _subImages.size()) {
subImageId = state;
drawSubImage = true;
} else
- warning("Type 8 Image Var %d: %d exceeds number of subImages %d", _var8, state, _numSubImages);
+ warning("Image Switch Var %d: %d exceeds number of subImages %d", _imageSwitchVar, state, _subImages.size());
}
@@ -476,18 +450,26 @@ void MystResourceType8::drawConditionalDataToScreen(uint16 state, bool update) {
}
}
-uint16 MystResourceType8::getType8Var() {
- return _var8;
+uint16 MystAreaImageSwitch::getImageSwitchVar() {
+ return _imageSwitchVar;
+}
+
+MystAreaImageSwitch::SubImage MystAreaImageSwitch::getSubImage(uint index) const {
+ return _subImages[index];
}
-const Common::String MystResourceType8::describe() {
+void MystAreaImageSwitch::setSubImageRect(uint index, const Common::Rect &rect) {
+ _subImages[index].rect = rect;
+}
+
+const Common::String MystAreaImageSwitch::describe() {
Common::String desc = Common::String::format("%s var: %2d",
- MystResourceType7::describe().c_str(), _var8);
+ MystAreaActionSwitch::describe().c_str(), _imageSwitchVar);
- if (_numSubImages > 0) {
+ if (_subImages.size() > 0) {
desc += " subImgs:";
- for (uint i = 0; i < _numSubImages; i++)
+ for (uint i = 0; i < _subImages.size(); i++)
desc += Common::String::format(" %d", (int16)_subImages[i].wdib);
}
@@ -496,7 +478,8 @@ const Common::String MystResourceType8::describe() {
// No MystResourceType9!
-MystResourceType10::MystResourceType10(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) : MystResourceType11(vm, rlstStream, parent) {
+MystAreaSlider::MystAreaSlider(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) :
+ MystAreaDrag(vm, rlstStream, parent) {
_dragSound = rlstStream->readUint16LE();
debugC(kDebugResource, "\tdrag sound : %d", _dragSound);
@@ -505,23 +488,23 @@ MystResourceType10::MystResourceType10(MohawkEngine_Myst *vm, Common::SeekableRe
_sliderHeight = _rect.bottom - _rect.top;
}
-MystResourceType10::~MystResourceType10() {
+MystAreaSlider::~MystAreaSlider() {
}
-void MystResourceType10::setStep(uint16 step) {
+void MystAreaSlider::setStep(uint16 step) {
_rect.top = _minV + _stepV * step - _sliderHeight / 2;
_rect.bottom = _rect.top + _sliderHeight;
_subImages[0].rect.top = 333 - _rect.bottom - 1;
_subImages[0].rect.bottom = 333 - _rect.top - 1;
}
-void MystResourceType10::setPosition(uint16 pos) {
+void MystAreaSlider::setPosition(uint16 pos) {
Common::Point mouse;
mouse.y = pos;
updatePosition(mouse);
}
-Common::Rect MystResourceType10::boundingBox() {
+Common::Rect MystAreaSlider::boundingBox() {
Common::Rect bb;
bb.top = _rect.top;
@@ -544,7 +527,7 @@ Common::Rect MystResourceType10::boundingBox() {
return bb;
}
-void MystResourceType10::restoreBackground() {
+void MystAreaSlider::restoreBackground() {
// Restore background
Common::Rect src = boundingBox();
Common::Rect dest = boundingBox();
@@ -553,14 +536,11 @@ void MystResourceType10::restoreBackground() {
_vm->_gfx->copyImageSectionToScreen(_vm->getCardBackgroundId(), src, dest);
}
-void MystResourceType10::handleMouseDown() {
- // Tell the engine we are dragging a resource
- _vm->_dragResource = this;
-
+void MystAreaSlider::handleMouseDown() {
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
updatePosition(mouse);
- MystResourceType11::handleMouseDown();
+ MystAreaDrag::handleMouseDown();
// Restore background
restoreBackground();
@@ -569,7 +549,7 @@ void MystResourceType10::handleMouseDown() {
drawConditionalDataToScreen(2);
}
-void MystResourceType10::handleMouseUp() {
+void MystAreaSlider::handleMouseUp() {
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
updatePosition(mouse);
@@ -593,19 +573,16 @@ void MystResourceType10::handleMouseUp() {
value = _pos.x;
}
- _vm->_scriptParser->setVarValue(_var8, value);
-
- MystResourceType11::handleMouseUp();
+ _vm->_scriptParser->setVarValue(_imageSwitchVar, value);
- // No longer in drag mode
- _vm->_dragResource = 0;
+ MystAreaDrag::handleMouseUp();
}
-void MystResourceType10::handleMouseDrag() {
+void MystAreaSlider::handleMouseDrag() {
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
updatePosition(mouse);
- MystResourceType11::handleMouseDrag();
+ MystAreaDrag::handleMouseDrag();
// Restore background
restoreBackground();
@@ -614,7 +591,7 @@ void MystResourceType10::handleMouseDrag() {
drawConditionalDataToScreen(2);
}
-void MystResourceType10::updatePosition(const Common::Point &mouse) {
+void MystAreaSlider::updatePosition(const Common::Point &mouse) {
bool positionChanged = false;
Common::Point mouseClipped;
@@ -667,7 +644,8 @@ void MystResourceType10::updatePosition(const Common::Point &mouse) {
_vm->_sound->replaceSoundMyst(_dragSound);
}
-MystResourceType11::MystResourceType11(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) : MystResourceType8(vm, rlstStream, parent) {
+MystAreaDrag::MystAreaDrag(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) :
+ MystAreaImageSwitch(vm, rlstStream, parent) {
_flagHV = rlstStream->readUint16LE();
_minH = rlstStream->readUint16LE();
_maxH = rlstStream->readUint16LE();
@@ -694,16 +672,15 @@ MystResourceType11::MystResourceType11(MohawkEngine_Myst *vm, Common::SeekableRe
debugCN(kDebugResource, "Type 11 _mouseDragOpcode: %d\n", _mouseDragOpcode);
debugCN(kDebugResource, "Type 11 _mouseUpOpcode: %d\n", _mouseUpOpcode);
- for (byte i = 0; i < 3; i++) {
+ for (byte i = 0; i < ARRAYSIZE(_lists); i++) {
debugC(kDebugResource, "\tList %d:", i);
- _lists[i].listCount = rlstStream->readUint16LE();
- debugC(kDebugResource, "\t%d values", _lists[i].listCount);
+ uint16 listCount = rlstStream->readUint16LE();
+ debugC(kDebugResource, "\t%d values", listCount);
- _lists[i].list = new uint16[_lists[i].listCount];
- for (uint16 j = 0; j < _lists[i].listCount; j++) {
- _lists[i].list[j] = rlstStream->readUint16LE();
- debugC(kDebugResource, "\tValue %d: %d", j, _lists[i].list[j]);
+ for (uint16 j = 0; j < listCount; j++) {
+ _lists[i].push_back(rlstStream->readUint16LE());
+ debugC(kDebugResource, "\tValue %d: %d", j, _lists[i][j]);
}
}
@@ -717,44 +694,42 @@ MystResourceType11::MystResourceType11(MohawkEngine_Myst *vm, Common::SeekableRe
_stepV = (_maxV - _minV) / (_stepsV - 1);
}
-MystResourceType11::~MystResourceType11() {
- for (byte i = 0; i < 3; i++)
- delete[] _lists[i].list;
+MystAreaDrag::~MystAreaDrag() {
}
-void MystResourceType11::handleMouseDown() {
+void MystAreaDrag::handleMouseDown() {
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
setPositionClipping(mouse, _pos);
_vm->_scriptParser->setInvokingResource(this);
- _vm->_scriptParser->runOpcode(_mouseDownOpcode, _var8);
+ _vm->_scriptParser->runOpcode(_mouseDownOpcode, _imageSwitchVar);
}
-void MystResourceType11::handleMouseUp() {
+void MystAreaDrag::handleMouseUp() {
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
setPositionClipping(mouse, _pos);
_vm->_scriptParser->setInvokingResource(this);
- _vm->_scriptParser->runOpcode(_mouseUpOpcode, _var8);
+ _vm->_scriptParser->runOpcode(_mouseUpOpcode, _imageSwitchVar);
}
-void MystResourceType11::handleMouseDrag() {
+void MystAreaDrag::handleMouseDrag() {
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
setPositionClipping(mouse, _pos);
_vm->_scriptParser->setInvokingResource(this);
- _vm->_scriptParser->runOpcode(_mouseDragOpcode, _var8);
+ _vm->_scriptParser->runOpcode(_mouseDragOpcode, _imageSwitchVar);
}
-const Common::String MystResourceType11::describe() {
+const Common::String MystAreaDrag::describe() {
return Common::String::format("%s down: %s drag: %s up: %s",
- MystResourceType8::describe().c_str(),
+ MystAreaImageSwitch::describe().c_str(),
_vm->_scriptParser->getOpcodeDesc(_mouseDownOpcode).c_str(),
_vm->_scriptParser->getOpcodeDesc(_mouseDragOpcode).c_str(),
_vm->_scriptParser->getOpcodeDesc(_mouseUpOpcode).c_str());
}
-void MystResourceType11::setPositionClipping(const Common::Point &mouse, Common::Point &dest) {
+void MystAreaDrag::setPositionClipping(const Common::Point &mouse, Common::Point &dest) {
if (_flagHV & 2)
dest.y = CLIP<uint16>(mouse.y, _minV, _maxV);
@@ -762,19 +737,20 @@ void MystResourceType11::setPositionClipping(const Common::Point &mouse, Common:
dest.x = CLIP<uint16>(mouse.x, _minH, _maxH);
}
-uint16 MystResourceType11::getList1(uint16 index) {
- return (index < _lists[0].listCount) ? _lists[0].list[index] : 0;
+uint16 MystAreaDrag::getList1(uint16 index) {
+ return (index < _lists[0].size()) ? _lists[0][index] : 0;
}
-uint16 MystResourceType11::getList2(uint16 index) {
- return (index < _lists[1].listCount) ? _lists[1].list[index] : 0;
+uint16 MystAreaDrag::getList2(uint16 index) {
+ return (index < _lists[1].size()) ? _lists[1][index] : 0;
}
-uint16 MystResourceType11::getList3(uint16 index) {
- return (index < _lists[2].listCount) ? _lists[2].list[index] : 0;
+uint16 MystAreaDrag::getList3(uint16 index) {
+ return (index < _lists[2].size()) ? _lists[2][index] : 0;
}
-MystResourceType12::MystResourceType12(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) : MystResourceType11(vm, rlstStream, parent) {
+MystVideoInfo::MystVideoInfo(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) :
+ MystAreaDrag(vm, rlstStream, parent) {
_numFrames = rlstStream->readUint16LE();
_firstFrame = rlstStream->readUint16LE();
uint16 frameWidth = rlstStream->readUint16LE();
@@ -795,16 +771,16 @@ MystResourceType12::MystResourceType12(MohawkEngine_Myst *vm, Common::SeekableRe
debugC(kDebugResource, "\t_frameRect.bottom: %d", _frameRect.bottom);
}
-MystResourceType12::~MystResourceType12() {
+MystVideoInfo::~MystVideoInfo() {
}
-void MystResourceType12::drawFrame(uint16 frame) {
+void MystVideoInfo::drawFrame(uint16 frame) {
_currentFrame = _firstFrame + frame;
_vm->_gfx->copyImageToScreen(_currentFrame, _frameRect);
_vm->_system->updateScreen();
}
-bool MystResourceType12::pullLeverV() {
+bool MystVideoInfo::pullLeverV() {
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
// Make the handle follow the mouse
@@ -820,7 +796,7 @@ bool MystResourceType12::pullLeverV() {
return step == maxStep;
}
-void MystResourceType12::releaseLeverV() {
+void MystVideoInfo::releaseLeverV() {
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
// Get current lever frame
@@ -836,7 +812,8 @@ void MystResourceType12::releaseLeverV() {
}
}
-MystResourceType13::MystResourceType13(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) : MystResource(vm, rlstStream, parent) {
+MystAreaHover::MystAreaHover(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) :
+ MystArea(vm, rlstStream, parent) {
_enterOpcode = rlstStream->readUint16LE();
_leaveOpcode = rlstStream->readUint16LE();
@@ -844,27 +821,27 @@ MystResourceType13::MystResourceType13(MohawkEngine_Myst *vm, Common::SeekableRe
debugC(kDebugResource, "\t_leaveOpcode: %d", _leaveOpcode);
}
-void MystResourceType13::handleMouseEnter() {
+void MystAreaHover::handleMouseEnter() {
// Pass along the enter opcode to the script parser
// The variable to use is stored in the dest field
_vm->_scriptParser->runOpcode(_enterOpcode, _dest);
}
-void MystResourceType13::handleMouseLeave() {
+void MystAreaHover::handleMouseLeave() {
// Pass along the leave opcode (with no parameters) to the script parser
// The variable to use is stored in the dest field
_vm->_scriptParser->runOpcode(_leaveOpcode, _dest);
}
-void MystResourceType13::handleMouseUp() {
+void MystAreaHover::handleMouseUp() {
// Type 13 Resources do nothing on Mouse Clicks.
// This is required to override the inherited default
- // i.e. MystResource::handleMouseUp
+ // i.e. MystArea::handleMouseUp
}
-const Common::String MystResourceType13::describe() {
+const Common::String MystAreaHover::describe() {
return Common::String::format("%s enter: %s leave: %s",
- MystResource::describe().c_str(),
+ MystArea::describe().c_str(),
_vm->_scriptParser->getOpcodeDesc(_enterOpcode).c_str(),
_vm->_scriptParser->getOpcodeDesc(_leaveOpcode).c_str());
}
diff --git a/engines/mohawk/myst_areas.h b/engines/mohawk/myst_areas.h
index 97ec882497..b19a2df9e2 100644
--- a/engines/mohawk/myst_areas.h
+++ b/engines/mohawk/myst_areas.h
@@ -32,19 +32,19 @@ namespace Mohawk {
// Myst Resource Types
enum ResourceType {
- kMystForwardArea = 0,
- kMystLeftArea = 1,
- kMystRightArea = 2,
- kMystDownArea = 3,
- kMystUpArea = 4,
- kMystAction = 5,
- kMystVideo = 6,
- kMystSwitch = 7,
- kMystConditionalImage = 8,
- kMystSlider = 10,
- kMystDragArea = 11,
+ kMystAreaForward = 0,
+ kMystAreaLeft = 1,
+ kMystAreaRight = 2,
+ kMystAreaDown = 3,
+ kMystAreaUp = 4,
+ kMystAreaAction = 5,
+ kMystAreaVideo = 6,
+ kMystAreaActionSwitch = 7,
+ kMystAreaImageSwitch = 8,
+ kMystAreaSlider = 10,
+ kMystAreaDrag = 11,
kMystVideoInfo = 12,
- kMystHoverArea = 13
+ kMystAreaHover = 13
};
// Myst Resource Flags
@@ -56,16 +56,14 @@ enum {
kMystZipModeEnableFlag = (1 << 3)
};
-class MystResource {
+class MystArea {
public:
- MystResource(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent);
- virtual ~MystResource();
+ MystArea(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent);
+ virtual ~MystArea();
+
virtual const Common::String describe();
void drawBoundingRect();
- MystResource *_parent;
- ResourceType type;
-
bool contains(Common::Point point) { return _rect.contains(point); }
virtual void drawDataToScreen() {}
virtual void handleCardChange() {}
@@ -75,7 +73,7 @@ public:
void setEnabled(bool enabled);
bool isDrawSubimages() { return _flags & kMystSubimageEnableFlag; }
uint16 getDest() { return _dest; }
- virtual uint16 getType8Var() { return 0xFFFF; }
+ virtual uint16 getImageSwitchVar() { return 0xFFFF; }
bool unreachableZipDest();
bool canBecomeActive();
@@ -84,6 +82,8 @@ public:
virtual void handleMouseDown() {}
virtual void handleMouseDrag() {}
+ MystArea *_parent;
+ ResourceType type;
protected:
MohawkEngine_Myst *_vm;
@@ -92,21 +92,25 @@ protected:
uint16 _dest;
};
-class MystResourceType5 : public MystResource {
+class MystAreaAction : public MystArea {
public:
- MystResourceType5(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent);
- void handleMouseUp();
- const Common::String describe();
+ MystAreaAction(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent);
+
+ void handleMouseUp() override;
+ const Common::String describe() override;
protected:
MystScript _script;
};
-class MystResourceType6 : public MystResourceType5 {
+class MystAreaVideo : public MystAreaAction {
public:
- MystResourceType6(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent);
+ MystAreaVideo(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent);
+
VideoHandle playMovie();
- void handleCardChange();
+ VideoHandle getMovieHandle();
+
+ void handleCardChange() override;
bool isPlaying();
void setDirection(int16 direction) { _direction = direction; }
void setBlocking(bool blocking) { _playBlocking = blocking; }
@@ -114,6 +118,7 @@ public:
protected:
static Common::String convertMystVideoName(Common::String name);
+
Common::String _videoFile;
int16 _left;
int16 _top;
@@ -121,58 +126,63 @@ protected:
int16 _direction; // 1 => forward, -1 => backwards
uint16 _playBlocking;
uint16 _playOnCardChange;
- uint16 _u3;
+ uint16 _playRate; // percents
};
-class MystResourceType7 : public MystResource {
+class MystAreaActionSwitch : public MystArea {
public:
- MystResourceType7(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent);
- virtual ~MystResourceType7();
+ MystAreaActionSwitch(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent);
+ virtual ~MystAreaActionSwitch();
- virtual void drawDataToScreen();
- virtual void handleCardChange();
+ virtual void drawDataToScreen() override;
+ virtual void handleCardChange() override;
- virtual void handleMouseUp();
- virtual void handleMouseDown();
+ virtual void handleMouseUp() override;
+ virtual void handleMouseDown() override;
- MystResource *getSubResource(uint16 index) { return _subResources[index]; }
+ MystArea *getSubResource(uint16 index) { return _subResources[index]; }
protected:
- uint16 _var7;
- uint16 _numSubResources;
- Common::Array<MystResource *> _subResources;
+ typedef void (MystArea::*AreaHandler)();
+
+ void doSwitch(AreaHandler handler);
+
+ uint16 _actionSwitchVar;
+ Common::Array<MystArea *> _subResources;
};
-class MystResourceType8 : public MystResourceType7 {
+class MystAreaImageSwitch : public MystAreaActionSwitch {
public:
- MystResourceType8(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent);
- virtual ~MystResourceType8();
- virtual const Common::String describe();
-
- virtual void drawDataToScreen();
- void drawConditionalDataToScreen(uint16 state, bool update = true);
- uint16 getType8Var();
+ MystAreaImageSwitch(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent);
+ virtual ~MystAreaImageSwitch();
struct SubImage {
uint16 wdib;
Common::Rect rect;
- } *_subImages;
+ };
+
+ virtual const Common::String describe() override;
+ virtual void drawDataToScreen() override;
+ void drawConditionalDataToScreen(uint16 state, bool update = true);
+ uint16 getImageSwitchVar() override;
+
+ SubImage getSubImage(uint index) const;
+ void setSubImageRect(uint index, const Common::Rect &rect);
protected:
- uint16 _var8;
- uint16 _numSubImages;
+ uint16 _imageSwitchVar;
+ Common::Array<SubImage> _subImages;
};
-// No MystResourceType9!
-
-class MystResourceType11 : public MystResourceType8 {
+class MystAreaDrag : public MystAreaImageSwitch {
public:
- MystResourceType11(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent);
- virtual ~MystResourceType11();
- const Common::String describe();
+ MystAreaDrag(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent);
+ virtual ~MystAreaDrag();
- void handleMouseDown();
- void handleMouseUp();
- void handleMouseDrag();
+ const Common::String describe() override;
+
+ virtual void handleMouseDown() override;
+ virtual void handleMouseUp() override;
+ virtual void handleMouseDrag() override;
uint16 getList1(uint16 index);
uint16 getList2(uint16 index);
@@ -183,6 +193,8 @@ public:
Common::Point _pos;
protected:
+ typedef Common::Array<uint16> ValueList;
+
void setPositionClipping(const Common::Point &mouse, Common::Point &dest);
uint16 _flagHV;
@@ -197,21 +209,17 @@ protected:
uint16 _mouseDownOpcode;
uint16 _mouseDragOpcode;
uint16 _mouseUpOpcode;
- struct {
- uint16 listCount;
- uint16 *list;
- } _lists[3];
-
+ ValueList _lists[3];
};
-class MystResourceType10 : public MystResourceType11 {
+class MystAreaSlider : public MystAreaDrag {
public:
- MystResourceType10(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent);
- virtual ~MystResourceType10();
+ MystAreaSlider(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent);
+ virtual ~MystAreaSlider();
- void handleMouseDown();
- void handleMouseUp();
- void handleMouseDrag();
+ void handleMouseDown() override;
+ void handleMouseUp() override;
+ void handleMouseDrag() override;
void setStep(uint16 step);
void setPosition(uint16 pos);
void restoreBackground();
@@ -225,10 +233,11 @@ protected:
uint16 _sliderHeight;
};
-class MystResourceType12 : public MystResourceType11 {
+class MystVideoInfo : public MystAreaDrag {
public:
- MystResourceType12(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent);
- virtual ~MystResourceType12();
+ MystVideoInfo(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent);
+ virtual ~MystVideoInfo();
+
void drawFrame(uint16 frame);
bool pullLeverV();
void releaseLeverV();
@@ -243,12 +252,13 @@ private:
uint16 _currentFrame;
};
-class MystResourceType13 : public MystResource {
+class MystAreaHover : public MystArea {
public:
- MystResourceType13(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent);
- const Common::String describe();
+ MystAreaHover(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent);
+
+ const Common::String describe() override;
- void handleMouseUp();
+ void handleMouseUp() override;
void handleMouseEnter();
void handleMouseLeave();
diff --git a/engines/mohawk/myst_graphics.cpp b/engines/mohawk/myst_graphics.cpp
index 49f97cca63..427fba4d22 100644
--- a/engines/mohawk/myst_graphics.cpp
+++ b/engines/mohawk/myst_graphics.cpp
@@ -40,15 +40,14 @@ MystGraphics::MystGraphics(MohawkEngine_Myst* vm) : GraphicsManager(), _vm(vm) {
if (_vm->getFeatures() & GF_ME) {
// High color
- initGraphics(_viewport.width(), _viewport.height(), true, NULL);
+ initGraphics(_viewport.width(), _viewport.height(), true, nullptr);
if (_vm->_system->getScreenFormat().bytesPerPixel == 1)
error("Myst ME requires greater than 256 colors to run");
} else {
// Paletted
initGraphics(_viewport.width(), _viewport.height(), true);
- setBasePalette();
- setPaletteToScreen();
+ clearScreenPalette();
}
_pixelFormat = _vm->_system->getScreenFormat();
@@ -73,7 +72,7 @@ MohawkSurface *MystGraphics::decodeImage(uint16 id) {
// if it's a PICT or WDIB resource. If it's Myst ME it's most likely a PICT, and if it's
// original it's definitely a WDIB. However, Myst ME throws us another curve ball in
// that PICT resources can contain WDIB's instead of PICT's.
- Common::SeekableReadStream *dataStream = NULL;
+ Common::SeekableReadStream *dataStream = nullptr;
if (_vm->getFeatures() & GF_ME && _vm->hasResource(ID_PICT, id)) {
// The PICT resource exists. However, it could still contain a MystBitmap
@@ -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.
@@ -95,7 +94,7 @@ MohawkSurface *MystGraphics::decodeImage(uint16 id) {
dataStream->seek(0);
}
- MohawkSurface *mhkSurface = 0;
+ MohawkSurface *mhkSurface = nullptr;
if (isPict) {
Image::PICTDecoder pict;
@@ -103,12 +102,17 @@ MohawkSurface *MystGraphics::decodeImage(uint16 id) {
if (!pict.loadStream(*dataStream))
error("Could not decode Myst ME PICT");
+ delete dataStream;
+
mhkSurface = new MohawkSurface(pict.getSurface()->convertTo(_pixelFormat));
} else {
mhkSurface = _bmpDecoder->decodeImage(dataStream);
- if (_vm->getFeatures() & GF_ME)
+ if (_vm->getFeatures() & GF_ME) {
mhkSurface->convertToTrueColor();
+ } else {
+ remapSurfaceToSystemPalette(mhkSurface);
+ }
}
assert(mhkSurface);
@@ -202,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();
}
}
@@ -225,9 +229,8 @@ void MystGraphics::copyBackBufferToScreen(Common::Rect r) {
void MystGraphics::runTransition(TransitionType type, Common::Rect rect, uint16 steps, uint16 delay) {
- // Do not artificially delay during transitions
- int oldEnableDrawingTimeSimulation = _enableDrawingTimeSimulation;
- _enableDrawingTimeSimulation = 0;
+ // Transitions are barely visible without adding delays between the draw calls
+ enableDrawingTimeSimulation(true);
switch (type) {
case kTransitionLeftToRight: {
@@ -288,7 +291,10 @@ void MystGraphics::runTransition(TransitionType type, Common::Rect rect, uint16
debugC(kDebugView, "Dissolve");
for (int16 step = 0; step < 8; step++) {
- simulatePreviousDrawDelay(rect);
+ // Only one eighth of the rect pixels are updated by a draw step,
+ // delay by one eighth of the regular time
+ simulatePreviousDrawDelay(Common::Rect(rect.width() / 8, rect.height()));
+
transitionDissolve(rect, step);
}
}
@@ -367,7 +373,7 @@ void MystGraphics::runTransition(TransitionType type, Common::Rect rect, uint16
error("Unknown transition %d", type);
}
- _enableDrawingTimeSimulation = oldEnableDrawingTimeSimulation;
+ enableDrawingTimeSimulation(false);
}
void MystGraphics::transitionDissolve(Common::Rect rect, uint step) {
@@ -639,8 +645,10 @@ void MystGraphics::simulatePreviousDrawDelay(const Common::Rect &dest) {
// Do not draw anything new too quickly after the previous draw call
// so that images stay at least a little while on screen
// This is enabled only for scripted draw calls
- if (time < _nextAllowedDrawTime)
+ if (time < _nextAllowedDrawTime) {
+ debugC(kDebugView, "Delaying draw call by %d ms", _nextAllowedDrawTime - time);
_vm->_system->delayMillis(_nextAllowedDrawTime - time);
+ }
}
// Next draw call allowed at DELAY + AERA * COEFF milliseconds from now
@@ -697,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,
@@ -723,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 6281c94cc8..cd09a53a3a 100644
--- a/engines/mohawk/myst_graphics.h
+++ b/engines/mohawk/myst_graphics.h
@@ -56,13 +56,12 @@ public:
void fadeFromBlack();
void clearScreenPalette();
- void setBasePalette();
void setPaletteToScreen();
const byte *getPalette() const { return _palette; }
protected:
- MohawkSurface *decodeImage(uint16 id);
- MohawkEngine *getVM() { return (MohawkEngine *)_vm; }
+ MohawkSurface *decodeImage(uint16 id) override;
+ MohawkEngine *getVM() override { return (MohawkEngine *)_vm; }
private:
MohawkEngine_Myst *_vm;
@@ -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 15d74a2253..596180ddb2 100644
--- a/engines/mohawk/myst_scripts.cpp
+++ b/engines/mohawk/myst_scripts.cpp
@@ -29,8 +29,8 @@
#include "mohawk/video.h"
#include "common/system.h"
+#include "common/memstream.h"
#include "common/textconsole.h"
-#include "gui/message.h"
namespace Mohawk {
@@ -38,7 +38,7 @@ MystScriptEntry::MystScriptEntry() {
type = kMystScriptNone;
var = 0;
argc = 0;
- argv = 0;
+ argv = nullptr;
resourceId = 0;
u1 = 0;
}
@@ -81,7 +81,7 @@ MystScriptParser::MystScriptParser(MohawkEngine_Myst *vm) :
_vm(vm),
_globals(vm->_gameState->_globals) {
setupCommonOpcodes();
- _invokingResource = NULL;
+ _invokingResource = nullptr;
_savedCardId = 0;
_savedCursorId = 0;
_tempVar = 0;
@@ -154,7 +154,7 @@ void MystScriptParser::setupCommonOpcodes() {
#undef OPCODE
-void MystScriptParser::runScript(MystScript script, MystResource *invokingResource) {
+void MystScriptParser::runScript(MystScript script, MystArea *invokingResource) {
debugC(kDebugScript, "Script Size: %d", script->size());
// Scripted drawing takes more time to simulate older hardware
@@ -260,15 +260,6 @@ bool MystScriptParser::setVarValue(uint16 var, uint16 value) {
return false;
}
-// NOTE: Check to be used on Opcodes where var is thought
-// not to be used. This emits a warning if var is nonzero.
-// It is possible that the opcode does use var 0 in this case,
-// but this will catch the majority of missed cases.
-void MystScriptParser::varUnusedCheck(uint16 op, uint16 var) {
- if (var != 0)
- warning("Opcode %d: Unused Var %d", op, var);
-}
-
void MystScriptParser::animatedUpdate(uint16 argc, uint16 *argv, uint16 delay) {
uint16 argsRead = 0;
@@ -331,7 +322,7 @@ void MystScriptParser::o_changeCardSwitch4(uint16 op, uint16 var, uint16 argc, u
if (value)
_vm->changeToCard(argv[value -1 ], kTransitionDissolve);
- else if (_invokingResource != NULL)
+ else if (_invokingResource != nullptr)
_vm->changeToCard(_invokingResource->getDest(), kTransitionDissolve);
else
warning("Missing invokingResource in altDest call");
@@ -344,7 +335,7 @@ void MystScriptParser::o_changeCardSwitchLtR(uint16 op, uint16 var, uint16 argc,
if (value)
_vm->changeToCard(argv[value -1 ], kTransitionLeftToRight);
- else if (_invokingResource != NULL)
+ else if (_invokingResource != nullptr)
_vm->changeToCard(_invokingResource->getDest(), kTransitionLeftToRight);
else
warning("Missing invokingResource in altDest call");
@@ -357,7 +348,7 @@ void MystScriptParser::o_changeCardSwitchRtL(uint16 op, uint16 var, uint16 argc,
if (value)
_vm->changeToCard(argv[value -1 ], kTransitionRightToLeft);
- else if (_invokingResource != NULL)
+ else if (_invokingResource != nullptr)
_vm->changeToCard(_invokingResource->getDest(), kTransitionRightToLeft);
else
warning("Missing invokingResource in altDest call");
@@ -398,7 +389,7 @@ void MystScriptParser::o_redrawCard(uint16 op, uint16 var, uint16 argc, uint16 *
void MystScriptParser::o_goToDest(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Change To Dest of Invoking Resource", op);
- if (_invokingResource != NULL)
+ if (_invokingResource != nullptr)
_vm->changeToCard(_invokingResource->getDest(), kTransitionCopy);
else
warning("Opcode %d: Missing invokingResource", op);
@@ -407,7 +398,7 @@ void MystScriptParser::o_goToDest(uint16 op, uint16 var, uint16 argc, uint16 *ar
void MystScriptParser::o_goToDestForward(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Change To Dest of Invoking Resource", op);
- if (_invokingResource != NULL)
+ if (_invokingResource != nullptr)
_vm->changeToCard(_invokingResource->getDest(), kTransitionDissolve);
else
warning("Opcode %d: Missing invokingResource", op);
@@ -416,7 +407,7 @@ void MystScriptParser::o_goToDestForward(uint16 op, uint16 var, uint16 argc, uin
void MystScriptParser::o_goToDestLeft(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Change To Dest of Invoking Resource", op);
- if (_invokingResource != NULL)
+ if (_invokingResource != nullptr)
_vm->changeToCard(_invokingResource->getDest(), kTransitionPartToRight);
else
warning("Opcode %d: Missing invokingResource", op);
@@ -425,7 +416,7 @@ void MystScriptParser::o_goToDestLeft(uint16 op, uint16 var, uint16 argc, uint16
void MystScriptParser::o_goToDestRight(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Change To Dest of Invoking Resource", op);
- if (_invokingResource != NULL)
+ if (_invokingResource != nullptr)
_vm->changeToCard(_invokingResource->getDest(), kTransitionPartToLeft);
else
warning("Opcode %d: Missing invokingResource", op);
@@ -434,7 +425,7 @@ void MystScriptParser::o_goToDestRight(uint16 op, uint16 var, uint16 argc, uint1
void MystScriptParser::o_goToDestUp(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Change To Dest of Invoking Resource", op);
- if (_invokingResource != NULL)
+ if (_invokingResource != nullptr)
_vm->changeToCard(_invokingResource->getDest(), kTransitionTopToBottom);
else
warning("Opcode %d: Missing invokingResource", op);
@@ -442,7 +433,10 @@ void MystScriptParser::o_goToDestUp(uint16 op, uint16 var, uint16 argc, uint16 *
void MystScriptParser::o_triggerMovie(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Trigger Type 6 Resource Movie..", op);
- // TODO: If movie has sound, pause background music
+ // The original has code to pause the background music before playing the movie,
+ // if the movie has a sound track, as well as code to resume it afterwards. But since
+ // the movie has not yet been loaded at this point, it is impossible to know
+ // if the movie actually has a sound track. The code is never executed.
int16 direction = 1;
if (argc == 1)
@@ -451,11 +445,9 @@ void MystScriptParser::o_triggerMovie(uint16 op, uint16 var, uint16 argc, uint16
debugC(kDebugScript, "\tDirection: %d", direction);
// Trigger resource 6 movie overriding play direction
- MystResourceType6 *resource = static_cast<MystResourceType6 *>(_invokingResource);
+ MystAreaVideo *resource = getInvokingResource<MystAreaVideo>();
resource->setDirection(direction);
resource->playMovie();
-
- // TODO: If movie has sound, resume background music
}
void MystScriptParser::o_toggleVarNoRedraw(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
@@ -468,7 +460,7 @@ void MystScriptParser::o_drawAreaState(uint16 op, uint16 var, uint16 argc, uint1
debugC(kDebugScript, "Opcode %d: drawAreaState, state: %d", op, argv[0]);
debugC(kDebugScript, "\tVar: %d", var);
- MystResourceType8 *parent = static_cast<MystResourceType8 *>(_invokingResource->_parent);
+ MystAreaImageSwitch *parent = static_cast<MystAreaImageSwitch *>(getInvokingResource<MystArea>()->_parent);
parent->drawConditionalDataToScreen(argv[0]);
}
@@ -517,6 +509,11 @@ void MystScriptParser::o_changeCardPop(uint16 op, uint16 var, uint16 argc, uint1
debugC(kDebugScript, "Opcode %d: Return To Stored Card Id", op);
debugC(kDebugScript, "\tCardId: %d", _savedCardId);
+ if (_savedCardId == 0) {
+ warning("No pushed card to go back to");
+ return;
+ }
+
TransitionType transition = static_cast<TransitionType>(argv[0]);
_vm->changeToCard(_savedCardId, transition);
@@ -531,7 +528,7 @@ void MystScriptParser::o_enableAreas(uint16 op, uint16 var, uint16 argc, uint16
for (uint16 i = 0; i < count; i++) {
debugC(kDebugScript, "Enable hotspot index %d", argv[i + 1]);
- MystResource *resource = 0;
+ MystArea *resource = nullptr;
if (argv[i + 1] == 0xFFFF)
resource = _invokingResource;
else
@@ -556,7 +553,7 @@ void MystScriptParser::o_disableAreas(uint16 op, uint16 var, uint16 argc, uint16
for (uint16 i = 0; i < count; i++) {
debugC(kDebugScript, "Disable hotspot index %d", argv[i + 1]);
- MystResource *resource = 0;
+ MystArea *resource = nullptr;
if (argv[i + 1] == 0xFFFF)
resource = _invokingResource;
else
@@ -587,7 +584,7 @@ void MystScriptParser::o_toggleAreasActivation(uint16 op, uint16 var, uint16 arg
for (uint16 i = 0; i < count; i++) {
debugC(kDebugScript, "Enable/Disable hotspot index %d", argv[i + 1]);
- MystResource *resource = 0;
+ MystArea *resource = nullptr;
if (argv[i + 1] == 0xFFFF)
resource = _invokingResource;
else
@@ -682,82 +679,20 @@ void MystScriptParser::o_copyImageToBackBuffer(uint16 op, uint16 var, uint16 arg
_vm->_gfx->copyImageSectionToBackBuffer(imageId, srcRect, dstRect);
}
-// TODO: Implement common engine function for read and processing of sound blocks
-// for use by this opcode and VIEW sound block.
-// TODO: Though the playSound and PlaySoundBlocking opcodes play sounds immediately,
-// this opcode changes the main background sound playing..
-// Current behavior here and with VIEW sound block is not right as demonstrated
-// by Channelwood Card 3280 (Tank Valve) and water flow sound behavior in pipe
-// on cards leading from shed...
void MystScriptParser::o_changeBackgroundSound(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
- int16 *soundList = NULL;
- uint16 *soundListVolume = NULL;
-
// Used on Stoneship Card 2080
// Used on Channelwood Card 3225 with argc = 8 i.e. Conditional Sound List
- if (argc == 1 || argc == 2 || argc == 8) {
- debugC(kDebugScript, "Opcode %d: Process Sound Block", op);
- uint16 decodeIdx = 0;
-
- int16 soundAction = argv[decodeIdx++];
- uint16 soundVolume = 65535;
- if (soundAction == kMystSoundActionChangeVolume || soundAction > 0) {
- soundVolume = argv[decodeIdx++];
- } else if (soundAction == kMystSoundActionConditional) {
- debugC(kDebugScript, "Conditional sound list");
- uint16 condVar = argv[decodeIdx++];
- uint16 condVarValue = getVar(condVar);
- uint16 condCount = argv[decodeIdx++];
-
- debugC(kDebugScript, "\tcondVar: %d = %d", condVar, condVarValue);
- debugC(kDebugScript, "\tcondCount: %d", condCount);
-
- soundList = new int16[condCount];
- soundListVolume = new uint16[condCount];
-
- if (condVarValue >= condCount)
- warning("Opcode %d: Conditional sound variable outside range", op);
- else {
- for (uint16 i = 0; i < condCount; i++) {
- soundList[i] = argv[decodeIdx++];
- debugC(kDebugScript, "\t\tCondition %d: Action %d", i, soundList[i]);
- if (soundAction == kMystSoundActionChangeVolume || soundAction > 0) {
- soundListVolume[i] = argv[decodeIdx++];
- } else
- soundListVolume[i] = 65535;
- debugC(kDebugScript, "\t\tCondition %d: Volume %d", i, soundListVolume[i]);
- }
-
- soundAction = soundList[condVarValue];
- soundVolume = soundListVolume[condVarValue];
- }
- }
+ debugC(kDebugScript, "Opcode %d: Process Sound Block", op);
- if (soundAction == kMystSoundActionContinue)
- debugC(kDebugScript, "Continue current sound");
- else if (soundAction == kMystSoundActionChangeVolume) {
- debugC(kDebugScript, "Continue current sound, change volume");
- debugC(kDebugScript, "\tVolume: %d", soundVolume);
- _vm->_sound->changeBackgroundVolumeMyst(soundVolume);
- } else if (soundAction == kMystSoundActionStop) {
- debugC(kDebugScript, "Stop sound");
- _vm->_sound->stopBackgroundMyst();
- } else if (soundAction > 0) {
- debugC(kDebugScript, "Play new Sound, change volume");
- debugC(kDebugScript, "\tSound: %d", soundAction);
- debugC(kDebugScript, "\tVolume: %d", soundVolume);
- _vm->_sound->replaceBackgroundMyst(soundAction, soundVolume);
- } else {
- debugC(kDebugScript, "Unknown");
- warning("Unknown sound control value in opcode %d", op);
- }
- } else
- warning("Unknown arg count in opcode %d", op);
+ 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());
- delete[] soundList;
- soundList = NULL;
- delete[] soundListVolume;
- soundListVolume = NULL;
+ MystSoundBlock soundBlock = _vm->readSoundBlock(&readStream);
+ _vm->applySoundBlock(soundBlock);
}
void MystScriptParser::o_soundPlaySwitch(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
diff --git a/engines/mohawk/myst_scripts.h b/engines/mohawk/myst_scripts.h
index 7d8165c762..69052b10f5 100644
--- a/engines/mohawk/myst_scripts.h
+++ b/engines/mohawk/myst_scripts.h
@@ -34,7 +34,7 @@ namespace Mohawk {
#define DECLARE_OPCODE(x) void x(uint16 op, uint16 var, uint16 argc, uint16 *argv)
class MohawkEngine_Myst;
-class MystResource;
+class MystArea;
enum MystScriptType {
kMystScriptNone,
@@ -63,11 +63,11 @@ public:
MystScriptParser(MohawkEngine_Myst *vm);
virtual ~MystScriptParser();
- void runScript(MystScript script, MystResource *invokingResource = NULL);
- void runOpcode(uint16 op, uint16 var = 0, uint16 argc = 0, uint16 *argv = NULL);
+ void runScript(MystScript script, MystArea *invokingResource = nullptr);
+ void runOpcode(uint16 op, uint16 var = 0, uint16 argc = 0, uint16 *argv = nullptr);
const Common::String getOpcodeDesc(uint16 op);
MystScript readScript(Common::SeekableReadStream *stream, MystScriptType type);
- void setInvokingResource(MystResource *resource) { _invokingResource = resource; }
+ void setInvokingResource(MystArea *resource) { _invokingResource = resource; }
virtual void disablePersistentScripts() = 0;
virtual void runPersistentScripts() = 0;
@@ -151,8 +151,6 @@ protected:
Common::Array<MystOpcode *> _opcodes;
- MystResource *_invokingResource;
-
uint16 _savedCardId;
uint16 _savedMapCardId;
uint16 _savedCursorId;
@@ -163,9 +161,25 @@ protected:
static const uint16 _startCard[];
void setupCommonOpcodes();
- void varUnusedCheck(uint16 op, uint16 var);
+
+ template<class T>
+ T *getInvokingResource() const;
+
+private:
+ MystArea *_invokingResource;
};
+template<class T>
+T *MystScriptParser::getInvokingResource() const {
+ T *resource = dynamic_cast<T *>(_invokingResource);
+
+ if (!resource) {
+ error("Invoking resource has unexpected type");
+ }
+
+ return resource;
+}
+
} // End of namespace Mohawk
#undef DECLARE_OPCODE
diff --git a/engines/mohawk/myst_stacks/channelwood.cpp b/engines/mohawk/myst_stacks/channelwood.cpp
index dfa15a9b6c..21c3042359 100644
--- a/engines/mohawk/myst_stacks/channelwood.cpp
+++ b/engines/mohawk/myst_stacks/channelwood.cpp
@@ -170,7 +170,10 @@ uint16 Channelwood::getVar(uint16 var) {
return 0;
case 32: // Sound - Water Flowing in Pipe to Book Room Elevator
- return ((_state.waterValveStates & 0xf8) == 0xb0 && _state.pipeState) ? 1 : 0;
+ if ((_state.waterValveStates & 0xf8) == 0xb0)
+ return _state.pipeState ? 2 : 1;
+
+ return 0;
case 33: // Channelwood Lower Walkway to Upper Walkway Spiral Stair Upper Door State
if (_state.stairsUpperDoorState) {
if (_tempVar == 1)
@@ -360,7 +363,7 @@ void Channelwood::o_drawImageChangeCardAndVolume(uint16 op, uint16 var, uint16 a
void Channelwood::o_waterTankValveOpen(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Do Water Tank Valve Open Animation", op);
- Common::Rect rect = _invokingResource->getRect();
+ Common::Rect rect = getInvokingResource<MystArea>()->getRect();
for (uint i = 0; i < 2; i++)
for (uint16 imageId = 3601; imageId >= 3595; imageId--) {
@@ -374,7 +377,7 @@ void Channelwood::o_waterTankValveOpen(uint16 op, uint16 var, uint16 argc, uint1
void Channelwood::o_leverStartMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Generic lever start move", op);
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
lever->drawFrame(0);
_vm->_cursor->setCursor(700);
_leverPulled = false;
@@ -383,7 +386,7 @@ void Channelwood::o_leverStartMove(uint16 op, uint16 var, uint16 argc, uint16 *a
void Channelwood::o_leverMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Generic lever move", op);
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
if (lever->pullLeverV()) {
if (!_leverPulled) {
@@ -398,7 +401,7 @@ void Channelwood::o_leverMove(uint16 op, uint16 var, uint16 argc, uint16 *argv)
void Channelwood::o_leverMoveFail(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Generic lever move", op);
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
if (lever->pullLeverV()) {
if (!_leverPulled) {
@@ -416,7 +419,7 @@ void Channelwood::o_leverEndMove(uint16 op, uint16 var, uint16 argc, uint16 *arg
debugC(kDebugScript, "Opcode %d: Generic lever end move", op);
// Get current lever frame
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
// Release lever
lever->releaseLeverV();
@@ -436,7 +439,7 @@ void Channelwood::o_leverEndMoveResumeBackground(uint16 op, uint16 var, uint16 a
void Channelwood::o_leverEndMoveWithSound(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
o_leverEndMove(op, var, argc, argv);
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
uint16 soundId = lever->getList3(0);
if (soundId)
_vm->_sound->replaceSoundMyst(soundId);
@@ -458,7 +461,7 @@ void Channelwood::o_leverElev3EndMove(uint16 op, uint16 var, uint16 argc, uint16
void Channelwood::o_pumpLeverMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Pump lever move", op);
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
if (lever->pullLeverV()) {
uint16 soundId = lever->getList2(0);
@@ -472,7 +475,7 @@ void Channelwood::o_pumpLeverMove(uint16 op, uint16 var, uint16 argc, uint16 *ar
void Channelwood::o_pumpLeverEndMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
o_leverEndMove(op, var, argc, argv);
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
uint16 soundId = lever->getList3(0);
if (soundId)
_vm->_sound->replaceBackgroundMyst(soundId, 36864);
@@ -481,7 +484,7 @@ void Channelwood::o_pumpLeverEndMove(uint16 op, uint16 var, uint16 argc, uint16
void Channelwood::o_stairsDoorToggle(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Play stairs door video", op);
- MystResourceType6 *movie = static_cast<MystResourceType6 *>(_invokingResource);
+ MystAreaVideo *movie = getInvokingResource<MystAreaVideo>();
if (_state.stairsUpperDoorState) {
// Close door, play the open movie backwards
@@ -497,7 +500,7 @@ void Channelwood::o_stairsDoorToggle(uint16 op, uint16 var, uint16 argc, uint16
void Channelwood::o_valveHandleMove1(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Valve handle move", op);
- MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *handle = getInvokingResource<MystVideoInfo>();
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
if (handle->getRect().contains(mouse)) {
@@ -513,7 +516,7 @@ void Channelwood::o_valveHandleMove1(uint16 op, uint16 var, uint16 argc, uint16
void Channelwood::o_valveHandleMoveStart1(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Valve handle move start", op);
- MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *handle = getInvokingResource<MystVideoInfo>();
uint16 soundId = handle->getList1(0);
if (soundId)
_vm->_sound->replaceSoundMyst(soundId);
@@ -525,7 +528,7 @@ void Channelwood::o_valveHandleMoveStart1(uint16 op, uint16 var, uint16 argc, ui
void Channelwood::o_valveHandleMoveStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Valve handle move stop", op);
- MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *handle = getInvokingResource<MystVideoInfo>();
// Update state with valve position
if (_tempVar <= 5)
@@ -548,7 +551,7 @@ void Channelwood::o_valveHandleMoveStop(uint16 op, uint16 var, uint16 argc, uint
void Channelwood::o_valveHandleMove2(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Valve handle move", op);
- MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *handle = getInvokingResource<MystVideoInfo>();
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
if (handle->getRect().contains(mouse)) {
@@ -564,7 +567,7 @@ void Channelwood::o_valveHandleMove2(uint16 op, uint16 var, uint16 argc, uint16
void Channelwood::o_valveHandleMoveStart2(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Valve handle move start", op);
- MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *handle = getInvokingResource<MystVideoInfo>();
uint16 soundId = handle->getList1(0);
if (soundId)
_vm->_sound->replaceSoundMyst(soundId);
@@ -576,7 +579,7 @@ void Channelwood::o_valveHandleMoveStart2(uint16 op, uint16 var, uint16 argc, ui
void Channelwood::o_valveHandleMove3(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Valve handle move", op);
- MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *handle = getInvokingResource<MystVideoInfo>();
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
if (handle->getRect().contains(mouse)) {
@@ -592,7 +595,7 @@ void Channelwood::o_valveHandleMove3(uint16 op, uint16 var, uint16 argc, uint16
void Channelwood::o_valveHandleMoveStart3(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Valve handle move start", op);
- MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *handle = getInvokingResource<MystVideoInfo>();
uint16 soundId = handle->getList1(0);
if (soundId)
_vm->_sound->replaceSoundMyst(soundId);
@@ -618,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);
}
}
@@ -677,13 +688,13 @@ void Channelwood::o_hologramTemple(uint16 op, uint16 var, uint16 argc, uint16 *a
void Channelwood::o_executeMouseUp(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Execute mouse up", op);
- MystResourceType5 *resource = static_cast<MystResourceType5 *>(_vm->_resources[argv[0]]);
+ MystArea *resource = _vm->getViewResource<MystArea>(argv[0]);
resource->handleMouseUp();
}
void Channelwood::o_waterTankValveClose(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Do Water Tank Valve Close Animation", op);
- Common::Rect rect = _invokingResource->getRect();
+ Common::Rect rect = getInvokingResource<MystArea>()->getRect();
for (uint i = 0; i < 2; i++)
for (uint16 imageId = 3595; imageId <= 3601; imageId++) {
@@ -744,13 +755,14 @@ void Channelwood::o_soundReplace(uint16 op, uint16 var, uint16 argc, uint16 *arg
uint16 soundId = argv[0];
- // TODO: If is foreground playing
- _vm->_sound->replaceSoundMyst(soundId);
+ if (!_vm->_sound->isPlaying()) {
+ _vm->_sound->replaceSoundMyst(soundId);
+ }
}
void Channelwood::o_lever_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Generic lever init", op);
- _leverAction = static_cast<MystResourceType5 *>(_invokingResource);
+ _leverAction = getInvokingResource<MystArea>();
}
void Channelwood::o_pipeValve_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
diff --git a/engines/mohawk/myst_stacks/channelwood.h b/engines/mohawk/myst_stacks/channelwood.h
index bd5d7ffe94..ac875e52d8 100644
--- a/engines/mohawk/myst_stacks/channelwood.h
+++ b/engines/mohawk/myst_stacks/channelwood.h
@@ -40,16 +40,16 @@ public:
Channelwood(MohawkEngine_Myst *vm);
~Channelwood();
- void disablePersistentScripts();
- void runPersistentScripts();
+ void disablePersistentScripts() override;
+ void runPersistentScripts() override;
private:
void setupOpcodes();
- uint16 getVar(uint16 var);
- void toggleVar(uint16 var);
- bool setVarValue(uint16 var, uint16 value);
+ uint16 getVar(uint16 var) override;
+ void toggleVar(uint16 var) override;
+ bool setVarValue(uint16 var, uint16 value) override;
- virtual uint16 getMap() { return 9932; }
+ virtual uint16 getMap() override { return 9932; }
DECLARE_OPCODE(o_bridgeToggle);
DECLARE_OPCODE(o_pipeExtend);
@@ -94,7 +94,7 @@ private:
uint16 _doorOpened; // 68
bool _leverPulled;
- MystResourceType5 *_leverAction; // 72
+ MystArea *_leverAction; // 72
bool pipeChangeValve(bool open, uint16 mask);
};
diff --git a/engines/mohawk/myst_stacks/credits.cpp b/engines/mohawk/myst_stacks/credits.cpp
index b9ff8b26aa..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 {
@@ -37,6 +36,7 @@ namespace MystStacks {
Credits::Credits(MohawkEngine_Myst *vm) : MystScriptParser(vm) {
setupOpcodes();
+ _curImage = 0;
}
Credits::~Credits() {
@@ -66,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/credits.h b/engines/mohawk/myst_stacks/credits.h
index 3c0f969203..c2c20372bd 100644
--- a/engines/mohawk/myst_stacks/credits.h
+++ b/engines/mohawk/myst_stacks/credits.h
@@ -40,12 +40,12 @@ public:
Credits(MohawkEngine_Myst *vm);
~Credits();
- void disablePersistentScripts();
- void runPersistentScripts();
+ void disablePersistentScripts() override;
+ void runPersistentScripts() override;
private:
void setupOpcodes();
- uint16 getVar(uint16 var);
+ uint16 getVar(uint16 var) override;
DECLARE_OPCODE(o_runCredits);
diff --git a/engines/mohawk/myst_stacks/demo.h b/engines/mohawk/myst_stacks/demo.h
index f19b9a6c2c..64a392502f 100644
--- a/engines/mohawk/myst_stacks/demo.h
+++ b/engines/mohawk/myst_stacks/demo.h
@@ -40,8 +40,8 @@ public:
Demo(MohawkEngine_Myst *vm);
~Demo();
- void disablePersistentScripts();
- void runPersistentScripts();
+ void disablePersistentScripts() override;
+ void runPersistentScripts() override;
private:
void setupOpcodes();
diff --git a/engines/mohawk/myst_stacks/dni.h b/engines/mohawk/myst_stacks/dni.h
index 3dc4645bd3..1a5f0911f9 100644
--- a/engines/mohawk/myst_stacks/dni.h
+++ b/engines/mohawk/myst_stacks/dni.h
@@ -40,12 +40,12 @@ public:
Dni(MohawkEngine_Myst *vm);
~Dni();
- void disablePersistentScripts();
- void runPersistentScripts();
+ void disablePersistentScripts() override;
+ void runPersistentScripts() override;
private:
void setupOpcodes();
- uint16 getVar(uint16 var);
+ uint16 getVar(uint16 var) override;
void atrus_run();
void loopVideo_run();
diff --git a/engines/mohawk/myst_stacks/intro.cpp b/engines/mohawk/myst_stacks/intro.cpp
index dc66984398..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 {
@@ -170,7 +168,7 @@ void Intro::mystLinkBook_run() {
void Intro::o_mystLinkBook_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Myst link book init", op);
- _linkBookMovie = static_cast<MystResourceType6 *>(_invokingResource);
+ _linkBookMovie = getInvokingResource<MystAreaVideo>();
_startTime = 1;
_linkBookRunning = true;
}
diff --git a/engines/mohawk/myst_stacks/intro.h b/engines/mohawk/myst_stacks/intro.h
index a6c4a594d2..0095706795 100644
--- a/engines/mohawk/myst_stacks/intro.h
+++ b/engines/mohawk/myst_stacks/intro.h
@@ -29,7 +29,7 @@
namespace Mohawk {
-class MystResourceType6;
+class MystAreaVideo;
struct MystScriptEntry;
namespace MystStacks {
@@ -41,12 +41,12 @@ public:
Intro(MohawkEngine_Myst *vm);
~Intro();
- void disablePersistentScripts();
- void runPersistentScripts();
+ void disablePersistentScripts() override;
+ void runPersistentScripts() override;
private:
void setupOpcodes();
- uint16 getVar(uint16 var);
+ uint16 getVar(uint16 var) override;
DECLARE_OPCODE(o_useLinkBook);
@@ -60,7 +60,7 @@ private:
uint16 _introStep;
bool _linkBookRunning;
- MystResourceType6 *_linkBookMovie;
+ MystAreaVideo *_linkBookMovie;
};
} // End of 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/makingof.h b/engines/mohawk/myst_stacks/makingof.h
index 79ef913bcf..41f91bc3fa 100644
--- a/engines/mohawk/myst_stacks/makingof.h
+++ b/engines/mohawk/myst_stacks/makingof.h
@@ -40,8 +40,8 @@ public:
MakingOf(MohawkEngine_Myst *vm);
~MakingOf();
- void disablePersistentScripts();
- void runPersistentScripts();
+ void disablePersistentScripts() override;
+ void runPersistentScripts() override;
private:
void setupOpcodes();
diff --git a/engines/mohawk/myst_stacks/mechanical.cpp b/engines/mohawk/myst_stacks/mechanical.cpp
index ffcaa226c6..3324c9a22d 100644
--- a/engines/mohawk/myst_stacks/mechanical.cpp
+++ b/engines/mohawk/myst_stacks/mechanical.cpp
@@ -40,6 +40,9 @@ Mechanical::Mechanical(MohawkEngine_Myst *vm) :
setupOpcodes();
_elevatorGoingMiddle = false;
+ _elevatorPosition = 0;
+
+ _crystalLit = 0;
_mystStaircaseState = false;
_fortressPosition = 0;
@@ -277,7 +280,7 @@ void Mechanical::o_throneEnablePassage(uint16 op, uint16 var, uint16 argc, uint1
void Mechanical::o_birdCrankStart(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Mechanical bird crank start", op);
- MystResourceType11 *crank = static_cast<MystResourceType11 *>(_invokingResource);
+ MystAreaDrag *crank = getInvokingResource<MystAreaDrag>();
uint16 crankSoundId = crank->getList2(0);
_vm->_sound->replaceSoundMyst(crankSoundId, Audio::Mixer::kMaxChannelVolume, true);
@@ -285,16 +288,16 @@ void Mechanical::o_birdCrankStart(uint16 op, uint16 var, uint16 argc, uint16 *ar
_birdSingEndTime = 0;
_birdCrankStartTime = _vm->_system->getMillis();
- MystResourceType6 *crankMovie = static_cast<MystResourceType6 *>(crank->getSubResource(0));
+ MystAreaVideo *crankMovie = static_cast<MystAreaVideo *>(crank->getSubResource(0));
crankMovie->playMovie();
}
void Mechanical::o_birdCrankStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Mechanical bird crank stop", op);
- MystResourceType11 *crank = static_cast<MystResourceType11 *>(_invokingResource);
+ MystAreaDrag *crank = getInvokingResource<MystAreaDrag>();
- MystResourceType6 *crankMovie = static_cast<MystResourceType6 *>(crank->getSubResource(0));
+ MystAreaVideo *crankMovie = static_cast<MystAreaVideo *>(crank->getSubResource(0));
crankMovie->pauseMovie(true);
uint16 crankSoundId = crank->getList2(1);
@@ -334,7 +337,7 @@ void Mechanical::o_fortressStaircaseMovie(uint16 op, uint16 var, uint16 argc, ui
void Mechanical::o_elevatorRotationStart(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Elevator rotation lever start", op);
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
lever->drawFrame(0);
_elevatorRotationLeverMoving = true;
@@ -349,7 +352,7 @@ void Mechanical::o_elevatorRotationMove(uint16 op, uint16 var, uint16 argc, uint
debugC(kDebugScript, "Opcode %d: Elevator rotation lever move", op);
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
// Make the handle follow the mouse
int16 maxStep = lever->getNumFrames() - 1;
@@ -367,7 +370,7 @@ void Mechanical::o_elevatorRotationStop(uint16 op, uint16 var, uint16 argc, uint
debugC(kDebugScript, "Opcode %d: Elevator rotation lever stop", op);
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
// Get current lever frame
int16 maxStep = lever->getNumFrames() - 1;
@@ -416,7 +419,7 @@ void Mechanical::o_fortressRotationSpeedStart(uint16 op, uint16 var, uint16 argc
_vm->_cursor->setCursor(700);
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
lever->drawFrame(0);
}
@@ -424,7 +427,7 @@ void Mechanical::o_fortressRotationSpeedMove(uint16 op, uint16 var, uint16 argc,
debugC(kDebugScript, "Opcode %d Fortress rotation speed lever move", op);
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
// Make the handle follow the mouse
int16 maxStep = lever->getNumFrames() - 1;
@@ -441,7 +444,7 @@ void Mechanical::o_fortressRotationSpeedMove(uint16 op, uint16 var, uint16 argc,
void Mechanical::o_fortressRotationSpeedStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d Fortress rotation speed lever stop", op);
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
// Release lever
for (int i = _fortressRotationSpeed; i >= 0; i--) {
@@ -459,7 +462,7 @@ void Mechanical::o_fortressRotationBrakeStart(uint16 op, uint16 var, uint16 argc
_vm->_cursor->setCursor(700);
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
lever->drawFrame(_fortressRotationBrake);
}
@@ -467,7 +470,7 @@ void Mechanical::o_fortressRotationBrakeMove(uint16 op, uint16 var, uint16 argc,
debugC(kDebugScript, "Opcode %d Fortress rotation brake lever move", op);
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
// Make the handle follow the mouse
int16 maxStep = lever->getNumFrames() - 1;
@@ -484,7 +487,7 @@ void Mechanical::o_fortressRotationBrakeMove(uint16 op, uint16 var, uint16 argc,
void Mechanical::o_fortressRotationBrakeStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d Fortress rotation brake lever stop", op);
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
lever->drawFrame(_fortressRotationBrake);
_vm->checkCursorHints();
@@ -495,7 +498,7 @@ void Mechanical::o_fortressSimulationSpeedStart(uint16 op, uint16 var, uint16 ar
_vm->_cursor->setCursor(700);
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
lever->drawFrame(0);
}
@@ -503,7 +506,7 @@ void Mechanical::o_fortressSimulationSpeedMove(uint16 op, uint16 var, uint16 arg
debugC(kDebugScript, "Opcode %d Fortress rotation simulator speed lever move", op);
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
// Make the handle follow the mouse
int16 maxStep = lever->getNumFrames() - 1;
@@ -520,7 +523,7 @@ void Mechanical::o_fortressSimulationSpeedMove(uint16 op, uint16 var, uint16 arg
void Mechanical::o_fortressSimulationSpeedStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d Fortress rotation simulator speed lever stop", op);
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
// Release lever
for (int i = _fortressSimulationSpeed; i >= 0; i--) {
@@ -538,7 +541,7 @@ void Mechanical::o_fortressSimulationBrakeStart(uint16 op, uint16 var, uint16 ar
_vm->_cursor->setCursor(700);
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
lever->drawFrame(_fortressSimulationBrake);
}
@@ -546,7 +549,7 @@ void Mechanical::o_fortressSimulationBrakeMove(uint16 op, uint16 var, uint16 arg
debugC(kDebugScript, "Opcode %d Fortress rotation simulator brake lever move", op);
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
// Make the handle follow the mouse
int16 maxStep = lever->getNumFrames() - 1;
@@ -563,7 +566,7 @@ void Mechanical::o_fortressSimulationBrakeMove(uint16 op, uint16 var, uint16 arg
void Mechanical::o_fortressSimulationBrakeStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d Fortress rotation simulator brake lever stop", op);
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
lever->drawFrame(_fortressSimulationBrake);
_vm->checkCursorHints();
@@ -664,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
@@ -737,7 +740,7 @@ void Mechanical::o_throne_init(uint16 op, uint16 var, uint16 argc, uint16 *argv)
// Used on Card 6238 (Sirrus' Throne) and Card 6027 (Achenar's Throne)
debugC(kDebugScript, "Opcode %d: Brother throne init", op);
- _invokingResource->setEnabled(getVar(var));
+ getInvokingResource<MystArea>()->setEnabled(getVar(var));
}
void Mechanical::o_fortressStaircase_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
@@ -763,13 +766,13 @@ void Mechanical::o_bird_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
_birdSinging = false;
_birdSingEndTime = 0;
- _bird = static_cast<MystResourceType6 *>(_invokingResource);
+ _bird = getInvokingResource<MystAreaVideo>();
}
void Mechanical::o_snakeBox_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Snake box init", op);
- _snakeBox = static_cast<MystResourceType6 *>(_invokingResource);
+ _snakeBox = getInvokingResource<MystAreaVideo>();
}
void Mechanical::elevatorRotation_run() {
@@ -798,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();
@@ -872,7 +875,7 @@ void Mechanical::fortressRotation_run() {
void Mechanical::o_fortressRotation_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Fortress rotation init", op);
- _fortressRotationGears = static_cast<MystResourceType6 *>(_invokingResource);
+ _fortressRotationGears = getInvokingResource<MystAreaVideo>();
VideoHandle gears = _fortressRotationGears->playMovie();
gears->setLooping(true);
@@ -938,13 +941,22 @@ void Mechanical::fortressSimulation_run() {
holo->setLooping(true);
holo->setRate(0);
+ // HACK: Support negative rates with edit lists
+ _fortressSimulationHoloRate = 0;
+ // END HACK
+
_vm->_cursor->showCursor();
_fortressSimulationInit = false;
} else {
- VideoHandle holo = _fortressSimulationHolo->playMovie();
+ VideoHandle holo = _fortressSimulationHolo->getMovieHandle();
double oldRate = holo->getRate().toDouble();
+
+ // HACK: Support negative rates with edit lists
+ oldRate = _fortressSimulationHoloRate;
+ // END HACK
+
uint32 moviePosition = Audio::Timestamp(holo->getTime(), 600).totalNumberOfFrames();
int32 positionInQuarter = 900 - (moviePosition + 900) % 1800;
@@ -978,7 +990,26 @@ void Mechanical::fortressSimulation_run() {
newRate = CLIP<double>(newRate, -2.5, 2.5);
- holo->setRate(Common::Rational((int)(newRate * 1000.0), 1000));
+ // HACK: Support negative rates with edit lists
+
+ // Our current QuickTime implementation does not support negative
+ // playback rates for movies using edit lists.
+ // The fortress rotation simulator movie this code handles is the
+ // only movie in the game requiring that feature.
+
+ // This hack approximates the next frame to display when the rate
+ // is negative, and seeks to it. It's not intended to be precise.
+
+ _fortressSimulationHoloRate = newRate;
+
+ if (_fortressSimulationHoloRate < 0) {
+ double newMoviePosition = moviePosition + _fortressSimulationHoloRate * 10;
+ holo->setRate(0);
+ holo->seek(Audio::Timestamp(0, (uint)newMoviePosition, 600));
+ } else {
+ holo->setRate(Common::Rational((int)(newRate * 1000.0), 1000));
+ }
+ // END HACK
_gearsWereRunning = true;
} else if (_gearsWereRunning) {
@@ -986,6 +1017,11 @@ void Mechanical::fortressSimulation_run() {
uint16 simulationPosition = (moviePosition + 900) / 1800 % 4;
holo->setRate(0);
+
+ // HACK: Support negative rates with edit lists
+ _fortressSimulationHoloRate = 0;
+ // END HACK
+
holo->seek(Audio::Timestamp(0, 1800 * simulationPosition, 600));
_vm->_sound->playSoundBlocking( _fortressRotationSounds[simulationPosition]);
@@ -997,7 +1033,7 @@ void Mechanical::fortressSimulation_run() {
void Mechanical::o_fortressSimulation_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Fortress rotation simulator init", op);
- _fortressSimulationHolo = static_cast<MystResourceType6 *>(_invokingResource);
+ _fortressSimulationHolo = getInvokingResource<MystAreaVideo>();
_fortressSimulationStartSound1 = argv[0];
_fortressSimulationStartSound2 = argv[1];
@@ -1019,7 +1055,7 @@ void Mechanical::o_fortressSimulation_init(uint16 op, uint16 var, uint16 argc, u
void Mechanical::o_fortressSimulationStartup_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Fortress rotation simulator startup init", op);
- _fortressSimulationStartup = static_cast<MystResourceType6 *>(_invokingResource);
+ _fortressSimulationStartup = getInvokingResource<MystAreaVideo>();
}
} // End of namespace MystStacks
diff --git a/engines/mohawk/myst_stacks/mechanical.h b/engines/mohawk/myst_stacks/mechanical.h
index 6360b2be2d..aae02df433 100644
--- a/engines/mohawk/myst_stacks/mechanical.h
+++ b/engines/mohawk/myst_stacks/mechanical.h
@@ -40,16 +40,16 @@ public:
Mechanical(MohawkEngine_Myst *vm);
~Mechanical();
- void disablePersistentScripts();
- void runPersistentScripts();
+ void disablePersistentScripts() override;
+ void runPersistentScripts() override;
private:
void setupOpcodes();
- uint16 getVar(uint16 var);
- void toggleVar(uint16 var);
- bool setVarValue(uint16 var, uint16 value);
+ uint16 getVar(uint16 var) override;
+ void toggleVar(uint16 var) override;
+ bool setVarValue(uint16 var, uint16 value) override;
- virtual uint16 getMap() { return 9931; }
+ virtual uint16 getMap() override { return 9931; }
void birdSing_run();
void elevatorRotation_run();
@@ -109,7 +109,7 @@ private:
uint16 _fortressRotationBrake; // 80
uint16 _fortressPosition; // 82
uint16 _fortressRotationSounds[4]; // 86 to 92
- MystResourceType6 *_fortressRotationGears; // 172
+ MystAreaVideo *_fortressRotationGears; // 172
bool _fortressRotationShortMovieWorkaround;
uint32 _fortressRotationShortMovieCount;
@@ -121,8 +121,12 @@ private:
uint16 _fortressSimulationBrake; // 98
uint16 _fortressSimulationStartSound1; // 102
uint16 _fortressSimulationStartSound2; // 100
- MystResourceType6 *_fortressSimulationHolo; // 160
- MystResourceType6 *_fortressSimulationStartup; // 164
+ MystAreaVideo *_fortressSimulationHolo; // 160
+ MystAreaVideo *_fortressSimulationStartup; // 164
+
+ // HACK: Support negative rates with edit lists
+ double _fortressSimulationHoloRate;
+ // END HACK
uint16 _elevatorGoingDown; // 112
@@ -143,10 +147,10 @@ private:
bool _birdSinging; // 144
uint32 _birdCrankStartTime; // 136
uint32 _birdSingEndTime; // 140
- MystResourceType6 *_bird; // 152
+ MystAreaVideo *_bird; // 152
- MystResourceType6 *_snakeBox; // 156
+ MystAreaVideo *_snakeBox; // 156
};
} // End of namespace MystStacks
diff --git a/engines/mohawk/myst_stacks/myst.cpp b/engines/mohawk/myst_stacks/myst.cpp
index 98f0aa5349..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 {
@@ -50,14 +48,16 @@ Myst::Myst(MohawkEngine_Myst *vm) :
_libraryBookcaseChanged = false;
_dockVaultState = 0;
_cabinDoorOpened = 0;
+ _cabinHandleDown = 0;
_cabinMatchState = 2;
+ _cabinGaugeMovieEnabled = false;
_matchBurning = false;
- _tree = 0;
- _treeAlcove = 0;
+ _tree = nullptr;
+ _treeAlcove = nullptr;
_treeStopped = false;
_treeMinPosition = 0;
_imagerValidationStep = 0;
- _observatoryCurrentSlider = 0;
+ _observatoryCurrentSlider = nullptr;
_butterfliesMoviePlayed = false;
_state.treeLastMoveTime = _vm->_system->getMillis();
}
@@ -626,7 +626,7 @@ uint16 Myst::getVar(uint16 var) {
case 307: // Cabin Boiler Fully Pressurized
return _state.cabinPilotLightLit == 1 && _state.cabinValvePosition > 12;
case 308: // Cabin handle position
- return 0; // Not implemented in the original
+ return _cabinHandleDown;
default:
return MystScriptParser::getVar(var);
}
@@ -764,6 +764,9 @@ bool Myst::setVarValue(uint16 var, uint16 value) {
case 304: // Myst Library Image Present on Tower Rotation Map
_towerRotationMapInitialized = value;
break;
+ case 308: // Cabin handle position
+ _cabinHandleDown = value;
+ break;
case 309: // Tree stopped
_treeStopped = value;
break;
@@ -860,14 +863,14 @@ void Myst::o_fireplaceToggleButton(uint16 op, uint16 var, uint16 argc, uint16 *a
if (line & bitmask) {
// Unset button
for (uint i = 4795; i >= 4779; i--) {
- _vm->_gfx->copyImageToScreen(i, _invokingResource->getRect());
+ _vm->_gfx->copyImageToScreen(i, getInvokingResource<MystArea>()->getRect());
_vm->_system->updateScreen();
}
_fireplaceLines[var - 17] &= ~bitmask;
} else {
// Set button
for (uint i = 4779; i <= 4795; i++) {
- _vm->_gfx->copyImageToScreen(i, _invokingResource->getRect());
+ _vm->_gfx->copyImageToScreen(i, getInvokingResource<MystArea>()->getRect());
_vm->_system->updateScreen();
}
_fireplaceLines[var - 17] |= bitmask;
@@ -1251,7 +1254,7 @@ void Myst::o_imagerPlayButton(uint16 op, uint16 var, uint16 argc, uint16 *argv)
void Myst::o_imagerEraseButton(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Imager erase button", op);
- _imagerRedButton = static_cast<MystResourceType8 *>(_invokingResource->_parent);
+ _imagerRedButton = static_cast<MystAreaImageSwitch *>(getInvokingResource<MystArea>()->_parent);
for (uint i = 0; i < 4; i++)
_imagerSound[i] = argv[i];
_imagerValidationCard = argv[4];
@@ -1351,7 +1354,7 @@ void Myst::o_towerElevatorAnimation(uint16 op, uint16 var, uint16 argc, uint16 *
void Myst::o_generatorButtonPressed(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Generator button pressed", op);
- MystResource *button = _invokingResource->_parent;
+ MystArea *button = getInvokingResource<MystArea>()->_parent;
generatorRedrawRocket();
@@ -1376,7 +1379,7 @@ void Myst::o_generatorButtonPressed(uint16 op, uint16 var, uint16 argc, uint16 *
if (_generatorVoltage)
_vm->_sound->replaceSoundMyst(6297);
else {
- _vm->_sound->replaceSoundMyst(7297); // TODO: Replace with play sound and replace background 4297
+ _vm->_sound->replaceSoundMyst(7297);
_vm->_sound->replaceBackgroundMyst(4297);
}
@@ -1385,7 +1388,7 @@ void Myst::o_generatorButtonPressed(uint16 op, uint16 var, uint16 argc, uint16 *
}
// Redraw button
- _vm->redrawArea(button->getType8Var());
+ _vm->redrawArea(button->getImageSwitchVar());
// Blow breaker
if (_state.generatorVoltage > 59)
@@ -1398,8 +1401,8 @@ void Myst::generatorRedrawRocket() {
_vm->redrawArea(97);
}
-void Myst::generatorButtonValue(MystResource *button, uint16 &mask, uint16 &value) {
- switch (button->getType8Var()) {
+void Myst::generatorButtonValue(MystArea *button, uint16 &mask, uint16 &value) {
+ switch (button->getImageSwitchVar()) {
case 52: // Generator Switch #1
mask = 1;
value = 10;
@@ -1466,7 +1469,7 @@ void Myst::o_cabinSafeHandleStartMove(uint16 op, uint16 var, uint16 argc, uint16
debugC(kDebugScript, "Opcode %d: Cabin safe handle start move", op);
// Used on Card 4100
- MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *handle = getInvokingResource<MystVideoInfo>();
handle->drawFrame(0);
_vm->_cursor->setCursor(700);
_tempVar = 0;
@@ -1476,7 +1479,7 @@ void Myst::o_cabinSafeHandleMove(uint16 op, uint16 var, uint16 argc, uint16 *arg
debugC(kDebugScript, "Opcode %d: Cabin safe handle move", op);
// Used on Card 4100
- MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *handle = getInvokingResource<MystVideoInfo>();
if (handle->pullLeverV()) {
// Sound not played yet
@@ -1506,7 +1509,7 @@ void Myst::o_cabinSafeHandleEndMove(uint16 op, uint16 var, uint16 argc, uint16 *
debugC(kDebugScript, "Opcode %d: Cabin safe handle end move", op);
// Used on Card 4100
- MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *handle = getInvokingResource<MystVideoInfo>();
handle->drawFrame(0);
_vm->checkCursorHints();
}
@@ -1804,7 +1807,7 @@ void Myst::o_observatoryTimeSliderMove(uint16 op, uint16 var, uint16 argc, uint1
void Myst::o_circuitBreakerStartMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Circuit breaker start move", op);
- MystResourceType12 *breaker = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *breaker = getInvokingResource<MystVideoInfo>();
breaker->drawFrame(0);
_vm->_cursor->setCursor(700);
_tempVar = 0;
@@ -1813,7 +1816,7 @@ void Myst::o_circuitBreakerStartMove(uint16 op, uint16 var, uint16 argc, uint16
void Myst::o_circuitBreakerMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Circuit breaker move", op);
- MystResourceType12 *breaker = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *breaker = getInvokingResource<MystVideoInfo>();
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
int16 maxStep = breaker->getStepsV() - 1;
@@ -1828,7 +1831,7 @@ void Myst::o_circuitBreakerMove(uint16 op, uint16 var, uint16 argc, uint16 *argv
// Breaker switched
if (step == maxStep) {
// Choose breaker
- if (breaker->getType8Var() == 93) {
+ if (breaker->getImageSwitchVar() == 93) {
// Voltage is still too high or not broken
if (_state.generatorVoltage > 59 || _state.generatorBreakers != 1) {
uint16 soundId = breaker->getList2(1);
@@ -1864,8 +1867,8 @@ void Myst::o_circuitBreakerMove(uint16 op, uint16 var, uint16 argc, uint16 *argv
void Myst::o_circuitBreakerEndMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Circuit breaker end move", op);
- MystResourceType12 *breaker = static_cast<MystResourceType12 *>(_invokingResource);
- _vm->redrawArea(breaker->getType8Var());
+ MystVideoInfo *breaker = getInvokingResource<MystVideoInfo>();
+ _vm->redrawArea(breaker->getImageSwitchVar());
_vm->checkCursorHints();
}
@@ -2138,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);
}
@@ -2187,22 +2190,22 @@ void Myst::o_rocketSoundSliderEndMove(uint16 op, uint16 var, uint16 argc, uint16
if (_state.generatorVoltage == 59 && !_state.generatorBreakers && _rocketSliderSound)
_vm->_sound->stopSound();
- if (_invokingResource == _rocketSlider1)
+ if (getInvokingResource<MystArea>() == _rocketSlider1)
_state.rocketSliderPosition[0] = _rocketSlider1->_pos.y;
- else if (_invokingResource == _rocketSlider2)
+ else if (getInvokingResource<MystArea>() == _rocketSlider2)
_state.rocketSliderPosition[1] = _rocketSlider2->_pos.y;
- else if (_invokingResource == _rocketSlider3)
+ else if (getInvokingResource<MystArea>() == _rocketSlider3)
_state.rocketSliderPosition[2] = _rocketSlider3->_pos.y;
- else if (_invokingResource == _rocketSlider4)
+ else if (getInvokingResource<MystArea>() == _rocketSlider4)
_state.rocketSliderPosition[3] = _rocketSlider4->_pos.y;
- else if (_invokingResource == _rocketSlider5)
+ else if (getInvokingResource<MystArea>() == _rocketSlider5)
_state.rocketSliderPosition[4] = _rocketSlider5->_pos.y;
_vm->_sound->resumeBackgroundMyst();
}
void Myst::rocketSliderMove() {
- MystResourceType10 *slider = static_cast<MystResourceType10 *>(_invokingResource);
+ MystAreaSlider *slider = getInvokingResource<MystAreaSlider>();
if (_state.generatorVoltage == 59 && !_state.generatorBreakers) {
uint16 soundId = rocketSliderGetSound(slider->_pos.y);
@@ -2262,7 +2265,7 @@ void Myst::rocketCheckSolution() {
if (solved) {
// Reset lever position
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
lever->drawFrame(0);
// Book appearing
@@ -2299,17 +2302,17 @@ void Myst::rocketCheckSolution() {
void Myst::o_rocketPianoStart(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Rocket piano start move", op);
- MystResourceType11 *key = static_cast<MystResourceType11 *>(_invokingResource);
+ MystAreaDrag *key = getInvokingResource<MystAreaDrag>();
// What the hell??
- Common::Rect src = key->_subImages[1].rect;
- Common::Rect rect = key->_subImages[0].rect;
+ Common::Rect src = key->getSubImage(1).rect;
+ Common::Rect rect = key->getSubImage(0).rect;
Common::Rect dest = rect;
dest.top = 332 - rect.bottom;
dest.bottom = 332 - rect.top;
// Draw pressed piano key
- _vm->_gfx->copyImageSectionToScreen(key->_subImages[1].wdib, src, dest);
+ _vm->_gfx->copyImageSectionToScreen(key->getSubImage(1).wdib, src, dest);
_vm->_system->updateScreen();
// Play note
@@ -2326,29 +2329,29 @@ void Myst::o_rocketPianoMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
Common::Rect piano = Common::Rect(85, 123, 460, 270);
// Unpress previous key
- MystResourceType11 *key = static_cast<MystResourceType11 *>(_invokingResource);
+ MystAreaDrag *key = getInvokingResource<MystAreaDrag>();
- Common::Rect src = key->_subImages[0].rect;
+ Common::Rect src = key->getSubImage(0).rect;
Common::Rect dest = src;
dest.top = 332 - src.bottom;
dest.bottom = 332 - src.top;
// Draw unpressed piano key
- _vm->_gfx->copyImageSectionToScreen(key->_subImages[0].wdib, src, dest);
+ _vm->_gfx->copyImageSectionToScreen(key->getSubImage(0).wdib, src, dest);
if (piano.contains(mouse)) {
- MystResource *resource = _vm->updateCurrentResource();
- if (resource && resource->type == kMystDragArea) {
+ MystArea *resource = _vm->updateCurrentResource();
+ if (resource && resource->type == kMystAreaDrag) {
// Press new key
- key = static_cast<MystResourceType11 *>(resource);
- src = key->_subImages[1].rect;
- Common::Rect rect = key->_subImages[0].rect;
+ key = static_cast<MystAreaDrag *>(resource);
+ src = key->getSubImage(1).rect;
+ Common::Rect rect = key->getSubImage(0).rect;
dest = rect;
dest.top = 332 - rect.bottom;
dest.bottom = 332 - rect.top;
// Draw pressed piano key
- _vm->_gfx->copyImageSectionToScreen(key->_subImages[1].wdib, src, dest);
+ _vm->_gfx->copyImageSectionToScreen(key->getSubImage(1).wdib, src, dest);
// Play note
if (_state.generatorVoltage == 59 && !_state.generatorBreakers) {
@@ -2368,15 +2371,15 @@ void Myst::o_rocketPianoMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
void Myst::o_rocketPianoStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Rocket piano end move", op);
- MystResourceType8 *key = static_cast<MystResourceType8 *>(_invokingResource);
+ MystAreaImageSwitch *key = getInvokingResource<MystAreaImageSwitch>();
- Common::Rect &src = key->_subImages[0].rect;
+ Common::Rect src = key->getSubImage(0).rect;
Common::Rect dest = src;
dest.top = 332 - src.bottom;
dest.bottom = 332 - src.top;
// Draw unpressed piano key
- _vm->_gfx->copyImageSectionToScreen(key->_subImages[0].wdib, src, dest);
+ _vm->_gfx->copyImageSectionToScreen(key->getSubImage(0).wdib, src, dest);
_vm->_system->updateScreen();
_vm->_sound->stopSound();
@@ -2386,7 +2389,7 @@ void Myst::o_rocketPianoStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
void Myst::o_rocketLeverStartMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Rocket lever start move", op);
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
_vm->_cursor->setCursor(700);
_rocketLeverPosition = 0;
@@ -2406,7 +2409,7 @@ void Myst::o_rocketOpenBook(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
void Myst::o_rocketLeverMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Rocket lever move", op);
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
// Make the lever follow the mouse
@@ -2435,7 +2438,7 @@ void Myst::o_rocketLeverMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
void Myst::o_rocketLeverEndMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Rocket lever end move", op);
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
_vm->checkCursorHints();
_rocketLeverPosition = 0;
@@ -2712,7 +2715,7 @@ void Myst::clockWheel_run() {
}
void Myst::clockWheelStartTurn(uint16 wheel) {
- MystResourceType11 *resource = static_cast<MystResourceType11 *>(_invokingResource);
+ MystAreaDrag *resource = getInvokingResource<MystAreaDrag>();
uint16 soundId = resource->getList1(0);
if (soundId)
@@ -2835,10 +2838,10 @@ void Myst::o_observatoryChangeSettingStop(uint16 op, uint16 var, uint16 argc, ui
_observatoryIncrement = 0;
// Restore button and slider
- _vm->_gfx->copyBackBufferToScreen(_invokingResource->getRect());
+ _vm->_gfx->copyBackBufferToScreen(getInvokingResource<MystArea>()->getRect());
if (_observatoryCurrentSlider) {
_vm->redrawResource(_observatoryCurrentSlider);
- _observatoryCurrentSlider = 0;
+ _observatoryCurrentSlider = nullptr;
}
_vm->_sound->resumeBackgroundMyst();
}
@@ -2874,7 +2877,7 @@ void Myst::o_imagerEraseStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
void Myst::o_clockLeverStartMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Clock lever start move", op);
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
lever->drawFrame(0);
_vm->_cursor->setCursor(700);
_clockMiddleGearMovedAlone = false;
@@ -2885,7 +2888,7 @@ void Myst::o_clockLeverMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Clock left lever move", op);
if (!_clockLeverPulled) {
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
// If lever pulled
if (lever->pullLeverV()) {
@@ -2977,7 +2980,7 @@ void Myst::o_clockLeverEndMove(uint16 op, uint16 var, uint16 argc, uint16 *argv)
_vm->_sound->replaceSoundMyst(8113);
// Release lever
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
lever->releaseLeverV();
// Check if puzzle is solved
@@ -3021,7 +3024,7 @@ void Myst::clockGearsCheckSolution() {
void Myst::o_clockResetLeverStartMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Clock reset lever start move", op);
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
lever->drawFrame(0);
_vm->_cursor->setCursor(700);
}
@@ -3029,7 +3032,7 @@ void Myst::o_clockResetLeverStartMove(uint16 op, uint16 var, uint16 argc, uint16
void Myst::o_clockResetLeverMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Clock reset lever move", op);
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
// If pulled
if (lever->pullLeverV() && _clockWeightPosition != 0)
@@ -3084,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");
@@ -3125,7 +3130,7 @@ void Myst::o_clockResetLeverEndMove(uint16 op, uint16 var, uint16 argc, uint16 *
debugC(kDebugScript, "Opcode %d: Clock reset lever end move", op);
// Get current lever frame
- MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource);
+ MystVideoInfo *lever = getInvokingResource<MystVideoInfo>();
lever->releaseLeverV();
@@ -3189,8 +3194,8 @@ void Myst::towerRotationMap_run() {
void Myst::o_towerRotationMap_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
_towerRotationMapRunning = true;
- _towerRotationMapTower = static_cast<MystResourceType11 *>(_invokingResource);
- _towerRotationMapLabel = static_cast<MystResourceType8 *>(_vm->_resources[argv[0]]);
+ _towerRotationMapTower = getInvokingResource<MystAreaImageSwitch>();
+ _towerRotationMapLabel = _vm->getViewResource<MystAreaImageSwitch>(argv[0]);
_tempVar = 0;
_startTime = 0;
_towerRotationMapClicked = false;
@@ -3202,7 +3207,7 @@ void Myst::towerRotationDrawBuildings() {
// Draw other resources
for (uint i = 1; i <= 10; i++) {
- MystResourceType8 *resource = static_cast<MystResourceType8 *>(_vm->_resources[i]);
+ MystAreaImageSwitch *resource = _vm->getViewResource<MystAreaImageSwitch>(i);
_vm->redrawResource(resource, false);
}
}
@@ -3313,7 +3318,7 @@ void Myst::o_forechamberDoor_init(uint16 op, uint16 var, uint16 argc, uint16 *ar
void Myst::o_shipAccess_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
// Enable acces to the ship
if (_state.shipFloating) {
- _invokingResource->setEnabled(true);
+ getInvokingResource<MystArea>()->setEnabled(true);
}
}
@@ -3322,7 +3327,7 @@ void Myst::o_butterflies_init(uint16 op, uint16 var, uint16 argc, uint16 *argv)
// Used for Card 4256 (Butterfly Movie Activation)
if (!_butterfliesMoviePlayed) {
- MystResourceType6 *butterflies = static_cast<MystResourceType6 *>(_invokingResource);
+ MystAreaVideo *butterflies = getInvokingResource<MystAreaVideo>();
butterflies->playMovie();
_butterfliesMoviePlayed = true;
@@ -3333,8 +3338,8 @@ void Myst::o_imager_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Imager init", op);
debugC(kDebugScript, "Var: %d", var);
- MystResourceType7 *select = static_cast<MystResourceType7 *>(_invokingResource);
- _imagerMovie = static_cast<MystResourceType6 *>(select->getSubResource(getVar(var)));
+ MystAreaActionSwitch *select = getInvokingResource<MystAreaActionSwitch>();
+ _imagerMovie = static_cast<MystAreaVideo *>(select->getSubResource(getVar(var)));
_imagerRunning = true;
}
@@ -3377,8 +3382,8 @@ void Myst::libraryBookcaseTransform_run(void) {
void Myst::o_libraryBookcaseTransform_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
if (_libraryBookcaseChanged) {
- MystResourceType7 *resource = static_cast<MystResourceType7 *>(_invokingResource);
- _libraryBookcaseMovie = static_cast<MystResourceType6 *>(resource->getSubResource(getVar(0)));
+ MystAreaActionSwitch *resource = getInvokingResource<MystAreaActionSwitch>();
+ _libraryBookcaseMovie = static_cast<MystAreaVideo *>(resource->getSubResource(getVar(0)));
_libraryBookcaseSoundId = argv[0];
_libraryBookcaseMoving = true;
}
@@ -3471,17 +3476,17 @@ void Myst::o_observatory_init(uint16 op, uint16 var, uint16 argc, uint16 *argv)
_tempVar = 0;
_observatoryNotInitialized = true;
- _observatoryVisualizer = static_cast<MystResourceType8 *>(_invokingResource);
- _observatoryGoButton = static_cast<MystResourceType8 *>(_vm->_resources[argv[0]]);
+ _observatoryVisualizer = getInvokingResource<MystAreaImageSwitch>();
+ _observatoryGoButton = _vm->getViewResource<MystAreaImageSwitch>(argv[0]);
if (observatoryIsDDMMYYYY2400()) {
- _observatoryDaySlider = static_cast<MystResourceType10 *>(_vm->_resources[argv[1]]);
- _observatoryMonthSlider = static_cast<MystResourceType10 *>(_vm->_resources[argv[2]]);
+ _observatoryDaySlider = _vm->getViewResource<MystAreaSlider>(argv[1]);
+ _observatoryMonthSlider = _vm->getViewResource<MystAreaSlider>(argv[2]);
} else {
- _observatoryMonthSlider = static_cast<MystResourceType10 *>(_vm->_resources[argv[1]]);
- _observatoryDaySlider = static_cast<MystResourceType10 *>(_vm->_resources[argv[2]]);
+ _observatoryMonthSlider = _vm->getViewResource<MystAreaSlider>(argv[1]);
+ _observatoryDaySlider = _vm->getViewResource<MystAreaSlider>(argv[2]);
}
- _observatoryYearSlider = static_cast<MystResourceType10 *>(_vm->_resources[argv[3]]);
- _observatoryTimeSlider = static_cast<MystResourceType10 *>(_vm->_resources[argv[4]]);
+ _observatoryYearSlider = _vm->getViewResource<MystAreaSlider>(argv[3]);
+ _observatoryTimeSlider = _vm->getViewResource<MystAreaSlider>(argv[4]);
// Set date selection sliders position
_observatoryDaySlider->setPosition(_state.observatoryDaySlider);
@@ -3503,18 +3508,14 @@ bool Myst::observatoryIsDDMMYYYY2400() {
}
void Myst::observatoryUpdateVisualizer(uint16 x, uint16 y) {
- Common::Rect &visu0 = _observatoryVisualizer->_subImages[0].rect;
- Common::Rect &visu1 = _observatoryVisualizer->_subImages[1].rect;
-
- visu0.left = x;
- visu0.right = visu0.left + 105;
- visu0.bottom = 512 - y;
- visu0.top = visu0.bottom - 106;
+ Common::Rect visu;
+ visu.left = x;
+ visu.right = visu.left + 105;
+ visu.bottom = 512 - y;
+ visu.top = visu.bottom - 106;
- visu1.left = visu0.left;
- visu1.top = visu0.top;
- visu1.right = visu0.right;
- visu1.bottom = visu0.bottom;
+ _observatoryVisualizer->setSubImageRect(0, visu);
+ _observatoryVisualizer->setSubImageRect(1, visu);
}
void Myst::observatorySetTargetToSetting() {
@@ -3618,13 +3619,13 @@ void Myst::gullsFly2_run() {
void Myst::o_treeCard_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Enter tree card", op);
- _tree = static_cast<MystResourceType8 *>(_invokingResource);
+ _tree = getInvokingResource<MystAreaImageSwitch>();
}
void Myst::o_treeEntry_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Enter tree card with entry", op);
- _treeAlcove = static_cast<MystResourceType5 *>(_invokingResource);
+ _treeAlcove = getInvokingResource<MystArea>();
_treeMinAccessiblePosition = argv[0];
_treeMaxAccessiblePosition = argv[1];
@@ -3683,16 +3684,16 @@ void Myst::boilerFireUpdate(bool init) {
void Myst::boilerGaugeInit() {
if (_vm->getCurCard() == 4098) {
_cabinGaugeMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabingau", kMystStack));
- if (!_cabinFireMovie)
+ if (!_cabinGaugeMovie)
error("Failed to open cabingau movie");
- _cabinFireMovie->moveTo(243, 96);
+ _cabinGaugeMovie->moveTo(243, 96);
} else {
_cabinGaugeMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabcgfar", kMystStack));
- if (!_cabinFireMovie)
+ if (!_cabinGaugeMovie)
error("Failed to open cabcgfar movie");
- _cabinFireMovie->moveTo(254, 136);
+ _cabinGaugeMovie->moveTo(254, 136);
}
Audio::Timestamp frame;
@@ -3703,16 +3704,18 @@ 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) {
debugC(kDebugScript, "Opcode %d: Rocket sliders init", op);
- _rocketSlider1 = static_cast<MystResourceType10 *>(_vm->_resources[argv[0]]);
- _rocketSlider2 = static_cast<MystResourceType10 *>(_vm->_resources[argv[1]]);
- _rocketSlider3 = static_cast<MystResourceType10 *>(_vm->_resources[argv[2]]);
- _rocketSlider4 = static_cast<MystResourceType10 *>(_vm->_resources[argv[3]]);
- _rocketSlider5 = static_cast<MystResourceType10 *>(_vm->_resources[argv[4]]);
+ _rocketSlider1 = _vm->getViewResource<MystAreaSlider>(argv[0]);
+ _rocketSlider2 = _vm->getViewResource<MystAreaSlider>(argv[1]);
+ _rocketSlider3 = _vm->getViewResource<MystAreaSlider>(argv[2]);
+ _rocketSlider4 = _vm->getViewResource<MystAreaSlider>(argv[3]);
+ _rocketSlider5 = _vm->getViewResource<MystAreaSlider>(argv[4]);
// Initialize sliders position
for (uint i = 0; i < 5; i++)
@@ -3828,13 +3831,13 @@ void Myst::o_bookAddSpecialPage_exit(uint16 op, uint16 var, uint16 argc, uint16
void Myst::o_treeCard_exit(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Exit tree card", op);
- _tree = 0;
+ _tree = nullptr;
}
void Myst::o_treeEntry_exit(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Exit tree card with entry", op);
- _treeAlcove = 0;
+ _treeAlcove = nullptr;
}
void Myst::o_boiler_exit(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 a83609f640..6e2f7cc1c8 100644
--- a/engines/mohawk/myst_stacks/myst.h
+++ b/engines/mohawk/myst_stacks/myst.h
@@ -40,21 +40,20 @@ public:
Myst(MohawkEngine_Myst *vm);
~Myst();
- virtual void disablePersistentScripts();
- virtual void runPersistentScripts();
+ virtual void disablePersistentScripts() override;
+ virtual void runPersistentScripts() override;
protected:
void setupOpcodes();
- uint16 getVar(uint16 var);
- void toggleVar(uint16 var);
- bool setVarValue(uint16 var, uint16 value);
+ uint16 getVar(uint16 var) override;
+ void toggleVar(uint16 var) override;
+ bool setVarValue(uint16 var, uint16 value) override;
- virtual uint16 getMap() { return 9934; }
+ virtual uint16 getMap() override { return 9934; }
void towerRotationMap_run();
virtual void libraryBookcaseTransform_run();
void generatorControlRoom_run();
- void opcode_212_run();
void libraryCombinationBook_run();
void clockWheel_run();
void matchBurn_run();
@@ -192,11 +191,11 @@ protected:
bool _generatorControlRoomRunning;
uint16 _generatorVoltage; // 58
- MystResourceType10 *_rocketSlider1; // 248
- MystResourceType10 *_rocketSlider2; // 252
- MystResourceType10 *_rocketSlider3; // 256
- MystResourceType10 *_rocketSlider4; // 260
- MystResourceType10 *_rocketSlider5; // 264
+ MystAreaSlider *_rocketSlider1; // 248
+ MystAreaSlider *_rocketSlider2; // 252
+ MystAreaSlider *_rocketSlider3; // 256
+ MystAreaSlider *_rocketSlider4; // 260
+ MystAreaSlider *_rocketSlider5; // 264
uint16 _rocketSliderSound; // 294
uint16 _rocketLeverPosition; // 296
VideoHandle _rocketLinkBook;
@@ -214,7 +213,7 @@ protected:
uint32 _gullsNextTime; // 216
bool _libraryBookcaseMoving;
- MystResourceType6 *_libraryBookcaseMovie; // 104
+ MystAreaVideo *_libraryBookcaseMovie; // 104
uint16 _libraryBookcaseSoundId; // 284
bool _libraryBookcaseChanged; // 288
uint16 _libraryBookSound1; // 298
@@ -223,13 +222,13 @@ protected:
uint16 _courtyardBoxSound; // 302
bool _imagerValidationRunning;
- MystResourceType8 *_imagerRedButton; // 304
+ MystAreaImageSwitch *_imagerRedButton; // 304
uint16 _imagerSound[4]; // 308 to 314
uint16 _imagerValidationCard; // 316
uint16 _imagerValidationStep; // 318
bool _imagerRunning;
- MystResourceType6 *_imagerMovie; // 64
+ MystAreaVideo *_imagerMovie; // 64
uint16 _fireplaceLines[6]; // 74 to 84
@@ -248,8 +247,8 @@ protected:
bool _towerRotationBlinkLabel;
uint16 _towerRotationBlinkLabelCount;
uint16 _towerRotationMapInitialized; // 292
- MystResourceType11 *_towerRotationMapTower; // 108
- MystResourceType8 *_towerRotationMapLabel; // 112
+ MystAreaImageSwitch *_towerRotationMapTower; // 108
+ MystAreaImageSwitch *_towerRotationMapLabel; // 112
uint16 _towerRotationSpeed; // 124
bool _towerRotationMapClicked; // 132
bool _towerRotationOverSpot; // 136
@@ -257,10 +256,13 @@ protected:
bool _matchBurning;
uint16 _matchGoOutCnt;
uint16 _cabinDoorOpened; // 56
+ uint16 _cabinHandleDown; // 344
uint16 _cabinMatchState; // 60
uint32 _matchGoOutTime; // 144
VideoHandle _cabinFireMovie; // 240
+
+ bool _cabinGaugeMovieEnabled;
VideoHandle _cabinGaugeMovie; // 244
bool _boilerPressureIncreasing;
@@ -269,8 +271,8 @@ protected:
bool _basementPressureDecreasing;
bool _treeStopped; // 236
- MystResourceType8 *_tree; // 220
- MystResourceType5 *_treeAlcove; // 224
+ MystAreaImageSwitch *_tree; // 220
+ MystArea *_treeAlcove; // 224
uint16 _treeMinPosition; // 228
uint16 _treeMinAccessiblePosition; // 230
uint16 _treeMaxAccessiblePosition; // 232
@@ -280,21 +282,21 @@ protected:
bool _observatoryDayChanging;
bool _observatoryYearChanging;
bool _observatoryTimeChanging;
- MystResourceType8 *_observatoryVisualizer; // 184
- MystResourceType8 *_observatoryGoButton; // 188
- MystResourceType10 *_observatoryDaySlider; // 192
- MystResourceType10 *_observatoryMonthSlider; // 196
- MystResourceType10 *_observatoryYearSlider; // 200
- MystResourceType10 *_observatoryTimeSlider; // 204
+ MystAreaImageSwitch *_observatoryVisualizer; // 184
+ MystAreaImageSwitch *_observatoryGoButton; // 188
+ MystAreaSlider *_observatoryDaySlider; // 192
+ MystAreaSlider *_observatoryMonthSlider; // 196
+ MystAreaSlider *_observatoryYearSlider; // 200
+ MystAreaSlider *_observatoryTimeSlider; // 204
uint32 _observatoryLastTime; // 208
bool _observatoryNotInitialized; // 212
int16 _observatoryIncrement; // 346
- MystResourceType10 *_observatoryCurrentSlider; // 348
+ MystAreaSlider *_observatoryCurrentSlider; // 348
bool _greenBookRunning;
void generatorRedrawRocket();
- void generatorButtonValue(MystResource *button, uint16 &offset, uint16 &value);
+ void generatorButtonValue(MystArea *button, uint16 &offset, uint16 &value);
void rocketSliderMove();
uint16 rocketSliderGetSound(uint16 pos);
diff --git a/engines/mohawk/myst_stacks/preview.cpp b/engines/mohawk/myst_stacks/preview.cpp
index 4cae4aaca7..42458758f5 100644
--- a/engines/mohawk/myst_stacks/preview.cpp
+++ b/engines/mohawk/myst_stacks/preview.cpp
@@ -239,13 +239,13 @@ void Preview::o_library_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Library init", op);
// Used for Card 3002 (Myst Island Overview)
- _library = static_cast<MystResourceType8 *>(_invokingResource);
+ _library = getInvokingResource<MystAreaImageSwitch>();
}
void Preview::o_libraryBookcaseTransformDemo_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
if (_libraryBookcaseChanged) {
- MystResourceType7 *resource = static_cast<MystResourceType7 *>(_invokingResource);
- _libraryBookcaseMovie = static_cast<MystResourceType6 *>(resource->getSubResource(getVar(303)));
+ MystAreaActionSwitch *resource = getInvokingResource<MystAreaActionSwitch>();
+ _libraryBookcaseMovie = static_cast<MystAreaVideo *>(resource->getSubResource(getVar(303)));
_libraryBookcaseSoundId = argv[0];
_libraryBookcaseMoving = true;
}
diff --git a/engines/mohawk/myst_stacks/preview.h b/engines/mohawk/myst_stacks/preview.h
index 0959e935f5..9d833b35e2 100644
--- a/engines/mohawk/myst_stacks/preview.h
+++ b/engines/mohawk/myst_stacks/preview.h
@@ -40,8 +40,8 @@ public:
Preview(MohawkEngine_Myst *vm);
~Preview();
- void disablePersistentScripts();
- void runPersistentScripts();
+ void disablePersistentScripts() override;
+ void runPersistentScripts() override;
private:
void setupOpcodes();
@@ -56,7 +56,7 @@ private:
DECLARE_OPCODE(o_library_init);
uint16 _libraryState; // 4
- MystResourceType8 *_library; // 32
+ MystAreaImageSwitch *_library; // 32
bool _speechRunning;
uint _speechStep;
@@ -67,7 +67,7 @@ private:
void speech_run();
void speechUpdateCue();
- void libraryBookcaseTransform_run();
+ void libraryBookcaseTransform_run() override;
};
} // End of namespace MystStacks
diff --git a/engines/mohawk/myst_stacks/selenitic.cpp b/engines/mohawk/myst_stacks/selenitic.cpp
index 8b95c7fa53..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 {
@@ -39,9 +38,12 @@ namespace MystStacks {
Selenitic::Selenitic(MohawkEngine_Myst *vm) :
MystScriptParser(vm), _state(vm->_gameState->_selenitic) {
setupOpcodes();
- _invokingResource = NULL;
_mazeRunnerPosition = 288;
_mazeRunnerDirection = 8;
+ _mazeRunnerDoorOpened = false;
+
+ _soundReceiverDirection = 0;
+ _soundReceiverStartTime = 0;
}
Selenitic::~Selenitic() {
@@ -669,14 +671,20 @@ void Selenitic::soundReceiverUpdate() {
}
void Selenitic::soundReceiverDrawView() {
+ soundReceiverSetSubimageRect();
+ soundReceiverDrawAngle();
+}
+
+void Selenitic::soundReceiverSetSubimageRect() const {
uint32 left = ((*_soundReceiverPosition) * 1800) / 3600;
- _soundReceiverViewer->_subImages->rect.left = left;
- _soundReceiverViewer->_subImages->rect.right = left + 136;
+ Common::Rect rect = _soundReceiverViewer->getSubImage(0).rect;
- _soundReceiverViewer->drawConditionalDataToScreen(0);
+ rect.left = left;
+ rect.right = left + 136;
- soundReceiverDrawAngle();
+ _soundReceiverViewer->setSubImageRect(0, rect);
+ _soundReceiverViewer->drawConditionalDataToScreen(0);
}
void Selenitic::soundReceiverDrawAngle() {
@@ -770,7 +778,7 @@ uint16 Selenitic::soundLockCurrentSound(uint16 position, bool pixels) {
return 0;
}
-MystResourceType10 *Selenitic::soundLockSliderFromVar(uint16 var) {
+MystAreaSlider *Selenitic::soundLockSliderFromVar(uint16 var) {
switch (var) {
case 20:
return _soundLockSlider1;
@@ -784,13 +792,13 @@ MystResourceType10 *Selenitic::soundLockSliderFromVar(uint16 var) {
return _soundLockSlider5;
}
- return 0;
+ return nullptr;
}
void Selenitic::o_soundLockMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Sound lock move", op);
- MystResourceType10 *slider = soundLockSliderFromVar(var);
+ MystAreaSlider *slider = soundLockSliderFromVar(var);
uint16 soundId = soundLockCurrentSound(slider->_pos.y, true);
if (_soundLockSoundId != soundId) {
@@ -802,7 +810,7 @@ void Selenitic::o_soundLockMove(uint16 op, uint16 var, uint16 argc, uint16 *argv
void Selenitic::o_soundLockStartMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Sound lock start move", op);
- MystResourceType10 *slider = soundLockSliderFromVar(var);
+ MystAreaSlider *slider = soundLockSliderFromVar(var);
_vm->_cursor->setCursor(700);
_vm->_sound->pauseBackgroundMyst();
@@ -814,7 +822,7 @@ void Selenitic::o_soundLockStartMove(uint16 op, uint16 var, uint16 argc, uint16
void Selenitic::o_soundLockEndMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Sound lock end move", op);
- MystResourceType10 *slider = soundLockSliderFromVar(var);
+ MystAreaSlider *slider = soundLockSliderFromVar(var);
uint16 *value = &_state.soundLockSliderPositions[0];
switch (var) {
@@ -858,7 +866,7 @@ void Selenitic::o_soundLockEndMove(uint16 op, uint16 var, uint16 argc, uint16 *a
_vm->_sound->resumeBackgroundMyst();
}
-void Selenitic::soundLockCheckSolution(MystResourceType10 *slider, uint16 value, uint16 solution, bool &solved) {
+void Selenitic::soundLockCheckSolution(MystAreaSlider *slider, uint16 value, uint16 solution, bool &solved) {
slider->drawConditionalDataToScreen(2);
_vm->_sound->replaceSoundMyst(soundLockCurrentSound(value / 12, false));
_vm->_system->delayMillis(1500);
@@ -926,15 +934,15 @@ void Selenitic::o_soundReceiverEndMove(uint16 op, uint16 var, uint16 argc, uint1
}
void Selenitic::o_mazeRunnerCompass_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
- _mazeRunnerCompass = static_cast<MystResourceType8 *>(_invokingResource);
+ _mazeRunnerCompass = getInvokingResource<MystAreaImageSwitch>();
}
void Selenitic::o_mazeRunnerWindow_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
- _mazeRunnerWindow = static_cast<MystResourceType8 *>(_invokingResource);
+ _mazeRunnerWindow = getInvokingResource<MystAreaImageSwitch>();
}
void Selenitic::o_mazeRunnerLight_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
- _mazeRunnerLight = static_cast<MystResourceType8 *>(_invokingResource);
+ _mazeRunnerLight = getInvokingResource<MystAreaImageSwitch>();
}
void Selenitic::soundReceiver_run() {
@@ -942,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();
@@ -1056,24 +1067,26 @@ void Selenitic::o_soundReceiver_init(uint16 op, uint16 var, uint16 argc, uint16
// Used for Card 1245 (Sound Receiver)
_soundReceiverRunning = true;
- _soundReceiverRightButton = static_cast<MystResourceType8 *>(_vm->_resources[0]);
- _soundReceiverLeftButton = static_cast<MystResourceType8 *>(_vm->_resources[1]);
- _soundReceiverSigmaButton = static_cast<MystResourceType8 *>(_vm->_resources[2]);
- _soundReceiverSources[4] = static_cast<MystResourceType8 *>(_vm->_resources[3]);
- _soundReceiverSources[3] = static_cast<MystResourceType8 *>(_vm->_resources[4]);
- _soundReceiverSources[2] = static_cast<MystResourceType8 *>(_vm->_resources[5]);
- _soundReceiverSources[1] = static_cast<MystResourceType8 *>(_vm->_resources[6]);
- _soundReceiverSources[0] = static_cast<MystResourceType8 *>(_vm->_resources[7]);
- _soundReceiverViewer = static_cast<MystResourceType8 *>(_vm->_resources[8]);
- _soundReceiverAngle1 = static_cast<MystResourceType8 *>(_vm->_resources[10]);
- _soundReceiverAngle2 = static_cast<MystResourceType8 *>(_vm->_resources[11]);
- _soundReceiverAngle3 = static_cast<MystResourceType8 *>(_vm->_resources[12]);
- _soundReceiverAngle4 = static_cast<MystResourceType8 *>(_vm->_resources[13]);
+ _soundReceiverRightButton = _vm->getViewResource<MystAreaImageSwitch>(0);
+ _soundReceiverLeftButton = _vm->getViewResource<MystAreaImageSwitch>(1);
+ _soundReceiverSigmaButton = _vm->getViewResource<MystAreaImageSwitch>(2);
+ _soundReceiverSources[4] = _vm->getViewResource<MystAreaImageSwitch>(3);
+ _soundReceiverSources[3] = _vm->getViewResource<MystAreaImageSwitch>(4);
+ _soundReceiverSources[2] = _vm->getViewResource<MystAreaImageSwitch>(5);
+ _soundReceiverSources[1] = _vm->getViewResource<MystAreaImageSwitch>(6);
+ _soundReceiverSources[0] = _vm->getViewResource<MystAreaImageSwitch>(7);
+ _soundReceiverViewer = _vm->getViewResource<MystAreaImageSwitch>(8);
+ _soundReceiverAngle1 = _vm->getViewResource<MystAreaImageSwitch>(10);
+ _soundReceiverAngle2 = _vm->getViewResource<MystAreaImageSwitch>(11);
+ _soundReceiverAngle3 = _vm->getViewResource<MystAreaImageSwitch>(12);
+ _soundReceiverAngle4 = _vm->getViewResource<MystAreaImageSwitch>(13);
uint16 currentSource = _state.soundReceiverCurrentSource;
_soundReceiverPosition = &_state.soundReceiverPositions[currentSource];
_soundReceiverCurrentSource = _soundReceiverSources[currentSource];
+ soundReceiverSetSubimageRect();
+
_soundReceiverSigmaPressed = false;
}
@@ -1081,31 +1094,31 @@ void Selenitic::o_soundLock_init(uint16 op, uint16 var, uint16 argc, uint16 *arg
debugC(kDebugScript, "Opcode %d: Sound lock init", op);
for (uint i = 0; i < _vm->_resources.size(); i++) {
- if (_vm->_resources[i]->type == kMystSlider) {
- switch (_vm->_resources[i]->getType8Var()) {
+ if (_vm->_resources[i]->type == kMystAreaSlider) {
+ switch (_vm->_resources[i]->getImageSwitchVar()) {
case 20:
- _soundLockSlider1 = static_cast<MystResourceType10 *>(_vm->_resources[i]);
+ _soundLockSlider1 = _vm->getViewResource<MystAreaSlider>(i);
_soundLockSlider1->setStep(_state.soundLockSliderPositions[0]);
break;
case 21:
- _soundLockSlider2 = static_cast<MystResourceType10 *>(_vm->_resources[i]);
+ _soundLockSlider2 = _vm->getViewResource<MystAreaSlider>(i);
_soundLockSlider2->setStep(_state.soundLockSliderPositions[1]);
break;
case 22:
- _soundLockSlider3 = static_cast<MystResourceType10 *>(_vm->_resources[i]);
+ _soundLockSlider3 = _vm->getViewResource<MystAreaSlider>(i);
_soundLockSlider3->setStep(_state.soundLockSliderPositions[2]);
break;
case 23:
- _soundLockSlider4 = static_cast<MystResourceType10 *>(_vm->_resources[i]);
+ _soundLockSlider4 = _vm->getViewResource<MystAreaSlider>(i);
_soundLockSlider4->setStep(_state.soundLockSliderPositions[3]);
break;
case 24:
- _soundLockSlider5 = static_cast<MystResourceType10 *>(_vm->_resources[i]);
+ _soundLockSlider5 = _vm->getViewResource<MystAreaSlider>(i);
_soundLockSlider5->setStep(_state.soundLockSliderPositions[4]);
break;
}
- } else if (_vm->_resources[i]->type == kMystConditionalImage && _vm->_resources[i]->getType8Var() == 28) {
- _soundLockButton = static_cast<MystResourceType8 *>(_vm->_resources[i]);
+ } else if (_vm->_resources[i]->type == kMystAreaImageSwitch && _vm->_resources[i]->getImageSwitchVar() == 28) {
+ _soundLockButton = _vm->getViewResource<MystAreaImageSwitch>(i);
}
}
@@ -1113,11 +1126,11 @@ void Selenitic::o_soundLock_init(uint16 op, uint16 var, uint16 argc, uint16 *arg
}
void Selenitic::o_mazeRunnerRight_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
- _mazeRunnerRightButton = static_cast<MystResourceType8 *>(_invokingResource);
+ _mazeRunnerRightButton = getInvokingResource<MystAreaImageSwitch>();
}
void Selenitic::o_mazeRunnerLeft_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
- _mazeRunnerLeftButton = static_cast<MystResourceType8 *>(_invokingResource);
+ _mazeRunnerLeftButton = getInvokingResource<MystAreaImageSwitch>();
}
const uint16 Selenitic::_mazeRunnerMap[300][4] = {
diff --git a/engines/mohawk/myst_stacks/selenitic.h b/engines/mohawk/myst_stacks/selenitic.h
index c669d01012..fc9649755d 100644
--- a/engines/mohawk/myst_stacks/selenitic.h
+++ b/engines/mohawk/myst_stacks/selenitic.h
@@ -29,7 +29,7 @@
namespace Mohawk {
-class MystResourceType8;
+class MystAreaImageSwitch;
struct MystScriptEntry;
namespace MystStacks {
@@ -41,16 +41,16 @@ public:
Selenitic(MohawkEngine_Myst *vm);
~Selenitic();
- void disablePersistentScripts();
- void runPersistentScripts();
+ void disablePersistentScripts() override;
+ void runPersistentScripts() override;
private:
void setupOpcodes();
- uint16 getVar(uint16 var);
- void toggleVar(uint16 var);
- bool setVarValue(uint16 var, uint16 value);
+ uint16 getVar(uint16 var) override;
+ void toggleVar(uint16 var) override;
+ bool setVarValue(uint16 var, uint16 value) override;
- virtual uint16 getMap() { return 9930; }
+ virtual uint16 getMap() override { return 9930; }
DECLARE_OPCODE(o_mazeRunnerMove);
DECLARE_OPCODE(o_mazeRunnerSoundRepeat);
@@ -80,43 +80,44 @@ private:
bool _soundReceiverRunning;
bool _soundReceiverSigmaPressed; // 6
- MystResourceType8 *_soundReceiverSources[5]; // 92 -> 108
- MystResourceType8 *_soundReceiverCurrentSource; // 112
+ MystAreaImageSwitch *_soundReceiverSources[5]; // 92 -> 108
+ MystAreaImageSwitch *_soundReceiverCurrentSource; // 112
uint16 *_soundReceiverPosition; // 116
uint16 _soundReceiverDirection; // 120
uint16 _soundReceiverSpeed; // 122
uint32 _soundReceiverStartTime; //124
- MystResourceType8 *_soundReceiverViewer; // 128
- MystResourceType8 *_soundReceiverRightButton; // 132
- MystResourceType8 *_soundReceiverLeftButton; // 136
- MystResourceType8 *_soundReceiverAngle1; // 140
- MystResourceType8 *_soundReceiverAngle2; // 144
- MystResourceType8 *_soundReceiverAngle3; // 148
- MystResourceType8 *_soundReceiverAngle4; // 152
- MystResourceType8 *_soundReceiverSigmaButton; // 156
+ MystAreaImageSwitch *_soundReceiverViewer; // 128
+ MystAreaImageSwitch *_soundReceiverRightButton; // 132
+ MystAreaImageSwitch *_soundReceiverLeftButton; // 136
+ MystAreaImageSwitch *_soundReceiverAngle1; // 140
+ MystAreaImageSwitch *_soundReceiverAngle2; // 144
+ MystAreaImageSwitch *_soundReceiverAngle3; // 148
+ MystAreaImageSwitch *_soundReceiverAngle4; // 152
+ MystAreaImageSwitch *_soundReceiverSigmaButton; // 156
static const uint16 _mazeRunnerMap[300][4];
static const uint8 _mazeRunnerVideos[300][4];
uint16 _mazeRunnerPosition; // 56
uint16 _mazeRunnerDirection; // 58
- MystResourceType8 *_mazeRunnerWindow; // 68
- MystResourceType8 *_mazeRunnerCompass; // 72
- MystResourceType8 *_mazeRunnerLight; // 76
- MystResourceType8 *_mazeRunnerRightButton; // 80
- MystResourceType8 *_mazeRunnerLeftButton; // 84
+ MystAreaImageSwitch *_mazeRunnerWindow; // 68
+ MystAreaImageSwitch *_mazeRunnerCompass; // 72
+ MystAreaImageSwitch *_mazeRunnerLight; // 76
+ MystAreaImageSwitch *_mazeRunnerRightButton; // 80
+ MystAreaImageSwitch *_mazeRunnerLeftButton; // 84
bool _mazeRunnerDoorOpened; // 160
uint16 _soundLockSoundId;
- MystResourceType10 *_soundLockSlider1; // 164
- MystResourceType10 *_soundLockSlider2; // 168
- MystResourceType10 *_soundLockSlider3; // 172
- MystResourceType10 *_soundLockSlider4; // 176
- MystResourceType10 *_soundLockSlider5; // 180
- MystResourceType8 *_soundLockButton; // 184
+ MystAreaSlider *_soundLockSlider1; // 164
+ MystAreaSlider *_soundLockSlider2; // 168
+ MystAreaSlider *_soundLockSlider3; // 172
+ MystAreaSlider *_soundLockSlider4; // 176
+ MystAreaSlider *_soundLockSlider5; // 180
+ MystAreaImageSwitch *_soundLockButton; // 184
void soundReceiverLeftRight(uint direction);
void soundReceiverUpdate();
+ void soundReceiverSetSubimageRect() const;
void soundReceiverDrawView();
void soundReceiverDrawAngle();
void soundReceiverIncreaseSpeed();
@@ -125,8 +126,8 @@ private:
void soundReceiverSolution(uint16 source, uint16 &solution, bool &enabled);
uint16 soundLockCurrentSound(uint16 position, bool pixels);
- MystResourceType10 *soundLockSliderFromVar(uint16 var);
- void soundLockCheckSolution(MystResourceType10 *slider, uint16 value, uint16 solution, bool &solved);
+ MystAreaSlider *soundLockSliderFromVar(uint16 var);
+ void soundLockCheckSolution(MystAreaSlider *slider, uint16 value, uint16 solution, bool &solved);
bool mazeRunnerForwardAllowed(uint16 position);
void mazeRunnerUpdateCompass();
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_stacks/slides.h b/engines/mohawk/myst_stacks/slides.h
index fb7868a03c..a0c9ae5821 100644
--- a/engines/mohawk/myst_stacks/slides.h
+++ b/engines/mohawk/myst_stacks/slides.h
@@ -40,8 +40,8 @@ public:
Slides(MohawkEngine_Myst *vm);
~Slides();
- void disablePersistentScripts();
- void runPersistentScripts();
+ void disablePersistentScripts() override;
+ void runPersistentScripts() override;
private:
void setupOpcodes();
diff --git a/engines/mohawk/myst_stacks/stoneship.cpp b/engines/mohawk/myst_stacks/stoneship.cpp
index 1113ceeac9..293c0f96f4 100644
--- a/engines/mohawk/myst_stacks/stoneship.cpp
+++ b/engines/mohawk/myst_stacks/stoneship.cpp
@@ -50,6 +50,8 @@ Stoneship::Stoneship(MohawkEngine_Myst *vm) :
_chestDrawersOpen = 0;
_chestAchenarBottomDrawerClosed = 1;
+ _brotherDoorOpen = 0;
+
// Drop key
if (_state.trapdoorKeyState == 1)
_state.trapdoorKeyState = 2;
@@ -402,9 +404,9 @@ void Stoneship::o_pumpTurnOff(uint16 op, uint16 var, uint16 argc, uint16 *argv)
}
for (uint i = 0; i < _vm->_resources.size(); i++) {
- MystResource *resource = _vm->_resources[i];
- if (resource->type == kMystConditionalImage && resource->getType8Var() == buttonVar) {
- static_cast<MystResourceType8 *>(resource)->drawConditionalDataToScreen(0, true);
+ MystArea *resource = _vm->_resources[i];
+ if (resource->type == kMystAreaImageSwitch && resource->getImageSwitchVar() == buttonVar) {
+ static_cast<MystAreaImageSwitch *>(resource)->drawConditionalDataToScreen(0, true);
break;
}
}
@@ -437,9 +439,9 @@ void Stoneship::o_cabinBookMovie(uint16 op, uint16 var, uint16 argc, uint16 *arg
void Stoneship::o_drawerOpenSirius(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Open drawer", op);
- MystResourceType8 *drawer = static_cast<MystResourceType8 *>(_vm->_resources[argv[0]]);
+ MystAreaImageSwitch *drawer = _vm->getViewResource<MystAreaImageSwitch>(argv[0]);
- if (drawer->getType8Var() == 35) {
+ if (drawer->getImageSwitchVar() == 35) {
drawer->drawConditionalDataToScreen(getVar(102), 0);
} else {
drawer->drawConditionalDataToScreen(0, 0);
@@ -466,7 +468,7 @@ void Stoneship::o_telescopeStart(uint16 op, uint16 var, uint16 argc, uint16 *arg
void Stoneship::o_telescopeMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Telescope move", op);
- MystResourceType11 *display = static_cast<MystResourceType11 *>(_invokingResource);
+ MystAreaDrag *display = getInvokingResource<MystAreaDrag>();
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
// Compute telescope position
@@ -489,7 +491,7 @@ void Stoneship::o_telescopeStop(uint16 op, uint16 var, uint16 argc, uint16 *argv
void Stoneship::o_generatorStart(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Generator start", op);
- MystResourceType11 *handle = static_cast<MystResourceType11 *>(_invokingResource);
+ MystAreaDrag *handle = getInvokingResource<MystAreaDrag>();
uint16 soundId = handle->getList1(0);
if (soundId)
@@ -504,7 +506,7 @@ void Stoneship::o_generatorStart(uint16 op, uint16 var, uint16 argc, uint16 *arg
_batteryNextTime = _vm->_system->getMillis() + 1000;
// Start handle movie
- MystResourceType6 *movie = static_cast<MystResourceType6 *>(handle->getSubResource(0));
+ MystAreaVideo *movie = static_cast<MystAreaVideo *>(handle->getSubResource(0));
movie->playMovie();
soundId = handle->getList2(0);
@@ -530,8 +532,8 @@ void Stoneship::o_generatorStop(uint16 op, uint16 var, uint16 argc, uint16 *argv
}
// Pause handle movie
- MystResourceType11 *handle = static_cast<MystResourceType11 *>(_invokingResource);
- MystResourceType6 *movie = static_cast<MystResourceType6 *>(handle->getSubResource(0));
+ MystAreaDrag *handle = getInvokingResource<MystAreaDrag>();
+ MystAreaVideo *movie = static_cast<MystAreaVideo *>(handle->getSubResource(0));
movie->pauseMovie(true);
uint16 soundId = handle->getList3(0);
@@ -582,7 +584,7 @@ void Stoneship::batteryDeplete_run() {
void Stoneship::o_drawerOpenAchenar(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Open drawer", op);
- MystResourceType8 *drawer = static_cast<MystResourceType8 *>(_vm->_resources[argv[0]]);
+ MystAreaImageSwitch *drawer = _vm->getViewResource<MystAreaImageSwitch>(argv[0]);
drawer->drawConditionalDataToScreen(0, 0);
_vm->_gfx->runTransition(kTransitionTopToBottom, drawer->getRect(), 25, 5);
}
@@ -617,7 +619,7 @@ void Stoneship::o_hologramSelectionStart(uint16 op, uint16 var, uint16 argc, uin
void Stoneship::o_hologramSelectionMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Hologram move", op);
- MystResourceType11 *handle = static_cast<MystResourceType11 *>(_invokingResource);
+ MystAreaDrag *handle = getInvokingResource<MystAreaDrag>();
const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
if (handle->getRect().contains(mouse)) {
@@ -806,7 +808,7 @@ void Stoneship::o_cloudOrbLeave(uint16 op, uint16 var, uint16 argc, uint16 *argv
_cloudOrbMovie->pauseMovie(true);
_vm->_sound->replaceSoundMyst(_cloudOrbStopSound);
- _vm->_gfx->runTransition(kTransitionTopToBottom, _invokingResource->getRect(), 4, 0);
+ _vm->_gfx->runTransition(kTransitionTopToBottom, getInvokingResource<MystArea>()->getRect(), 4, 0);
}
void Stoneship::o_drawerCloseOpened(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
@@ -822,20 +824,20 @@ void Stoneship::drawerClose(uint16 drawer) {
_vm->drawCardBackground();
_vm->drawResourceImages();
- MystResource *res = _vm->_resources[drawer];
+ MystArea *res = _vm->_resources[drawer];
_vm->_gfx->runTransition(kTransitionBottomToTop, res->getRect(), 25, 5);
}
void Stoneship::o_hologramDisplay_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Hologram display init", op);
- _hologramDisplay = static_cast<MystResourceType6 *>(_invokingResource);
+ _hologramDisplay = getInvokingResource<MystAreaVideo>();
_hologramDisplayPos = 0;
}
void Stoneship::o_hologramSelection_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Hologram selection init", op);
- _hologramSelection = static_cast<MystResourceType6 *>(_invokingResource);
+ _hologramSelection = getInvokingResource<MystAreaVideo>();
}
void Stoneship::batteryGaugeUpdate() {
@@ -856,7 +858,7 @@ void Stoneship::o_battery_init(uint16 op, uint16 var, uint16 argc, uint16 *argv)
// Used for Card 2160 (Lighthouse Battery Pack Closeup)
debugC(kDebugScript, "Opcode %d: Battery init", op);
- _batteryGauge = static_cast<MystResourceType8 *>(_invokingResource);
+ _batteryGauge = getInvokingResource<MystAreaImageSwitch>();
batteryGaugeUpdate();
}
@@ -1014,7 +1016,7 @@ void Stoneship::o_achenarDrawers_init(uint16 op, uint16 var, uint16 argc, uint16
void Stoneship::o_cloudOrb_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Cloud orb init", op);
- _cloudOrbMovie = static_cast<MystResourceType6 *>(_invokingResource);
+ _cloudOrbMovie = getInvokingResource<MystAreaVideo>();
_cloudOrbSound = argv[0];
_cloudOrbStopSound = argv[1];
}
diff --git a/engines/mohawk/myst_stacks/stoneship.h b/engines/mohawk/myst_stacks/stoneship.h
index 4e1b42f26b..776641a787 100644
--- a/engines/mohawk/myst_stacks/stoneship.h
+++ b/engines/mohawk/myst_stacks/stoneship.h
@@ -40,16 +40,16 @@ public:
Stoneship(MohawkEngine_Myst *vm);
~Stoneship();
- void disablePersistentScripts();
- void runPersistentScripts();
+ void disablePersistentScripts() override;
+ void runPersistentScripts() override;
private:
void setupOpcodes();
- uint16 getVar(uint16 var);
- void toggleVar(uint16 var);
- bool setVarValue(uint16 var, uint16 value);
+ uint16 getVar(uint16 var) override;
+ void toggleVar(uint16 var) override;
+ bool setVarValue(uint16 var, uint16 value) override;
- virtual uint16 getMap() { return 9933; }
+ virtual uint16 getMap() override { return 9933; }
DECLARE_OPCODE(o_pumpTurnOff);
DECLARE_OPCODE(o_brotherDoorOpen);
@@ -98,7 +98,7 @@ private:
bool _batteryGaugeRunning;
uint16 _batteryLastCharge; // 92
- MystResourceType8 *_batteryGauge; // 96
+ MystAreaImageSwitch *_batteryGauge; // 96
void batteryGaugeUpdate();
void batteryGauge_run();
@@ -113,8 +113,8 @@ private:
void drawerClose(uint16 drawer);
uint16 _hologramTurnedOn; // 80
- MystResourceType6 *_hologramDisplay; // 84
- MystResourceType6 *_hologramSelection; // 88
+ MystAreaVideo *_hologramDisplay; // 84
+ MystAreaVideo *_hologramSelection; // 88
uint16 _hologramDisplayPos;
bool _tunnelRunning;
@@ -135,7 +135,7 @@ private:
void telescope_run();
void telescopeLighthouseDraw();
- MystResourceType6 *_cloudOrbMovie; // 136
+ MystAreaVideo *_cloudOrbMovie; // 136
uint16 _cloudOrbSound; // 140
uint16 _cloudOrbStopSound; // 142
diff --git a/engines/mohawk/myst_state.cpp b/engines/mohawk/myst_state.cpp
index 3e54017df8..213a976413 100644
--- a/engines/mohawk/myst_state.cpp
+++ b/engines/mohawk/myst_state.cpp
@@ -26,11 +26,41 @@
#include "common/debug.h"
#include "common/serializer.h"
+#include "common/system.h"
#include "common/textconsole.h"
#include "common/util.h"
+#include "graphics/thumbnail.h"
+
namespace Mohawk {
+MystSaveMetadata::MystSaveMetadata() {
+ saveDay = 0;
+ saveMonth = 0;
+ saveYear = 0;
+ saveHour = 0;
+ saveMinute = 0;
+ totalPlayTime = 0;
+}
+
+bool MystSaveMetadata::sync(Common::Serializer &s) {
+ static const Common::Serializer::Version kCurrentVersion = 1;
+
+ if (!s.syncVersion(kCurrentVersion)) {
+ return false;
+ }
+
+ s.syncAsByte(saveDay);
+ s.syncAsByte(saveMonth);
+ s.syncAsUint16LE(saveYear);
+ s.syncAsByte(saveHour);
+ s.syncAsByte(saveMinute);
+ s.syncString(saveDescription);
+ s.syncAsUint32LE(totalPlayTime);
+
+ return true;
+}
+
MystGameState::MystGameState(MohawkEngine_Myst *vm, Common::SaveFileManager *saveFileMan) : _vm(vm), _saveFileMan(saveFileMan) {
// Most of the variables are zero at game start.
memset(&_globals, 0, sizeof(_globals));
@@ -76,14 +106,39 @@ MystGameState::MystGameState(MohawkEngine_Myst *vm, Common::SaveFileManager *sav
MystGameState::~MystGameState() {
}
-Common::StringArray MystGameState::generateSaveGameList() {
- return _saveFileMan->listSavefiles("*.mys");
+bool MystGameState::load(int slot) {
+ if (!loadState(slot)) {
+ return false;
+ }
+
+ loadMetadata(slot);
+
+ // Set Channelwood elevator state to down, because we start on the lower level
+ _channelwood.elevatorState = 0;
+
+ // Switch us back to the intro stack, to the linking book
+ _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)
+ _vm->setMainCursor(kBluePageCursor);
+ else if (_globals.heldPage < 13)
+ _vm->setMainCursor(kRedPageCursor);
+ else // if (globals.heldPage == 13)
+ _vm->setMainCursor(kWhitePageCursor);
+
+ return true;
}
-bool MystGameState::load(const Common::String &filename) {
+bool MystGameState::loadState(int slot) {
+ Common::String filename = buildSaveFilename(slot);
Common::InSaveFile *loadFile = _saveFileMan->openForLoading(filename);
- if (!loadFile)
+ if (!loadFile) {
return false;
+ }
debugC(kDebugSaveLoad, "Loading game from '%s'", filename.c_str());
@@ -96,42 +151,54 @@ bool MystGameState::load(const Common::String &filename) {
return false;
}
- Common::Serializer s(loadFile, 0);
+ Common::Serializer s(loadFile, nullptr);
syncGameState(s, size == 664);
delete loadFile;
- // Set Channelwood elevator state to down, because we start on the lower level
- _channelwood.elevatorState = 0;
+ return true;
+}
- // Switch us back to the intro stack, to the linking book
- _vm->changeToStack(kIntroStack, 5, 0, 0);
+void MystGameState::loadMetadata(int slot) {
+ // Open the metadata file
+ Common::String filename = buildMetadataFilename(slot);
+ Common::InSaveFile *metadataFile = _vm->getSaveFileManager()->openForLoading(filename);
+ if (!metadataFile) {
+ return;
+ }
- // Set our default cursor
- if (_globals.heldPage == 0 || _globals.heldPage > 13)
- _vm->setMainCursor(kDefaultMystCursor);
- else if (_globals.heldPage < 7)
- _vm->setMainCursor(kBluePageCursor);
- else if (_globals.heldPage < 13)
- _vm->setMainCursor(kRedPageCursor);
- else // if (globals.heldPage == 13)
- _vm->setMainCursor(kWhitePageCursor);
+ debugC(kDebugSaveLoad, "Loading metadata from '%s'", filename.c_str());
- return true;
+ Common::Serializer m(metadataFile, nullptr);
+
+ // Read the metadata file
+ if (_metadata.sync(m)) {
+ _vm->setTotalPlayTime(_metadata.totalPlayTime);
+ }
+
+ delete metadataFile;
}
-bool MystGameState::save(const Common::String &fname) {
- Common::String filename(fname);
- // Make sure we have the right extension
- if (!filename.hasSuffix(".mys") && !filename.hasSuffix(".MYS"))
- filename += ".mys";
+bool MystGameState::save(int slot, const Common::String &desc) {
+ if (!saveState(slot)) {
+ return false;
+ }
+
+ updateMetadateForSaving(desc);
+
+ return saveMetadata(slot);
+}
+bool MystGameState::saveState(int slot) {
+ // Make sure we have the right extension
+ Common::String filename = buildSaveFilename(slot);
Common::OutSaveFile *saveFile = _saveFileMan->openForSaving(filename);
- if (!saveFile)
+ if (!saveFile) {
return false;
+ }
debugC(kDebugSaveLoad, "Saving game to '%s'", filename.c_str());
- Common::Serializer s(0, saveFile);
+ Common::Serializer s(nullptr, saveFile);
syncGameState(s, _vm->getFeatures() & GF_ME);
saveFile->finalize();
delete saveFile;
@@ -139,6 +206,101 @@ bool MystGameState::save(const Common::String &fname) {
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;
+ g_system->getTimeAndDate(t);
+ _metadata.saveYear = t.tm_year + 1900;
+ _metadata.saveMonth = t.tm_mon + 1;
+ _metadata.saveDay = t.tm_mday;
+ _metadata.saveHour = t.tm_hour;
+ _metadata.saveMinute = t.tm_min;
+ _metadata.saveDescription = desc;
+ _metadata.totalPlayTime = _vm->getTotalPlayTime();
+}
+
+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 = buildMetadataFilename(slot);
+ Common::OutSaveFile *metadataFile = _saveFileMan->openForSaving(metadataFilename);
+ if (!metadataFile) {
+ return false;
+ }
+
+ // Save the metadata
+ Common::Serializer m(nullptr, metadataFile);
+ _metadata.sync(m);
+
+ // Append a thumbnail
+ Graphics::saveThumbnail(*metadataFile);
+
+ metadataFile->finalize();
+ delete metadataFile;
+
+ return true;
+}
+
+SaveStateDescriptor MystGameState::querySaveMetaInfos(int slot) {
+ // Open the metadata file
+ Common::String filename = buildMetadataFilename(slot);
+ Common::InSaveFile *metadataFile = g_system->getSavefileManager()->openForLoading(filename);
+ if (!metadataFile) {
+ return SaveStateDescriptor();
+ }
+
+ Common::Serializer m(metadataFile, nullptr);
+
+ // Read the metadata file
+ Mohawk::MystSaveMetadata metadata;
+ if (!metadata.sync(m)) {
+ delete metadataFile;
+ 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);
+ desc.setPlayTime(metadata.totalPlayTime);
+ desc.setThumbnail(Graphics::loadThumbnail(*metadataFile));
+
+ delete metadataFile;
+
+ return desc;
+}
+
+Common::String MystGameState::querySaveDescription(int slot) {
+ // Open the metadata file
+ Common::String filename = buildMetadataFilename(slot);
+ Common::InSaveFile *metadataFile = g_system->getSavefileManager()->openForLoading(filename);
+ if (!metadataFile) {
+ return "";
+ }
+
+ Common::Serializer m(metadataFile, nullptr);
+
+ // Read the metadata file
+ Mohawk::MystSaveMetadata metadata;
+ if (!metadata.sync(m)) {
+ delete metadataFile;
+ return "";
+ }
+
+ delete metadataFile;
+
+ return metadata.saveDescription;
+}
+
void MystGameState::syncGameState(Common::Serializer &s, bool isME) {
// Globals first
s.syncAsUint16LE(_globals.u0);
@@ -315,13 +477,18 @@ 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());
- _saveFileMan->removeSavefile(saveName.c_str());
+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(filename);
+ g_system->getSavefileManager()->removeSavefile(metadataFilename);
}
void MystGameState::addZipDest(uint16 stack, uint16 view) {
- ZipDests *zipDests = 0;
+ ZipDests *zipDests = nullptr;
// The demo has no zip dest storage
if (_vm->getFeatures() & GF_DEMO)
diff --git a/engines/mohawk/myst_state.h b/engines/mohawk/myst_state.h
index b07a0f2469..7d5f3f7102 100644
--- a/engines/mohawk/myst_state.h
+++ b/engines/mohawk/myst_state.h
@@ -27,6 +27,8 @@
#include "common/file.h"
#include "common/str.h"
+#include "engines/savestate.h"
+
namespace Common {
class Serializer;
}
@@ -35,15 +37,33 @@ namespace Mohawk {
class MohawkEngine_Myst;
+struct MystSaveMetadata {
+ uint8 saveDay;
+ uint8 saveMonth;
+ uint16 saveYear;
+
+ uint8 saveHour;
+ uint8 saveMinute;
+
+ uint32 totalPlayTime;
+
+ Common::String saveDescription;
+
+ MystSaveMetadata();
+ bool sync(Common::Serializer &s);
+};
+
class MystGameState {
public:
MystGameState(MohawkEngine_Myst*, Common::SaveFileManager*);
~MystGameState();
- Common::StringArray generateSaveGameList();
- bool load(const Common::String &);
- bool save(const Common::String &);
- void deleteSave(const Common::String &);
+ static SaveStateDescriptor querySaveMetaInfos(int slot);
+ static Common::String querySaveDescription(int slot);
+
+ 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);
@@ -268,8 +288,17 @@ public:
uint32 generatorDepletionTime;
} _stoneship;
+ MystSaveMetadata _metadata;
+
private:
void syncGameState(Common::Serializer &s, bool isME);
+ 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(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 198627e012..38cb0b3608 100644
--- a/engines/mohawk/sound.cpp
+++ b/engines/mohawk/sound.cpp
@@ -21,13 +21,14 @@
*/
#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"
@@ -163,8 +164,26 @@ Audio::SoundHandle *Sound::replaceSoundMyst(uint16 id, byte volume, bool loop) {
void Sound::playSoundBlocking(uint16 id, byte volume) {
Audio::SoundHandle *handle = playSound(id, volume);
- while (_vm->_mixer->isSoundHandleActive(*handle))
+ while (_vm->_mixer->isSoundHandleActive(*handle) && !_vm->shouldQuit()) {
+ Common::Event event;
+ while (_vm->_system->getEventManager()->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ switch (event.kbd.keycode) {
+ case Common::KEYCODE_SPACE:
+ _vm->pauseGame();
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ // Cut down on CPU usage
_vm->_system->delayMillis(10);
+ }
}
void Sound::playMidi(uint16 id) {
@@ -625,7 +644,7 @@ uint16 Sound::convertMystID(uint16 id) {
return id;
}
-Audio::SoundHandle *Sound::replaceBackgroundMyst(uint16 id, uint16 volume) {
+void Sound::replaceBackgroundMyst(uint16 id, uint16 volume) {
debug(0, "Replacing background sound with %d", id);
// TODO: The original engine does fading
@@ -641,8 +660,11 @@ Audio::SoundHandle *Sound::replaceBackgroundMyst(uint16 id, uint16 volume) {
// Check if sound is already playing
if (_mystBackgroundSound.type == kUsedHandle && _vm->_mixer->isSoundHandleActive(_mystBackgroundSound.handle)
- && _vm->getResourceName(ID_MSND, convertMystID(_mystBackgroundSound.id)).hasPrefix(prefix))
- return &_mystBackgroundSound.handle;
+ && _vm->getResourceName(ID_MSND, convertMystID(_mystBackgroundSound.id)).hasPrefix(prefix)) {
+ // The sound is already playing, just change the volume
+ changeBackgroundVolumeMyst(volume);
+ return;
+ }
// Stop old background sound
stopBackgroundMyst();
@@ -659,10 +681,7 @@ Audio::SoundHandle *Sound::replaceBackgroundMyst(uint16 id, uint16 volume) {
Audio::AudioStream *audStream = Audio::makeLoopingAudioStream(rewindStream, 0);
_vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_mystBackgroundSound.handle, audStream, -1, volume >> 8);
- return &_mystBackgroundSound.handle;
}
-
- return NULL;
}
void Sound::stopBackgroundMyst() {
diff --git a/engines/mohawk/sound.h b/engines/mohawk/sound.h
index 75c9492d96..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?
@@ -136,7 +138,7 @@ public:
// Myst-specific sound functions
Audio::SoundHandle *replaceSoundMyst(uint16 id, byte volume = Audio::Mixer::kMaxChannelVolume, bool loop = false);
- Audio::SoundHandle *replaceBackgroundMyst(uint16 id, uint16 volume = 0xFFFF);
+ void replaceBackgroundMyst(uint16 id, uint16 volume = 0xFFFF);
void pauseBackgroundMyst();
void resumeBackgroundMyst();
void stopBackgroundMyst();
diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp
index ff4a69cd28..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() {
@@ -184,7 +184,7 @@ void VideoManager::playMovieBlocking(const Common::String &fileName, uint16 x, u
}
ptr->start();
- waitUntilMovieEnds(ptr);
+ waitUntilMovieEnds(VideoHandle(ptr));
}
void VideoManager::playMovieBlockingCentered(const Common::String &fileName, bool clearScreen) {
@@ -200,7 +200,7 @@ void VideoManager::playMovieBlockingCentered(const Common::String &fileName, boo
ptr->center();
ptr->start();
- waitUntilMovieEnds(ptr);
+ waitUntilMovieEnds(VideoHandle(ptr));
}
void VideoManager::waitUntilMovieEnds(VideoHandle videoHandle) {
@@ -278,7 +278,7 @@ VideoHandle VideoManager::playMovie(const Common::String &fileName) {
return VideoHandle();
ptr->start();
- return ptr;
+ return VideoHandle(ptr);
}
VideoHandle VideoManager::playMovie(uint16 id) {
@@ -287,7 +287,7 @@ VideoHandle VideoManager::playMovie(uint16 id) {
return VideoHandle();
ptr->start();
- return ptr;
+ return VideoHandle(ptr);
}
bool VideoManager::updateMovies() {
@@ -317,50 +317,13 @@ 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 width/height to make sure we stay on the screen (Myst does this a few times)
- uint16 width = MIN<int32>(video->getWidth(), _vm->_system->getWidth() - (*it)->getX());
- uint16 height = MIN<int32>(video->getHeight(), _vm->_system->getHeight() - (*it)->getY());
- _vm->_system->copyRectToScreen(frame->getPixels(), frame->pitch, (*it)->getX(), (*it)->getY(), width, 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;
- }
}
}
// Check the video time
- _vm->doVideoTimer(*it, false);
+ _vm->doVideoTimer(VideoHandle(*it), false);
// Remember to increase the iterator
it++;
@@ -370,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();
@@ -430,7 +461,7 @@ VideoHandle VideoManager::playMovieRiven(uint16 id) {
ptr->start();
}
- return ptr;
+ return VideoHandle(ptr);
}
}
@@ -445,7 +476,7 @@ void VideoManager::playMovieBlockingRiven(uint16 id) {
ptr->moveTo(_mlstRecords[i].left, _mlstRecords[i].top);
ptr->setVolume(_mlstRecords[i].volume);
ptr->start();
- waitUntilMovieEnds(ptr);
+ waitUntilMovieEnds(VideoHandle(ptr));
return;
}
}
@@ -522,7 +553,7 @@ VideoHandle VideoManager::findVideoHandleRiven(uint16 id) {
if (_mlstRecords[i].code == id)
for (VideoList::iterator it = _videos.begin(); it != _videos.end(); it++)
if ((*it)->getID() == _mlstRecords[i].movieID)
- return *it;
+ return VideoHandle(*it);
return VideoHandle();
}
@@ -533,7 +564,7 @@ VideoHandle VideoManager::findVideoHandle(uint16 id) {
for (VideoList::iterator it = _videos.begin(); it != _videos.end(); it++)
if ((*it)->getID() == id)
- return *it;
+ return VideoHandle(*it);
return VideoHandle();
}
@@ -544,7 +575,7 @@ VideoHandle VideoManager::findVideoHandle(const Common::String &fileName) {
for (VideoList::iterator it = _videos.begin(); it != _videos.end(); it++)
if ((*it)->getFileName().equalsIgnoreCase(fileName))
- return *it;
+ return VideoHandle(*it);
return VideoHandle();
}
@@ -558,12 +589,10 @@ 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();
- handle->close();
+ drawNextFrame(handle._ptr);
+ handle->stop();
}
VideoManager::VideoList::iterator VideoManager::findEntry(VideoEntryPtr ptr) {
diff --git a/engines/mohawk/video.h b/engines/mohawk/video.h
index 106a32f8e2..d0edab9def 100644
--- a/engines/mohawk/video.h
+++ b/engines/mohawk/video.h
@@ -293,7 +293,7 @@ private:
/**
* Constructor for internal VideoManager use
*/
- VideoHandle(VideoEntryPtr ptr);
+ explicit VideoHandle(VideoEntryPtr ptr);
/**
* The video entry this is associated with
@@ -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/mortevielle/utils.cpp b/engines/mortevielle/utils.cpp
index cbc22e4886..651bd5bf57 100644
--- a/engines/mortevielle/utils.cpp
+++ b/engines/mortevielle/utils.cpp
@@ -1728,12 +1728,12 @@ void MortevielleEngine::showMoveMenuAlert() {
void MortevielleEngine::showConfigScreen() {
// FIXME: need a DOS palette, index 9 (light blue). Also we should show DOS font here
Common::String tmpStr;
- int width, cy = 0;
+ int cy = 0;
clearScreen();
do {
++cy;
tmpStr = getString(cy + kStartingScreenStringIndex);
- width = _screenSurface->getStringWidth(tmpStr);
+ int width = _screenSurface->getStringWidth(tmpStr);
_text->displayStr(tmpStr, 320 - width / 2, cy * 8, 80, 1, 2);
} while (cy != 20);
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 57580395bf..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 {
@@ -241,11 +258,10 @@ SaveStateList NeverhoodMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Neverhood::NeverhoodEngine::SaveHeader header;
Common::String pattern = target;
- pattern += ".???";
+ pattern += ".###";
Common::StringArray filenames;
filenames = saveFileMan->listSavefiles(pattern.c_str());
- Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
SaveStateList saveList;
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); file++) {
@@ -262,6 +278,8 @@ SaveStateList NeverhoodMetaEngine::listSaves(const char *target) const {
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
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 6911041e58..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"
@@ -93,6 +95,10 @@ void MenuModule::setLoadgameInfo(uint index) {
_savegameSlot = (*_savegameList)[index].slotNum;
}
+void MenuModule::setLoadgameSlot(int slot) {
+ _savegameSlot = slot;
+}
+
void MenuModule::setSavegameInfo(const Common::String &description, uint index, bool newSavegame) {
_savegameDescription = description;
_savegameSlot = newSavegame ? -1 : (*_savegameList)[index].slotNum;
@@ -605,7 +611,8 @@ void TextEditWidget::onClick() {
++newCursorPos;
_cursorPos = MIN((int)_entryString.size(), newCursorPos);
}
- _cursorSurface->setVisible(true);
+ if (!_readOnly)
+ _cursorSurface->setVisible(true);
refresh();
}
Widget::onClick();
@@ -912,7 +919,7 @@ GameStateMenu::GameStateMenu(NeverhoodEngine *vm, Module *parentModule, Savegame
if (slot >= 0) {
if (!isSave) {
- ((MenuModule*)_parentModule)->setLoadgameInfo(slot);
+ ((MenuModule*)_parentModule)->setLoadgameSlot(slot);
} else {
((MenuModule*)_parentModule)->setSavegameInfo(saveDesc,
slot, slot >= saveCount);
@@ -1054,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,
@@ -1064,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[] = {
@@ -1085,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) {
@@ -1098,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[] = {
@@ -1130,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/menumodule.h b/engines/neverhood/menumodule.h
index 6508ccbdf2..1c4ade2369 100644
--- a/engines/neverhood/menumodule.h
+++ b/engines/neverhood/menumodule.h
@@ -43,6 +43,7 @@ public:
MenuModule(NeverhoodEngine *vm, Module *parentModule, int which);
virtual ~MenuModule();
void setLoadgameInfo(uint index);
+ void setLoadgameSlot(int slot);
void setSavegameInfo(const Common::String &description, uint index, bool newSavegame);
void setDeletegameInfo(uint index);
void refreshSaveGameList();
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/module2700.cpp b/engines/neverhood/modules/module2700.cpp
index a510c02558..e0c6509793 100644
--- a/engines/neverhood/modules/module2700.cpp
+++ b/engines/neverhood/modules/module2700.cpp
@@ -761,7 +761,7 @@ void Scene2702::moveCarToPoint(NPoint pt) {
_tracks.findTrackPoint(pt, minMatchTrackIndex, minMatchDistance, _dataResource);
if (minMatchTrackIndex >= 0 && minMatchTrackIndex != _currTrackIndex) {
_newTrackIndex = minMatchTrackIndex;
- _newTrackDestX = pt.x;
+ _newTrackDest = pt;
if (_isUpperTrack) {
if (_currTrackIndex == 0)
sendMessage(_asCar, 0x2003, _trackPoints->size() - 1);
@@ -773,7 +773,7 @@ void Scene2702::moveCarToPoint(NPoint pt) {
sendMessage(_asCar, 0x2003, _trackPoints->size() - 1);
} else {
_newTrackIndex = -1;
- sendMessage(_asCar, 0x2004, pt.x);
+ sendMessage(_asCar, 0x2004, pt);
}
}
@@ -790,7 +790,7 @@ void Scene2702::changeTrack() {
sendMessage(_asCar, NM_POSITION_CHANGE, 0);
else
sendMessage(_asCar, NM_POSITION_CHANGE, _trackPoints->size() - 1);
- sendMessage(_asCar, 0x2004, _newTrackDestX);
+ sendMessage(_asCar, 0x2004, _newTrackDest);
_newTrackIndex = -1;
}
@@ -1092,14 +1092,14 @@ void Scene2706::moveCarToPoint(NPoint pt) {
_tracks.findTrackPoint(pt, minMatchTrackIndex, minMatchDistance, _dataResource);
if (minMatchTrackIndex >= 0 && minMatchTrackIndex != _currTrackIndex) {
_newTrackIndex = minMatchTrackIndex;
- _newTrackDestX = pt.x;
+ _newTrackDest = pt;
if (_currTrackIndex == 0)
sendMessage(_asCar, 0x2003, _trackPoints->size() - 1);
else
sendMessage(_asCar, 0x2003, 0);
} else {
_newTrackIndex = -1;
- sendMessage(_asCar, 0x2004, pt.x);
+ sendMessage(_asCar, 0x2004, pt);
}
}
@@ -1111,7 +1111,7 @@ void Scene2706::changeTrack() {
sendMessage(_asCar, NM_POSITION_CHANGE, _trackPoints->size() - 1);
else
sendMessage(_asCar, NM_POSITION_CHANGE, 0);
- sendMessage(_asCar, 0x2004, _newTrackDestX);
+ sendMessage(_asCar, 0x2004, _newTrackDest);
_newTrackIndex = -1;
}
diff --git a/engines/neverhood/modules/module2700.h b/engines/neverhood/modules/module2700.h
index 9ac2159765..ece8866cd4 100644
--- a/engines/neverhood/modules/module2700.h
+++ b/engines/neverhood/modules/module2700.h
@@ -76,7 +76,7 @@ protected:
Sprite *_asCarShadow;
Sprite *_asCarTrackShadow;
Sprite *_asCarConnectorShadow;
- int16 _newTrackDestX;
+ NPoint _newTrackDest;
bool _isInLight;
int _currTrackIndex, _newTrackIndex;
bool _isUpperTrack;
@@ -132,7 +132,7 @@ protected:
Sprite *_asCarConnector;
Sprite *_asCarTrackShadow;
Sprite *_asCarConnectorShadow;
- int16 _newTrackDestX;
+ NPoint _newTrackDest;
int _currTrackIndex, _newTrackIndex;
Tracks _tracks;
NPointArray *_trackPoints;
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 c0a235cae3..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"
@@ -77,10 +79,6 @@ Common::Error NeverhoodEngine::run() {
_gameState.sceneNum = 0;
_gameState.which = 0;
- // Assign default values to the config manager, in case settings are missing
- ConfMan.registerDefault("originalsaveload", "false");
- ConfMan.registerDefault("skiphallofrecordsscenes", "false");
-
_staticData = new StaticData();
_staticData->load("neverhood.dat");
_gameVars = new GameVars();
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/resourceman.cpp b/engines/neverhood/resourceman.cpp
index 2065a13347..7320cfa4e4 100644
--- a/engines/neverhood/resourceman.cpp
+++ b/engines/neverhood/resourceman.cpp
@@ -96,28 +96,31 @@ struct EntrySizeFix {
static const EntrySizeFix entrySizeFixes[] = {
// fileHash offset diskSize size fixedSize
// Fixes for the Russian "Dyadyushka Risech" version
- { 0x041137051, 667019, 23391, 41398, 41401 }, // "Options" menu header text
+ { 0x041137051, 667019, 23391, 41398, 29191 }, // "Options" menu header text
{ 0x00f960021, 402268, 1704, 4378, 1870 }, // "Save" menu
{ 0x01301a7ea, 1220008, 2373, 4146, 2877 }, // "Load" menu
{ 0x084181e81, 201409, 1622, 5058, 1833 }, // "Delete" menu
+ { 0x0C10B2015, 690410, 5850, 11162, 7870 }, // Menu text
{ 0x008C0AC24, 1031009, 3030, 6498, 3646 }, // Overwrite dialog
- { 0x0c6604282, 12813649, 19623, 35894, 35895 }, // One of the fonts when reading Willie's notes
+ { 0x0c6604282, 12813649, 19623, 35894, 30370 }, // One of the fonts when reading Willie's notes
{ 0x080283101, 13104841, 1961, 3712, 3511 }, // First message from Willie
+ { 0x058208810, 46010519, 24852, 131874, 131776 }, // Entry to hut with musical lock (untested)
{ 0x000918480, 17676417, 581, 916, 706 }, // First wall in the museum
- { 0x00800090C, 16064875, 19555, 38518, 38526 }, // First wall in the museum
- { 0x058208810, 46010519, 24852, 131874, 131776 }, // Entry to hut with musical lock
+ { 0x00800090C, 16064875, 19555, 38518, 30263 }, // First wall in the museum
{ 0x00008E486, 39600019, 240, 454, 271 }, // Second wall in the museum
{ 0x003086004, 39621755, 482, 614, 600 }, // Second wall in the museum
- { 0x02008048E, 39611075, 3798, 21089, 21087 }, // Next couple of walls in the museum
- { 0x008586283, 39587864, 12155, 29731, 29730 }, // Next couple of walls in the museum
- { 0x030A84C80, 39606142, 4933, 16305, 16275 }, // Next couple of walls in the museum
- { 0x000C9A480, 39614873, 6882, 23915, 23913 }, // Next couple of walls in the museum
- { 0x000098880, 39603114, 3028, 10860, 10859 }, // Next couple of walls in the museum
- { 0x040080183, 39600259, 2855, 13400, 13395 }, // Last buggy wall in the museum
+ { 0x02008048E, 39611075, 3798, 21089, 6374 }, // Next walls in the museum
+ { 0x008586283, 39587864, 12155, 29731, 20582 }, // Next walls in the museum
+ { 0x030A84C80, 39606142, 4933, 16305, 8770 }, // Next walls in the museum
+ { 0x000C9A480, 39614873, 6882, 23915, 11571 }, // Next walls in the museum
+ { 0x000098880, 39603114, 3028, 10860, 4762 }, // Next walls in the museum
+ { 0x040080183, 39600259, 2855, 13400, 4305 }, // Next walls in the museum
+ { 0x004290188, 39580567, 7297, 27131, 12322 }, // Next walls in the museum
// Fixes for the Russian "Fargus" version
{ 0x041137051, 758264, 29037, 49590, 49591 }, // "Options" menu header text
{ 0x0c10b2015, 787304, 4414, 15848, 15853 }, // Text on option buttons
+ { 0x006802920, 1076824, 1010, 5642, 1546 }, // Crash in front of the Aqua House
//
{ 0, 0, 0, 0, 0 }
};
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 277f1cbe69..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 {
@@ -271,9 +271,8 @@ bool ParallactionMetaEngine::createInstance(OSystem *syst, Engine **engine, cons
SaveStateList ParallactionMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
- Common::String pattern(ConfMan.getDomain(target)->getVal("gameid") + ".0??");
+ Common::String pattern(ConfMan.getDomain(target)->getVal("gameid") + ".0##");
Common::StringArray filenames = saveFileMan->listSavefiles(pattern);
- sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
SaveStateList saveList;
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
@@ -290,6 +289,8 @@ SaveStateList ParallactionMetaEngine::listSaves(const char *target) const {
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
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 72e9400acd..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());
@@ -194,7 +191,7 @@ int SaveLoad::selectSaveFile(Common::String &selectedName, bool saveMode, const
bool SaveLoad::loadGame() {
Common::String null;
- int _di = selectSaveFile(null, false, "Load file", "Load");
+ int _di = selectSaveFile(null, false, _("Load file"), _("Load"));
if (_di == -1) {
return false;
}
@@ -209,7 +206,7 @@ bool SaveLoad::loadGame() {
bool SaveLoad::saveGame() {
Common::String saveName;
- int slot = selectSaveFile(saveName, true, "Save file", "Save");
+ int slot = selectSaveFile(saveName, true, _("Save file"), _("Save"));
if (slot == -1) {
return false;
}
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/parallaction/staticres.cpp b/engines/parallaction/staticres.cpp
index 40bac5b64d..d7e49b0fca 100644
--- a/engines/parallaction/staticres.cpp
+++ b/engines/parallaction/staticres.cpp
@@ -96,6 +96,7 @@ byte braAmigaFramesDefaultPalette[48] = {
};
+// For the data source and license look into gui/themes/fonts/topaz in ScummVM distribution
byte amigaTopazFont[2600] = {
0x00, 0x00, 0x03, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x79, 0x00, 0x00, 0x03, 0xe9, 0x00, 0x00, 0x02, 0x79,
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 f556d81eab..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() {
@@ -279,7 +281,7 @@ void GraphicsMan::drawTransparentWithTransDrawNode(Graphics::Surface *screen, Dr
// first and last row at the same time (height = 1) - no anti-alias
continue;
}
- // new color value based on orginal screen surface color and sprite's edge pixel color
+ // new color value based on original screen surface color and sprite's edge pixel color
*dst2 = transTableData[*dst2 * 256 + value];
}
}
@@ -375,30 +377,30 @@ byte GraphicsMan::getBlendTableColor(byte pixelColor, byte backgroundPixelColor,
const byte *originalPalette = _vm->_roomBmp->getPalette();
int redFirstOrg = originalPalette[pixelColor * 3] * _vm->_mst_shadow / 256;
- CLIP(redFirstOrg, 0, 255);
+ redFirstOrg = CLIP(redFirstOrg, 0, 255);
if (_vm->_mst_shadow <= 256) {
int redFirstBack = originalPalette[backgroundPixelColor * 3] * (256 - _vm->_mst_shadow) / 256;
- CLIP(redFirstBack, 0, 255);
+ redFirstBack = CLIP(redFirstBack, 0, 255);
redFirstOrg += redFirstBack;
- CLIP(redFirstOrg, 0, 255);
+ redFirstOrg = CLIP(redFirstOrg, 0, 255);
}
int greenFirstOrg = originalPalette[pixelColor * 3 + 1] * _vm->_mst_shadow / 256;
- CLIP(greenFirstOrg, 0, 255);
+ greenFirstOrg = CLIP(greenFirstOrg, 0, 255);
if (_vm->_mst_shadow <= 256) {
int greenFirstBack = originalPalette[backgroundPixelColor * 3 + 1] * (256 - _vm->_mst_shadow) / 256;
- CLIP(greenFirstBack, 0, 255);
+ greenFirstBack = CLIP(greenFirstBack, 0, 255);
greenFirstOrg += greenFirstBack;
- CLIP(greenFirstOrg, 0, 255);
+ greenFirstOrg = CLIP(greenFirstOrg, 0, 255);
}
int blueFirstOrg = originalPalette[pixelColor * 3 + 2] * _vm->_mst_shadow / 256;
- CLIP(blueFirstOrg, 0, 255);
+ blueFirstOrg = CLIP(blueFirstOrg, 0, 255);
if (_vm->_mst_shadow <= 256) {
int blueFirstBack = originalPalette[backgroundPixelColor * 3 + 2] * (256 - _vm->_mst_shadow) / 256;
- CLIP(blueFirstBack, 0, 255);
+ blueFirstBack = CLIP(blueFirstBack, 0, 255);
blueFirstOrg += blueFirstBack;
- CLIP(blueFirstOrg, 0, 255);
+ blueFirstOrg = CLIP(blueFirstOrg, 0, 255);
}
int bigValue = PrinceEngine::kIntMax; // infinity
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 5a7b4c6ad0..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
{
@@ -185,6 +196,32 @@ static const QueenGameDescription gameDescriptions[] = {
},
},
+ // DOS Floppy - Russian
+ {
+ {
+ "queen",
+ "Floppy",
+ AD_ENTRY1s("queen.1", "0d1c10d5c3a1bd90bc0b3859a3258093", 22677657),
+ Common::RU_RUS,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NOSPEECH)
+ },
+ },
+
+ // 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
{
{
@@ -198,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
@@ -243,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
{
@@ -271,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)
{
@@ -364,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)
@@ -388,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 {
@@ -430,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;
}
@@ -461,10 +503,9 @@ SaveStateList QueenMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Common::StringArray filenames;
char saveDesc[32];
- Common::String pattern("queen.s??");
+ Common::String pattern("queen.s##");
filenames = saveFileMan->listSavefiles(pattern);
- sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
SaveStateList saveList;
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
@@ -483,6 +524,8 @@ SaveStateList QueenMetaEngine::listSaves(const char *target) const {
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
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 8487811398..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 {
@@ -180,10 +180,9 @@ SaveStateList SagaMetaEngine::listSaves(const char *target) const {
Common::StringArray filenames;
char saveDesc[SAVE_TITLE_SIZE];
Common::String pattern = target;
- pattern += ".s??";
+ pattern += ".s##";
filenames = saveFileMan->listSavefiles(pattern);
- sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
SaveStateList saveList;
int slotNum = 0;
@@ -203,6 +202,8 @@ SaveStateList SagaMetaEngine::listSaves(const char *target) const {
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
diff --git a/engines/saga/detection_tables.h b/engines/saga/detection_tables.h
index 98009326ae..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),
@@ -825,6 +855,39 @@ static const SAGAGameDescription gameDescriptions[] = {
IHNMCD_GameFonts,
NULL,
},
+
+ // I Have No Mouth And I Must Scream - Russian fan translaction v1.0 (by jack7277 et al)
+ {
+ {
+ "ihnm",
+ "",
+ {
+ {"musicfm.res", GAME_MUSICFILE_FM, "0439083e3dfdc51b486071d45872ae52", -1},
+ {"musicgm.res", GAME_MUSICFILE_GM, "80f875a1fb384160d1f4b27166eef583", -1},
+ {"scream.res", GAME_RESOURCEFILE, "ac00dd9e6701e8edbb49429dacbc4731", 79210049},
+ {"patch.re_", GAME_PATCHFILE | GAME_RESOURCEFILE, "58b79e61594779513c7f2d35509fa89e", -1},
+ {"scripts.res", GAME_SCRIPTFILE, "be38bbc5a26be809dbf39f13befebd01", -1},
+ //{"sfx.res", GAME_SOUNDFILE, "1c610d543f32ec8b525e3f652536f269", -1},
+ // There are two English versions of the game, each one with a different sfx.res file
+ // Known MD5 checksums for sfx.res in the English version of the game are
+ // 1c610d543f32ec8b525e3f652536f269 and 45a9a9f5d37740be24fd2ae2edf36573
+ {"sfx.res", GAME_SOUNDFILE, NULL, -1},
+ { NULL, 0, NULL, 0}
+ },
+ Common::RU_RUS,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NOASPECT)
+ },
+ GID_IHNM,
+ 0,
+ IHNM_DEFAULT_SCENE,
+ &IHNM_Resources,
+ ARRAYSIZE(IHNMCD_GameFonts),
+ IHNMCD_GameFonts,
+ NULL,
+ },
+
// I Have No Mouth And I Must Scream - Mac English CD
{
{
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/font.cpp b/engines/saga/font.cpp
index 73d42598cb..66a4e1c530 100644
--- a/engines/saga/font.cpp
+++ b/engines/saga/font.cpp
@@ -232,7 +232,7 @@ void Font::createOutline(FontData *font) {
}
int Font::translateChar(int charId) {
- if (charId <= 127)
+ if (charId <= 127 || (_vm->getLanguage() == Common::RU_RUS && charId <= 254))
return charId; // normal character
else
return _charMap[charId - 128]; // extended character
diff --git a/engines/saga/interface.cpp b/engines/saga/interface.cpp
index 44581f26fc..c663313f01 100644
--- a/engines/saga/interface.cpp
+++ b/engines/saga/interface.cpp
@@ -332,6 +332,9 @@ void Interface::saveReminderCallback(void *refCon) {
}
void Interface::updateSaveReminder() {
+ // CHECKME: This is potentially called from a different thread because it is
+ // called from a timer callback. However, it does not seem to take any
+ // precautions to avoid race conditions.
if (_active && _panelMode == kPanelMain) {
_saveReminderState = _saveReminderState % _vm->getDisplayInfo().saveReminderNumSprites + 1;
drawStatusBar();
@@ -864,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;
@@ -897,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;
@@ -1153,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 == ' ')) {
@@ -1859,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)
@@ -2280,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/itedata.cpp b/engines/saga/itedata.cpp
index da70733f4e..3577499399 100644
--- a/engines/saga/itedata.cpp
+++ b/engines/saga/itedata.cpp
@@ -422,6 +422,30 @@ const char *ITEinterfaceTextStrings[][53] = {
NULL,
NULL,
"Cardango una partida guardada"
+ },
+ // Russian IHNM
+ {
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xC2\xFB\xE9\xF2\xE8 \xE8\xE7 \xE8\xE3\xF0\xFB?",
+ "Load Successful!",
+ "\xC2\xE2\xE5\xE4\xE8\xF2\xE5 \xE8\xEC\xFF \xE7\xE0\xEF\xE8\xF1\xE8",
+ "\xC4\xE0\xF2\xFC %s >> %s",
+ "\xC8\xF1\xEF\xEE\xEB\xFC\xE7\xEE\xE2\xE0\xF2\xFC %s >> %s",
+ "[\xCD\xEE\xE2\xE0\xFF \xE7\xE0\xEF\xE8\xF1\xFC]",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ " \xC7\xE0\xE3\xF0\xF3\xE7\xEA\xE0 "
}
};
diff --git a/engines/saga/music.cpp b/engines/saga/music.cpp
index 663f5991d0..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"
@@ -224,6 +227,9 @@ void Music::musicVolumeGaugeCallback(void *refCon) {
}
void Music::musicVolumeGauge() {
+ // CHECKME: This is potentially called from a different thread because it is
+ // called from a timer callback. However, it does not seem to take any
+ // precautions to avoid race conditions.
int volume;
_currentVolumePercent += 10;
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 705834f1b7..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,
@@ -399,6 +404,9 @@ void Puzzle::hintTimerCallback(void *refCon) {
}
void Puzzle::solicitHint() {
+ // CHECKME: This is potentially called from a different thread because it is
+ // called from a timer callback. However, it does not seem to take any
+ // precautions to avoid race conditions.
int i;
_vm->_actor->setSpeechColor(1, kITEColorBlack);
diff --git a/engines/saga/render.cpp b/engines/saga/render.cpp
index 1f23a388d0..b932e228ad 100644
--- a/engines/saga/render.cpp
+++ b/engines/saga/render.cpp
@@ -276,6 +276,9 @@ void Render::fpsTimerCallback(void *refCon) {
}
void Render::fpsTimer() {
+ // CHECKME: This is potentially called from a different thread because it is
+ // called from a timer callback. However, it does not seem to take any
+ // precautions to avoid race conditions.
_fps = _renderedFrameCount;
_renderedFrameCount = 0;
}
diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp
index b94bb66bb4..649888e7ea 100644
--- a/engines/saga/saga.cpp
+++ b/engines/saga/saga.cpp
@@ -503,6 +503,9 @@ const char *SagaEngine::getTextString(int textStringId) {
case Common::ES_ESP:
lang = 3;
break;
+ case Common::RU_RUS:
+ lang = 4;
+ break;
default:
lang = 0;
break;
@@ -575,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/savestate.h b/engines/savestate.h
index 54eff0f8cb..21ade602fa 100644
--- a/engines/savestate.h
+++ b/engines/savestate.h
@@ -27,7 +27,6 @@
#include "common/str.h"
#include "common/ptr.h"
-
namespace Graphics {
struct Surface;
}
@@ -205,5 +204,13 @@ private:
/** List of savestates. */
typedef Common::Array<SaveStateDescriptor> SaveStateList;
+/**
+ * Comparator object to compare SaveStateDescriptor's based on slot.
+ */
+struct SaveStateDescriptorSlotComparator {
+ bool operator()(const SaveStateDescriptor &x, const SaveStateDescriptor &y) const {
+ return x.getSaveSlot() < y.getSaveSlot();
+ }
+};
#endif
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 1e95393e4d..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
@@ -137,8 +136,12 @@ Console::Console(SciEngine *engine) : GUI::Debugger(),
registerCmd("wl", WRAP_METHOD(Console, cmdWindowList)); // alias
registerCmd("plane_list", WRAP_METHOD(Console, cmdPlaneList));
registerCmd("pl", WRAP_METHOD(Console, cmdPlaneList)); // alias
+ registerCmd("visible_plane_list", WRAP_METHOD(Console, cmdVisiblePlaneList));
+ 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
@@ -190,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
@@ -330,6 +334,7 @@ bool Console::cmdHelp(int argc, const char **argv) {
debugPrintf("debugflag_list - Lists the available debug flags and their status\n");
debugPrintf("debugflag_enable - Enables a debug flag\n");
debugPrintf("debugflag_disable - Disables a debug flag\n");
+ debugPrintf("debuglevel - Shows or sets debug level\n");
debugPrintf("\n");
debugPrintf("Commands\n");
debugPrintf("--------\n");
@@ -380,7 +385,9 @@ bool Console::cmdHelp(int argc, const char **argv) {
debugPrintf(" animate_list / al - Shows the current list of objects in kAnimate's draw list (SCI0 - SCI1.1)\n");
debugPrintf(" window_list / wl - Shows a list of all the windows (ports) in the draw list (SCI0 - SCI1.1)\n");
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");
@@ -483,14 +490,17 @@ bool Console::cmdGetVersion(int argc, const char **argv) {
debugPrintf("Move count type: %s\n", (_engine->_features->handleMoveCount()) ? "increment" : "ignore");
debugPrintf("SetCursor type: %s\n", getSciVersionDesc(_engine->_features->detectSetCursorType()));
#ifdef ENABLE_SCI32
- if (getSciVersion() >= SCI_VERSION_2)
- debugPrintf("kString type: %s\n", (_engine->_features->detectSci2StringFunctionType() == kSci2StringFunctionOld) ? "SCI2 (old)" : "SCI2.1 (new)");
- if (getSciVersion() == SCI_VERSION_2_1)
+ if ((getSciVersion() >= SCI_VERSION_2_1_EARLY) && (getSciVersion() <= SCI_VERSION_2_1_LATE))
debugPrintf("SCI2.1 kernel table: %s\n", (_engine->_features->detectSci21KernelType() == SCI_VERSION_2) ? "modified SCI2 (old)" : "SCI2.1 (new)");
#endif
debugPrintf("View type: %s\n", viewTypeDesc[g_sci->getResMan()->getViewType()]);
- debugPrintf("Uses palette merging: %s\n", g_sci->_gfxPalette->isMerging() ? "yes" : "no");
- debugPrintf("Uses 16 bit color matching: %s\n", g_sci->_gfxPalette->isUsing16bitColorMatch() ? "yes" : "no");
+ if (getSciVersion() <= SCI_VERSION_1_1) {
+ debugPrintf("kAnimate fastCast enabled: %s\n", g_sci->_gfxAnimate->isFastCastEnabled() ? "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");
@@ -996,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;
@@ -1046,7 +1056,7 @@ bool Console::cmdVerifyScripts(int argc, const char **argv) {
if (!script)
debugPrintf("Error: script %d couldn't be loaded\n", itr->getNumber());
- if (getSciVersion() <= SCI_VERSION_2_1) {
+ if (getSciVersion() <= SCI_VERSION_2_1_LATE) {
heap = _engine->getResMan()->findResource(ResourceId(kResourceTypeHeap, itr->getNumber()), false);
if (!heap)
debugPrintf("Error: script %d doesn't have a corresponding heap\n", itr->getNumber());
@@ -1502,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;
@@ -1539,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 {
@@ -1612,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;
@@ -1620,7 +1630,14 @@ bool Console::cmdSetPalette(int argc, const char **argv) {
uint16 resourceId = atoi(argv[1]);
- _engine->_gfxPalette->kernelSetFromResource(resourceId, true);
+#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;
}
@@ -1639,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);
@@ -1768,6 +1785,21 @@ bool Console::cmdPlaneList(int argc, const char **argv) {
return true;
}
+bool Console::cmdVisiblePlaneList(int argc, const char **argv) {
+#ifdef ENABLE_SCI32
+ if (_engine->_gfxFrameout) {
+ debugPrintf("Visible plane list:\n");
+ _engine->_gfxFrameout->printVisiblePlaneList(this);
+ } else {
+ debugPrintf("This SCI version does not have a list of planes\n");
+ }
+#else
+ debugPrintf("SCI32 isn't included in this compiled executable\n");
+#endif
+ return true;
+}
+
+
bool Console::cmdPlaneItemList(int argc, const char **argv) {
if (argc != 2) {
debugPrintf("Shows the list of items for a plane\n");
@@ -1796,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);
@@ -1809,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;
@@ -1876,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");
@@ -2092,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;
@@ -2128,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;
@@ -2513,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) {
@@ -3038,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:
@@ -3903,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) {
}
@@ -4261,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));
@@ -4291,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 {
@@ -4310,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));
@@ -4341,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 8b10912fbe..cf85def950 100644
--- a/engines/sci/console.h
+++ b/engines/sci/console.h
@@ -96,7 +96,9 @@ private:
bool cmdAnimateList(int argc, const char **argv);
bool cmdWindowList(int argc, const char **argv);
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
@@ -137,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 bac9b3467a..f5797dc106 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,18 @@ 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"},
+ {"hoyle5bridge", "Hoyle Bridge"},
+ {"hoyle5children", "Hoyle Children's Collection"},
+ {"hoyle5solitaire", "Hoyle Solitaire"},
{"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 +154,19 @@ 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 },
+ { "hoyle5bridge", GID_HOYLE5 },
+ { "hoyle5children", GID_HOYLE5 },
+ { "hoyle5solitaire", GID_HOYLE5 },
{ "iceman", GID_ICEMAN },
+ { "inndemo", GID_INNDEMO },
{ "islandbrain", GID_ISLANDBRAIN },
{ "jones", GID_JONES },
{ "kq1sci", GID_KQ1 },
@@ -183,12 +197,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 +372,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";
@@ -379,6 +395,26 @@ static const ADExtraGuiOptionsMap optionsList[] = {
},
{
+ GAMEOPTION_HIGH_RESOLUTION_GRAPHICS,
+ {
+ _s("Enable high resolution graphics"),
+ _s("Enable high resolution graphics/content"),
+ "enable_high_resolution_graphics",
+ true
+ }
+ },
+
+ {
+ 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"),
@@ -463,7 +499,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 {
@@ -516,8 +552,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")) {
@@ -568,7 +604,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles,
ResourceManager resMan;
resMan.addAppropriateSourcesForDetection(fslist);
- resMan.initForDetection();
+ resMan.init();
// TODO: Add error handling.
#ifndef ENABLE_SCI32
@@ -600,7 +636,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
@@ -643,7 +679,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";
@@ -676,7 +712,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;
}
@@ -714,18 +750,17 @@ SaveStateList SciMetaEngine::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..)
SaveStateList saveList;
- int slotNum = 0;
+ int slotNr = 0;
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
- slotNum = atoi(file->c_str() + file->size() - 3);
+ slotNr = atoi(file->c_str() + file->size() - 3);
- if (slotNum >= 0 && slotNum <= 99) {
+ if (slotNr >= 0 && slotNr <= 99) {
Common::InSaveFile *in = saveFileMan->openForLoading(*file);
if (in) {
SavegameMetadata meta;
@@ -734,53 +769,81 @@ SaveStateList SciMetaEngine::listSaves(const char *target) const {
delete in;
continue;
}
- saveList.push_back(SaveStateDescriptor(slotNum, meta.name));
+ SaveStateDescriptor descriptor(slotNr, meta.name);
+
+ if (slotNr == 0) {
+ // ScummVM auto-save slot, not used by SCI
+ // SCI does not support auto-saving, but slot 0 is reserved for auto-saving in ScummVM.
+ descriptor.setWriteProtectedFlag(true);
+ } else {
+ descriptor.setWriteProtectedFlag(false);
+ }
+
+ saveList.push_back(descriptor);
delete in;
}
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
-SaveStateDescriptor SciMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
- Common::String fileName = Common::String::format("%s.%03d", target, slot);
+SaveStateDescriptor SciMetaEngine::querySaveMetaInfos(const char *target, int slotNr) const {
+ Common::String fileName = Common::String::format("%s.%03d", target, slotNr);
Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(fileName);
+ SaveStateDescriptor descriptor(slotNr, "");
+
+ // Do not allow save slot 0 (used for auto-saving) to be deleted or
+ // overwritten. SCI does not support auto-saving, but slot 0 is reserved for auto-saving in ScummVM.
+ if (slotNr == 0) {
+ descriptor.setWriteProtectedFlag(true);
+ descriptor.setDeletableFlag(false);
+ } else {
+ descriptor.setWriteProtectedFlag(false);
+ descriptor.setDeletableFlag(true);
+ }
if (in) {
SavegameMetadata meta;
+
if (!get_savegame_metadata(in, &meta)) {
// invalid
delete in;
- SaveStateDescriptor desc(slot, "Invalid");
- return desc;
+ descriptor.setDescription("*Invalid*");
+ return descriptor;
}
- SaveStateDescriptor desc(slot, meta.name);
+ descriptor.setDescription(meta.name);
Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*in);
- desc.setThumbnail(thumbnail);
+ descriptor.setThumbnail(thumbnail);
int day = (meta.saveDate >> 24) & 0xFF;
int month = (meta.saveDate >> 16) & 0xFF;
int year = meta.saveDate & 0xFFFF;
- desc.setSaveDate(year, month, day);
+ descriptor.setSaveDate(year, month, day);
int hour = (meta.saveTime >> 16) & 0xFF;
int minutes = (meta.saveTime >> 8) & 0xFF;
- desc.setSaveTime(hour, minutes);
+ descriptor.setSaveTime(hour, minutes);
- desc.setPlayTime(meta.playTime * 1000);
+ if (meta.version >= 34) {
+ descriptor.setPlayTime(meta.playTime * 1000 / 60);
+ } else {
+ descriptor.setPlayTime(meta.playTime * 1000);
+ }
delete in;
- return desc;
+ return descriptor;
}
-
- return SaveStateDescriptor();
+ // Return empty descriptor
+ return descriptor;
}
int SciMetaEngine::getMaximumSaveSlot() const { return 99; }
diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h
index 55305c4b42..b945b5559c 100644
--- a/engines/sci/detection_tables.h
+++ b/engines/sci/detection_tables.h
@@ -22,13 +22,15 @@
namespace Sci {
-#define GAMEOPTION_PREFER_DIGITAL_SFX GUIO_GAMEOPTIONS1
-#define GAMEOPTION_ORIGINAL_SAVELOAD GUIO_GAMEOPTIONS2
-#define GAMEOPTION_FB01_MIDI GUIO_GAMEOPTIONS3
-#define GAMEOPTION_JONES_CDAUDIO GUIO_GAMEOPTIONS4
-#define GAMEOPTION_KQ6_WINDOWS_CURSORS GUIO_GAMEOPTIONS5
-#define GAMEOPTION_SQ4_SILVER_CURSORS GUIO_GAMEOPTIONS6
-#define GAMEOPTION_EGA_UNDITHER GUIO_GAMEOPTIONS7
+#define GAMEOPTION_PREFER_DIGITAL_SFX GUIO_GAMEOPTIONS1
+#define GAMEOPTION_ORIGINAL_SAVELOAD GUIO_GAMEOPTIONS2
+#define GAMEOPTION_FB01_MIDI GUIO_GAMEOPTIONS3
+#define GAMEOPTION_JONES_CDAUDIO GUIO_GAMEOPTIONS4
+#define GAMEOPTION_KQ6_WINDOWS_CURSORS GUIO_GAMEOPTIONS5
+#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
@@ -172,6 +174,16 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::ES_ESP, Common::kPlatformDOS, ADGF_ADDENGLISH, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Castle of Dr. Brain aka Dr. Brain Puzzle no Shiro - Japanese PC-98 Floppy (from m_kiewitz)
+ // includes both Japanese and English text
+ // Executable scanning reports "x.yyy.zzz", VERSION file reports "1.000"
+ {"castlebrain", "", {
+ {"resource.map", 0, "ff9674d5d0215a7ebae25ee38d5a72af", 2631},
+ {"resource.000", 0, "27ec5fa09cd12a7fd16e86d96a2ed245", 548272},
+ {"resource.001", 0, "7c3e82c390e934de9b7afcab6de9cec4", 1117317},
+ AD_LISTEND},
+ Common::JA_JPN, Common::kPlatformPC98, ADGF_ADDENGLISH, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
#ifdef ENABLE_SCI32
// Inside the Chest / Behind the Developer's Shield
// SCI interpreter version 2.000.000
@@ -228,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", {
@@ -325,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", "", {
@@ -673,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
@@ -704,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"
@@ -712,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
@@ -720,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
@@ -728,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"
@@ -736,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, GUIO3(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"
@@ -744,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, GUIO4(GUIO_NOASPECT, 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
@@ -752,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, GUIO3(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"
@@ -760,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, GUIO3(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"
@@ -768,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, GUIO3(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
@@ -776,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, GUIO4(GUIO_NOASPECT, 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"
@@ -784,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, GUIO4(GUIO_NOASPECT, 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", "", {
@@ -793,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"
@@ -801,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/
@@ -809,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"
@@ -827,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"
@@ -845,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:
@@ -857,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
@@ -913,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", "", {
@@ -930,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", "", {
@@ -947,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", "", {
@@ -1037,6 +1132,68 @@ 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 GUIO3(GUIO_NOSPEECH, \
+ GUIO_NOASPECT, \
+ GUIO_NOLAUNCHLOAD)
+
+ // 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 },
+
+ // Hoyle 5 (Hoyle Classic Games) - Windows
+ {"hoyle5", "", {
+ {"resource.aud", 0, "cc4a7e21dc864ae21cf823e893c279ad", 257483406},
+ {"ressci.000", 0, "55ae04012a73abc15b93debf60a7df71", 16909704},
+ {"resmap.000", 0, "daf64a91344a7934fe4374765267c2af", 5767},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_HOYLE5 },
+
+ // Hoyle Bridge - Windows
+ {"hoyle5bridge", "", {
+ {"resource.aud", 0, "cc4a7e21dc864ae21cf823e893c279ad", 257585548},
+ {"ressci.000", 0, "b83cba09229d3003df9e0c864843f962", 16842499},
+ {"resmap.000", 0, "7b3e3030b0ad5f341053c18afce7d176", 5647},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_HOYLE5 },
+
+ // Hoyle Children's Collection - Windows
+ {"hoyle5children", "", {
+ {"resource.aud", 0, "cc4a7e21dc864ae21cf823e893c279ad", 257585548},
+ {"ressci.000", 0, "fd1f7dbeebd4510cd37e171a72f2b6ad", 16824349},
+ {"resmap.000", 0, "b0fe1bcc69596e10fe5caa11d0b55b23", 5671},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_HOYLE5 },
+
+ // Hoyle Solitaire (CD version) - Windows
+ {"hoyle5solitaire", "CD", {
+ {"resource.aud", 0, "d41d8cd98f00b204e9800998ecf8427e", 0},
+ {"ressci.000", 0, "fa4eeb24b1fbf6f33739995360554485", 11628203},
+ {"resmap.000", 0, "3f63df73a49800f080775d2a9ad0e949", 3079},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_HOYLE5 },
+
+ // Hoyle Solitaire (Hard Drive version) - Windows
+ {"hoyle5solitaire", "Hard Drive", {
+ {"resource.aud", 0, "d41d8cd98f00b204e9800998ecf8427e", 0},
+ {"ressci.000", 0, "da180c67d54d4208c84a48fcd8709671", 8582335},
+ {"resmap.000", 0, "e2feb47ab16f9e22a9b6a8580d1da3f0", 3055},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_HOYLE5 },
+
+#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", {
@@ -1520,13 +1677,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.000", 0, "71afd220d46bde1109c58e6acc0f3a01", 469094},
{"resource.001", 0, "72a569f46f1abf2d9d2b1526ad3799c3", 12808839},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformFMTowns, 0, GUIO2(GUIO_NOASPECT, GUIO_MIDITOWNS) },
- {"kq5", "", {
- {"resource.map", 0, "20c7cd248ff1a349ed354568eebd972b", 12733},
- {"resource.000", 0, "71afd220d46bde1109c58e6acc0f3a01", 469094},
- {"resource.001", 0, "72a569f46f1abf2d9d2b1526ad3799c3", 12808839},
- AD_LISTEND},
- Common::JA_JPN, Common::kPlatformFMTowns, 0, GUIO2(GUIO_NOASPECT, GUIO_MIDITOWNS) },
+ Common::JA_JPN, Common::kPlatformFMTowns, ADGF_ADDENGLISH, GUIO3(GUIO_NOASPECT, GAMEOPTION_ORIGINAL_SAVELOAD, GUIO_MIDITOWNS) },
// King's Quest 5 - Japanese PC-98 Floppy 0.000.015 (supplied by omer_mor in bug report #3073583)
{"kq5", "", {
@@ -1559,7 +1710,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "eb9e177281b7cde188dc0d83194cd365", 8960},
{"resource.msg", 0, "3cf5de44de36191f109d425b8450efc8", 259510},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_CD | ADGF_DEMO, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_CD | ADGF_DEMO, GUIO5(GUIO_NOSPEECH, GAMEOPTION_HIGH_RESOLUTION_GRAPHICS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
// King's Quest 6 - English DOS Floppy
// SCI interpreter version 1.001.054
@@ -1613,7 +1764,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "7a550ebfeae2575ca00d47703a6a774c", 9215},
{"resource.000", 0, "233394a5f33b475ae5975e7e9a420865", 8376352},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_CD, GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_CD, GUIO4(GAMEOPTION_HIGH_RESOLUTION_GRAPHICS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
// King's Quest 6 - English Windows CD (from the King's Quest Collection)
// Executable scanning reports "1.cfs.158", VERSION file reports "1.034 9/11/94 - KQ6 version 1.000.00G"
@@ -1622,7 +1773,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "7a550ebfeae2575ca00d47703a6a774c", 9215},
{"resource.000", 0, "233394a5f33b475ae5975e7e9a420865", 8376352},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_CD, GUIO5(GUIO_NOASPECT, GAMEOPTION_KQ6_WINDOWS_CURSORS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_CD, GUIO6(GUIO_NOASPECT, GAMEOPTION_HIGH_RESOLUTION_GRAPHICS, GAMEOPTION_KQ6_WINDOWS_CURSORS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
// King's Quest 6 - English Macintosh Floppy
// VERSION file reports "1.0"
@@ -1634,14 +1785,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, GUIO5(GUIO_NOSPEECH, 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"
@@ -1649,7 +1801,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, GUIO5(GUIO_NOSPEECH, 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"
@@ -1657,7 +1836,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, GUIO5(GUIO_NOSPEECH, 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"
@@ -1665,15 +1844,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, GUIO5(GUIO_NOSPEECH, 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, GUIO5(GUIO_NOSPEECH, 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"
@@ -1681,7 +1852,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, GUIO5(GUIO_NOSPEECH, 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
@@ -1689,7 +1860,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
@@ -1697,7 +1868,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, GUIO5(GUIO_NOSPEECH, 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
@@ -1937,6 +2108,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
@@ -1994,6 +2176,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
@@ -2008,6 +2201,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", "", {
@@ -2275,6 +2481,14 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformDOS, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Larry 6 - French DOS Floppy - LOWRES (provided by theco33)
+ // SCI interpreter version 1.001.113
+ {"lsl6", "", {
+ {"resource.map", 0, "1e07144d3b06a3269236880170978acb", 6943},
+ {"resource.000", 0, "7884a8db9253e29e6b37a2651fd90ba3", 5749882},
+ AD_LISTEND},
+ Common::FR_FRA, Common::kPlatformDOS, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Larry 6 - English/German/French DOS CD - LOWRES
// SCI interpreter version 1.001.115
{"lsl6", "", {
@@ -2344,13 +2558,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
@@ -2358,7 +2578,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
@@ -2366,7 +2586,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
@@ -2374,7 +2605,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)
@@ -2383,7 +2614,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
@@ -2391,7 +2622,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
@@ -2399,7 +2630,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
@@ -2407,7 +2638,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"
@@ -2415,16 +2646,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
@@ -2433,7 +2676,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"
@@ -2443,7 +2686,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"
@@ -2453,7 +2696,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"
@@ -2463,7 +2706,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
@@ -2582,21 +2825,22 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "b11e971ccd2040bebba59dfb409a08ef", 5772},
{"resource.001", 0, "d49625d9b8005ec01c852f8322a82867", 4330713},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformFMTowns, 0, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
- {"mothergoose256", "", {
- {"resource.map", 0, "b11e971ccd2040bebba59dfb409a08ef", 5772},
- {"resource.001", 0, "d49625d9b8005ec01c852f8322a82867", 4330713},
- AD_LISTEND},
- Common::JA_JPN, Common::kPlatformFMTowns, 0, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ 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"
@@ -2604,7 +2848,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
@@ -2616,6 +2860,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", "", {
@@ -2634,7 +2914,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"
@@ -2657,7 +2937,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
@@ -2676,7 +2956,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"
@@ -2684,7 +2964,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"
@@ -2695,7 +2975,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:
@@ -2711,10 +2991,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},
@@ -2728,13 +3020,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},
@@ -2747,17 +3051,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
@@ -2844,6 +3138,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", "", {
@@ -2863,7 +3168,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) },
+ // 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
{"pq2", "", {
{"resource.map", 0, "883804c616dca1d82373bf9fda3a71d2", 4656},
@@ -2871,7 +3188,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.002", 0, "05fdee43a228dd6ea4d1a92ccae3f788", 637662},
{"resource.003", 0, "05fdee43a228dd6ea4d1a92ccae3f788", 684395},
AD_LISTEND},
- Common::JA_JPN, Common::kPlatformPC98, ADGF_ADDENGLISH, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::JA_JPN, Common::kPlatformPC98, ADGF_ADDENGLISH, GUIO6(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
// Police Quest 3 - English Amiga
// Executable scanning reports "1.004.024"
@@ -2958,20 +3275,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, GUIO3(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
@@ -2979,7 +3307,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, GUIO3(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?)
@@ -2987,7 +3315,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
@@ -2995,7 +3323,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?)
@@ -3003,7 +3331,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"
@@ -3011,7 +3350,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"
@@ -3019,7 +3358,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"
@@ -3034,7 +3373,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)
@@ -3130,6 +3469,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", {
@@ -3209,6 +3561,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", "", {
@@ -3370,20 +3723,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
@@ -3391,7 +3754,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"
@@ -3399,7 +3762,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"
@@ -3407,7 +3770,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"
@@ -3415,7 +3785,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)
@@ -3428,7 +3798,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", "", {
@@ -3439,7 +3809,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", "", {
@@ -3450,7 +3820,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?)
@@ -3458,23 +3828,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"
@@ -3482,7 +3858,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.
@@ -3500,7 +3876,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)
@@ -3508,7 +3884,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
@@ -3630,6 +4006,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)
@@ -4028,13 +4416,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)
@@ -4042,7 +4442,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"
@@ -4050,7 +4450,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)
@@ -4058,7 +4458,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)
@@ -4066,7 +4466,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)
@@ -4094,13 +4494,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, 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
@@ -4108,7 +4518,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, 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"
@@ -4117,7 +4527,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, 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
@@ -4125,7 +4535,16 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "bb3b0b22ff08df54fbe2d06263409be6", 9799},
{"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887},
AD_LISTEND},
- Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE, 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
+ // VERSION file "1.0"
+ {"torin", "", {
+ {"resmap.000", 0, "e55c3097329b3c53752301e01c6af2fb", 9787},
+ {"ressci.000", 0, "118f9bec04bfe17c4f87bbb5ddb43c18", 56127540},
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO_TORIN },
// Torin's Passage (Multilingual) - German Windows CD
// SCI interpreter version 2.100.002
@@ -4133,7 +4552,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, 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
@@ -4141,7 +4560,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, 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
@@ -4149,7 +4568,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, 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", "", {
@@ -4161,7 +4590,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, 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
@@ -4185,7 +4614,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
FANMADE_L("Grostesteing: Plus Mechant que Jamais", "ec9a97ccb134f69249f6ea8b16c13d8e", 1500, "b869f5f11bfe2ab5f67f4f0c618f2ce1", 464657, Common::FR_FRA), // FIXME: Accent
FANMADE("Humanoid Demo", "97d8331293a6d57e8bad58c1efc89a63", 624, "fb354b9abe64011b12159e45d724633f", 452320),
FANMADE("Island of Secrets Demo 0.3", "61279176c3e4530fec9b578877aecda7", 504, "7f4ed7a81b86bea22c62bc98e6d9ec39", 197790),
- FANMADE("Jim’s Quest 1: The Phantom Thesis", "0af50be1d3f0cb77a09137709a76ef4f", 960, "9c042c136548b20d9183495668e03526", 496446),
+ FANMADE("Jim's Quest 1: The Phantom Thesis", "0af50be1d3f0cb77a09137709a76ef4f", 960, "9c042c136548b20d9183495668e03526", 496446),
FANMADE("King's Quest II SCI Pre-Alpha Version", "cdea1c081022e7697a1afffb1d2f9f6a", 2646, "fb2ce39002c3e05f3d83533638dea105", 2310356),
FANMADE("Knight's Quest Demo 1.0", "5e816edf993956752ed06fccfeeae6d9", 1260, "959321f88a22905fa1f8c6d897874744", 703836),
FANMADE("LockerGnome Quest", "3eeff9130206cad0c4e1551e2b9dd2c5", 420, "ae05ca90806fd90cc43f147c82d3547c", 158906),
diff --git a/engines/sci/engine/features.cpp b/engines/sci/engine/features.cpp
index be062dba64..a993506f7a 100644
--- a/engines/sci/engine/features.cpp
+++ b/engines/sci/engine/features.cpp
@@ -40,7 +40,6 @@ GameFeatures::GameFeatures(SegManager *segMan, Kernel *kernel) : _segMan(segMan)
_moveCountType = kMoveCountUninitialized;
#ifdef ENABLE_SCI32
_sci21KernelType = SCI_VERSION_NONE;
- _sci2StringFunctionType = kSci2StringFunctionUninitialized;
#endif
_usesCdTrack = Common::File::exists("cdaudio.map");
if (!ConfMan.getBool("use_cdaudio"))
@@ -143,8 +142,8 @@ SciVersion GameFeatures::detectDoSoundType() {
// SCI0LATE. Although the last SCI0EARLY game (lsl2) uses SCI0LATE resources
_doSoundType = g_sci->getResMan()->detectEarlySound() ? SCI_VERSION_0_EARLY : SCI_VERSION_0_LATE;
#ifdef ENABLE_SCI32
- } else if (getSciVersion() >= SCI_VERSION_2_1) {
- _doSoundType = SCI_VERSION_2_1;
+ } else if (getSciVersion() >= SCI_VERSION_2_1_EARLY) {
+ _doSoundType = SCI_VERSION_2_1_EARLY;
#endif
} else if (SELECTOR(nodePtr) == -1) {
// No nodePtr selector, so this game is definitely using newer
@@ -271,7 +270,7 @@ SciVersion GameFeatures::detectLofsType() {
return _lofsType;
}
- if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
+ if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
// SCI1.1 type, i.e. we compensate for the fact that the heap is attached
// to the end of the script
_lofsType = SCI_VERSION_1_1;
@@ -475,7 +474,7 @@ bool GameFeatures::autoDetectSci21KernelType() {
}
warning("autoDetectSci21KernelType(): Sound object not loaded, assuming a SCI2.1 table");
- _sci21KernelType = SCI_VERSION_2_1;
+ _sci21KernelType = SCI_VERSION_2_1_EARLY;
return true;
}
@@ -514,7 +513,7 @@ bool GameFeatures::autoDetectSci21KernelType() {
_sci21KernelType = SCI_VERSION_2;
return true;
} else if (kFuncNum == 0x75) {
- _sci21KernelType = SCI_VERSION_2_1;
+ _sci21KernelType = SCI_VERSION_2_1_EARLY;
return true;
}
}
@@ -532,65 +531,6 @@ SciVersion GameFeatures::detectSci21KernelType() {
}
return _sci21KernelType;
}
-
-Sci2StringFunctionType GameFeatures::detectSci2StringFunctionType() {
- if (_sci2StringFunctionType == kSci2StringFunctionUninitialized) {
- if (getSciVersion() <= SCI_VERSION_1_1) {
- error("detectSci21StringFunctionType() called from SCI1.1 or earlier");
- } else if (getSciVersion() == SCI_VERSION_2) {
- // SCI2 games are always using the old type
- _sci2StringFunctionType = kSci2StringFunctionOld;
- } else if (getSciVersion() == SCI_VERSION_3) {
- // SCI3 games are always using the new type
- _sci2StringFunctionType = kSci2StringFunctionNew;
- } else { // SCI2.1
- if (!autoDetectSci21StringFunctionType())
- _sci2StringFunctionType = kSci2StringFunctionOld;
- else
- _sci2StringFunctionType = kSci2StringFunctionNew;
- }
- }
-
- debugC(1, kDebugLevelVM, "Detected SCI2 kString type: %s", (_sci2StringFunctionType == kSci2StringFunctionOld) ? "old" : "new");
-
- return _sci2StringFunctionType;
-}
-
-bool GameFeatures::autoDetectSci21StringFunctionType() {
- // Look up the script address
- reg_t addr = getDetectionAddr("Str", SELECTOR(size));
-
- if (!addr.getSegment())
- return false;
-
- uint16 offset = addr.getOffset();
- Script *script = _segMan->getScript(addr.getSegment());
-
- while (true) {
- int16 opparams[4];
- byte extOpcode;
- byte opcode;
- offset += readPMachineInstruction(script->getBuf(offset), extOpcode, opparams);
- opcode = extOpcode >> 1;
-
- // Check for end of script
- if (opcode == op_ret || offset >= script->getBufSize())
- break;
-
- if (opcode == op_callk) {
- uint16 kFuncNum = opparams[0];
-
- // SCI2.1 games which use the new kString functions call kString(8).
- // Earlier ones call the callKernel script function, but not kString
- // directly
- if (_kernel->getKernelName(kFuncNum) == "String")
- return true;
- }
- }
-
- return false; // not found a call to kString
-}
-
#endif
bool GameFeatures::autoDetectMoveCountType() {
diff --git a/engines/sci/engine/features.h b/engines/sci/engine/features.h
index a4d715fee0..1c410267e6 100644
--- a/engines/sci/engine/features.h
+++ b/engines/sci/engine/features.h
@@ -34,12 +34,6 @@ enum MoveCountType {
kIncrementMoveCount
};
-enum Sci2StringFunctionType {
- kSci2StringFunctionUninitialized,
- kSci2StringFunctionOld,
- kSci2StringFunctionNew
-};
-
class GameFeatures {
public:
GameFeatures(SegManager *segMan, Kernel *kernel);
@@ -82,13 +76,6 @@ public:
* @return Graphics functions type, SCI_VERSION_2 / SCI_VERSION_2_1
*/
SciVersion detectSci21KernelType();
-
- /**
- * Autodetects the string subfunctions used in SCI2 - SCI3
- * @return string subfunctions type, kSci2StringFunctionOld / kSci2StringFunctionNew
- */
- Sci2StringFunctionType detectSci2StringFunctionType();
-
#endif
/**
@@ -132,13 +119,11 @@ private:
bool autoDetectMoveCountType();
#ifdef ENABLE_SCI32
bool autoDetectSci21KernelType();
- bool autoDetectSci21StringFunctionType();
#endif
SciVersion _doSoundType, _setCursorType, _lofsType, _gfxFunctionsType, _messageFunctionType;
#ifdef ENABLE_SCI32
SciVersion _sci21KernelType;
- Sci2StringFunctionType _sci2StringFunctionType;
#endif
MoveCountType _moveCountType;
diff --git a/engines/sci/engine/file.cpp b/engines/sci/engine/file.cpp
index 623caec856..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
@@ -66,15 +173,52 @@ reg_t file_open(EngineState *s, const Common::String &filename, int mode, bool u
bool isCompressed = true;
const SciGameId gameId = g_sci->getGameId();
- if ((gameId == GID_QFG1 || gameId == GID_QFG1VGA || gameId == GID_QFG2 || gameId == GID_QFG3)
- && englishName.hasSuffix(".sav")) {
- // QFG Characters are saved via the CharSave object.
- // We leave them uncompressed so that they can be imported in later QFG
- // games.
- // Rooms/Scripts: QFG1: 601, QFG2: 840, QFG3/4: 52
- isCompressed = false;
+
+ // QFG Characters are saved via the CharSave object.
+ // We leave them uncompressed so that they can be imported in later QFG
+ // games, even when using the original interpreter.
+ // We check for room numbers in here, because the file suffix can be changed by the user.
+ // Rooms/Scripts: QFG1(EGA/VGA): 601, QFG2: 840, QFG3/4: 52
+ switch (gameId) {
+ case GID_QFG1:
+ case GID_QFG1VGA:
+ if (s->currentRoomNumber() == 601)
+ isCompressed = false;
+ break;
+ case GID_QFG2:
+ if (s->currentRoomNumber() == 840)
+ isCompressed = false;
+ break;
+ case GID_QFG3:
+ case GID_QFG4:
+ if (s->currentRoomNumber() == 52)
+ isCompressed = false;
+ break;
+ default:
+ 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);
@@ -110,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;
@@ -129,7 +265,7 @@ reg_t file_open(EngineState *s, const Common::String &filename, int mode, bool u
}
FileHandle *getFileFromHandle(EngineState *s, uint handle) {
- if (handle == 0 || handle == VIRTUALFILE_HANDLE) {
+ if ((handle == 0) || ((handle >= VIRTUALFILE_HANDLE_START) && (handle <= VIRTUALFILE_HANDLE_END))) {
error("Attempt to use invalid file handle (%d)", handle);
return 0;
}
@@ -236,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();
@@ -349,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 052eb735e9..982d7b7823 100644
--- a/engines/sci/engine/file.h
+++ b/engines/sci/engine/file.h
@@ -41,8 +41,10 @@ enum {
MAX_SAVEGAME_NR = 20 /**< Maximum number of savegames */
};
-#define VIRTUALFILE_HANDLE 200
-#define PHANTASMAGORIA_SAVEGAME_INDEX "phantsg.dir"
+#define VIRTUALFILE_HANDLE_START 32000
+#define VIRTUALFILE_HANDLE_SCI32SAVE 32100
+#define VIRTUALFILE_HANDLE_SCIAUDIO 32300
+#define VIRTUALFILE_HANDLE_END 32300
struct SavegameDesc {
int16 id;
@@ -90,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 bfb7bfcd08..2afb8b73d1 100644
--- a/engines/sci/engine/kernel.cpp
+++ b/engines/sci/engine/kernel.cpp
@@ -35,6 +35,9 @@ namespace Sci {
Kernel::Kernel(ResourceManager *resMan, SegManager *segMan)
: _resMan(resMan), _segMan(segMan), _invalid("<invalid>") {
+#ifdef ENABLE_SCI32
+ _kernelFunc_StringId = 0;
+#endif
}
Kernel::~Kernel() {
@@ -81,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)
@@ -118,7 +127,7 @@ void Kernel::loadSelectorNames() {
// Starting with KQ7, Mac versions have a BE name table. GK1 Mac and earlier (and all
// other platforms) always use LE.
- bool isBE = (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2_1
+ bool isBE = (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2_1_EARLY
&& g_sci->getGameId() != GID_GK1);
if (!r) { // No such resource?
@@ -603,6 +612,10 @@ void Kernel::mapFunctions() {
}
#ifdef ENABLE_SCI32
+ if (kernelName == "String") {
+ _kernelFunc_StringId = id;
+ }
+
// HACK: Phantasmagoria Mac uses a modified kDoSound (which *nothing*
// else seems to use)!
if (g_sci->getPlatform() == Common::kPlatformMacintosh && g_sci->getGameId() == GID_PHANTASMAGORIA && kernelName == "DoSound") {
@@ -842,11 +855,11 @@ void Kernel::loadKernelNames(GameFeatures *features) {
// In the Windows version of KQ6 CD, the empty kSetSynonyms
// function has been replaced with kPortrait. In KQ6 Mac,
// kPlayBack has been replaced by kShowMovie.
- if (g_sci->getPlatform() == Common::kPlatformWindows)
+ if ((g_sci->getPlatform() == Common::kPlatformWindows) || (g_sci->forceHiresGraphics()))
_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
}
@@ -863,15 +876,17 @@ void Kernel::loadKernelNames(GameFeatures *features) {
_kernelNames = Common::StringArray(sci2_default_knames, kKernelEntriesSci2);
break;
- case SCI_VERSION_2_1:
+ case SCI_VERSION_2_1_EARLY:
+ case SCI_VERSION_2_1_MIDDLE:
+ case SCI_VERSION_2_1_LATE:
if (features->detectSci21KernelType() == SCI_VERSION_2) {
// Some early SCI2.1 games use a modified SCI2 kernel table instead of
// the SCI2.1 kernel table. We detect which version to use based on
// 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
@@ -882,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 57b4d9455b..5ff4f932be 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -75,6 +75,10 @@ struct SciWorkaroundEntry; // from workarounds.h
* vocab.997. This results in much more readable code. Thus, this vocabulary isn't
* used at all.
*
+ * 993.voc (unneeded) - Contains the SCI3 equivalent of vocab.994; like its predecessor,
+ * the raw selector numbers can be deduced and used instead. In fact, one version of this
+ * file has turned out to cover all versiona of SCI3.
+ *
* SCI0 parser vocabularies:
* - vocab.901 / 901.voc - suffix vocabulary
* - vocab.900 / 900.voc - parse tree branches
@@ -154,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.
@@ -173,6 +178,12 @@ public:
typedef Common::Array<KernelFunction> KernelFunctionArray;
KernelFunctionArray _kernelFuncs; /**< Table of kernel functions. */
+#ifdef ENABLE_SCI32
+ // id of kString function, for quick usage in kArray
+ // kArray calls kString in case parameters are strings
+ uint16 _kernelFunc_StringId;
+#endif
+
/**
* Determines whether a list of registers matches a given signature.
* If no signature is given (i.e., if sig is NULL), this is always
@@ -410,27 +421,117 @@ 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);
reg_t kString(EngineState *s, int argc, reg_t *argv);
+
+reg_t kStringNew(EngineState *s, int argc, reg_t *argv);
+reg_t kStringSize(EngineState *s, int argc, reg_t *argv);
+reg_t kStringAt(EngineState *s, int argc, reg_t *argv);
+reg_t kStringPutAt(EngineState *s, int argc, reg_t *argv);
+reg_t kStringFree(EngineState *s, int argc, reg_t *argv);
+reg_t kStringFill(EngineState *s, int argc, reg_t *argv);
+reg_t kStringCopy(EngineState *s, int argc, reg_t *argv);
+reg_t kStringCompare(EngineState *s, int argc, reg_t *argv);
+reg_t kStringDup(EngineState *s, int argc, reg_t *argv);
+reg_t kStringGetData(EngineState *s, int argc, reg_t *argv);
+reg_t kStringLen(EngineState *s, int argc, reg_t *argv);
+reg_t kStringPrintf(EngineState *s, int argc, reg_t *argv);
+reg_t kStringPrintfBuf(EngineState *s, int argc, reg_t *argv);
+reg_t kStringAtoi(EngineState *s, int argc, reg_t *argv);
+reg_t kStringTrim(EngineState *s, int argc, reg_t *argv);
+reg_t kStringUpper(EngineState *s, int argc, reg_t *argv);
+reg_t kStringLower(EngineState *s, int argc, reg_t *argv);
+reg_t kStringTrn(EngineState *s, int argc, reg_t *argv);
+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);
-// "Screen items" in SCI32 are views
+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);
-// Text
+
reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv);
-reg_t kDisposeTextBitmap(EngineState *s, int argc, reg_t *argv);
-// "Planes" in SCI32 are pictures
+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);
@@ -445,12 +546,33 @@ reg_t kEditText(EngineState *s, int argc, reg_t *argv);
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 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 kPalVaryUnknown(EngineState *s, int argc, reg_t *argv);
-reg_t kPalVaryUnknown2(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);
+reg_t kPalVaryOff(EngineState *s, int argc, reg_t *argv);
+reg_t kPalVaryMergeTarget(EngineState *s, int argc, reg_t *argv);
+reg_t kPalVarySetTime(EngineState *s, int argc, reg_t *argv);
+reg_t kPalVarySetTarget(EngineState *s, int argc, reg_t *argv);
+reg_t kPalVarySetStart(EngineState *s, int argc, reg_t *argv);
+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);
@@ -463,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);
@@ -484,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);
@@ -499,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 2cbd79366d..8a1176eed8 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -34,6 +34,15 @@ namespace Sci {
// . -> any type
// i* -> optional multiple integers
// .* -> any parameters afterwards (or none)
+//
+// data types:
+// i - regular integer
+// o - object
+// r - reference
+// n - node
+// 0 - NULL
+// . - any
+// ! - invalid reference/offset
struct SciKernelMapSubEntry {
SciVersion fromVersion;
@@ -51,12 +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_SCI21 SCI_VERSION_2_1, 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
@@ -65,7 +81,7 @@ struct SciKernelMapSubEntry {
#define SIG_SOUNDSCI0 SCI_VERSION_0_EARLY, SCI_VERSION_0_LATE
#define SIG_SOUNDSCI1EARLY SCI_VERSION_1_EARLY, SCI_VERSION_1_EARLY
#define SIG_SOUNDSCI1LATE SCI_VERSION_1_LATE, SCI_VERSION_1_LATE
-#define SIG_SOUNDSCI21 SCI_VERSION_2_1, SCI_VERSION_3
+#define SIG_SOUNDSCI21 SCI_VERSION_2_1_EARLY, SCI_VERSION_3
#define SIGFOR_ALL 0x3f
#define SIGFOR_DOS 1 << 0
@@ -86,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 },
@@ -99,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 },
@@ -112,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 },
@@ -127,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 },
@@ -136,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
@@ -190,31 +267,43 @@ static const SciKernelMapSubEntry kGraph_subops[] = {
// version, subId, function-mapping, signature, workarounds
static const SciKernelMapSubEntry kPalVary_subops[] = {
- { SIG_SCI21, 0, MAP_CALL(PalVaryInit), "ii(i)(i)(i)", NULL },
- { SIG_SCIALL, 0, MAP_CALL(PalVaryInit), "ii(i)(i)", NULL },
- { SIG_SCIALL, 1, MAP_CALL(PalVaryReverse), "(i)(i)(i)", NULL },
- { SIG_SCIALL, 2, MAP_CALL(PalVaryGetCurrentStep), "", NULL },
- { SIG_SCIALL, 3, MAP_CALL(PalVaryDeinit), "", NULL },
- { SIG_SCIALL, 4, MAP_CALL(PalVaryChangeTarget), "i", NULL },
- { SIG_SCIALL, 5, MAP_CALL(PalVaryChangeTicks), "i", NULL },
- { SIG_SCIALL, 6, MAP_CALL(PalVaryPauseResume), "i", NULL },
+ { SIG_SCI16, 0, MAP_CALL(PalVaryInit), "ii(i)(i)", NULL },
+ { SIG_SCI16, 1, MAP_CALL(PalVaryReverse), "(i)(i)(i)", NULL },
+ { SIG_SCI16, 2, MAP_CALL(PalVaryGetCurrentStep), "", NULL },
+ { SIG_SCI16, 3, MAP_CALL(PalVaryDeinit), "", NULL },
+ { SIG_SCI16, 4, MAP_CALL(PalVaryChangeTarget), "i", NULL },
+ { SIG_SCI16, 5, MAP_CALL(PalVaryChangeTicks), "i", NULL },
+ { SIG_SCI16, 6, MAP_CALL(PalVaryPauseResume), "i", NULL },
#ifdef ENABLE_SCI32
- { SIG_SCI32, 8, MAP_CALL(PalVaryUnknown), "i", NULL },
- { SIG_SCI32, 9, MAP_CALL(PalVaryUnknown2), "i", NULL },
+ { SIG_SCI32, 0, MAP_CALL(PalVarySetVary), "i(i)(i)(ii)", 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 },
+ { SIG_SCI32, 5, MAP_CALL(PalVarySetTime), "i", NULL },
+ { SIG_SCI32, 6, MAP_CALL(PalVaryPauseResume), "i", NULL },
+ { SIG_SCI32, 7, MAP_CALL(PalVarySetTarget), "i", NULL },
+ { SIG_SCI32, 8, MAP_CALL(PalVarySetStart), "i", NULL },
+ { SIG_SCI32, 9, MAP_CALL(PalVaryMergeStart), "i", NULL },
#endif
SCI_SUBOPENTRY_TERMINATOR
};
// version, subId, function-mapping, signature, workarounds
static const SciKernelMapSubEntry kPalette_subops[] = {
- { SIG_SCIALL, 1, MAP_CALL(PaletteSetFromResource), "i(i)", NULL },
- { SIG_SCIALL, 2, MAP_CALL(PaletteSetFlag), "iii", NULL },
- { SIG_SCIALL, 3, MAP_CALL(PaletteUnsetFlag), "iii", kPaletteUnsetFlag_workarounds },
- { SIG_SCIALL, 4, MAP_CALL(PaletteSetIntensity), "iii(i)", NULL },
- { SIG_SCIALL, 5, MAP_CALL(PaletteFindColor), "iii", NULL },
- { SIG_SCIALL, 6, MAP_CALL(PaletteAnimate), "i*", NULL },
- { SIG_SCIALL, 7, MAP_CALL(PaletteSave), "", NULL },
- { SIG_SCIALL, 8, MAP_CALL(PaletteRestore), "[r0]", 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(PaletteFindColor32), "iii", NULL },
+#endif
+ { SIG_SCI16, 4, MAP_CALL(PaletteSetIntensity), "iii(i)", NULL },
+ { SIG_SCI16, 5, MAP_CALL(PaletteFindColor), "iii", NULL },
+ { SIG_SCI16, 6, MAP_CALL(PaletteAnimate), "i*", NULL },
+ { SIG_SCI16, 7, MAP_CALL(PaletteSave), "", NULL },
+ { SIG_SCI16, 8, MAP_CALL(PaletteRestore), "[r0]", NULL },
SCI_SUBOPENTRY_TERMINATOR
};
@@ -246,6 +335,17 @@ 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 },
@@ -260,32 +360,168 @@ 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_SCI21, 0, MAP_CALL(NewList), "", NULL },
- { SIG_SCI21, 1, MAP_CALL(DisposeList), "l", NULL },
- { SIG_SCI21, 2, MAP_CALL(NewNode), ".(.)", NULL },
- { SIG_SCI21, 3, MAP_CALL(FirstNode), "[l0]", NULL },
- { SIG_SCI21, 4, MAP_CALL(LastNode), "l", NULL },
- { SIG_SCI21, 5, MAP_CALL(EmptyList), "l", NULL },
- { SIG_SCI21, 6, MAP_CALL(NextNode), "n", NULL },
- { SIG_SCI21, 7, MAP_CALL(PrevNode), "n", NULL },
- { SIG_SCI21, 8, MAP_CALL(NodeValue), "[n0]", NULL },
- { SIG_SCI21, 9, MAP_CALL(AddAfter), "lnn.", NULL },
- { SIG_SCI21, 10, MAP_CALL(AddToFront), "ln.", NULL },
- { SIG_SCI21, 11, MAP_CALL(AddToEnd), "ln(.)", NULL },
- { SIG_SCI21, 12, MAP_CALL(AddBefore), "ln.", NULL },
- { SIG_SCI21, 13, MAP_CALL(MoveToFront), "ln", NULL },
- { SIG_SCI21, 14, MAP_CALL(MoveToEnd), "ln", NULL },
- { SIG_SCI21, 15, MAP_CALL(FindKey), "l.", NULL },
- { SIG_SCI21, 16, MAP_CALL(DeleteKey), "l.", NULL },
- { SIG_SCI21, 17, MAP_CALL(ListAt), "li", NULL },
- { SIG_SCI21, 18, MAP_CALL(ListIndexOf) , "l[io]", NULL },
- { SIG_SCI21, 19, MAP_CALL(ListEachElementDo), "li(.*)", NULL },
- { SIG_SCI21, 20, MAP_CALL(ListFirstTrue), "li(.*)", NULL },
- { SIG_SCI21, 21, MAP_CALL(ListAllTrue), "li(.*)", NULL },
- { SIG_SCI21, 22, MAP_CALL(Sort), "ooo", NULL },
+ { SIG_SINCE_SCI21, 0, MAP_CALL(NewList), "", NULL },
+ { SIG_SINCE_SCI21, 1, MAP_CALL(DisposeList), "l", NULL },
+ { SIG_SINCE_SCI21, 2, MAP_CALL(NewNode), ".(.)", NULL },
+ { SIG_SINCE_SCI21, 3, MAP_CALL(FirstNode), "[l0]", NULL },
+ { SIG_SINCE_SCI21, 4, MAP_CALL(LastNode), "l", NULL },
+ { SIG_SINCE_SCI21, 5, MAP_CALL(EmptyList), "l", NULL },
+ { SIG_SINCE_SCI21, 6, MAP_CALL(NextNode), "n", NULL },
+ { SIG_SINCE_SCI21, 7, MAP_CALL(PrevNode), "n", NULL },
+ { SIG_SINCE_SCI21, 8, MAP_CALL(NodeValue), "[n0]", NULL },
+ { SIG_SINCE_SCI21, 9, MAP_CALL(AddAfter), "lnn.", NULL },
+ { SIG_SINCE_SCI21, 10, MAP_CALL(AddToFront), "ln.", NULL },
+ { SIG_SINCE_SCI21, 11, MAP_CALL(AddToEnd), "ln(.)", NULL },
+ { SIG_SINCE_SCI21, 12, MAP_CALL(AddBefore), "ln.", NULL },
+ { SIG_SINCE_SCI21, 13, MAP_CALL(MoveToFront), "ln", NULL },
+ { SIG_SINCE_SCI21, 14, MAP_CALL(MoveToEnd), "ln", NULL },
+ { SIG_SINCE_SCI21, 15, MAP_CALL(FindKey), "l.", NULL },
+ { SIG_SINCE_SCI21, 16, MAP_CALL(DeleteKey), "l.", NULL },
+ { SIG_SINCE_SCI21, 17, MAP_CALL(ListAt), "li", NULL },
+ { SIG_SINCE_SCI21, 18, MAP_CALL(ListIndexOf) , "l[io]", NULL },
+ { SIG_SINCE_SCI21, 19, MAP_CALL(ListEachElementDo), "li(.*)", NULL },
+ { SIG_SINCE_SCI21, 20, MAP_CALL(ListFirstTrue), "li(.*)", NULL },
+ { SIG_SINCE_SCI21, 21, MAP_CALL(ListAllTrue), "li(.*)", NULL },
+ { SIG_SINCE_SCI21, 22, MAP_CALL(Sort), "ooo", NULL },
+ 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 },
+ { SIG_SCI32, 1, MAP_CALL(StringSize), "[or]", NULL },
+ { SIG_SCI32, 2, MAP_CALL(StringAt), "[or]i", NULL },
+ { SIG_SCI32, 3, MAP_CALL(StringPutAt), "[or]i(i*)", NULL },
+ // StringFree accepts invalid references
+ { SIG_SCI32, 4, MAP_CALL(StringFree), "[or0!]", NULL },
+ { SIG_SCI32, 5, MAP_CALL(StringFill), "[or]ii", NULL },
+ { SIG_SCI32, 6, MAP_CALL(StringCopy), "[or]i[or]ii", NULL },
+ { SIG_SCI32, 7, MAP_CALL(StringCompare), "[or][or](i)", NULL },
+
+ // =SCI2, SCI2.1 Early and SCI2.1 Middle=
+ { SIG_UNTIL_SCI21MID, 8, MAP_CALL(StringDup), "[or]", NULL },
+ // TODO: This gets called with null references in Torin. Check if this is correct, or it's
+ // caused by missing functionality
+ { SIG_UNTIL_SCI21MID, 9, MAP_CALL(StringGetData), "[or0]", NULL },
+ { SIG_UNTIL_SCI21MID, 10, MAP_CALL(StringLen), "[or]", NULL },
+ { SIG_UNTIL_SCI21MID, 11, MAP_CALL(StringPrintf), "[or](.*)", NULL },
+ { SIG_UNTIL_SCI21MID, 12, MAP_CALL(StringPrintfBuf), "[or](.*)", NULL },
+ { SIG_UNTIL_SCI21MID, 13, MAP_CALL(StringAtoi), "[or]", NULL },
+ { SIG_UNTIL_SCI21MID, 14, MAP_CALL(StringTrim), "[or]i", NULL },
+ { SIG_UNTIL_SCI21MID, 15, MAP_CALL(StringUpper), "[or]", NULL },
+ { SIG_UNTIL_SCI21MID, 16, MAP_CALL(StringLower), "[or]", NULL },
+ // the following 2 are unknown atm (happen in Phantasmagoria)
+ // possibly translate?
+ { SIG_UNTIL_SCI21MID, 17, MAP_CALL(StringTrn), "[or]", NULL },
+ { SIG_UNTIL_SCI21MID, 18, MAP_CALL(StringTrnExclude), "[or]", NULL },
+
+ // SCI2.1 Late + SCI3 - kStringDup + kStringGetData were removed
+ { SIG_SINCE_SCI21LATE, 8, MAP_CALL(StringLen), "[or]", NULL },
+ { SIG_SINCE_SCI21LATE, 9, MAP_CALL(StringPrintf), "[or](.*)", NULL },
+ { SIG_SINCE_SCI21LATE,10, MAP_CALL(StringPrintfBuf), "[or](.*)", NULL },
+ { SIG_SINCE_SCI21LATE,11, MAP_CALL(StringAtoi), "[or]", NULL },
+ { SIG_SINCE_SCI21LATE,12, MAP_CALL(StringTrim), "[or]i", NULL },
+ { SIG_SINCE_SCI21LATE,13, MAP_CALL(StringUpper), "[or]", NULL },
+ { SIG_SINCE_SCI21LATE,14, MAP_CALL(StringLower), "[or]", NULL },
+ { SIG_SINCE_SCI21LATE,15, MAP_CALL(StringTrn), "[or]", NULL },
+ { SIG_SINCE_SCI21LATE,16, MAP_CALL(StringTrnExclude), "[or]", NULL },
+ SCI_SUBOPENTRY_TERMINATOR
+};
+
+// 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), "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
+};
+
#endif
struct SciKernelMapEntry {
@@ -314,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 },
@@ -337,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 },
@@ -420,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 },
@@ -429,14 +672,17 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(Said), SIG_EVERYWHERE, "[r0]", NULL, NULL },
{ MAP_CALL(SaveGame), SIG_EVERYWHERE, "[r0]i[r0](r0)", NULL, NULL },
{ MAP_CALL(ScriptID), SIG_EVERYWHERE, "[io](i)", NULL, NULL },
- { MAP_CALL(SetCursor), SIG_SCI21, SIGFOR_ALL, "i(i)([io])(i*)", NULL, NULL },
+ { MAP_CALL(SetCursor), SIG_SINCE_SCI21, SIGFOR_ALL, "i(i)([io])(i*)", NULL, NULL },
// TODO: SCI2.1 may supply an object optionally (mother goose sci21 right on startup) - find out why
{ MAP_CALL(SetCursor), SIG_SCI11, SIGFOR_ALL, "i(i)(i)(i)(iiiiii)", NULL, NULL },
{ MAP_CALL(SetCursor), SIG_EVERYWHERE, "i(i)(i)(i)(i)", NULL, kSetCursor_workarounds },
{ 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 },
@@ -454,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 },
@@ -489,14 +735,18 @@ 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 },
- { MAP_CALL(FrameOut), SIG_EVERYWHERE, "", 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 },
{ MAP_CALL(IsHiRes), SIG_EVERYWHERE, "", NULL, NULL },
@@ -505,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
@@ -513,7 +765,7 @@ static SciKernelMapEntry s_kernelMap[] = {
// our garbage collector (i.e. the SCI0-SCI1.1 semantics).
{ "Purge", kFlushResources, SIG_EVERYWHERE, "i", NULL, NULL },
{ MAP_CALL(SetShowStyle), SIG_EVERYWHERE, "ioiiiii([ri])(i)", NULL, NULL },
- { MAP_CALL(String), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_CALL(String), SIG_EVERYWHERE, "(.*)", kString_subops, NULL },
{ MAP_CALL(UpdatePlane), SIG_EVERYWHERE, "o", NULL, NULL },
{ MAP_CALL(UpdateScreenItem), SIG_EVERYWHERE, "o", NULL, NULL },
{ MAP_CALL(ObjectIntersect), SIG_EVERYWHERE, "oo", NULL, NULL },
@@ -521,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
@@ -557,39 +809,37 @@ 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 },
- // SetScroll is called by script 64909, Styler::doit(), but it doesn't seem to
- // be used at all (plus, it was then changed to a dummy function in SCI3).
- // Since this is most likely unused, and we got no test case, error out when
- // it is called in order to find an actual call to it.
- { MAP_DUMMY(SetScroll), SIG_EVERYWHERE, "(.*)", NULL, NULL },
// SCI2.1 Kernel Functions
{ MAP_CALL(CD), SIG_EVERYWHERE, "(.*)", NULL, NULL },
{ MAP_CALL(IsOnMe), SIG_EVERYWHERE, "iioi", NULL, NULL },
- { MAP_CALL(List), SIG_SCI21, SIGFOR_ALL, "(.*)", kList_subops, 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(ScrollWindow), SIG_EVERYWHERE, "io(.*)", NULL, NULL },
- { MAP_CALL(SetFontRes), SIG_EVERYWHERE, "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(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, 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
@@ -638,16 +888,18 @@ 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
- // MorphOn - used by SQ6, script 900, the datacorder reprogramming puzzle (from room 270)
+ // 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 },
// SCI3 Kernel Functions
- { MAP_CALL(PlayDuck), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_CALL(PlayDuck), SIG_EVERYWHERE, "(.*)", NULL, NULL },
#endif
- { NULL, NULL, SIG_EVERYWHERE, NULL, NULL, NULL }
+ { NULL, NULL, SIG_EVERYWHERE, NULL, NULL, NULL }
};
/** Default kernel name table. */
@@ -941,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 8e16e0a07a..534d9ce713 100644
--- a/engines/sci/engine/kevent.cpp
+++ b/engines/sci/engine/kevent.cpp
@@ -42,6 +42,7 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
reg_t obj = argv[1];
SciEvent curEvent;
int modifier_mask = getSciVersion() <= SCI_VERSION_01 ? SCI_KEYMOD_ALL : SCI_KEYMOD_NO_FOOLOCK;
+ uint16 modifiers = 0;
SegManager *segMan = s->_segMan;
Common::Point mousePos;
@@ -58,7 +59,7 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
// In case we use a simulated event we query the current mouse position
mousePos = g_sci->_gfxCursor->getPosition();
#ifdef ENABLE_SCI32
- if (getSciVersion() >= SCI_VERSION_2_1)
+ if (getSciVersion() >= SCI_VERSION_2_1_EARLY)
g_sci->_gfxCoordAdjuster->fromDisplayToScript(mousePos.y, mousePos.x);
#endif
// Limit the mouse cursor position, if necessary
@@ -82,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)
- 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();
@@ -100,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;
@@ -110,7 +130,27 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
writeSelectorValue(segMan, obj, SELECTOR(x), mousePos.x);
writeSelectorValue(segMan, obj, SELECTOR(y), mousePos.y);
- //s->_gui->moveCursor(s->gfx_state->pointer_pos.x, s->gfx_state->pointer_pos.y);
+ // Get current keyboard modifiers, only keep relevant bits
+ modifiers = curEvent.modifiers & modifier_mask;
+ if (g_sci->getPlatform() == Common::kPlatformDOS) {
+ // We are supposed to emulate SCI running in DOS
+
+ // We set the higher byte of the modifiers to 02h
+ // Original SCI also did that indirectly, because it asked BIOS for shift status
+ // via AH=0x02 INT16, which then sets the shift flags in AL
+ // AH is supposed to be destroyed in that case and it's not defined that 0x02
+ // is still in it on return. The value of AX was then set into the modifiers selector.
+ // At least one fan-made game (Betrayed Alliance) requires 0x02 to be in the upper byte,
+ // otherwise the darts game (script 111) will not work properly.
+
+ // It seems Sierra fixed this behaviour (effectively bug) in the SCI1 keyboard driver.
+ // SCI32 also resets the upper byte.
+
+ // This was verified in SSCI itself by creating a SCI game and checking behavior.
+ if (getSciVersion() <= SCI_VERSION_01) {
+ modifiers |= 0x0200;
+ }
+ }
switch (curEvent.type) {
case SCI_EVENT_QUIT:
@@ -125,34 +165,21 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
writeSelectorValue(segMan, obj, SELECTOR(message), curEvent.character);
// We only care about the translated character
- writeSelectorValue(segMan, obj, SELECTOR(modifiers), curEvent.modifiers & modifier_mask);
+ writeSelectorValue(segMan, obj, SELECTOR(modifiers), modifiers);
break;
case SCI_EVENT_MOUSE_RELEASE:
case SCI_EVENT_MOUSE_PRESS:
-
// track left buttton clicks, if requested
- if (curEvent.type == SCI_EVENT_MOUSE_PRESS && curEvent.data == 1 && g_debug_track_mouse_clicks) {
+ if (curEvent.type == SCI_EVENT_MOUSE_PRESS && curEvent.modifiers == 0 && g_debug_track_mouse_clicks) {
g_sci->getSciDebugger()->debugPrintf("Mouse clicked at %d, %d\n",
mousePos.x, mousePos.y);
}
if (mask & curEvent.type) {
- int extra_bits = 0;
-
- switch (curEvent.data) {
- case 2:
- extra_bits = SCI_KEYMOD_LSHIFT | SCI_KEYMOD_RSHIFT;
- break;
- case 3:
- extra_bits = SCI_KEYMOD_CTRL;
- default:
- break;
- }
-
writeSelectorValue(segMan, obj, SELECTOR(type), curEvent.type);
writeSelectorValue(segMan, obj, SELECTOR(message), 0);
- writeSelectorValue(segMan, obj, SELECTOR(modifiers), (curEvent.modifiers | extra_bits) & modifier_mask);
+ writeSelectorValue(segMan, obj, SELECTOR(modifiers), modifiers);
s->r_acc = make_reg(0, 1);
}
break;
@@ -161,7 +188,7 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
// Return a null event
writeSelectorValue(segMan, obj, SELECTOR(type), SCI_EVENT_NONE);
writeSelectorValue(segMan, obj, SELECTOR(message), 0);
- writeSelectorValue(segMan, obj, SELECTOR(modifiers), curEvent.modifiers & modifier_mask);
+ writeSelectorValue(segMan, obj, SELECTOR(modifiers), modifiers);
s->r_acc = NULL_REG;
}
diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp
index 61ac76d0a7..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"
@@ -37,7 +38,6 @@
#include "sci/engine/state.h"
#include "sci/engine/kernel.h"
#include "sci/engine/savegame.h"
-#include "sci/graphics/menu.h"
#include "sci/sound/audio.h"
#include "sci/console.h"
@@ -258,20 +258,12 @@ reg_t kFileIOOpen(EngineState *s, int argc, reg_t *argv) {
}
debugC(kDebugLevelFile, "kFileIO(open): %s, 0x%x", name.c_str(), mode);
-#ifdef ENABLE_SCI32
- if (name == PHANTASMAGORIA_SAVEGAME_INDEX) {
- if (s->_virtualIndexFile) {
- return make_reg(0, VIRTUALFILE_HANDLE);
- } 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);
- }
- }
+ if (name.hasPrefix("sciAudio\\")) {
+ // fan-made sciAudio extension, don't create those files and instead return a virtual handle
+ return make_reg(0, VIRTUALFILE_HANDLE_SCIAUDIO);
}
+#ifdef ENABLE_SCI32
// 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
@@ -309,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);
+ 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
@@ -345,12 +337,10 @@ reg_t kFileIOClose(EngineState *s, int argc, reg_t *argv) {
uint16 handle = argv[0].toUint16();
-#ifdef ENABLE_SCI32
- if (handle == VIRTUALFILE_HANDLE) {
- s->_virtualIndexFile->close();
+ if (handle >= VIRTUALFILE_HANDLE_START) {
+ // it's a virtual handle? ignore it
return SIGNAL_REG;
}
-#endif
FileHandle *f = getFileFromHandle(s, handle);
if (f) {
@@ -372,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) {
- 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
@@ -402,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) {
- 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)
@@ -454,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);
@@ -479,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)
- 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;
@@ -503,7 +464,7 @@ reg_t kFileIOWriteString(EngineState *s, int argc, reg_t *argv) {
// We skip creating these files, and instead handle the calls
// directly. Since the sciAudio calls are only creating text files,
// this is probably the most straightforward place to handle them.
- if (handle == 0xFFFF && str.hasPrefix("(sciAudio")) {
+ if (handle == VIRTUALFILE_HANDLE_SCIAUDIO) {
Common::List<ExecStack>::const_iterator iter = s->_executionStack.reverse_begin();
iter--; // sciAudio
iter--; // sciAudio child
@@ -511,13 +472,6 @@ reg_t kFileIOWriteString(EngineState *s, int argc, reg_t *argv) {
return NULL_REG;
}
-#ifdef ENABLE_SCI32
- if (handle == VIRTUALFILE_HANDLE) {
- s->_virtualIndexFile->write(str.c_str(), str.size());
- return NULL_REG;
- }
-#endif
-
FileHandle *f = getFileFromHandle(s, handle);
if (f) {
@@ -538,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)
- return make_reg(0, s->_virtualIndexFile->seek(offset, whence));
-#endif
-
FileHandle *f = getFileFromHandle(s, handle);
if (f && f->_in) {
@@ -582,16 +531,21 @@ 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) {
+ // HACK: Special case for Pepper's Adventure in Time
+ // The game checks like crazy for the file CDAUDIO when entering the game menu.
+ // On at least Windows that makes the engine slow down to a crawl and takes at least 1 second.
+ // Should get solved properly by changing the code below. This here is basically for 1.8.0 release.
+ // TODO: Fix this properly.
+ if (name == "CDAUDIO")
+ 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);
@@ -787,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 = 0; savegameId < SAVEGAMEID_OFFICIALRANGE_START; 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())
- break;
+ if (savegameId > SAVEGAMESLOT_LAST)
+ error("kSavegame: no more savegame slots available");
}
- if (savegameId == SAVEGAMEID_OFFICIALRANGE_START)
- error("kSavegame: no more savegame slots available");
}
} else {
error("kSaveGame: invalid savegameId used");
@@ -897,50 +873,8 @@ reg_t kRestoreGame(EngineState *s, int argc, reg_t *argv) {
gamestate_restore(s, in);
delete in;
- switch (g_sci->getGameId()) {
- case GID_MOTHERGOOSE:
- // WORKAROUND: Mother Goose SCI0
- // Script 200 / rm200::newRoom will set global C5h directly right after creating a child to the
- // current number of children plus 1.
- // We can't trust that global, that's why we set the actual savedgame id right here directly after
- // restoring a saved game.
- // If we didn't, the game would always save to a new slot
- s->variables[VAR_GLOBAL][0xC5].setOffset(SAVEGAMEID_OFFICIALRANGE_START + savegameId);
- break;
- case GID_MOTHERGOOSE256:
- // WORKAROUND: Mother Goose SCI1/SCI1.1 does some weird things for
- // saving a previously restored game.
- // We set the current savedgame-id directly and remove the script
- // code concerning this via script patch.
- s->variables[VAR_GLOBAL][0xB3].setOffset(SAVEGAMEID_OFFICIALRANGE_START + savegameId);
- break;
- case GID_JONES:
- // HACK: The code that enables certain menu items isn't called when a game is restored from the
- // launcher, or the "Restore game" option in the game's main menu - bugs #6537 and #6723.
- // These menu entries are disabled when the game is launched, and are enabled when a new game is
- // started. The code for enabling these entries is is all in script 1, room1::init, but that code
- // path is never followed in these two cases (restoring game from the menu, or restoring a game
- // from the ScummVM launcher). Thus, we perform the calls to enable the menus ourselves here.
- // These two are needed when restoring from the launcher
- // FIXME: The original interpreter saves and restores the menu state, so these attributes
- // are automatically reset there. We may want to do the same.
- g_sci->_gfxMenu->kernelSetAttribute(257 >> 8, 257 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Sierra -> About Jones
- g_sci->_gfxMenu->kernelSetAttribute(258 >> 8, 258 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Sierra -> Help
- // The rest are normally enabled from room1::init
- g_sci->_gfxMenu->kernelSetAttribute(769 >> 8, 769 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Options -> Delete current player
- g_sci->_gfxMenu->kernelSetAttribute(513 >> 8, 513 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Game -> Save Game
- g_sci->_gfxMenu->kernelSetAttribute(515 >> 8, 515 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Game -> Restore Game
- 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_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.
- g_sci->_gfxMenu->kernelSetAttribute(2, 1, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Game -> Save Game
- break;
- default:
- break;
- }
+ gamestate_afterRestoreFixUp(s, savegameId);
+
} else {
s->r_acc = TRUE_REG;
warning("Savegame #%d not found", savegameId);
diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp
index 8b790e6a58..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"
@@ -254,7 +255,7 @@ reg_t kGraph(EngineState *s, int argc, reg_t *argv) {
}
reg_t kGraphGetColorCount(EngineState *s, int argc, reg_t *argv) {
- return make_reg(0, g_sci->_gfxPalette->getTotalColorCount());
+ return make_reg(0, g_sci->_gfxPalette16->getTotalColorCount());
}
reg_t kGraphDrawLine(EngineState *s, int argc, reg_t *argv) {
@@ -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) {
@@ -492,7 +495,7 @@ reg_t kNumLoops(EngineState *s, int argc, reg_t *argv) {
loopCount = g_sci->_gfxCache->kernelViewGetLoopCount(viewId);
- debugC(kDebugLevelGraphics, "NumLoops(view.%d) = %d", viewId, loopCount);
+ debugC(9, kDebugLevelGraphics, "NumLoops(view.%d) = %d", viewId, loopCount);
return make_reg(0, loopCount);
}
@@ -505,7 +508,7 @@ reg_t kNumCels(EngineState *s, int argc, reg_t *argv) {
celCount = g_sci->_gfxCache->kernelViewGetCelCount(viewId, loopNo);
- debugC(kDebugLevelGraphics, "NumCels(view.%d, %d) = %d", viewId, loopNo, celCount);
+ debugC(9, kDebugLevelGraphics, "NumCels(view.%d, %d) = %d", viewId, loopNo, celCount);
return make_reg(0, celCount);
}
@@ -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) {
@@ -596,10 +607,10 @@ reg_t kPaletteSetFromResource(EngineState *s, int argc, reg_t *argv) {
// Non-VGA games don't use palette resources.
// This has been changed to 64 colors because Longbow Amiga does have
// one palette (palette 999).
- if (g_sci->_gfxPalette->getTotalColorCount() < 64)
+ if (g_sci->_gfxPalette16->getTotalColorCount() < 64)
return s->r_acc;
- g_sci->_gfxPalette->kernelSetFromResource(resourceId, force);
+ g_sci->_gfxPalette16->kernelSetFromResource(resourceId, force);
return s->r_acc;
}
@@ -607,7 +618,7 @@ reg_t kPaletteSetFlag(EngineState *s, int argc, reg_t *argv) {
uint16 fromColor = CLIP<uint16>(argv[0].toUint16(), 1, 255);
uint16 toColor = CLIP<uint16>(argv[1].toUint16(), 1, 255);
uint16 flags = argv[2].toUint16();
- g_sci->_gfxPalette->kernelSetFlag(fromColor, toColor, flags);
+ g_sci->_gfxPalette16->kernelSetFlag(fromColor, toColor, flags);
return s->r_acc;
}
@@ -615,7 +626,7 @@ reg_t kPaletteUnsetFlag(EngineState *s, int argc, reg_t *argv) {
uint16 fromColor = CLIP<uint16>(argv[0].toUint16(), 1, 255);
uint16 toColor = CLIP<uint16>(argv[1].toUint16(), 1, 255);
uint16 flags = argv[2].toUint16();
- g_sci->_gfxPalette->kernelUnsetFlag(fromColor, toColor, flags);
+ g_sci->_gfxPalette16->kernelUnsetFlag(fromColor, toColor, flags);
return s->r_acc;
}
@@ -626,10 +637,10 @@ reg_t kPaletteSetIntensity(EngineState *s, int argc, reg_t *argv) {
bool setPalette = (argc < 4) ? true : (argv[3].isNull()) ? true : false;
// Palette intensity in non-VGA SCI1 games has been removed
- if (g_sci->_gfxPalette->getTotalColorCount() < 256)
+ if (g_sci->_gfxPalette16->getTotalColorCount() < 256)
return s->r_acc;
- g_sci->_gfxPalette->kernelSetIntensity(fromColor, toColor, intensity, setPalette);
+ g_sci->_gfxPalette16->kernelSetIntensity(fromColor, toColor, intensity, setPalette);
return s->r_acc;
}
@@ -637,7 +648,7 @@ reg_t kPaletteFindColor(EngineState *s, int argc, reg_t *argv) {
uint16 r = argv[0].toUint16();
uint16 g = argv[1].toUint16();
uint16 b = argv[2].toUint16();
- return make_reg(0, g_sci->_gfxPalette->kernelFindColor(r, g, b));
+ return make_reg(0, g_sci->_gfxPalette16->kernelFindColor(r, g, b));
}
reg_t kPaletteAnimate(EngineState *s, int argc, reg_t *argv) {
@@ -645,18 +656,18 @@ reg_t kPaletteAnimate(EngineState *s, int argc, reg_t *argv) {
bool paletteChanged = false;
// Palette animation in non-VGA SCI1 games has been removed
- if (g_sci->_gfxPalette->getTotalColorCount() < 256)
+ if (g_sci->_gfxPalette16->getTotalColorCount() < 256)
return s->r_acc;
for (argNr = 0; argNr < argc; argNr += 3) {
uint16 fromColor = argv[argNr].toUint16();
uint16 toColor = argv[argNr + 1].toUint16();
int16 speed = argv[argNr + 2].toSint16();
- if (g_sci->_gfxPalette->kernelAnimate(fromColor, toColor, speed))
+ if (g_sci->_gfxPalette16->kernelAnimate(fromColor, toColor, speed))
paletteChanged = true;
}
if (paletteChanged)
- g_sci->_gfxPalette->kernelAnimateSet();
+ g_sci->_gfxPalette16->kernelAnimateSet();
// WORKAROUND: The game scripts in SQ4 floppy count the number of elapsed
// cycles in the intro from the number of successive kAnimate calls during
@@ -676,11 +687,11 @@ reg_t kPaletteAnimate(EngineState *s, int argc, reg_t *argv) {
}
reg_t kPaletteSave(EngineState *s, int argc, reg_t *argv) {
- return g_sci->_gfxPalette->kernelSave();
+ return g_sci->_gfxPalette16->kernelSave();
}
reg_t kPaletteRestore(EngineState *s, int argc, reg_t *argv) {
- g_sci->_gfxPalette->kernelRestore(argv[0]);
+ g_sci->_gfxPalette16->kernelRestore(argv[0]);
return argv[0];
}
@@ -695,7 +706,7 @@ reg_t kPalVaryInit(EngineState *s, int argc, reg_t *argv) {
uint16 ticks = argv[1].toUint16();
uint16 stepStop = argc >= 3 ? argv[2].toUint16() : 64;
uint16 direction = argc >= 4 ? argv[3].toUint16() : 1;
- if (g_sci->_gfxPalette->kernelPalVaryInit(paletteId, ticks, stepStop, direction))
+ if (g_sci->_gfxPalette16->kernelPalVaryInit(paletteId, ticks, stepStop, direction))
return SIGNAL_REG;
return NULL_REG;
}
@@ -705,40 +716,40 @@ reg_t kPalVaryReverse(EngineState *s, int argc, reg_t *argv) {
int16 stepStop = argc >= 2 ? argv[1].toUint16() : 0;
int16 direction = argc >= 3 ? argv[2].toSint16() : -1;
- return make_reg(0, g_sci->_gfxPalette->kernelPalVaryReverse(ticks, stepStop, direction));
+ return make_reg(0, g_sci->_gfxPalette16->kernelPalVaryReverse(ticks, stepStop, direction));
}
reg_t kPalVaryGetCurrentStep(EngineState *s, int argc, reg_t *argv) {
- return make_reg(0, g_sci->_gfxPalette->kernelPalVaryGetCurrentStep());
+ return make_reg(0, g_sci->_gfxPalette16->kernelPalVaryGetCurrentStep());
}
reg_t kPalVaryDeinit(EngineState *s, int argc, reg_t *argv) {
- g_sci->_gfxPalette->kernelPalVaryDeinit();
+ g_sci->_gfxPalette16->kernelPalVaryDeinit();
return NULL_REG;
}
reg_t kPalVaryChangeTarget(EngineState *s, int argc, reg_t *argv) {
GuiResourceId paletteId = argv[0].toUint16();
- int16 currentStep = g_sci->_gfxPalette->kernelPalVaryChangeTarget(paletteId);
+ int16 currentStep = g_sci->_gfxPalette16->kernelPalVaryChangeTarget(paletteId);
return make_reg(0, currentStep);
}
reg_t kPalVaryChangeTicks(EngineState *s, int argc, reg_t *argv) {
uint16 ticks = argv[0].toUint16();
- g_sci->_gfxPalette->kernelPalVaryChangeTicks(ticks);
+ g_sci->_gfxPalette16->kernelPalVaryChangeTicks(ticks);
return NULL_REG;
}
reg_t kPalVaryPauseResume(EngineState *s, int argc, reg_t *argv) {
bool pauseState = !argv[0].isNull();
- g_sci->_gfxPalette->kernelPalVaryPause(pauseState);
+ g_sci->_gfxPalette16->kernelPalVaryPause(pauseState);
return NULL_REG;
}
reg_t kAssertPalette(EngineState *s, int argc, reg_t *argv) {
GuiResourceId paletteId = argv[0].toUint16();
- g_sci->_gfxPalette->kernelAssertPalette(paletteId);
+ g_sci->_gfxPalette16->kernelAssertPalette(paletteId);
return s->r_acc;
}
@@ -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->_gfxPalette->resetRemapping();
- g_sci->_gfxPalette->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->_gfxPalette->resetRemapping();
- g_sci->_gfxPalette->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 8953f45266..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,14 +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/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 {
@@ -61,63 +64,67 @@ 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) {
- if (g_sci->_gfxFrameout->findScreenItem(argv[0]) == NULL)
- g_sci->_gfxFrameout->kernelAddScreenItem(argv[0]);
- else
- g_sci->_gfxFrameout->kernelUpdateScreenItem(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 s->r_acc;
}
reg_t kUpdateScreenItem(EngineState *s, int argc, reg_t *argv) {
+ debugC(7, kDebugLevelGraphics, "kUpdateScreenItem %x:%x (%s)", PRINT_REG(argv[0]), s->_segMan->getObjectName(argv[0]));
g_sci->_gfxFrameout->kernelUpdateScreenItem(argv[0]);
return s->r_acc;
}
reg_t kDeleteScreenItem(EngineState *s, int argc, reg_t *argv) {
+ debugC(6, kDebugLevelGraphics, "kDeleteScreenItem %x:%x (%s)", PRINT_REG(argv[0]), s->_segMan->getObjectName(argv[0]));
g_sci->_gfxFrameout->kernelDeleteScreenItem(argv[0]);
return s->r_acc;
}
reg_t kAddPlane(EngineState *s, int argc, reg_t *argv) {
+ 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)", 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)", PRINT_REG(argv[0]), s->_segMan->getObjectName(argv[0]));
g_sci->_gfxFrameout->kernelDeletePlane(argv[0]);
return s->r_acc;
}
-reg_t kUpdatePlane(EngineState *s, int argc, reg_t *argv) {
- g_sci->_gfxFrameout->kernelUpdatePlane(argv[0]);
+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();
- int16 pictureX = argv[2].toSint16();
- int16 pictureY = argv[3].toSint16();
+ int16 x = argv[2].toSint16();
+ int16 y = argv[3].toSint16();
+ bool mirrorX = argc > 4 ? argv[4].toSint16() : false;
- g_sci->_gfxFrameout->kernelAddPicAt(planeObj, pictureId, pictureX, pictureY);
+ g_sci->_gfxFrameout->kernelAddPicAt(planeObj, pictureId, x, y, mirrorX);
return s->r_acc;
}
@@ -126,8 +133,14 @@ reg_t kGetHighPlanePri(EngineState *s, int argc, reg_t *argv) {
}
reg_t kFrameOut(EngineState *s, int argc, reg_t *argv) {
- g_sci->_gfxFrameout->kernelFrameout();
- return NULL_REG;
+ bool showBits = argc > 0 ? argv[0].toUint16() : true;
+ 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 s->r_acc;
}
reg_t kObjectIntersect(EngineState *s, int argc, reg_t *argv) {
@@ -136,81 +149,95 @@ 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 illegalBits = argv[3].getOffset();
- Common::Rect nsRect = g_sci->_gfxCompare->getNSRect(targetObject);
-
- uint16 itemX = readSelectorValue(s->_segMan, targetObject, SELECTOR(x));
- uint16 itemY = readSelectorValue(s->_segMan, targetObject, SELECTOR(y));
- // If top and left are negative, we need to adjust coordinates by the item's x and y
- if (nsRect.left < 0)
- nsRect.translate(itemX, 0);
- if (nsRect.top < 0)
- nsRect.translate(0, itemY);
-
- // we assume that x, y are local coordinates
-
- bool contained = nsRect.contains(x, y);
- if (contained && illegalBits) {
- // If illegalbits are set, we check the color of the pixel that got clicked on
- // for now, we return false if the pixel is transparent
- // although illegalBits may get differently set, don't know yet how this really works out
- uint16 viewId = readSelectorValue(s->_segMan, targetObject, SELECTOR(view));
- int16 loopNo = readSelectorValue(s->_segMan, targetObject, SELECTOR(loop));
- int16 celNo = readSelectorValue(s->_segMan, targetObject, SELECTOR(cel));
- if (g_sci->_gfxCompare->kernelIsItSkip(viewId, loopNo, celNo, Common::Point(x - nsRect.left, y - nsRect.top)))
- contained = false;
- }
- return make_reg(0, contained);
+ int16 x = argv[0].toSint16();
+ int16 y = argv[1].toSint16();
+ reg_t object = argv[2];
+ bool checkPixel = argv[3].toSint16();
+
+ return g_sci->_gfxFrameout->kernelIsOnMe(object, Common::Point(x, y), checkPixel);
}
reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv) {
- switch (argv[0].toUint16()) {
- case 0: {
- if (argc != 4) {
- warning("kCreateTextBitmap(0): expected 4 arguments, got %i", argc);
- return NULL_REG;
- }
- reg_t object = argv[3];
- Common::String text = s->_segMan->getString(readSelector(s->_segMan, object, SELECTOR(text)));
- debugC(kDebugLevelStrings, "kCreateTextBitmap case 0 (%04x:%04x, %04x:%04x, %04x:%04x)",
- PRINT_REG(argv[1]), PRINT_REG(argv[2]), PRINT_REG(argv[3]));
- debugC(kDebugLevelStrings, "%s", text.c_str());
- int16 maxWidth = argv[1].toUint16();
- int16 maxHeight = argv[2].toUint16();
- g_sci->_gfxCoordAdjuster->fromScriptToDisplay(maxHeight, maxWidth);
- // These values can be larger than the screen in the SQ6 demo, room 100
- // TODO: Find out why. For now, don't show any text in that room.
- if (g_sci->getGameId() == GID_SQ6 && g_sci->isDemo() && s->currentRoomNumber() == 100)
- return NULL_REG;
- return g_sci->_gfxText32->createTextBitmap(object, maxWidth, maxHeight);
- }
- case 1: {
- if (argc != 2) {
- warning("kCreateTextBitmap(1): expected 2 arguments, got %i", argc);
- return NULL_REG;
- }
- reg_t object = argv[1];
- Common::String text = s->_segMan->getString(readSelector(s->_segMan, object, SELECTOR(text)));
- debugC(kDebugLevelStrings, "kCreateTextBitmap case 1 (%04x:%04x)", PRINT_REG(argv[1]));
- debugC(kDebugLevelStrings, "%s", text.c_str());
- return g_sci->_gfxText32->createTextBitmap(object);
- }
- default:
- warning("CreateTextBitmap(%d)", argv[0].toUint16());
+ SegManager *segMan = s->_segMan;
+
+ int16 subop = argv[0].toUint16();
+
+ int16 width = 0;
+ int16 height = 0;
+ reg_t object;
+
+ if (subop == 0) {
+ width = argv[1].toUint16();
+ height = argv[2].toUint16();
+ object = argv[3];
+ } else if (subop == 1) {
+ object = argv[1];
+ } else {
+ warning("Invalid kCreateTextBitmap subop %d", subop);
return NULL_REG;
}
+
+ Common::String text = segMan->getString(readSelector(segMan, object, SELECTOR(text)));
+ int16 foreColor = readSelectorValue(segMan, object, SELECTOR(fore));
+ int16 backColor = readSelectorValue(segMan, object, SELECTOR(back));
+ int16 skipColor = readSelectorValue(segMan, object, SELECTOR(skip));
+ GuiResourceId fontId = (GuiResourceId)readSelectorValue(segMan, object, SELECTOR(font));
+ int16 borderColor = readSelectorValue(segMan, object, SELECTOR(borderColor));
+ int16 dimmed = readSelectorValue(segMan, object, SELECTOR(dimmed));
+
+ Common::Rect rect(
+ readSelectorValue(segMan, object, SELECTOR(textLeft)),
+ readSelectorValue(segMan, object, SELECTOR(textTop)),
+ readSelectorValue(segMan, object, SELECTOR(textRight)) + 1,
+ readSelectorValue(segMan, object, SELECTOR(textBottom)) + 1
+ );
+
+ if (subop == 0) {
+ TextAlign alignment = (TextAlign)readSelectorValue(segMan, object, SELECTOR(mode));
+ 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));
+ 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:
@@ -228,442 +255,508 @@ 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());
+}
+
/**
- * Used for scene transitions, replacing (but reusing parts of) the old
- * transition code.
+ * Causes an immediate plane transition with an optional transition
+ * effect
*/
reg_t kSetShowStyle(EngineState *s, int argc, reg_t *argv) {
- // Can be called with 7 or 8 parameters
- // The style defines which transition to perform. Related to the transition
- // tables inside graphics/transitions.cpp
- uint16 showStyle = argv[0].toUint16(); // 0 - 15
- reg_t planeObj = argv[1]; // the affected plane
- Common::String planeObjName = s->_segMan->getObjectName(planeObj);
- uint16 seconds = argv[2].toUint16(); // seconds that the transition lasts
- uint16 backColor = argv[3].toUint16(); // target back color(?). When fading out, it's 0x0000. When fading in, it's 0xffff
- int16 priority = argv[4].toSint16(); // always 0xc8 (200) when fading in/out
- uint16 animate = argv[5].toUint16(); // boolean, animate or not while the transition lasts
- uint16 refFrame = argv[6].toUint16(); // refFrame, always 0 when fading in/out
+ ShowStyleType type = (ShowStyleType)argv[0].toUint16();
+ reg_t planeObj = argv[1];
+ int16 seconds = argv[2].toSint16();
+ // NOTE: This value seems to indicate whether the transition is an
+ // “exit†transition (0) or an “enter†transition (-1) for fade
+ // transitions. For other types of transitions, it indicates a palette
+ // index value to use when filling the screen.
+ int16 back = argv[3].toSint16();
+ int16 priority = argv[4].toSint16();
+ int16 animate = argv[5].toSint16();
+ // TODO: Rename to frameOutNow?
+ int16 refFrame = argv[6].toSint16();
+ int16 blackScreen;
+ reg_t pFadeArray;
int16 divisions;
- // If the game has the pFadeArray selector, another parameter is used here,
- // before the optional last parameter
- bool hasFadeArray = g_sci->getKernel()->findSelector("pFadeArray") > 0;
- if (hasFadeArray) {
- // argv[7]
- divisions = (argc >= 9) ? argv[8].toSint16() : -1; // divisions (transition steps?)
- } else {
- divisions = (argc >= 8) ? argv[7].toSint16() : -1; // divisions (transition steps?)
+ // SCI 2–2.1early
+ if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
+ blackScreen = 0;
+ pFadeArray = NULL_REG;
+ divisions = argc > 7 ? argv[7].toSint16() : -1;
}
-
- if (showStyle > 15) {
- warning("kSetShowStyle: Illegal style %d for plane %04x:%04x", showStyle, PRINT_REG(planeObj));
- return s->r_acc;
+ // SCI 2.1mid–2.1late
+ else if (getSciVersion() < SCI_VERSION_3) {
+ blackScreen = 0;
+ pFadeArray = argc > 7 ? argv[7] : NULL_REG;
+ divisions = argc > 8 ? argv[8].toSint16() : -1;
+ }
+ // SCI 3
+ else {
+ blackScreen = argv[7].toSint16();
+ pFadeArray = argc > 8 ? argv[8] : NULL_REG;
+ divisions = argc > 9 ? argv[9].toSint16() : -1;
}
- // GK1 calls fadeout (13) / fadein (14) with the following parameters:
- // seconds: 1
- // backColor: 0 / -1
- // fade: 200
- // animate: 0
- // refFrame: 0
- // divisions: 0 / 20
+// TODO: Reuse later for SCI2 and SCI3 implementation and then discard
+// warning("kSetShowStyle: effect %d, plane: %04x:%04x (%s), sec: %d, "
+// "dir: %d, prio: %d, animate: %d, ref frame: %d, black screen: %d, "
+// "pFadeArray: %04x:%04x (%s), divisions: %d",
+// type, PRINT_REG(planeObj), s->_segMan->getObjectName(planeObj), seconds,
+// back, priority, animate, refFrame, blackScreen,
+// PRINT_REG(pFadeArray), s->_segMan->getObjectName(pFadeArray), divisions);
- // TODO: Check if the plane is in the list of planes to draw
+ // NOTE: The order of planeObj and showStyle are reversed
+ // because this is how SCI3 called the corresponding method
+ // on the KernelMgr
+ g_sci->_gfxFrameout->kernelSetShowStyle(argc, planeObj, type, seconds, back, priority, animate, refFrame, pFadeArray, divisions, blackScreen);
- Common::String effectName = "unknown";
+ return s->r_acc;
+}
- switch (showStyle) {
- case 0: // no transition / show
- effectName = "show";
- break;
- case 13: // fade out
- effectName = "fade out";
- // TODO
- break;
- case 14: // fade in
- effectName = "fade in";
- // TODO
- break;
- default:
- // TODO
- break;
- }
+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)));
+}
- warning("kSetShowStyle: effect %d (%s) - plane: %04x:%04x (%s), sec: %d, "
- "back: %d, prio: %d, animate: %d, ref frame: %d, divisions: %d",
- showStyle, effectName.c_str(), PRINT_REG(planeObj), planeObjName.c_str(),
- seconds, backColor, priority, animate, refFrame, divisions);
- return s->r_acc;
+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());
-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);
+ int16 result = 0;
+
+ switch (argv[0].toUint16()) {
+ case 0:
+ result = view._displace.x;
break;
- case 17: // Destroy, called by ScrollableWindow::dispose
- g_sci->_gfxFrameout->clearScrollTexts();
+ case 1:
+ result = view._displace.y;
break;
- case 13: // Delete, unused
- case 18: // Text, unused
- case 19: // Reconstruct, unused
- error("kScrollWindow: Unused subop %d invoked", op);
+ case 2:
+ case 3:
+ // null operation
break;
- default:
- error("kScrollWindow: unknown subop %d", op);
+ 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) {
+ if (!s)
+ return make_reg(0, getSciVersion());
+ error("not supposed to call this");
+}
+
+reg_t kScrollWindowCreate(EngineState *s, int argc, reg_t *argv) {
+ 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) {
+ 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) {
+ 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 kSetFontRes(EngineState *s, int argc, reg_t *argv) {
- // TODO: This defines the resolution that the fonts are supposed to be displayed
- // in. Currently, this is only used for showing high-res fonts in GK1 Mac, but
- // should be extended to handle other font resolutions such as those
+reg_t kScrollWindowModify(EngineState *s, int argc, reg_t *argv) {
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
- int xResolution = argv[0].toUint16();
- //int yResolution = argv[1].toUint16();
+ 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);
+}
- g_sci->_gfxScreen->setFontIsUpscaled(xResolution == 640 &&
- g_sci->_gfxScreen->getUpscaledHires() != GFX_SCREEN_UPSCALED_DISABLED);
+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 kFont(EngineState *s, int argc, reg_t *argv) {
- // Handle font settings for SCI2.1
+reg_t kScrollWindowShow(EngineState *s, int argc, reg_t *argv) {
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
- switch (argv[0].toUint16()) {
- case 1:
- // Set font resolution
- return kSetFontRes(s, argc - 1, argv + 1);
- default:
- warning("kFont: unknown subop %d", argv[0].toUint16());
- }
+ scrollWindow->show();
+
+ return s->r_acc;
+}
+
+reg_t kScrollWindowPageUp(EngineState *s, int argc, reg_t *argv) {
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
+
+ scrollWindow->pageUp();
+
+ return s->r_acc;
+}
+
+reg_t kScrollWindowPageDown(EngineState *s, int argc, reg_t *argv) {
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
+
+ scrollWindow->pageDown();
+
+ return s->r_acc;
+}
+
+reg_t kScrollWindowUpArrow(EngineState *s, int argc, reg_t *argv) {
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
+
+ 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;
}
-// TODO: Eventually, all of the kBitmap operations should be put
-// in a separate class
+reg_t kScrollWindowEnd(EngineState *s, int argc, reg_t *argv) {
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
-#define BITMAP_HEADER_SIZE 46
+ 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 s->r_acc;
+}
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.
+ if (!s)
+ return make_reg(0, getSciVersion());
+ error("not supposed to call this");
+}
- 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_LE_UINT16(memoryPtr, width);
- WRITE_LE_UINT16(memoryPtr + 2, height);
- 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 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;
+
+ BitmapResource bitmap(s->_segMan, width, height, skipColor, 0, 0, scaledWidth, scaledHeight, 0, useRemap);
+ memset(bitmap.getPixels(), backColor, width * height);
+ return bitmap.getObject();
+}
+reg_t kBitmapDestroy(EngineState *s, int argc, reg_t *argv) {
+ s->_segMan->freeHunkEntry(argv[0]);
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 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);
+}
- if (!controlObject.isNull()) {
- g_sci->_gfxControls32->kernelTexteditChange(controlObject);
- }
+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;
+}
+
+reg_t kBitmapDrawText(EngineState *s, int argc, reg_t *argv) {
+ // called e.g. from TextButton::createBitmap() in Torin's Passage, script 64894
+
+ 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 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;
+}
+
+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) {
- 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);
+ 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) {
- 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);
+ 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);
+
return s->r_acc;
}
+
reg_t kDeleteLine(EngineState *s, int argc, reg_t *argv) {
- 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;
}
@@ -691,158 +784,214 @@ reg_t kSetScroll(EngineState *s, int argc, reg_t *argv) {
return kStub(s, argc, argv);
}
-reg_t kPalVaryUnknown(EngineState *s, int argc, reg_t *argv) {
- // TODO: Unknown (seems to be SCI32 exclusive)
- return kStub(s, argc, 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 s->r_acc;
}
-reg_t kPalVaryUnknown2(EngineState *s, int argc, reg_t *argv) {
- // TODO: Unknown (seems to be SCI32 exclusive)
- // It seems to be related to the day/night palette effects in QFG4, and
- // accepts a palette resource ID. It is triggered right when the night
- // effect is initially applied (when exiting the caves).
- // In QFG4, there are two scene palettes: 790 for night, and 791 for day.
- // Initially, the game starts at night time, but this is called with the
- // ID of the day time palette (i.e. 791).
- return kStub(s, argc, argv);
+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) {
+ uint16 fromColor = argv[0].toUint16();
+ uint16 toColor = argv[1].toUint16();
+ uint16 percent = argv[2].toUint16();
+ g_sci->_gfxPalette32->setFade(percent, fromColor, toColor);
+ return s->r_acc;
+}
+
+reg_t kPalVarySetVary(EngineState *s, int argc, reg_t *argv) {
+ GuiResourceId paletteId = argv[0].toUint16();
+ int time = argc > 1 ? argv[1].toSint16() * 60 : 0;
+ int16 percent = argc > 2 ? argv[2].toSint16() : 100;
+ int16 fromColor;
+ int16 toColor;
+
+ if (argc > 4) {
+ fromColor = argv[3].toSint16();
+ toColor = argv[4].toSint16();
+ } else {
+ fromColor = toColor = -1;
+ }
+
+ g_sci->_gfxPalette32->kernelPalVarySet(paletteId, percent, time, fromColor, toColor);
+ 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 s->r_acc;
+}
+
+reg_t kPalVaryGetPercent(EngineState *s, int argc, reg_t *argv) {
+ return make_reg(0, g_sci->_gfxPalette32->getVaryPercent());
+}
+
+reg_t kPalVaryOff(EngineState *s, int argc, reg_t *argv) {
+ g_sci->_gfxPalette32->varyOff();
+ return s->r_acc;
+}
+
+reg_t kPalVaryMergeTarget(EngineState *s, int argc, reg_t *argv) {
+ GuiResourceId paletteId = argv[0].toUint16();
+ g_sci->_gfxPalette32->kernelPalVaryMergeTarget(paletteId);
+ return make_reg(0, g_sci->_gfxPalette32->getVaryPercent());
+}
+
+reg_t kPalVarySetTime(EngineState *s, int argc, reg_t *argv) {
+ int time = argv[0].toSint16() * 60;
+ g_sci->_gfxPalette32->setVaryTime(time);
+ return s->r_acc;
+}
+
+reg_t kPalVarySetTarget(EngineState *s, int argc, reg_t *argv) {
+ GuiResourceId paletteId = argv[0].toUint16();
+ g_sci->_gfxPalette32->kernelPalVarySetTarget(paletteId);
+ return make_reg(0, g_sci->_gfxPalette32->getVaryPercent());
+}
+
+reg_t kPalVarySetStart(EngineState *s, int argc, reg_t *argv) {
+ GuiResourceId paletteId = argv[0].toUint16();
+ g_sci->_gfxPalette32->kernelPalVarySetStart(paletteId);
+ return make_reg(0, g_sci->_gfxPalette32->getVaryPercent());
+}
+
+reg_t kPalVaryMergeStart(EngineState *s, int argc, reg_t *argv) {
+ GuiResourceId paletteId = argv[0].toUint16();
+ g_sci->_gfxPalette32->kernelPalVaryMergeStart(paletteId);
+ return make_reg(0, g_sci->_gfxPalette32->getVaryPercent());
}
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 0: { // Palette animation initialization
- // 3 or 4 extra params
- // Case 1 sends fromColor and speed again, so we don't need them here.
- // Only toColor is stored
- //uint16 fromColor = argv[1].toUint16();
- s->_palCycleToColor = argv[2].toUint16();
- //uint16 speed = argv[3].toUint16();
-
- // Invalidate the picture, so that the palette steps calls (case 1
- // below) can update its palette without it being overwritten by the
- // view/picture palettes.
- g_sci->_gfxScreen->_picNotValid = 1;
-
- // TODO: The fourth optional parameter is an unknown integer, and is 0 by default
- if (argc == 5) {
- // When this variant is used, picNotValid doesn't seem to be set
- // (e.g. GK1 room 480). In this case, the animation step calls are
- // not made, so perhaps this signifies the palette cycling steps
- // to make.
- // GK1 sets this to 6 (6 palette steps?)
- g_sci->_gfxScreen->_picNotValid = 0;
- }
- kStub(s, argc, argv);
- }
- break;
- case 1: { // Palette animation step
- // This is the same as the old kPaletteAnimate call, with 1 set of colors.
- // The end color is set up during initialization in case 0 above.
-
- // 1 or 2 extra params
- uint16 fromColor = argv[1].toUint16();
- uint16 speed = (argc == 2) ? 1 : argv[2].toUint16();
- // TODO: For some reason, this doesn't set the color correctly
- // (e.g. LSL6 intro, room 100, Sierra logo)
- if (g_sci->_gfxPalette->kernelAnimate(fromColor, s->_palCycleToColor, speed))
- g_sci->_gfxPalette->kernelAnimateSet();
- }
- // No kStub() call here, as this gets called loads of times, like kPaletteAnimate
- break;
- // case 2 hasn't been encountered
- // case 3 hasn't been encountered
- case 4: // reset any palette cycling and make the picture valid again
- // Gets called when changing rooms and after palette cycling animations finish
- // 0 or 1 extra params
- if (argc == 1) {
- g_sci->_gfxScreen->_picNotValid = 0;
- // TODO: This also seems to perform more steps
- } else {
- // The variant with the 1 extra param resets remapping to base
- // TODO
- }
- kStub(s, argc, argv);
- break;
- default:
- // TODO
- kStub(s, argc, argv);
- 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->_gfxPalette->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->_gfxPalette->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->_gfxPalette->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->_gfxPalette->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->_gfxPalette->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->_gfxPalette->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/klists.cpp b/engines/sci/engine/klists.cpp
index 66590da23f..c0da2daaeb 100644
--- a/engines/sci/engine/klists.cpp
+++ b/engines/sci/engine/klists.cpp
@@ -669,26 +669,44 @@ reg_t kArray(EngineState *s, int argc, reg_t *argv) {
// TODO: we need to either merge SCI2 strings and
// arrays together, and in the future merge them with
// the SCI1 strings and arrays in the segment manager
+ bool callStringFunc = false;
if (op == 0) {
// New, check if the target type is 3 (string)
if (argv[2].toUint16() == 3)
- return kString(s, argc, argv);
+ callStringFunc = true;
} else {
if (s->_segMan->getSegmentType(argv[1].getSegment()) == SEG_TYPE_STRING ||
s->_segMan->getSegmentType(argv[1].getSegment()) == SEG_TYPE_SCRIPT) {
- return kString(s, argc, argv);
+ callStringFunc = true;
}
#if 0
if (op == 6) {
if (s->_segMan->getSegmentType(argv[3].getSegment()) == SEG_TYPE_STRING ||
s->_segMan->getSegmentType(argv[3].getSegment()) == SEG_TYPE_SCRIPT) {
- return kString(s, argc, argv);
+ callStringFunc = true;
}
}
#endif
}
+ if (callStringFunc) {
+ Kernel *kernel = g_sci->getKernel();
+ uint16 kernelStringFuncId = kernel->_kernelFunc_StringId;
+ if (kernelStringFuncId) {
+ const KernelFunction *kernelStringFunc = &kernel->_kernelFuncs[kernelStringFuncId];
+
+ if (op < kernelStringFunc->subFunctionCount) {
+ // subfunction-id is valid
+ const KernelSubFunction *kernelStringSubCall = &kernelStringFunc->subFunctions[op];
+ argc--;
+ argv++; // remove subfunction-id from arguments
+ // and call the kString subfunction
+ return kernelStringSubCall->function(s, argc, argv);
+ }
+ }
+ }
+
switch (op) {
case 0: { // New
reg_t arrayHandle;
diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp
index 448e641b63..1924848717 100644
--- a/engines/sci/engine/kmisc.cpp
+++ b/engines/sci/engine/kmisc.cpp
@@ -218,7 +218,6 @@ enum {
reg_t kGetTime(EngineState *s, int argc, reg_t *argv) {
TimeDate loc_time;
- uint32 elapsedTime = g_engine->getTotalPlayTime();
int retval = 0; // Avoid spurious warning
g_system->getTimeAndDate(loc_time);
@@ -232,7 +231,7 @@ reg_t kGetTime(EngineState *s, int argc, reg_t *argv) {
switch (mode) {
case KGETTIME_TICKS :
- retval = elapsedTime * 60 / 1000;
+ retval = g_sci->getTickCount();
debugC(kDebugLevelTime, "GetTime(elapsed) returns %d", retval);
break;
case KGETTIME_TIME_12HOUR :
@@ -244,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;
@@ -269,7 +276,10 @@ reg_t kMemory(EngineState *s, int argc, reg_t *argv) {
switch (argv[0].toUint16()) {
case K_MEMORY_ALLOCATE_CRITICAL: {
int byteCount = argv[1].toUint16();
- // WORKAROUND:
+ // Sierra themselves allocated at least 2 bytes more than requested.
+ // Probably as a safety margin. And they also made size even.
+ //
+ // This behavior is required by at least these:
// - pq3 (multilingual) room 202
// when plotting crimes, allocates the returned bytes from kStrLen
// on "W" and "E" and wants to put a string in there, which doesn't
@@ -277,18 +287,22 @@ reg_t kMemory(EngineState *s, int argc, reg_t *argv) {
// - lsl5 (multilingual) room 280
// allocates memory according to a previous kStrLen for the name of
// the airport ladies (bug #3093818), which isn't enough
-
- // We always allocate 1 byte more, because of this
- byteCount++;
+ byteCount += 2 + (byteCount & 1);
if (!s->_segMan->allocDynmem(byteCount, "kMemory() critical", &s->r_acc)) {
error("Critical heap allocation failed");
}
break;
}
- case K_MEMORY_ALLOCATE_NONCRITICAL:
- s->_segMan->allocDynmem(argv[1].toUint16(), "kMemory() non-critical", &s->r_acc);
+ case K_MEMORY_ALLOCATE_NONCRITICAL: {
+ int byteCount = argv[1].toUint16();
+
+ // See above
+ byteCount += 2 + (byteCount & 1);
+
+ s->_segMan->allocDynmem(byteCount, "kMemory() non-critical", &s->r_acc);
break;
+ }
case K_MEMORY_FREE :
if (!s->_segMan->freeDynmem(argv[1])) {
if (g_sci->getGameId() == GID_QFG1VGA) {
@@ -395,6 +409,15 @@ 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 startup, specifies the number of the game to start.
+ s->_segMan->strcpy(data, "");
+ } else if (setting == "laptop") {
+ // Hoyle 5 startup.
+ s->_segMan->strcpy(data, "");
+ } else if (setting == "jumpto") {
+ // Hoyle 5 startup.
+ s->_segMan->strcpy(data, "");
} else {
error("GetConfig: Unknown configuration setting %s", setting.c_str());
}
@@ -487,7 +510,7 @@ reg_t kMacPlatform(EngineState *s, int argc, reg_t *argv) {
// In SCI1, its usage is still unknown
// In SCI1.1, it's NOP
// In SCI32, it's used for remapping cursor ID's
- if (getSciVersion() >= SCI_VERSION_2_1) // Set Mac cursor remap
+ if (getSciVersion() >= SCI_VERSION_2_1_EARLY) // Set Mac cursor remap
g_sci->_gfxCursor->setMacCursorRemapList(argc - 1, argv + 1);
else if (getSciVersion() != SCI_VERSION_1_1)
warning("Unknown SCI1 kMacPlatform(0) call");
@@ -540,6 +563,11 @@ reg_t kPlatform(EngineState *s, int argc, reg_t *argv) {
return NULL_REG;
}
+ if (g_sci->forceHiresGraphics()) {
+ // force Windows platform, so that hires-graphics are enabled
+ isWindows = true;
+ }
+
uint16 operation = (argc == 0) ? 0 : argv[0].toUint16();
switch (operation) {
@@ -586,18 +614,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 67d814b86f..06f16299aa 100644
--- a/engines/sci/engine/kpathing.cpp
+++ b/engines/sci/engine/kpathing.cpp
@@ -312,10 +312,10 @@ static void draw_line(EngineState *s, Common::Point p1, Common::Point p2, int ty
// Red : Barred access
// Yellow: Contained access
int poly_colors[4] = {
- g_sci->_gfxPalette->kernelFindColor(0, 255, 0), // green
- g_sci->_gfxPalette->kernelFindColor(0, 0, 255), // blue
- g_sci->_gfxPalette->kernelFindColor(255, 0, 0), // red
- g_sci->_gfxPalette->kernelFindColor(255, 255, 0) // yellow
+ g_sci->_gfxPalette16->kernelFindColor(0, 255, 0), // green
+ g_sci->_gfxPalette16->kernelFindColor(0, 0, 255), // blue
+ g_sci->_gfxPalette16->kernelFindColor(255, 0, 0), // red
+ g_sci->_gfxPalette16->kernelFindColor(255, 255, 0) // yellow
};
// Clip
@@ -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) {
@@ -334,8 +334,8 @@ static void draw_point(EngineState *s, Common::Point p, int start, int width, in
// Green: End point
// Blue: Starting point
int point_colors[2] = {
- g_sci->_gfxPalette->kernelFindColor(0, 255, 0), // green
- g_sci->_gfxPalette->kernelFindColor(0, 0, 255) // blue
+ g_sci->_gfxPalette16->kernelFindColor(0, 255, 0), // green
+ g_sci->_gfxPalette16->kernelFindColor(0, 0, 255) // blue
};
Common::Rect rect = Common::Rect(p.x - 1, p.y - 1, p.x - 1 + 3, p.y - 1 + 3);
@@ -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 5c271780dd..6fd130bceb 100644
--- a/engines/sci/engine/kscripts.cpp
+++ b/engines/sci/engine/kscripts.cpp
@@ -229,7 +229,7 @@ reg_t kScriptID(EngineState *s, int argc, reg_t *argv) {
uint16 address = scr->validateExportFunc(index, true);
// Point to the heap for SCI1.1 - SCI2.1 games
- if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1)
+ if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE)
address += scr->getScriptSize();
// Bugfix for the intro speed in PQ2 version 1.002.011.
@@ -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 6a1708d21a..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) {
- 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;
}
@@ -206,8 +230,15 @@ reg_t kDoAudio(EngineState *s, int argc, reg_t *argv) {
// athrxx: It seems from disasm that the original KQ5 FM-Towns loads a default language (Japanese) audio map at the beginning
// right after loading the video and audio drivers. The -1 language argument in here simply means that the original will stick
// with Japanese. Instead of doing that we switch to the language selected in the launcher.
- if (g_sci->getPlatform() == Common::kPlatformFMTowns && language == -1)
- language = (g_sci->getLanguage() == Common::JA_JPN) ? K_LANG_JAPANESE : K_LANG_ENGLISH;
+ if (g_sci->getPlatform() == Common::kPlatformFMTowns && language == -1) {
+ // FM-Towns calls us to get the current language / also set the default language
+ // This doesn't just happen right at the start, but also when the user clicks on the Sierra logo in the game menu
+ // It uses the result of this call to either show "English Voices" or "Japanese Voices".
+
+ // Language should have been set by setLauncherLanguage() already (or could have been modified by the scripts).
+ // Get this language setting, so that the chosen language will get set for resource manager.
+ language = g_sci->getSciLanguage();
+ }
debugC(kDebugLevelSound, "kDoAudio: set language to %d", language);
@@ -225,27 +256,40 @@ 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. kDoAudio in Pharkas sits at seg026:038C
+ // 3 new subops in Pharkas CD (including CD demo). kDoAudio in Pharkas sits at seg026:038C
case 11:
// Not sure where this is used yet
warning("kDoAudio: Unhandled case 11, %d extra arguments passed", argc - 1);
break;
case 12:
- // Seems to be some sort of audio sync, used in Pharkas. Silenced the
- // warning due to the high level of spam it produces. (takes no params)
- //warning("kDoAudio: Unhandled case 12, %d extra arguments passed", argc - 1);
+ // SSCI calls this function with no parameters from
+ // the TalkRandCycle class and branches on the return
+ // value like a boolean. The conjectured purpose of
+ // this function is to ensure that the talker's mouth
+ // does not move if there is read jitter (slow CD
+ // drive, scratched CD). The old behavior here of not
+ // doing anything caused a nonzero value to be left in
+ // the accumulator by chance. This is equivalent, but
+ // more explicit.
+
+ return make_reg(0, 1);
break;
case 13:
- // Used in Pharkas whenever a speech sample starts (takes no params)
- //warning("kDoAudio: Unhandled case 13, %d extra arguments passed", argc - 1);
+ // SSCI returns a serial number for the played audio
+ // here, used in the PointsSound class. The reason is severalfold:
+
+ // 1. SSCI does not support multiple wave effects at once
+ // 2. FPFP may disable its icon bar during the points sound.
+ // 3. Each new sound preempts any sound already playing.
+ // 4. If the points sound is interrupted before completion,
+ // the icon bar could remain disabled.
+
+ // Since points (1) and (3) do not apply to us, we can simply
+ // return a constant here. This is equivalent to the
+ // old behavior, as above.
+ return make_reg(0, 1);
break;
case 17:
// Seems to be some sort of audio sync, used in SQ6. Silenced the
@@ -260,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) {
@@ -278,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());
@@ -295,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
@@ -309,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 eef758a0d9..1c08bf597c 100644
--- a/engines/sci/engine/kstring.cpp
+++ b/engines/sci/engine/kstring.cpp
@@ -661,202 +661,238 @@ 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;
+// 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;
+ SciString *string = s->_segMan->allocateString(&stringHandle);
+ string->setSize(argv[0].toUint16());
+
+ // Make sure the first character is a null character
+ if (string->getSize() > 0)
+ string->setValue(0, 0);
+
+ return stringHandle;
+}
+
+reg_t kStringSize(EngineState *s, int argc, reg_t *argv) {
+ return make_reg(0, s->_segMan->getString(argv[0]).size());
+}
+
+// At (return value at an index)
+reg_t kStringAt(EngineState *s, int argc, reg_t *argv) {
+ // Note that values are put in bytes to avoid sign extension
+ if (argv[0].getSegment() == s->_segMan->getStringSegmentId()) {
+ SciString *string = s->_segMan->lookupString(argv[0]);
+ byte val = string->getRawData()[argv[1].toUint16()];
+ return make_reg(0, val);
+ } else {
+ Common::String string = s->_segMan->getString(argv[0]);
+ byte val = string[argv[1].toUint16()];
+ return make_reg(0, val);
}
+}
+// Atput (put value at an index)
+reg_t kStringPutAt(EngineState *s, int argc, reg_t *argv) {
+ SciString *string = s->_segMan->lookupString(argv[0]);
+
+ uint32 index = argv[1].toUint16();
+ uint32 count = argc - 2;
+
+ if (index + count > 65535)
+ return NULL_REG;
+
+ if (string->getSize() < index + count)
+ string->setSize(index + count);
+
+ for (uint16 i = 0; i < count; i++)
+ string->setValue(i + index, argv[i + 2].toUint16());
+
+ return argv[0]; // We also have to return the handle
+}
+
+reg_t kStringFree(EngineState *s, int argc, reg_t *argv) {
+ // Freeing of strings is handled by the garbage collector
return s->r_acc;
}
-reg_t kString(EngineState *s, int argc, reg_t *argv) {
- uint16 op = argv[0].toUint16();
+reg_t kStringFill(EngineState *s, int argc, reg_t *argv) {
+ SciString *string = s->_segMan->lookupString(argv[0]);
+ uint16 index = argv[1].toUint16();
- if (g_sci->_features->detectSci2StringFunctionType() == kSci2StringFunctionNew) {
- if (op >= 8) // Dup, GetData have been removed
- op += 2;
- }
+ // A count of -1 means fill the rest of the array
+ uint16 count = argv[2].toSint16() == -1 ? string->getSize() - index : argv[2].toUint16();
+ uint16 stringSize = string->getSize();
- switch (op) {
- case 0: { // New
- reg_t stringHandle;
- SciString *string = s->_segMan->allocateString(&stringHandle);
- string->setSize(argv[1].toUint16());
+ if (stringSize < index + count)
+ string->setSize(index + count);
- // Make sure the first character is a null character
- if (string->getSize() > 0)
- string->setValue(0, 0);
+ for (uint16 i = 0; i < count; i++)
+ string->setValue(i + index, argv[3].toUint16());
- return stringHandle;
- }
- case 1: // Size
- return make_reg(0, s->_segMan->getString(argv[1]).size());
- case 2: { // At (return value at an index)
- // Note that values are put in bytes to avoid sign extension
- if (argv[1].getSegment() == s->_segMan->getStringSegmentId()) {
- SciString *string = s->_segMan->lookupString(argv[1]);
- byte val = string->getRawData()[argv[2].toUint16()];
- return make_reg(0, val);
- } else {
- Common::String string = s->_segMan->getString(argv[1]);
- byte val = string[argv[2].toUint16()];
- return make_reg(0, val);
+ return argv[0];
+}
+
+reg_t kStringCopy(EngineState *s, int argc, reg_t *argv) {
+ const char *string2 = 0;
+ uint32 string2Size = 0;
+ Common::String string;
+
+ if (argv[2].getSegment() == s->_segMan->getStringSegmentId()) {
+ SciString *sstr;
+ sstr = s->_segMan->lookupString(argv[2]);
+ string2 = sstr->getRawData();
+ string2Size = sstr->getSize();
+ } else {
+ string = s->_segMan->getString(argv[2]);
+ string2 = string.c_str();
+ string2Size = string.size() + 1;
+ }
+
+ uint32 index1 = argv[1].toUint16();
+ uint32 index2 = argv[3].toUint16();
+
+ if (argv[0] == argv[2]) {
+ // source and destination string are one and the same
+ if (index1 == index2) {
+ // even same index? ignore this call
+ // Happens in KQ7, when starting a chapter
+ return argv[0];
}
+ // TODO: this will crash, when setSize() is triggered later
+ // we need to exactly replicate original interpreter behavior
+ warning("kString(Copy): source is the same as destination string");
}
- case 3: { // Atput (put value at an index)
- SciString *string = s->_segMan->lookupString(argv[1]);
- uint32 index = argv[2].toUint16();
- uint32 count = argc - 3;
+ // The original engine ignores bad copies too
+ if (index2 >= string2Size)
+ return NULL_REG;
- if (index + count > 65535)
- break;
+ // A count of -1 means fill the rest of the array
+ uint32 count = string2Size - index2;
+ if (argv[4].toSint16() != -1) {
+ count = MIN(count, (uint32)argv[4].toUint16());
+ }
+// reg_t strAddress = argv[0];
- if (string->getSize() < index + count)
- string->setSize(index + count);
+ SciString *string1 = s->_segMan->lookupString(argv[0]);
+ //SciString *string1 = !argv[1].isNull() ? s->_segMan->lookupString(argv[1]) : s->_segMan->allocateString(&strAddress);
- for (uint16 i = 0; i < count; i++)
- string->setValue(i + index, argv[i + 3].toUint16());
+ if (string1->getSize() < index1 + count)
+ string1->setSize(index1 + count);
- return argv[1]; // We also have to return the handle
- }
- case 4: // Free
- // Freeing of strings is handled by the garbage collector
- return s->r_acc;
- case 5: { // Fill
- SciString *string = s->_segMan->lookupString(argv[1]);
- uint16 index = argv[2].toUint16();
+ // Note: We're accessing from c_str() here because the
+ // string's size ignores the trailing 0 and therefore
+ // triggers an assert when doing string2[i + index2].
+ for (uint16 i = 0; i < count; i++)
+ string1->setValue(i + index1, string2[i + index2]);
- // A count of -1 means fill the rest of the array
- uint16 count = argv[3].toSint16() == -1 ? string->getSize() - index : argv[3].toUint16();
- uint16 stringSize = string->getSize();
+ return argv[0];
+}
+
+reg_t kStringCompare(EngineState *s, int argc, reg_t *argv) {
+ Common::String string1 = argv[0].isNull() ? "" : s->_segMan->getString(argv[0]);
+ Common::String string2 = argv[1].isNull() ? "" : s->_segMan->getString(argv[1]);
+
+ if (argc == 3) // Strncmp
+ return make_reg(0, strncmp(string1.c_str(), string2.c_str(), argv[2].toUint16()));
+ else // Strcmp
+ return make_reg(0, strcmp(string1.c_str(), string2.c_str()));
+}
- if (stringSize < index + count)
- string->setSize(index + count);
+// was removed for SCI2.1 Late+
+reg_t kStringDup(EngineState *s, int argc, reg_t *argv) {
+ reg_t stringHandle;
- for (uint16 i = 0; i < count; i++)
- string->setValue(i + index, argv[4].toUint16());
+ SciString *dupString = s->_segMan->allocateString(&stringHandle);
- return argv[1];
+ if (argv[0].getSegment() == s->_segMan->getStringSegmentId()) {
+ *dupString = *s->_segMan->lookupString(argv[0]);
+ } else {
+ dupString->fromString(s->_segMan->getString(argv[0]));
}
- case 6: { // Cpy
- const char *string2 = 0;
- uint32 string2Size = 0;
- Common::String string;
-
- if (argv[3].getSegment() == s->_segMan->getStringSegmentId()) {
- SciString *sstr;
- sstr = s->_segMan->lookupString(argv[3]);
- string2 = sstr->getRawData();
- string2Size = sstr->getSize();
- } else {
- string = s->_segMan->getString(argv[3]);
- string2 = string.c_str();
- string2Size = string.size() + 1;
- }
- uint32 index1 = argv[2].toUint16();
- uint32 index2 = argv[4].toUint16();
+ return stringHandle;
+}
- // The original engine ignores bad copies too
- if (index2 > string2Size)
- break;
+// was removed for SCI2.1 Late+
+reg_t kStringGetData(EngineState *s, int argc, reg_t *argv) {
+ if (!s->_segMan->isHeapObject(argv[0]))
+ return argv[0];
- // A count of -1 means fill the rest of the array
- uint32 count = argv[5].toSint16() == -1 ? string2Size - index2 + 1 : argv[5].toUint16();
- reg_t strAddress = argv[1];
+ return readSelector(s->_segMan, argv[0], SELECTOR(data));
+}
- SciString *string1 = s->_segMan->lookupString(argv[1]);
- //SciString *string1 = !argv[1].isNull() ? s->_segMan->lookupString(argv[1]) : s->_segMan->allocateString(&strAddress);
+reg_t kStringLen(EngineState *s, int argc, reg_t *argv) {
+ return make_reg(0, s->_segMan->strlen(argv[0]));
+}
- if (string1->getSize() < index1 + count)
- string1->setSize(index1 + count);
+reg_t kStringPrintf(EngineState *s, int argc, reg_t *argv) {
+ reg_t stringHandle;
+ s->_segMan->allocateString(&stringHandle);
- // Note: We're accessing from c_str() here because the
- // string's size ignores the trailing 0 and therefore
- // triggers an assert when doing string2[i + index2].
- for (uint16 i = 0; i < count; i++)
- string1->setValue(i + index1, string2[i + index2]);
+ reg_t *adjustedArgs = new reg_t[argc + 1];
+ adjustedArgs[0] = stringHandle;
+ memcpy(&adjustedArgs[1], argv, argc * sizeof(reg_t));
- return strAddress;
- }
- case 7: { // Cmp
- Common::String string1 = argv[1].isNull() ? "" : s->_segMan->getString(argv[1]);
- Common::String string2 = argv[2].isNull() ? "" : s->_segMan->getString(argv[2]);
-
- if (argc == 4) // Strncmp
- return make_reg(0, strncmp(string1.c_str(), string2.c_str(), argv[3].toUint16()));
- else // Strcmp
- return make_reg(0, strcmp(string1.c_str(), string2.c_str()));
- }
- case 8: { // Dup
- reg_t stringHandle;
+ kFormat(s, argc + 1, adjustedArgs);
+ delete[] adjustedArgs;
+ return stringHandle;
+}
- SciString *dupString = s->_segMan->allocateString(&stringHandle);
+reg_t kStringPrintfBuf(EngineState *s, int argc, reg_t *argv) {
+ return kFormat(s, argc, argv);
+}
- if (argv[1].getSegment() == s->_segMan->getStringSegmentId()) {
- *dupString = *s->_segMan->lookupString(argv[1]);
- } else {
- dupString->fromString(s->_segMan->getString(argv[1]));
- }
+reg_t kStringAtoi(EngineState *s, int argc, reg_t *argv) {
+ Common::String string = s->_segMan->getString(argv[0]);
+ return make_reg(0, (uint16)atoi(string.c_str()));
+}
- return stringHandle;
- }
- case 9: // Getdata
- if (!s->_segMan->isHeapObject(argv[1]))
- return argv[1];
-
- return readSelector(s->_segMan, argv[1], SELECTOR(data));
- case 10: // Stringlen
- return make_reg(0, s->_segMan->strlen(argv[1]));
- case 11: { // Printf
- reg_t stringHandle;
- s->_segMan->allocateString(&stringHandle);
-
- reg_t *adjustedArgs = new reg_t[argc];
- adjustedArgs[0] = stringHandle;
- memcpy(&adjustedArgs[1], argv + 1, (argc - 1) * sizeof(reg_t));
-
- kFormat(s, argc, adjustedArgs);
- delete[] adjustedArgs;
- return stringHandle;
- }
- case 12: // Printf Buf
- return kFormat(s, argc - 1, argv + 1);
- case 13: { // atoi
- Common::String string = s->_segMan->getString(argv[1]);
- return make_reg(0, (uint16)atoi(string.c_str()));
- }
- // New subops in SCI2.1 late / SCI3
- case 14: // unknown
- warning("kString, subop %d", op);
- return NULL_REG;
- case 15: { // upper
- Common::String string = s->_segMan->getString(argv[1]);
+reg_t kStringTrim(EngineState *s, int argc, reg_t *argv) {
+ Common::String string = s->_segMan->getString(argv[0]);
- string.toUppercase();
- s->_segMan->strcpy(argv[1], string.c_str());
- return NULL_REG;
- }
- case 16: { // lower
- Common::String string = s->_segMan->getString(argv[1]);
+ string.trim();
+ // TODO: Second parameter (bitfield, trim from left, right, center)
+ warning("kStringTrim (%d)", argv[1].getOffset());
+ s->_segMan->strcpy(argv[0], string.c_str());
+ return NULL_REG;
+}
- string.toLowercase();
- s->_segMan->strcpy(argv[1], string.c_str());
- return NULL_REG;
- }
- default:
- error("Unknown kString subop %d", argv[0].toUint16());
- }
+reg_t kStringUpper(EngineState *s, int argc, reg_t *argv) {
+ Common::String string = s->_segMan->getString(argv[0]);
+
+ string.toUppercase();
+ s->_segMan->strcpy(argv[0], string.c_str());
+ return NULL_REG;
+}
+reg_t kStringLower(EngineState *s, int argc, reg_t *argv) {
+ Common::String string = s->_segMan->getString(argv[0]);
+
+ string.toLowercase();
+ s->_segMan->strcpy(argv[0], string.c_str());
+ return NULL_REG;
+}
+
+// Possibly kStringTranslate?
+reg_t kStringTrn(EngineState *s, int argc, reg_t *argv) {
+ warning("kStringTrn (argc = %d)", argc);
+ return NULL_REG;
+}
+
+// Possibly kStringTranslateExclude?
+reg_t kStringTrnExclude(EngineState *s, int argc, reg_t *argv) {
+ warning("kStringTrnExclude (argc = %d)", argc);
return NULL_REG;
}
+reg_t kString(EngineState *s, int argc, reg_t *argv) {
+ if (!s)
+ return make_reg(0, getSciVersion());
+ error("not supposed to call this");
+}
+
#endif
} // End of namespace Sci
diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp
index f925111fc9..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
@@ -181,7 +182,7 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
// for the video, so we'll just play it from there for now.
#ifdef ENABLE_SCI32
- if (getSciVersion() >= SCI_VERSION_2_1) {
+ if (getSciVersion() >= SCI_VERSION_2_1_EARLY) {
// SCI2.1 always has argv[0] as 1, the rest of the arguments seem to
// follow SCI1.1/2.
if (argv[0].toUint16() != 1)
@@ -231,7 +232,7 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
initGraphics(screenWidth, screenHeight, screenWidth > 320);
else {
g_sci->_gfxScreen->kernelSyncWithFramebuffer();
- g_sci->_gfxPalette->kernelSyncScreenPalette();
+ g_sci->_gfxPalette16->kernelSyncScreenPalette();
}
}
@@ -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/message.cpp b/engines/sci/engine/message.cpp
index 640175b20a..5300b72b71 100644
--- a/engines/sci/engine/message.cpp
+++ b/engines/sci/engine/message.cpp
@@ -182,7 +182,7 @@ bool MessageState::getRecord(CursorStack &stack, bool recurse, MessageRecord &re
#ifdef ENABLE_SCI32
case 5: // v5 seems to be compatible with v4
// SCI32 Mac is different than SCI32 DOS/Win here
- if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2_1)
+ if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2_1_EARLY)
reader = new MessageReaderV4_MacSCI32(res->data, res->size);
else
#endif
diff --git a/engines/sci/engine/object.cpp b/engines/sci/engine/object.cpp
index eeff45163d..0566d6955f 100644
--- a/engines/sci/engine/object.cpp
+++ b/engines/sci/engine/object.cpp
@@ -45,7 +45,7 @@ static bool relocateBlock(Common::Array<reg_t> &block, int block_location, Segme
return false;
}
block[idx].setSegment(segment); // Perform relocation
- if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1)
+ if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE)
block[idx].incOffset(scriptSize);
return true;
@@ -63,7 +63,7 @@ void Object::init(byte *buf, reg_t obj_pos, bool initVariables) {
for (int i = 0; i < _methodCount * 2 + 2; ++i) {
_baseMethod.push_back(READ_SCI11ENDIAN_UINT16(data + READ_LE_UINT16(data + kOffsetFunctionArea) + i * 2));
}
- } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
+ } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
_variables.resize(READ_SCI11ENDIAN_UINT16(data + 2));
_baseVars = (const uint16 *)(buf + READ_SCI11ENDIAN_UINT16(data + 4));
_methodCount = READ_SCI11ENDIAN_UINT16(buf + READ_SCI11ENDIAN_UINT16(data + 6));
@@ -75,7 +75,7 @@ void Object::init(byte *buf, reg_t obj_pos, bool initVariables) {
}
if (initVariables) {
- if (getSciVersion() <= SCI_VERSION_2_1) {
+ if (getSciVersion() <= SCI_VERSION_2_1_LATE) {
for (uint i = 0; i < _variables.size(); i++)
_variables[i] = make_reg(0, READ_SCI11ENDIAN_UINT16(data + (i * 2)));
} else {
@@ -92,7 +92,7 @@ int Object::locateVarSelector(SegManager *segMan, Selector slc) const {
const byte *buf = 0;
uint varnum = 0;
- if (getSciVersion() <= SCI_VERSION_2_1) {
+ if (getSciVersion() <= SCI_VERSION_2_1_LATE) {
const Object *obj = getClass(segMan);
varnum = getSciVersion() <= SCI_VERSION_1_LATE ? getVarCount() : obj->getVariable(1).toUint16();
buf = (const byte *)obj->_baseVars;
@@ -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 00fe7c6875..a7be170f4f 100644
--- a/engines/sci/engine/object.h
+++ b/engines/sci/engine/object.h
@@ -41,8 +41,21 @@ enum {
};
enum infoSelectorFlags {
- kInfoFlagClone = 0x0001,
- kInfoFlagClass = 0x8000
+ kInfoFlagClone = 0x0001,
+#ifdef ENABLE_SCI32
+ /**
+ * When set, indicates to game scripts that a screen
+ * item can be updated.
+ */
+ kInfoFlagViewVisible = 0x0008, // TODO: "dirty" ?
+
+ /**
+ * When set, the object has an associated screen item in
+ * the rendering tree.
+ */
+ kInfoFlagViewInserted = 0x0010,
+#endif
+ kInfoFlagClass = 0x8000
};
enum ObjectOffsets {
@@ -79,51 +92,68 @@ public:
}
reg_t getSpeciesSelector() const {
- if (getSciVersion() <= SCI_VERSION_2_1)
+ if (getSciVersion() < SCI_VERSION_3)
return _variables[_offset];
else // SCI3
return _speciesSelectorSci3;
}
void setSpeciesSelector(reg_t value) {
- if (getSciVersion() <= SCI_VERSION_2_1)
+ if (getSciVersion() < SCI_VERSION_3)
_variables[_offset] = value;
else // SCI3
_speciesSelectorSci3 = value;
}
reg_t getSuperClassSelector() const {
- if (getSciVersion() <= SCI_VERSION_2_1)
+ if (getSciVersion() < SCI_VERSION_3)
return _variables[_offset + 1];
else // SCI3
return _superClassPosSci3;
}
void setSuperClassSelector(reg_t value) {
- if (getSciVersion() <= SCI_VERSION_2_1)
+ if (getSciVersion() < SCI_VERSION_3)
_variables[_offset + 1] = value;
else // SCI3
_superClassPosSci3 = value;
}
reg_t getInfoSelector() const {
- if (getSciVersion() <= SCI_VERSION_2_1)
+ if (getSciVersion() < SCI_VERSION_3)
return _variables[_offset + 2];
else // SCI3
return _infoSelectorSci3;
}
void setInfoSelector(reg_t info) {
- if (getSciVersion() <= SCI_VERSION_2_1)
+ if (getSciVersion() < SCI_VERSION_3)
_variables[_offset + 2] = info;
else // SCI3
_infoSelectorSci3 = info;
}
- // No setter for the -info- selector
+#ifdef ENABLE_SCI32
+ void setInfoSelectorFlag(infoSelectorFlags flag) {
+ if (getSciVersion() < SCI_VERSION_3) {
+ _variables[_offset + 2] |= flag;
+ } else {
+ _infoSelectorSci3 |= flag;
+ }
+ }
+
+ // NOTE: In real engine, -info- is treated as byte size
+ void clearInfoSelectorFlag(infoSelectorFlags flag) {
+ if (getSciVersion() < SCI_VERSION_3) {
+ _variables[_offset + 2] &= ~flag;
+ } else {
+ _infoSelectorSci3 &= ~flag;
+ }
+ }
+#endif
reg_t getNameSelector() const {
- if (getSciVersion() <= SCI_VERSION_2_1)
+ if (getSciVersion() < SCI_VERSION_3)
return _offset + 3 < (uint16)_variables.size() ? _variables[_offset + 3] : NULL_REG;
else // SCI3
return _variables.size() ? _variables[0] : NULL_REG;
@@ -132,7 +162,7 @@ public:
// No setter for the name selector
reg_t getPropDictSelector() const {
- if (getSciVersion() <= SCI_VERSION_2_1)
+ if (getSciVersion() < SCI_VERSION_3)
return _variables[2];
else
// This should never occur, this is called from a SCI1.1 - SCI2.1 only function
@@ -140,7 +170,7 @@ public:
}
void setPropDictSelector(reg_t value) {
- if (getSciVersion() <= SCI_VERSION_2_1)
+ if (getSciVersion() < SCI_VERSION_3)
_variables[2] = value;
else
// This should never occur, this is called from a SCI1.1 - SCI2.1 only function
@@ -148,14 +178,14 @@ public:
}
reg_t getClassScriptSelector() const {
- if (getSciVersion() <= SCI_VERSION_2_1)
+ if (getSciVersion() < SCI_VERSION_3)
return _variables[4];
else // SCI3
return make_reg(0, READ_SCI11ENDIAN_UINT16(_baseObj + 6));
}
void setClassScriptSelector(reg_t value) {
- if (getSciVersion() <= SCI_VERSION_2_1)
+ if (getSciVersion() < SCI_VERSION_3)
_variables[4] = value;
else // SCI3
// This should never occur, this is called from a SCI1.1 - SCI2.1 only function
@@ -232,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);
@@ -248,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 93b3a997cc..31fb848a2c 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -39,6 +39,7 @@
#include "sci/engine/vm_types.h"
#include "sci/engine/script.h" // for SCI_OBJ_EXPORTS and SCI_OBJ_SYNONYMS
#include "sci/graphics/helpers.h"
+#include "sci/graphics/menu.h"
#include "sci/graphics/palette.h"
#include "sci/graphics/ports.h"
#include "sci/graphics/screen.h"
@@ -48,6 +49,8 @@
#ifdef ENABLE_SCI32
#include "sci/graphics/frameout.h"
+#include "sci/graphics/palette32.h"
+#include "sci/graphics/remap32.h"
#endif
namespace Sci {
@@ -58,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.
@@ -114,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) {
@@ -245,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);
@@ -272,7 +362,11 @@ static void sync_SavegameMetadata(Common::Serializer &s, SavegameMetadata &obj)
if (s.getVersion() >= 26)
s.syncAsUint32LE(obj.playTime);
} else {
- obj.playTime = g_engine->getTotalPlayTime() / 1000;
+ if (s.getVersion() >= 34) {
+ obj.playTime = g_sci->getTickCount();
+ } else {
+ obj.playTime = g_engine->getTotalPlayTime() / 1000;
+ }
s.syncAsUint32LE(obj.playTime);
}
}
@@ -304,7 +398,13 @@ void EngineState::saveLoadWithSerializer(Common::Serializer &s) {
_segMan->saveLoadWithSerializer(s);
g_sci->_soundCmd->syncPlayList(s);
- g_sci->_gfxPalette->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) {
@@ -324,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) {
@@ -465,7 +476,7 @@ void Script::syncStringHeap(Common::Serializer &s) {
break;
} while (1);
- } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1){
+ } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE){
// Strings in SCI1.1 come after the object instances
byte *buf = _heapStart + 4 + READ_SCI11ENDIAN_UINT16(_heapStart + 2) * 2;
@@ -721,6 +732,116 @@ void GfxPalette::saveLoadWithSerializer(Common::Serializer &s) {
}
}
+#ifdef ENABLE_SCI32
+void saveLoadPalette32(Common::Serializer &s, Palette *const palette) {
+ s.syncAsUint32LE(palette->timestamp);
+ for (int i = 0; i < ARRAYSIZE(palette->colors); ++i) {
+ s.syncAsByte(palette->colors[i].used);
+ s.syncAsByte(palette->colors[i].r);
+ s.syncAsByte(palette->colors[i].g);
+ s.syncAsByte(palette->colors[i].b);
+ }
+}
+
+void saveLoadOptionalPalette32(Common::Serializer &s, Palette **const palette) {
+ bool hasPalette;
+ if (s.isSaving()) {
+ hasPalette = (*palette != nullptr);
+ }
+ s.syncAsByte(hasPalette);
+ if (hasPalette) {
+ if (s.isLoading()) {
+ *palette = new Palette;
+ }
+ saveLoadPalette32(s, *palette);
+ }
+}
+
+void GfxPalette32::saveLoadWithSerializer(Common::Serializer &s) {
+ if (s.getVersion() < 34) {
+ return;
+ }
+
+ if (s.isLoading()) {
+ ++_version;
+ }
+
+ s.syncAsSint16LE(_varyDirection);
+ s.syncAsSint16LE(_varyPercent);
+ s.syncAsSint16LE(_varyTargetPercent);
+ s.syncAsSint16LE(_varyFromColor);
+ s.syncAsSint16LE(_varyToColor);
+ s.syncAsUint16LE(_varyNumTimesPaused);
+ s.syncAsByte(_needsUpdate);
+ s.syncAsSint32LE(_varyTime);
+ s.syncAsUint32LE(_varyLastTick);
+
+ for (int i = 0; i < ARRAYSIZE(_fadeTable); ++i) {
+ s.syncAsByte(_fadeTable[i]);
+ }
+ for (int i = 0; i < ARRAYSIZE(_cycleMap); ++i) {
+ s.syncAsByte(_cycleMap[i]);
+ }
+
+ saveLoadOptionalPalette32(s, &_varyTargetPalette);
+ saveLoadOptionalPalette32(s, &_varyStartPalette);
+ // NOTE: _sourcePalette and _nextPalette are not saved
+ // by SCI engine
+
+ for (int i = 0; i < ARRAYSIZE(_cyclers); ++i) {
+ PalCycler *cycler = nullptr;
+
+ bool hasCycler;
+ if (s.isSaving()) {
+ cycler = _cyclers[i];
+ hasCycler = (cycler != nullptr);
+ }
+ s.syncAsByte(hasCycler);
+
+ if (hasCycler) {
+ if (s.isLoading()) {
+ _cyclers[i] = cycler = new PalCycler;
+ }
+
+ s.syncAsByte(cycler->fromColor);
+ s.syncAsUint16LE(cycler->numColorsToCycle);
+ s.syncAsByte(cycler->currentCycle);
+ s.syncAsByte(cycler->direction);
+ s.syncAsUint32LE(cycler->lastUpdateTick);
+ s.syncAsSint16LE(cycler->delay);
+ s.syncAsUint16LE(cycler->numTimesPaused);
+ }
+ }
+}
+
+void GfxRemap32::saveLoadWithSerializer(Common::Serializer &s) {
+ if (s.getVersion() < 35) {
+ return;
+ }
+
+ s.syncAsByte(_numActiveRemaps);
+ s.syncAsByte(_blockedRangeStart);
+ s.syncAsSint16LE(_blockedRangeCount);
+
+ 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
+
void GfxPorts::saveLoadWithSerializer(Common::Serializer &s) {
// reset() is called directly way earlier in gamestate_restore()
if (s.getVersion() >= 27) {
@@ -811,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) {
@@ -866,7 +987,8 @@ bool gamestate_save(EngineState *s, Common::WriteStream *fh, const Common::Strin
extern void showScummVMDialog(const Common::String &message);
void gamestate_delayedrestore(EngineState *s) {
- Common::String fileName = g_sci->getSavegameName(s->_delayedRestoreGameId);
+ int savegameId = s->_delayedRestoreGameId; // delayedRestoreGameId gets destroyed within gamestate_restore()!
+ Common::String fileName = g_sci->getSavegameName(savegameId);
Common::SeekableReadStream *in = g_sci->getSaveFileManager()->openForLoading(fileName);
if (in) {
@@ -874,6 +996,7 @@ void gamestate_delayedrestore(EngineState *s) {
gamestate_restore(s, in);
delete in;
if (s->r_acc != make_reg(0, 1)) {
+ gamestate_afterRestoreFixUp(s, savegameId);
return;
}
}
@@ -881,6 +1004,73 @@ void gamestate_delayedrestore(EngineState *s) {
error("Restoring gamestate '%s' failed", fileName.c_str());
}
+void gamestate_afterRestoreFixUp(EngineState *s, int savegameId) {
+ switch (g_sci->getGameId()) {
+ case GID_MOTHERGOOSE:
+ // WORKAROUND: Mother Goose SCI0
+ // Script 200 / rm200::newRoom will set global C5h directly right after creating a child to the
+ // current number of children plus 1.
+ // We can't trust that global, that's why we set the actual savedgame id right here directly after
+ // restoring a saved game.
+ // If we didn't, the game would always save to a new slot
+ s->variables[VAR_GLOBAL][0xC5].setOffset(SAVEGAMEID_OFFICIALRANGE_START + savegameId);
+ break;
+ case GID_MOTHERGOOSE256:
+ // WORKAROUND: Mother Goose SCI1/SCI1.1 does some weird things for
+ // saving a previously restored game.
+ // We set the current savedgame-id directly and remove the script
+ // code concerning this via script patch.
+ s->variables[VAR_GLOBAL][0xB3].setOffset(SAVEGAMEID_OFFICIALRANGE_START + savegameId);
+ break;
+ case GID_JONES:
+ // HACK: The code that enables certain menu items isn't called when a game is restored from the
+ // launcher, or the "Restore game" option in the game's main menu - bugs #6537 and #6723.
+ // These menu entries are disabled when the game is launched, and are enabled when a new game is
+ // started. The code for enabling these entries is is all in script 1, room1::init, but that code
+ // path is never followed in these two cases (restoring game from the menu, or restoring a game
+ // from the ScummVM launcher). Thus, we perform the calls to enable the menus ourselves here.
+ // These two are needed when restoring from the launcher
+ // FIXME: The original interpreter saves and restores the menu state, so these attributes
+ // are automatically reset there. We may want to do the same.
+ g_sci->_gfxMenu->kernelSetAttribute(257 >> 8, 257 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Sierra -> About Jones
+ g_sci->_gfxMenu->kernelSetAttribute(258 >> 8, 258 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Sierra -> Help
+ // The rest are normally enabled from room1::init
+ g_sci->_gfxMenu->kernelSetAttribute(769 >> 8, 769 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Options -> Delete current player
+ g_sci->_gfxMenu->kernelSetAttribute(513 >> 8, 513 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Game -> Save Game
+ g_sci->_gfxMenu->kernelSetAttribute(515 >> 8, 515 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Game -> Restore Game
+ 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.
+ g_sci->_gfxMenu->kernelSetAttribute(2, 1, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Game -> Save Game
+ break;
+ default:
+ break;
+ }
+}
+
void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) {
SavegameMetadata meta;
@@ -922,13 +1112,31 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) {
if (g_sci->_gfxPorts)
g_sci->_gfxPorts->reset();
// clear screen
- if (g_sci->_gfxScreen)
- g_sci->_gfxScreen->clearForRestoreGame();
+ if (getSciVersion() <= SCI_VERSION_1_1) {
+ // Only do clearing the screen for SCI16
+ // Both SCI16 + SCI32 did not clear the screen.
+ // We basically do it for SCI16, because of KQ6.
+ // When hires portraits are shown and the user restores during that time, the portraits
+ // wouldn't get fully removed. In original SCI, the user wasn't able to restore during that time,
+ // so this is basically a workaround, so that ScummVM features work properly.
+ // For SCI32, behavior was verified in DOSBox, that SCI32 does not clear and also not redraw the screen.
+ // It only redraws elements that have changed in comparison to the state before the restore.
+ // If we cleared the screen for SCI32, we would have issues because of this behavior.
+ if (g_sci->_gfxScreen)
+ g_sci->_gfxScreen->clearForRestoreGame();
+ }
#ifdef ENABLE_SCI32
- // Also clear any SCI32 planes/screen items currently showing so they
- // don't show up after the load.
- if (getSciVersion() >= SCI_VERSION_2)
- g_sci->_gfxFrameout->clear();
+ // Delete current planes/elements of actively loaded VM, only when our ScummVM dialogs are patched in
+ // 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) {
+ 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);
@@ -944,11 +1152,22 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) {
// Time state:
s->lastWaitTime = g_system->getMillis();
s->_screenUpdateTime = g_system->getMillis();
- g_engine->setTotalPlayTime(meta.playTime * 1000);
+ if (meta.version >= 34) {
+ g_sci->setTickCount(meta.playTime);
+ } else {
+ g_engine->setTotalPlayTime(meta.playTime * 1000);
+ }
if (g_sci->_gfxPorts)
g_sci->_gfxPorts->saveLoadWithSerializer(ser);
+ // SCI32:
+ // Current planes/screen elements of freshly loaded VM are re-added by scripts in [gameID]::replay
+ // We don't have to do that in here.
+ // But we may have to do it ourselves in case we ever implement some soft-error handling in case
+ // a saved game can't be restored. That way we can restore the game screen.
+ // see _gfxFrameout->syncWithScripts()
+
Vocabulary *voc = g_sci->getVocabulary();
if (ser.getVersion() >= 30 && voc)
voc->saveLoadWithSerializer(ser);
@@ -966,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 5512b90fa8..43909accf2 100644
--- a/engines/sci/engine/savegame.h
+++ b/engines/sci/engine/savegame.h
@@ -37,6 +37,8 @@ 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
* 31 - priority for sound effects/music is now a signed int16, instead of a byte
@@ -58,7 +60,7 @@ struct EngineState;
*/
enum {
- CURRENT_SAVEGAME_VERSION = 33,
+ CURRENT_SAVEGAME_VERSION = 35,
MINIMUM_SAVEGAME_VERSION = 14
};
@@ -86,6 +88,9 @@ bool gamestate_save(EngineState *s, Common::WriteStream *save, const Common::Str
// does a delayed saved game restore, used by ScummVM game menu - see detection.cpp / SciEngine::loadGameState()
void gamestate_delayedrestore(EngineState *s);
+// does a few fixups right after restoring a saved game
+void gamestate_afterRestoreFixUp(EngineState *s, int savegameId);
+
/**
* Restores a game state from a directory.
* @param s An older state from the same game
diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp
index 36e33ccfa6..26a7ff5718 100644
--- a/engines/sci/engine/script.cpp
+++ b/engines/sci/engine/script.cpp
@@ -84,7 +84,7 @@ void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptP
if (getSciVersion() == SCI_VERSION_0_EARLY) {
_bufSize += READ_LE_UINT16(script->data) * 2;
- } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
+ } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
// In SCI1.1 - SCI2.1, the heap was in a separate space from the script. We append
// it to the end of the script, and adjust addressing accordingly.
// However, since we address the heap with a 16-bit pointer, the
@@ -142,7 +142,7 @@ void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptP
assert(_bufSize >= script->size);
memcpy(_buf, script->data, script->size);
- if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
+ if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, _nr), 0);
assert(heap != 0);
@@ -171,7 +171,7 @@ void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptP
_localsOffset = localsBlock - _buf + 4;
_localsCount = (READ_LE_UINT16(_buf + _localsOffset - 2) - 4) >> 1; // half block size
}
- } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
+ } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
if (READ_LE_UINT16(_buf + 1 + 5) > 0) { // does the script have an export table?
_exportTable = (const uint16 *)(_buf + 1 + 5 + 2);
_numExports = READ_SCI11ENDIAN_UINT16(_exportTable - 1);
@@ -387,7 +387,7 @@ void Script::identifyOffsets() {
scriptDataLeft -= blockSize;
} while (1);
- } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
+ } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
// Strings in SCI1.1 up to SCI2 come after the object instances
scriptDataPtr = _heapStart;
scriptDataLeft = _heapSize;
@@ -668,7 +668,7 @@ static bool relocateBlock(Common::Array<reg_t> &block, int block_location, Segme
return false;
}
block[idx].setSegment(segment); // Perform relocation
- if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1)
+ if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE)
block[idx].incOffset(scriptSize);
return true;
@@ -702,7 +702,7 @@ void Script::relocateSci0Sci21(reg_t block) {
uint16 heapSize = (uint16)_bufSize;
uint16 heapOffset = 0;
- if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
+ if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
heap = _heapStart;
heapSize = (uint16)_heapSize;
heapOffset = _scriptSize;
@@ -930,7 +930,7 @@ void Script::initializeClasses(SegManager *segMan) {
if (getSciVersion() <= SCI_VERSION_1_LATE) {
seeker = findBlockSCI0(SCI_OBJ_CLASS);
mult = 1;
- } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
+ } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
seeker = _heapStart + 4 + READ_SCI11ENDIAN_UINT16(_heapStart + 2) * 2;
mult = 2;
} else if (getSciVersion() == SCI_VERSION_3) {
@@ -962,7 +962,7 @@ void Script::initializeClasses(SegManager *segMan) {
if (isClass)
species = READ_SCI11ENDIAN_UINT16(seeker + 12);
classpos += 12;
- } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
+ } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
isClass = (READ_SCI11ENDIAN_UINT16(seeker + 14) & kInfoFlagClass); // -info- selector
species = READ_SCI11ENDIAN_UINT16(seeker + 10);
} else if (getSciVersion() == SCI_VERSION_3) {
@@ -1104,7 +1104,7 @@ void Script::initializeObjectsSci3(SegManager *segMan, SegmentId segmentId) {
void Script::initializeObjects(SegManager *segMan, SegmentId segmentId) {
if (getSciVersion() <= SCI_VERSION_1_LATE)
initializeObjectsSci0(segMan, segmentId);
- else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1)
+ else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE)
initializeObjectsSci11(segMan, segmentId);
else if (getSciVersion() == SCI_VERSION_3)
initializeObjectsSci3(segMan, segmentId);
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index 6915e12a0e..e6eed0b4b7 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -101,6 +101,8 @@ static const char *const selectorNameTable[] = {
"startText", // King's Quest 6 CD / Laura Bow 2 CD for audio+text support
"startAudio", // King's Quest 6 CD / Laura Bow 2 CD for audio+text support
"modNum", // King's Quest 6 CD / Laura Bow 2 CD for audio+text support
+ "cycler", // Space Quest 4 / system selector
+ "setLoop", // Laura Bow 1 Colonel's Bequest
NULL
};
@@ -127,7 +129,9 @@ enum ScriptPatcherSelectors {
SELECTOR_timesShownID,
SELECTOR_startText,
SELECTOR_startAudio,
- SELECTOR_modNum
+ SELECTOR_modNum,
+ SELECTOR_cycler,
+ SELECTOR_setLoop
};
// ===========================================================================
@@ -375,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
@@ -391,19 +423,73 @@ 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
};
// ===========================================================================
+
+// WORKAROUND
+// Freddy Pharkas intro screen
+// Sierra used inner loops for the scaling of the 2 title views.
+// Those inner loops don't call kGameIsRestarting, which is why
+// we do not update the screen and we also do not throttle.
+//
+// This patch fixes this and makes it work.
+// Applies to at least: English PC-CD
+// Responsible method: sTownScript::changeState(1), sTownScript::changeState(3) (script 110)
+static const uint16 freddypharkasSignatureIntroScaling[] = {
+ 0x38, SIG_ADDTOOFFSET(+2), // pushi (setLoop) (009b for PC CD)
+ 0x78, // push1
+ PATCH_ADDTOOFFSET(1), // push0 for first code, push1 for second code
+ 0x38, SIG_ADDTOOFFSET(+2), // pushi (setStep) (0143 for PC CD)
+ 0x7a, // push2
+ 0x39, 0x05, // pushi 05
+ 0x3c, // dup
+ 0x72, SIG_ADDTOOFFSET(+2), // lofsa (view)
+ SIG_MAGICDWORD,
+ 0x4a, 0x1e, // send 1e
+ 0x35, 0x0a, // ldi 0a
+ 0xa3, 0x02, // sal local[2]
+ // start of inner loop
+ 0x8b, 0x02, // lsl local[2]
+ SIG_ADDTOOFFSET(+43), // skip almost all of inner loop
+ 0xa3, 0x02, // sal local[2]
+ 0x33, 0xcf, // jmp [inner loop start]
+ SIG_END
+};
+
+static const uint16 freddypharkasPatchIntroScaling[] = {
+ // remove setLoop(), objects in heap are already prepared, saves 5 bytes
+ 0x38,
+ PATCH_GETORIGINALBYTE(+6),
+ PATCH_GETORIGINALBYTE(+7), // pushi (setStep)
+ 0x7a, // push2
+ 0x39, 0x05, // pushi 05
+ 0x3c, // dup
+ 0x72,
+ PATCH_GETORIGINALBYTE(+13),
+ PATCH_GETORIGINALBYTE(+14), // lofsa (view)
+ 0x4a, 0x18, // send 18 - adjusted
+ 0x35, 0x0a, // ldi 0a
+ 0xa3, 0x02, // sal local[2]
+ // start of new inner loop
+ 0x39, 0x00, // pushi 00
+ 0x43, 0x2c, 0x00, // callk GameIsRestarting <-- add this so that our speed throttler is triggered
+ SIG_ADDTOOFFSET(+47), // skip almost all of inner loop
+ 0x33, 0xca, // jmp [inner loop start]
+ PATCH_END
+};
+
// script 0 of freddy pharkas/CD PointsSound::check waits for a signal and if
// no signal received will call kDoSound(0xD) which is a dummy in sierra sci
// and ScummVM and will use acc (which is not set by the dummy) to trigger
@@ -522,6 +608,7 @@ static const uint16 freddypharkasPatchMacInventory[] = {
static const SciScriptPatcherEntry freddypharkasSignatures[] = {
{ true, 0, "CD: score early disposal", 1, freddypharkasSignatureScoreDisposal, freddypharkasPatchScoreDisposal },
{ true, 15, "Mac: broken inventory", 1, freddypharkasSignatureMacInventory, freddypharkasPatchMacInventory },
+ { true, 110, "intro scaling workaround", 2, freddypharkasSignatureIntroScaling, freddypharkasPatchIntroScaling },
{ true, 235, "CD: canister pickup hang", 3, freddypharkasSignatureCanisterHang, freddypharkasPatchCanisterHang },
{ true, 320, "ladder event issue", 2, freddypharkasSignatureLadderEvent, freddypharkasPatchLadderEvent },
SCI_SIGNATUREENTRY_TERMINATOR
@@ -755,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
@@ -785,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
};
@@ -1201,8 +1315,10 @@ static const uint16 kq6CDPatchAudioTextSupportJumpAlways[] = {
};
// Fixes "Girl In The Tower" to get played in dual mode as well
+// Also changes credits to use CD audio for dual mode.
+//
// Applies to at least: PC-CD
-// Patched method: rm740::cue
+// Patched method: rm740::cue (script 740), sCredits::init (script 52)
static const uint16 kq6CDSignatureAudioTextSupportGirlInTheTower[] = {
SIG_MAGICDWORD,
0x89, 0x5a, // lsg global[5a]
@@ -1329,6 +1445,7 @@ static const SciScriptPatcherEntry kq6Signatures[] = {
{ false, 928, "CD: audio + text support KQ6 4", 1, kq6CDSignatureAudioTextSupport4, kq6CDPatchAudioTextSupport4 },
{ false, 1009, "CD: audio + text support KQ6 Guards", 2, kq6CDSignatureAudioTextSupportGuards, kq6CDPatchAudioTextSupportGuards },
{ false, 1027, "CD: audio + text support KQ6 Stepmother", 1, kq6CDSignatureAudioTextSupportStepmother, kq6CDPatchAudioTextSupportJumpAlways },
+ { false, 52, "CD: audio + text support KQ6 Girl In The Tower", 1, kq6CDSignatureAudioTextSupportGirlInTheTower, kq6CDPatchAudioTextSupportGirlInTheTower },
{ false, 740, "CD: audio + text support KQ6 Girl In The Tower", 1, kq6CDSignatureAudioTextSupportGirlInTheTower, kq6CDPatchAudioTextSupportGirlInTheTower },
{ false, 370, "CD: audio + text support KQ6 Azure & Ariel", 6, kq6CDSignatureAudioTextSupportAzureAriel, kq6CDPatchAudioTextSupportAzureAriel },
{ false, 903, "CD: audio + text support KQ6 menu", 1, kq6CDSignatureAudioTextMenuSupport, kq6CDPatchAudioTextMenuSupport },
@@ -1336,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),
@@ -1375,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
};
@@ -1536,6 +1914,194 @@ static const SciScriptPatcherEntry larry6Signatures[] = {
};
// ===========================================================================
+// Laura Bow 1 - Colonel's Bequest
+//
+// This is basically just a broken easter egg in Colonel's Bequest.
+// A plane can show up in room 4, but that only happens really rarely.
+// Anyway the Sierra developer seems to have just entered the wrong loop,
+// which is why the statue view is used instead (loop 0).
+// We fix it to use the correct loop.
+//
+// This is only broken in the PC version. It was fixed for Amiga + Atari ST.
+//
+// Credits to OmerMor, for finding it.
+
+// Applies to at least: English PC Floppy
+// Responsible method: room4::init
+static const uint16 laurabow1SignatureEasterEggViewFix[] = {
+ 0x78, // push1
+ 0x76, // push0
+ SIG_MAGICDWORD,
+ 0x38, SIG_SELECTOR16(setLoop), // pushi "setLoop"
+ 0x78, // push1
+ 0x39, 0x03, // pushi 3 (loop 3, view only has 3 loops)
+ SIG_END
+};
+
+static const uint16 laurabow1PatchEasterEggViewFix[] = {
+ PATCH_ADDTOOFFSET(+7),
+ 0x02, // change loop to 2
+ 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, 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
+};
+
+// ===========================================================================
// Laura Bow 2
//
// Moving away the painting in the room with the hidden safe is problematic
@@ -1840,15 +2406,103 @@ static const SciScriptPatcherEntry laurabow2Signatures[] = {
// MG::replay somewhat calculates the savedgame-id used when saving again
// this doesn't work right and we remove the code completely.
// We set the savedgame-id directly right after restoring in kRestoreGame.
+// We also draw the background picture in here instead.
+// This Mixed Up Mother Goose draws the background picture before restoring,
+// instead of doing it properly in MG::replay. This fixes graphic issues,
+// when restoring from GMM.
+//
+// Applies to at least: English SCI1 CD, English SCI1.1 floppy, Japanese FM-Towns
+// Responsible method: MG::replay (script 0)
static const uint16 mothergoose256SignatureReplay[] = {
+ 0x7a, // push2
+ 0x78, // push1
+ 0x5b, 0x00, 0xbe, // lea global[BEh]
+ 0x36, // push
+ 0x43, 0x70, 0x04, // callk MemorySegment
+ 0x7a, // push2
+ 0x5b, 0x00, 0xbe, // lea global[BEh]
+ 0x36, // push
+ 0x76, // push0
+ 0x43, 0x62, 0x04, // callk StrAt
+ 0xa1, 0xaa, // sag global[AAh]
+ 0x7a, // push2
+ 0x5b, 0x00, 0xbe, // lea global[BEh]
+ 0x36, // push
+ 0x78, // push1
+ 0x43, 0x62, 0x04, // callk StrAt
+ 0x36, // push
+ 0x35, 0x20, // ldi 20
+ 0x04, // sub
+ 0xa1, SIG_ADDTOOFFSET(+1), // sag global[57h] -> FM-Towns [9Dh]
+ // 35 bytes
+ 0x39, 0x03, // pushi 03
+ 0x89, SIG_ADDTOOFFSET(+1), // lsg global[1Dh] -> FM-Towns [1Eh]
+ 0x76, // push0
+ 0x7a, // push2
+ 0x5b, 0x00, 0xbe, // lea global[BEh]
+ 0x36, // push
+ 0x7a, // push2
+ 0x43, 0x62, 0x04, // callk StrAt
+ 0x36, // push
+ 0x35, 0x01, // ldi 01
+ 0x04, // sub
+ 0x36, // push
+ 0x43, 0x62, 0x06, // callk StrAt
+ // 22 bytes
+ 0x7a, // push2
+ 0x5b, 0x00, 0xbe, // lea global[BE]
+ 0x36, // push
+ 0x39, 0x03, // pushi 03
+ 0x43, 0x62, 0x04, // callk StrAt
+ // 10 bytes
0x36, // push
0x35, SIG_MAGICDWORD, 0x20, // ldi 20
0x04, // sub
0xa1, 0xb3, // sag global[b3]
+ // 6 bytes
SIG_END
};
static const uint16 mothergoose256PatchReplay[] = {
+ 0x39, 0x06, // pushi 06
+ 0x76, // push0
+ 0x76, // push0
+ 0x38, PATCH_UINT16(200), // pushi 200d
+ 0x38, PATCH_UINT16(320), // pushi 320d
+ 0x76, // push0
+ 0x76, // push0
+ 0x43, 0x15, 0x0c, // callk SetPort -> set picture port to full screen
+ // 15 bytes
+ 0x39, 0x04, // pushi 04
+ 0x3c, // dup
+ 0x76, // push0
+ 0x38, PATCH_UINT16(255), // pushi 255d
+ 0x76, // push0
+ 0x43, 0x6f, 0x08, // callk Palette -> set intensity to 0 for all colors
+ // 11 bytes
+ 0x7a, // push2
+ 0x38, PATCH_UINT16(800), // pushi 800
+ 0x76, // push0
+ 0x43, 0x08, 0x04, // callk DrawPic -> draw picture 800
+ // 8 bytes
+ 0x39, 0x06, // pushi 06
+ 0x39, 0x0c, // pushi 0Ch
+ 0x76, // push0
+ 0x76, // push0
+ 0x38, PATCH_UINT16(200), // push 200
+ 0x38, PATCH_UINT16(320), // push 320
+ 0x78, // push1
+ 0x43, 0x6c, 0x0c, // callk Graph -> send everything to screen
+ // 16 bytes
+ 0x39, 0x06, // pushi 06
+ 0x76, // push0
+ 0x76, // push0
+ 0x38, PATCH_UINT16(156), // pushi 156d
+ 0x38, PATCH_UINT16(258), // pushi 258d
+ 0x39, 0x03, // pushi 03
+ 0x39, 0x04, // pushi 04
+ 0x43, 0x15, 0x0c, // callk SetPort -> set picture port back
+ // 17 bytes
0x34, PATCH_UINT16(0x0000), // ldi 0000 (dummy)
0x34, PATCH_UINT16(0x0000), // ldi 0000 (dummy)
PATCH_END
@@ -1856,6 +2510,9 @@ static const uint16 mothergoose256PatchReplay[] = {
// when saving, it also checks if the savegame ID is below 13.
// we change this to check if below 113 instead
+//
+// Applies to at least: English SCI1 CD, English SCI1.1 floppy, Japanese FM-Towns
+// Responsible method: Game::save (script 994 for SCI1), MG::save (script 0 for SCI1.1)
static const uint16 mothergoose256SignatureSaveLimit[] = {
0x89, SIG_MAGICDWORD, 0xb3, // lsg global[b3]
0x35, 0x0d, // ldi 0d
@@ -1879,6 +2536,50 @@ static const SciScriptPatcherEntry mothergoose256Signatures[] = {
// ===========================================================================
// Police Quest 1 VGA
+
+// When briefing is about to start in room 15, other officers will get into the room too.
+// When one of those officers gets into the way of ego, they will tell the player to sit down.
+// But control will be disabled right at that point. Ego may then go to his seat by himself,
+// or more often than not will just stand there. The player is unable to do anything.
+//
+// Sergeant Dooley will then enter the room. Tell the player to sit down 3 times and after
+// that it's game over.
+//
+// Because the Sergeant is telling the player to sit down, one has to assume that the player
+// is meant to still be in control. Which is why this script patch removes disabling of player control.
+//
+// The script also tries to make ego walk to the chair, but it fails because it gets stuck with other
+// actors. So I guess the safest way is to remove all of that and let the player do it manually.
+//
+// The responsible method seems to use a few hardcoded texts, which is why I have to assume that it's
+// not used anywhere else. I also checked all scripts and couldn't find any other calls to it.
+//
+// This of course also happens when using the original interpreter.
+//
+// Scripts work like this: manX::doit (script 134) triggers gab::changeState, which then triggers rm015::notify
+//
+// Applies to at least: English floppy
+// Responsible method: gab::changeState (script 152)
+// Fixes bug: #5865
+static const uint16 pq1vgaSignatureBriefingGettingStuck[] = {
+ 0x76, // push0
+ 0x45, 0x02, 0x00, // call export 2 of script 0 (disable control)
+ 0x38, SIG_ADDTOOFFSET(+2), // pushi notify
+ 0x76, // push0
+ 0x81, 0x02, // lag global[2] (get current room)
+ 0x4a, 0x04, // send 04
+ SIG_MAGICDWORD,
+ 0x8b, 0x02, // lsl local[2]
+ 0x35, 0x01, // ldi 01
+ 0x02, // add
+ SIG_END
+};
+
+static const uint16 pq1vgaPatchBriefingGettingStuck[] = {
+ 0x33, 0x0a, // jmp to lsl local[2], skip over export 2 and ::notify
+ PATCH_END // rm015::notify would try to make ego walk to the chair
+};
+
// When at the police station, you can put or get your gun from your locker.
// The script, that handles this, is buggy. It disposes the gun as soon as
// you click, but then waits 2 seconds before it also closes the locker.
@@ -1966,10 +2667,11 @@ static const uint16 pq1vgaPatchMapSaveRestoreBug[] = {
PATCH_END
};
-// script, description, signature patch
+// script, description, signature patch
static const SciScriptPatcherEntry pq1vgaSignatures[] = {
- { true, 341, "put gun in locker bug", 1, pq1vgaSignaturePutGunInLockerBug, pq1vgaPatchPutGunInLockerBug },
- { true, 500, "map save/restore bug", 2, pq1vgaSignatureMapSaveRestoreBug, pq1vgaPatchMapSaveRestoreBug },
+ { true, 152, "getting stuck while briefing is about to start", 1, pq1vgaSignatureBriefingGettingStuck, pq1vgaPatchBriefingGettingStuck },
+ { true, 341, "put gun in locker bug", 1, pq1vgaSignaturePutGunInLockerBug, pq1vgaPatchPutGunInLockerBug },
+ { true, 500, "map save/restore bug", 2, pq1vgaSignatureMapSaveRestoreBug, pq1vgaPatchMapSaveRestoreBug },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -2500,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,
@@ -2673,14 +3375,239 @@ 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.
+// It also doesn't call kGameIsRestarting. This may get fixed properly at some point
+// by rewriting the speed throttler.
+//
+// Additionally Sierra set the cycle speed of the hero to 0. Which explains
+// why the actions of the hero are so incredibly fast. This issue also happened
+// in the original interpreter, when the computer was too powerful.
+//
+// Applies to at least: English, French, German, Italian, Spanish PC floppy
+// Responsible method: combatControls::dispatchEvent (script 550) + WarriorObj in heap
+// Fixes bug #6247
+static const uint16 qfg3SignatureCombatSpeedThrottling1[] = {
+ 0x31, 0x0d, // bnt [skip code]
+ SIG_MAGICDWORD,
+ 0x89, 0xd2, // lsg global[D2h]
+ 0x35, 0x00, // ldi 0
+ 0x1e, // gt?
+ 0x31, 0x06, // bnt [skip code]
+ 0xe1, 0xd2, // -ag global[D2h] (jump skips over this)
+ 0x81, 0x58, // lag global[58h]
+ 0xa3, 0x01, // sal local[01]
+ SIG_END
+};
+
+static const uint16 qfg3PatchCombatSpeedThrottling1[] = {
+ 0x80, 0xd2, // lsg global[D2h]
+ 0x14, // or
+ 0x31, 0x06, // bnt [skip code] - saves 4 bytes
+ 0xe1, 0xd2, // -ag global[D2h]
+ 0x81, 0x58, // lag global[58h]
+ 0xa3, 0x01, // sal local[01] (jump skips over this)
+ // our code
+ 0x76, // push0
+ 0x43, 0x2c, 0x00, // callk GameIsRestarting <-- add this so that our speed throttler is triggered
+ PATCH_END
+};
+
+static const uint16 qfg3SignatureCombatSpeedThrottling2[] = {
+ SIG_MAGICDWORD,
+ SIG_UINT16(12), // priority 12
+ SIG_UINT16(0), // underbits 0
+ SIG_UINT16(0x4010), // signal 4010h
+ SIG_ADDTOOFFSET(+18),
+ SIG_UINT16(0), // scaleSignal 0
+ SIG_UINT16(128), // scaleX
+ SIG_UINT16(128), // scaleY
+ SIG_UINT16(128), // maxScale
+ SIG_UINT16(0), // cycleSpeed
+ SIG_END
+};
+
+static const uint16 qfg3PatchCombatSpeedThrottling2[] = {
+ PATCH_ADDTOOFFSET(+32),
+ PATCH_UINT16(5), // set cycleSpeed to 5
+ 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, 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
};
@@ -2836,6 +3763,66 @@ static const uint16 sq4CdPatchGetPointsForChangingBackClothes[] = {
PATCH_END
};
+
+// For Space Quest 4 CD, Sierra added a pick up animation for Roger, when he picks up the rope.
+//
+// When the player is detected by the zombie right at the start of the game, while picking up the rope,
+// scripts bomb out. This also happens, when using the original interpreter.
+//
+// This is caused by code, that's supposed to make Roger face the arriving drone.
+// We fix it, by checking if ego::cycler is actually set before calling that code.
+//
+// Applies to at least: English PC CD
+// Responsible method: droidShoots::changeState(3)
+// Fixes bug: #6076
+static const uint16 sq4CdSignatureGettingShotWhileGettingRope[] = {
+ 0x35, 0x02, // ldi 02
+ 0x65, 0x1a, // aTop cycles
+ 0x32, SIG_UINT16(0x02fa), // jmp [end]
+ SIG_MAGICDWORD,
+ 0x3c, // dup
+ 0x35, 0x02, // ldi 02
+ 0x1a, // eq?
+ 0x31, 0x0b, // bnt [state 3 check]
+ 0x76, // push0
+ 0x45, 0x02, 0x00, // call export 2 of script 0 -> disable controls
+ 0x35, 0x02, // ldi 02
+ 0x65, 0x1a, // aTop cycles
+ 0x32, SIG_UINT16(0x02e9), // jmp [end]
+ 0x3c, // dup
+ 0x35, 0x03, // ldi 03
+ 0x1a, // eq?
+ 0x31, 0x1e, // bnt [state 4 check]
+ 0x76, // push0
+ 0x45, 0x02, 0x00, // call export 2 of script 0 -> disable controls again??
+ 0x7a, // push2
+ 0x89, 0x00, // lsg global[0]
+ 0x72, SIG_UINT16(0x0242), // lofsa deathDroid
+ 0x36, // push
+ 0x45, 0x0d, 0x04, // call export 13 of script 0 -> set heading of ego to face droid
+ SIG_END
+};
+
+static const uint16 sq4CdPatchGettingShotWhileGettingRope[] = {
+ PATCH_ADDTOOFFSET(+11),
+ // this makes state 2 only do the 2 cycles wait, controls should always be disabled already at this point
+ 0x2f, 0xf3, // bt [previous state aTop cycles code]
+ // Now we check for state 3, this change saves us 11 bytes
+ 0x3c, // dup
+ 0x35, 0x03, // ldi 03
+ 0x1a, // eq?
+ 0x31, 0x29, // bnt [state 4 check]
+ // new state 3 code
+ 0x76, // push0
+ 0x45, 0x02, 0x00, // call export 2 of script 0 (disable controls, actually not needed)
+ 0x38, PATCH_SELECTOR16(cycler), // pushi cycler
+ 0x76, // push0
+ 0x81, 0x00, // lag global[0]
+ 0x4a, 0x04, // send 04 (get ego::cycler)
+ 0x30, PATCH_UINT16(10), // bnt [jump over heading call]
+ PATCH_END
+};
+
// The scripts in SQ4CD support simultaneous playing of speech and subtitles,
// but this was not available as an option. The following two patches enable
// this functionality in the game's GUI options dialog.
@@ -2932,6 +3919,7 @@ static const SciScriptPatcherEntry sq4Signatures[] = {
{ true, 700, "Floppy: throw stuff at sequel police bug", 1, sq4FloppySignatureThrowStuffAtSequelPoliceBug, sq4FloppyPatchThrowStuffAtSequelPoliceBug },
{ true, 45, "CD: walk in from below for room 45 fix", 1, sq4CdSignatureWalkInFromBelowRoom45, sq4CdPatchWalkInFromBelowRoom45 },
{ true, 396, "CD: get points for changing back clothes fix",1, sq4CdSignatureGetPointsForChangingBackClothes, sq4CdPatchGetPointsForChangingBackClothes },
+ { true, 701, "CD: getting shot, while getting rope", 1, sq4CdSignatureGettingShotWhileGettingRope, sq4CdPatchGettingShotWhileGettingRope },
{ true, 0, "CD: Babble icon speech and subtitles fix", 1, sq4CdSignatureBabbleIcon, sq4CdPatchBabbleIcon },
{ true, 818, "CD: Speech and subtitles option", 1, sq4CdSignatureTextOptions, sq4CdPatchTextOptions },
{ true, 818, "CD: Speech and subtitles option button", 1, sq4CdSignatureTextOptionsButton, sq4CdPatchTextOptionsButton },
@@ -3050,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]
@@ -3092,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?
@@ -3374,20 +4373,20 @@ bool ScriptPatcher::verifySignature(uint32 byteOffset, const uint16 *signatureDa
}
// will return -1 if no match was found, otherwise an offset to the start of the signature match
-int32 ScriptPatcher::findSignature(const SciScriptPatcherEntry *patchEntry, SciScriptPatcherRuntimeEntry *runtimeEntry, const byte *scriptData, const uint32 scriptSize) {
+int32 ScriptPatcher::findSignature(uint32 magicDWord, int magicOffset, const uint16 *signatureData, const char *patchDescription, const byte *scriptData, const uint32 scriptSize) {
if (scriptSize < 4) // we need to find a DWORD, so less than 4 bytes is not okay
return -1;
- const uint32 magicDWord = runtimeEntry->magicDWord; // is platform-specific BE/LE form, so that the later match will work
+ // magicDWord is in platform-specific BE/LE form, so that the later match will work, this was done for performance
const uint32 searchLimit = scriptSize - 3;
uint32 DWordOffset = 0;
// first search for the magic DWORD
while (DWordOffset < searchLimit) {
if (magicDWord == READ_UINT32(scriptData + DWordOffset)) {
// magic DWORD found, check if actual signature matches
- uint32 offset = DWordOffset + runtimeEntry->magicOffset;
+ uint32 offset = DWordOffset + magicOffset;
- if (verifySignature(offset, patchEntry->signatureData, patchEntry->description, scriptData, scriptSize))
+ if (verifySignature(offset, signatureData, patchDescription, scriptData, scriptSize))
return offset;
}
DWordOffset++;
@@ -3396,22 +4395,147 @@ int32 ScriptPatcher::findSignature(const SciScriptPatcherEntry *patchEntry, SciS
return -1;
}
-// This method calculates the magic DWORD for each entry in the signature table
-// and it also initializes the selector table for selectors used in the signatures/patches of the current game
-void ScriptPatcher::initSignature(const SciScriptPatcherEntry *patchTable) {
- const SciScriptPatcherEntry *curEntry = patchTable;
- SciScriptPatcherRuntimeEntry *curRuntimeEntry;
+int32 ScriptPatcher::findSignature(const SciScriptPatcherEntry *patchEntry, const SciScriptPatcherRuntimeEntry *runtimeEntry, const byte *scriptData, const uint32 scriptSize) {
+ return findSignature(runtimeEntry->magicDWord, runtimeEntry->magicOffset, patchEntry->signatureData, patchEntry->description, scriptData, scriptSize);
+}
+
+// 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 step;
int magicOffset;
byte magicDWord[4];
int magicDWordLeft = 0;
- const uint16 *curData;
uint16 curWord;
uint16 curCommand;
uint32 curValue;
byte byte1 = 0;
byte byte2 = 0;
+
+ memset(magicDWord, 0, sizeof(magicDWord));
+
+ curWord = *signatureData;
+ magicOffset = 0;
+ while (curWord != SIG_END) {
+ curCommand = curWord & SIG_COMMANDMASK;
+ curValue = curWord & SIG_VALUEMASK;
+ switch (curCommand) {
+ case SIG_MAGICDWORD: {
+ if (magicDWordIncluded) {
+ if ((calculatedMagicDWord) || (magicDWordLeft))
+ error("Script-Patcher: Magic-DWORD specified multiple times in signature\nFaulty patch: '%s'", signatureDescription);
+ magicDWordLeft = 4;
+ calculatedMagicDWordOffset = magicOffset;
+ } else {
+ error("Script-Patcher: Magic-DWORD sequence found in patch data\nFaulty patch: '%s'", signatureDescription);
+ }
+ break;
+ }
+ case SIG_CODE_ADDTOOFFSET: {
+ magicOffset -= curValue;
+ if (magicDWordLeft)
+ error("Script-Patcher: Magic-DWORD contains AddToOffset command\nFaulty patch: '%s'", signatureDescription);
+ break;
+ }
+ case SIG_CODE_UINT16:
+ case SIG_CODE_SELECTOR16: {
+ // UINT16 or 1
+ switch (curCommand) {
+ case SIG_CODE_UINT16: {
+ signatureData++; curWord = *signatureData;
+ if (curWord & SIG_COMMANDMASK)
+ error("Script-Patcher: signature entry inconsistent\nFaulty patch: '%s'", signatureDescription);
+ if (!_isMacSci11) {
+ byte1 = curValue;
+ byte2 = curWord & SIG_BYTEMASK;
+ } else {
+ byte1 = curWord & SIG_BYTEMASK;
+ byte2 = curValue;
+ }
+ break;
+ }
+ case SIG_CODE_SELECTOR16: {
+ curSelector = _selectorIdTable[curValue];
+ if (curSelector == -1) {
+ curSelector = g_sci->getKernel()->findSelector(selectorNameTable[curValue]);
+ _selectorIdTable[curValue] = curSelector;
+ }
+ if (!_isMacSci11) {
+ byte1 = curSelector & 0x00FF;
+ byte2 = curSelector >> 8;
+ } else {
+ byte1 = curSelector >> 8;
+ byte2 = curSelector & 0x00FF;
+ }
+ break;
+ }
+ }
+ magicOffset -= 2;
+ if (magicDWordLeft) {
+ // Remember current word for Magic DWORD
+ magicDWord[4 - magicDWordLeft] = byte1;
+ magicDWordLeft--;
+ if (magicDWordLeft) {
+ magicDWord[4 - magicDWordLeft] = byte2;
+ magicDWordLeft--;
+ }
+ if (!magicDWordLeft) {
+ // Magic DWORD is now known, convert to platform specific byte order
+ calculatedMagicDWord = READ_UINT32(magicDWord);
+ }
+ }
+ break;
+ }
+ case SIG_CODE_BYTE:
+ case SIG_CODE_SELECTOR8: {
+ if (curCommand == SIG_CODE_SELECTOR8) {
+ curSelector = _selectorIdTable[curValue];
+ if (curSelector == -1) {
+ curSelector = g_sci->getKernel()->findSelector(selectorNameTable[curValue]);
+ _selectorIdTable[curValue] = curSelector;
+ if (curSelector != -1) {
+ if (curSelector & 0xFF00)
+ error("Script-Patcher: 8 bit selector required, game uses 16 bit selector\nFaulty patch: '%s'", signatureDescription);
+ }
+ }
+ curValue = curSelector;
+ }
+ magicOffset--;
+ if (magicDWordLeft) {
+ // Remember current byte for Magic DWORD
+ magicDWord[4 - magicDWordLeft] = (byte)curValue;
+ magicDWordLeft--;
+ if (!magicDWordLeft) {
+ // Magic DWORD is now known, convert to platform specific byte order
+ calculatedMagicDWord = READ_UINT32(magicDWord);
+ }
+ }
+ break;
+ }
+ case PATCH_CODE_GETORIGINALBYTEADJUST: {
+ signatureData++; // skip over extra uint16
+ break;
+ }
+ default:
+ break;
+ }
+ signatureData++;
+ curWord = *signatureData;
+ }
+
+ if (magicDWordLeft)
+ error("Script-Patcher: Magic-DWORD beyond End-Of-Signature\nFaulty patch: '%s'", signatureDescription);
+ if (magicDWordIncluded) {
+ if (!calculatedMagicDWord) {
+ error("Script-Patcher: Magic-DWORD not specified in signature\nFaulty patch: '%s'", signatureDescription);
+ }
+ }
+}
+
+// This method calculates the magic DWORD for each entry in the signature table
+// and it also initializes the selector table for selectors used in the signatures/patches of the current game
+void ScriptPatcher::initSignature(const SciScriptPatcherEntry *patchTable) {
+ const SciScriptPatcherEntry *curEntry = patchTable;
+ SciScriptPatcherRuntimeEntry *curRuntimeEntry;
int patchEntryCount = 0;
// Count entries and allocate runtime data
@@ -3425,120 +4549,14 @@ void ScriptPatcher::initSignature(const SciScriptPatcherEntry *patchTable) {
curRuntimeEntry = _runtimeTable;
while (curEntry->signatureData) {
// process signature
- memset(magicDWord, 0, sizeof(magicDWord));
-
curRuntimeEntry->active = curEntry->defaultActive;
curRuntimeEntry->magicDWord = 0;
curRuntimeEntry->magicOffset = 0;
- for (step = 0; step < 2; step++) {
- switch (step) {
- case 0: curData = curEntry->signatureData; break;
- case 1: curData = curEntry->patchData; break;
- }
-
- curWord = *curData;
- magicOffset = 0;
- while (curWord != SIG_END) {
- curCommand = curWord & SIG_COMMANDMASK;
- curValue = curWord & SIG_VALUEMASK;
- switch (curCommand) {
- case SIG_MAGICDWORD: {
- if (step == 0) {
- if ((curRuntimeEntry->magicDWord) || (magicDWordLeft))
- error("Script-Patcher: Magic-DWORD specified multiple times in signature\nFaulty patch: '%s'", curEntry->description);
- magicDWordLeft = 4;
- curRuntimeEntry->magicOffset = magicOffset;
- }
- break;
- }
- case SIG_CODE_ADDTOOFFSET: {
- magicOffset -= curValue;
- if (magicDWordLeft)
- error("Script-Patcher: Magic-DWORD contains AddToOffset command\nFaulty patch: '%s'", curEntry->description);
- break;
- }
- case SIG_CODE_UINT16:
- case SIG_CODE_SELECTOR16: {
- // UINT16 or 1
- switch (curCommand) {
- case SIG_CODE_UINT16: {
- curData++; curWord = *curData;
- if (curWord & SIG_COMMANDMASK)
- error("Script-Patcher: signature entry inconsistent\nFaulty patch: '%s'", curEntry->description);
- if (!_isMacSci11) {
- byte1 = curValue;
- byte2 = curWord & SIG_BYTEMASK;
- } else {
- byte1 = curWord & SIG_BYTEMASK;
- byte2 = curValue;
- }
- break;
- }
- case SIG_CODE_SELECTOR16: {
- curSelector = _selectorIdTable[curValue];
- if (curSelector == -1) {
- curSelector = g_sci->getKernel()->findSelector(selectorNameTable[curValue]);
- _selectorIdTable[curValue] = curSelector;
- }
- if (!_isMacSci11) {
- byte1 = curSelector & 0x00FF;
- byte2 = curSelector >> 8;
- } else {
- byte1 = curSelector >> 8;
- byte2 = curSelector & 0x00FF;
- }
- break;
- }
- }
- magicOffset -= 2;
- if (magicDWordLeft) {
- // Remember current word for Magic DWORD
- magicDWord[4 - magicDWordLeft] = byte1;
- magicDWordLeft--;
- if (magicDWordLeft) {
- magicDWord[4 - magicDWordLeft] = byte2;
- magicDWordLeft--;
- }
- if (!magicDWordLeft) {
- curRuntimeEntry->magicDWord = READ_LE_UINT32(magicDWord);
- }
- }
- break;
- }
- case SIG_CODE_BYTE:
- case SIG_CODE_SELECTOR8: {
- if (curCommand == SIG_CODE_SELECTOR8) {
- curSelector = _selectorIdTable[curValue];
- if (curSelector == -1) {
- curSelector = g_sci->getKernel()->findSelector(selectorNameTable[curValue]);
- _selectorIdTable[curValue] = curSelector;
- if (curSelector != -1) {
- if (curSelector & 0xFF00)
- error("Script-Patcher: 8 bit selector required, game uses 16 bit selector\nFaulty patch: '%s'", curEntry->description);
- }
- }
- curValue = curSelector;
- }
- magicOffset--;
- if (magicDWordLeft) {
- // Remember current byte for Magic DWORD
- magicDWord[4 - magicDWordLeft] = (byte)curValue;
- magicDWordLeft--;
- if (!magicDWordLeft) {
- curRuntimeEntry->magicDWord = READ_LE_UINT32(magicDWord);
- }
- }
- }
- }
- curData++;
- curWord = *curData;
- }
- }
- if (magicDWordLeft)
- error("Script-Patcher: Magic-DWORD beyond End-Of-Signature\nFaulty patch: '%s'", curEntry->description);
- if (!curRuntimeEntry->magicDWord)
- error("Script-Patcher: Magic-DWORD not specified in signature\nFaulty patch: '%s'", curEntry->description);
+ // We verify the signature data and remember the calculated magic DWord from the signature data
+ calculateMagicDWordAndVerify(curEntry->description, curEntry->signatureData, true, curRuntimeEntry->magicDWord, curRuntimeEntry->magicOffset);
+ // We verify the patch data
+ calculateMagicDWordAndVerify(curEntry->description, curEntry->patchData, false, curRuntimeEntry->magicDWord, curRuntimeEntry->magicOffset);
curEntry++; curRuntimeEntry++;
}
@@ -3596,6 +4614,12 @@ 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;
case GID_LAURABOW2:
signatureTable = laurabow2Signatures;
break;
diff --git a/engines/sci/engine/script_patches.h b/engines/sci/engine/script_patches.h
index d15fce321b..645e0946b3 100644
--- a/engines/sci/engine/script_patches.h
+++ b/engines/sci/engine/script_patches.h
@@ -90,13 +90,32 @@ public:
ScriptPatcher();
~ScriptPatcher();
+ // Calculates the magic DWord for fast search and verifies signature/patch data
+ // Returns the magic DWord in platform-specific byte-order. This is done on purpose for performance.
+ void calculateMagicDWordAndVerify(const char *signatureDescription, const uint16 *signatureData, bool magicDWordIncluded, uint32 &calculatedMagicDWord, int &calculatedMagicDWordOffset);
+
+ // Called when a script is loaded to check for signature matches and apply patches in such cases
void processScript(uint16 scriptNr, byte *scriptData, const uint32 scriptSize);
+
+ // Verifies, if a given signature matches the given script data (pointed to by additional byte offset)
bool verifySignature(uint32 byteOffset, const uint16 *signatureData, const char *signatureDescription, const byte *scriptData, const uint32 scriptSize);
+ // searches for a given signature inside script data
+ // returns -1 in case it was not found or an offset to the matching data
+ int32 findSignature(uint32 magicDWord, int magicOffset, const uint16 *signatureData, const char *patchDescription, const byte *scriptData, const uint32 scriptSize);
+
private:
+ // Initializes a patch table and creates run time information for it (for enabling/disabling), also calculates magic DWORD)
void initSignature(const SciScriptPatcherEntry *patchTable);
+
+ // Enables a patch inside the patch table (used for optional patches like CD+Text support for KQ6 & LB2)
void enablePatch(const SciScriptPatcherEntry *patchTable, const char *searchDescription);
- int32 findSignature(const SciScriptPatcherEntry *patchEntry, SciScriptPatcherRuntimeEntry *runtimeEntry, const byte *scriptData, const uint32 scriptSize);
+
+ // Searches for a given signature entry inside script data
+ // returns -1 in case it was not found or an offset to the matching data
+ int32 findSignature(const SciScriptPatcherEntry *patchEntry, const SciScriptPatcherRuntimeEntry *runtimeEntry, const byte *scriptData, const uint32 scriptSize);
+
+ // Applies a patch to a given script + offset (overwrites parts)
void applyPatch(const SciScriptPatcherEntry *patchEntry, byte *scriptData, const uint32 scriptSize, int32 signatureOffset);
Selector *_selectorIdTable;
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 58c2b8d3e3..95e3cd15f9 100644
--- a/engines/sci/engine/seg_manager.cpp
+++ b/engines/sci/engine/seg_manager.cpp
@@ -144,11 +144,21 @@ Script *SegManager::allocateScript(int script_nr, SegmentId *segid) {
return (Script *)mem;
}
+SegmentId SegManager::getActualSegment(SegmentId seg) const {
+ if (getSciVersion() <= SCI_VERSION_2_1_LATE) {
+ return seg;
+ } else {
+ // Return the lower 14 bits of the segment
+ return (seg & 0x3FFF);
+ }
+}
+
void SegManager::deallocate(SegmentId seg) {
- if (seg < 1 || (uint)seg >= _heap.size())
+ SegmentId actualSegment = getActualSegment(seg);
+ if (actualSegment < 1 || (uint)actualSegment >= _heap.size())
error("Attempt to deallocate an invalid segment ID");
- SegmentObj *mobj = _heap[seg];
+ SegmentObj *mobj = _heap[actualSegment];
if (!mobj)
error("Attempt to deallocate an already freed segment");
@@ -169,7 +179,7 @@ void SegManager::deallocate(SegmentId seg) {
}
delete mobj;
- _heap[seg] = NULL;
+ _heap[actualSegment] = NULL;
}
bool SegManager::isHeapObject(reg_t pos) const {
@@ -185,22 +195,24 @@ void SegManager::deallocateScript(int script_nr) {
}
Script *SegManager::getScript(const SegmentId seg) {
- if (seg < 1 || (uint)seg >= _heap.size()) {
- error("SegManager::getScript(): seg id %x out of bounds", seg);
+ SegmentId actualSegment = getActualSegment(seg);
+ if (actualSegment < 1 || (uint)actualSegment >= _heap.size()) {
+ error("SegManager::getScript(): seg id %x out of bounds", actualSegment);
}
- if (!_heap[seg]) {
- error("SegManager::getScript(): seg id %x is not in memory", seg);
+ if (!_heap[actualSegment]) {
+ error("SegManager::getScript(): seg id %x is not in memory", actualSegment);
}
- if (_heap[seg]->getType() != SEG_TYPE_SCRIPT) {
- error("SegManager::getScript(): seg id %x refers to type %d != SEG_TYPE_SCRIPT", seg, _heap[seg]->getType());
+ if (_heap[actualSegment]->getType() != SEG_TYPE_SCRIPT) {
+ error("SegManager::getScript(): seg id %x refers to type %d != SEG_TYPE_SCRIPT", actualSegment, _heap[actualSegment]->getType());
}
- return (Script *)_heap[seg];
+ return (Script *)_heap[actualSegment];
}
Script *SegManager::getScriptIfLoaded(const SegmentId seg) const {
- if (seg < 1 || (uint)seg >= _heap.size() || !_heap[seg] || _heap[seg]->getType() != SEG_TYPE_SCRIPT)
+ SegmentId actualSegment = getActualSegment(seg);
+ if (actualSegment < 1 || (uint)actualSegment >= _heap.size() || !_heap[actualSegment] || _heap[actualSegment]->getType() != SEG_TYPE_SCRIPT)
return 0;
- return (Script *)_heap[seg];
+ return (Script *)_heap[actualSegment];
}
SegmentId SegManager::findSegmentByType(int type) const {
@@ -211,19 +223,22 @@ SegmentId SegManager::findSegmentByType(int type) const {
}
SegmentObj *SegManager::getSegmentObj(SegmentId seg) const {
- if (seg < 1 || (uint)seg >= _heap.size() || !_heap[seg])
+ SegmentId actualSegment = getActualSegment(seg);
+ if (actualSegment < 1 || (uint)actualSegment >= _heap.size() || !_heap[actualSegment])
return 0;
- return _heap[seg];
+ return _heap[actualSegment];
}
SegmentType SegManager::getSegmentType(SegmentId seg) const {
- if (seg < 1 || (uint)seg >= _heap.size() || !_heap[seg])
+ SegmentId actualSegment = getActualSegment(seg);
+ if (actualSegment < 1 || (uint)actualSegment >= _heap.size() || !_heap[actualSegment])
return SEG_TYPE_INVALID;
- return _heap[seg]->getType();
+ return _heap[actualSegment]->getType();
}
SegmentObj *SegManager::getSegment(SegmentId seg, SegmentType type) const {
- return getSegmentType(seg) == type ? _heap[seg] : NULL;
+ SegmentId actualSegment = getActualSegment(seg);
+ return getSegmentType(actualSegment) == type ? _heap[actualSegment] : NULL;
}
Object *SegManager::getObject(reg_t pos) const {
@@ -232,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) {
@@ -298,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;
@@ -389,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;
@@ -409,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) {
@@ -424,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) {
@@ -438,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) {
@@ -452,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) {
@@ -471,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) {
@@ -492,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;
@@ -502,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) {
@@ -822,10 +837,13 @@ byte *SegManager::allocDynmem(int size, const char *descr, reg_t *addr) {
d._size = size;
- if (size == 0)
+ // Original SCI only zeroed out heap memory on initialize
+ // They didn't do it again for every allocation
+ if (size) {
+ d._buf = (byte *)calloc(size, 1);
+ } else {
d._buf = NULL;
- else
- d._buf = (byte *)malloc(size);
+ }
d._description = descr;
@@ -855,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) {
@@ -895,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/seg_manager.h b/engines/sci/engine/seg_manager.h
index 2d6e624f6f..9da7e58770 100644
--- a/engines/sci/engine/seg_manager.h
+++ b/engines/sci/engine/seg_manager.h
@@ -472,6 +472,18 @@ private:
void createClassTable();
SegmentId findFreeSegment() const;
+
+ /**
+ * This implements our handling of scripts greater than 64K in size.
+ * They occur sporadically in SCI3 games (and in The Realm (SCI2.1),
+ * if we ever decide to support it). It works by "stealing" the upper
+ * two bits of the segment value to use as extra offset bits, making
+ * the maximum offset 0x3FFFF (262143). This is enough.
+ *
+ * The "actual" segment, then, is the segment value with the upper two
+ * bits masked out.
+ */
+ SegmentId getActualSegment(SegmentId seg) const;
};
} // End of namespace Sci
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 910f1f885f..ac621f58ae 100644
--- a/engines/sci/engine/selector.cpp
+++ b/engines/sci/engine/selector.cpp
@@ -179,6 +179,8 @@ void Kernel::mapSelectors() {
FIND_SELECTOR(fore);
FIND_SELECTOR(back);
FIND_SELECTOR(skip);
+ FIND_SELECTOR(borderColor);
+ FIND_SELECTOR(width);
FIND_SELECTOR(fixPriority);
FIND_SELECTOR(mirrored);
FIND_SELECTOR(visible);
@@ -187,6 +189,17 @@ void Kernel::mapSelectors() {
FIND_SELECTOR(inLeft);
FIND_SELECTOR(inBottom);
FIND_SELECTOR(inRight);
+ FIND_SELECTOR(textTop);
+ 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
}
@@ -199,6 +212,16 @@ reg_t readSelector(SegManager *segMan, reg_t object, Selector selectorId) {
return *address.getPointer(segMan);
}
+#ifdef ENABLE_SCI32
+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 (index >= 26 && index <= 44 && getSciVersion() >= SCI_VERSION_2) {
+ obj->setInfoSelectorFlag(kInfoFlagViewVisible);
+ }
+}
+#endif
+
void writeSelector(SegManager *segMan, reg_t object, Selector selectorId, reg_t value) {
ObjVarRef address;
@@ -211,8 +234,12 @@ void writeSelector(SegManager *segMan, reg_t object, Selector selectorId, reg_t
if (lookupSelector(segMan, object, selectorId, &address, NULL) != kSelectorVariable)
error("Selector '%s' of object at %04x:%04x could not be"
" written to", g_sci->getKernel()->getSelectorName(selectorId).c_str(), PRINT_REG(object));
- else
+ else {
*address.getPointer(segMan) = value;
+#ifdef ENABLE_SCI32
+ updateInfoFlagViewVisible(segMan->getObject(object), selectorId);
+#endif
+ }
}
void invokeSelector(EngineState *s, reg_t object, int selectorId,
diff --git a/engines/sci/engine/selector.h b/engines/sci/engine/selector.h
index b3dd393708..f2d06d1cf4 100644
--- a/engines/sci/engine/selector.h
+++ b/engines/sci/engine/selector.h
@@ -146,6 +146,8 @@ struct SelectorCache {
Selector back;
Selector skip;
Selector dimmed;
+ Selector borderColor;
+ Selector width;
Selector fixPriority;
Selector mirrored;
@@ -153,6 +155,12 @@ 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
};
@@ -191,6 +199,16 @@ void writeSelector(SegManager *segMan, reg_t object, Selector selectorId, reg_t
void invokeSelector(EngineState *s, reg_t object, int selectorId,
int k_argc, StackPtr k_argp, int argc = 0, const reg_t *argv = 0);
+#ifdef ENABLE_SCI32
+/**
+ * SCI32 set kInfoFlagViewVisible in the -info- selector if a certain
+ * range of properties was written to.
+ * 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 index);
+#endif
+
} // End of namespace Sci
#endif // SCI_ENGINE_KERNEL_H
diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp
index 417d98e2e2..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;
@@ -129,8 +124,6 @@ void EngineState::reset(bool isRestoring) {
_vmdPalStart = 0;
_vmdPalEnd = 256;
-
- _palCycleToColor = 255;
}
void EngineState::speedThrottler(uint32 neededSleep) {
diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h
index e7499e66c9..dd8d76f002 100644
--- a/engines/sci/engine/state.h
+++ b/engines/sci/engine/state.h
@@ -57,6 +57,10 @@ enum AbortGameState {
kAbortQuitGame = 3
};
+// slot 0 is the ScummVM auto-save slot, which is not used by us, but is still reserved
+#define SAVEGAMESLOT_FIRST 1
+#define SAVEGAMESLOT_LAST 99
+
// We assume that scripts give us savegameId 0->99 for creating a new save slot
// and savegameId 100->199 for existing save slots. Refer to kfile.cpp
enum {
@@ -127,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;
@@ -199,12 +201,11 @@ public:
uint16 _memorySegmentSize;
byte _memorySegment[kMemorySegmentMax];
+ // TODO: Excise video code from the state manager
VideoState _videoState;
uint16 _vmdPalStart, _vmdPalEnd;
bool _syncedAudioOptions;
- uint16 _palCycleToColor;
-
/**
* Resets the engine state.
*/
diff --git a/engines/sci/engine/static_selectors.cpp b/engines/sci/engine/static_selectors.cpp
index 188da3d5a2..8aa1697f07 100644
--- a/engines/sci/engine/static_selectors.cpp
+++ b/engines/sci/engine/static_selectors.cpp
@@ -114,16 +114,16 @@ static const SelectorRemap sciSelectorRemap[] = {
{ SCI_VERSION_1_1, SCI_VERSION_1_1, "cantBeHere", 54 },
// The following are not really needed. They've only been defined to
// ease game debugging.
- { SCI_VERSION_1_1, SCI_VERSION_2_1, "-objID-", 4096 },
- { SCI_VERSION_1_1, SCI_VERSION_2_1, "-size-", 4097 },
- { SCI_VERSION_1_1, SCI_VERSION_2_1, "-propDict-", 4098 },
- { SCI_VERSION_1_1, SCI_VERSION_2_1, "-methDict-", 4099 },
- { SCI_VERSION_1_1, SCI_VERSION_2_1, "-classScript-", 4100 },
- { SCI_VERSION_1_1, SCI_VERSION_2_1, "-script-", 4101 },
- { SCI_VERSION_1_1, SCI_VERSION_2_1, "-super-", 4102 },
+ { SCI_VERSION_1_1, SCI_VERSION_2_1_LATE, "-objID-", 4096 },
+ { SCI_VERSION_1_1, SCI_VERSION_2_1_LATE, "-size-", 4097 },
+ { SCI_VERSION_1_1, SCI_VERSION_2_1_LATE, "-propDict-", 4098 },
+ { SCI_VERSION_1_1, SCI_VERSION_2_1_LATE, "-methDict-", 4099 },
+ { SCI_VERSION_1_1, SCI_VERSION_2_1_LATE, "-classScript-", 4100 },
+ { SCI_VERSION_1_1, SCI_VERSION_2_1_LATE, "-script-", 4101 },
+ { SCI_VERSION_1_1, SCI_VERSION_2_1_LATE, "-super-", 4102 },
//
- { SCI_VERSION_1_1, SCI_VERSION_2_1, "-info-", 4103 },
- { SCI_VERSION_NONE, SCI_VERSION_NONE, 0, 0 }
+ { SCI_VERSION_1_1, SCI_VERSION_2_1_LATE, "-info-", 4103 },
+ { SCI_VERSION_NONE, SCI_VERSION_NONE, 0, 0 }
};
struct ClassReference {
diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp
index 6f02c96de8..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());
@@ -258,6 +259,10 @@ static void _exec_varselectors(EngineState *s) {
if (xs.argc) { // write?
*var = xs.variables_argp[1];
+#ifdef ENABLE_SCI32
+ updateInfoFlagViewVisible(s->_segMan->getObject(xs.addr.varp.obj), xs.addr.varp.varindex);
+#endif
+
} else // No, read
s->r_acc = *var;
}
@@ -308,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)
@@ -331,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);
}
@@ -382,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)
@@ -440,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)
@@ -830,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);
@@ -974,21 +983,24 @@ void run_vm(EngineState *s) {
break;
- case 0x26: // (38)
- case 0x27: // (39)
- if (getSciVersion() == SCI_VERSION_3) {
- if (extOpcode == 0x4c)
- s->r_acc = obj->getInfoSelector();
- else if (extOpcode == 0x4d)
- PUSH32(obj->getInfoSelector());
- else if (extOpcode == 0x4e)
- s->r_acc = obj->getSuperClassSelector(); // TODO: is this correct?
- // TODO: There are also opcodes in
- // here to get the superclass, and possibly the species too.
- else
- error("Dummy opcode 0x%x called", opcode); // should never happen
- } else
+ case op_infoToa: // (38)
+ if (getSciVersion() < SCI_VERSION_3)
+ error("Dummy opcode 0x%x called", opcode); // should never happen
+
+ if (!(extOpcode & 1))
+ s->r_acc = obj->getInfoSelector();
+ else
+ PUSH32(obj->getInfoSelector());
+ break;
+
+ case op_superToa: // (39)
+ if (getSciVersion() < SCI_VERSION_3)
error("Dummy opcode 0x%x called", opcode); // should never happen
+
+ if (!(extOpcode & 1))
+ s->r_acc = obj->getSuperClassSelector();
+ else
+ PUSH32(obj->getSuperClassSelector());
break;
case op_class: // 0x28 (40)
@@ -1092,6 +1104,9 @@ void run_vm(EngineState *s) {
case op_aTop: // 0x32 (50)
// Accumulator To Property
validate_property(s, obj, opparams[0]) = s->r_acc;
+#ifdef ENABLE_SCI32
+ updateInfoFlagViewVisible(obj, opparams[0]>>1);
+#endif
break;
case op_pTos: // 0x33 (51)
@@ -1102,6 +1117,9 @@ void run_vm(EngineState *s) {
case op_sTop: // 0x34 (52)
// Stack To Property
validate_property(s, obj, opparams[0]) = POP32();
+#ifdef ENABLE_SCI32
+ updateInfoFlagViewVisible(obj, opparams[0]>>1);
+#endif
break;
case op_ipToa: // 0x35 (53)
@@ -1116,7 +1134,9 @@ void run_vm(EngineState *s) {
opProperty += 1;
else
opProperty -= 1;
-
+#ifdef ENABLE_SCI32
+ updateInfoFlagViewVisible(obj, opparams[0]>>1);
+#endif
if (opcode == op_ipToa || opcode == op_dpToa)
s->r_acc = opProperty;
else
diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h
index cf65803929..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_;
@@ -176,8 +180,8 @@ enum SciOpcodes {
op_calle = 0x23, // 035
op_ret = 0x24, // 036
op_send = 0x25, // 037
- // dummy 0x26, // 038
- // dummy 0x27, // 039
+ op_infoToa = 0x26, // 038
+ op_superToa = 0x27, // 039
op_class = 0x28, // 040
// dummy 0x29, // 041
op_self = 0x2a, // 042
diff --git a/engines/sci/engine/vm_types.cpp b/engines/sci/engine/vm_types.cpp
index 65a82832cc..d74e2b194c 100644
--- a/engines/sci/engine/vm_types.cpp
+++ b/engines/sci/engine/vm_types.cpp
@@ -29,7 +29,7 @@
namespace Sci {
SegmentId reg_t::getSegment() const {
- if (getSciVersion() <= SCI_VERSION_2_1) {
+ if (getSciVersion() < SCI_VERSION_3) {
return _segment;
} else {
// Return the lower 14 bits of the segment
@@ -38,7 +38,7 @@ SegmentId reg_t::getSegment() const {
}
void reg_t::setSegment(SegmentId segment) {
- if (getSciVersion() <= SCI_VERSION_2_1) {
+ if (getSciVersion() < SCI_VERSION_3) {
_segment = segment;
} else {
// Set the lower 14 bits of the segment, and preserve the upper 2 ones for the offset
@@ -47,7 +47,7 @@ void reg_t::setSegment(SegmentId segment) {
}
uint32 reg_t::getOffset() const {
- if (getSciVersion() <= SCI_VERSION_2_1) {
+ if (getSciVersion() < SCI_VERSION_3) {
return _offset;
} else {
// Return the lower 16 bits from the offset, and the 17th and 18th bits from the segment
@@ -56,7 +56,7 @@ uint32 reg_t::getOffset() const {
}
void reg_t::setOffset(uint32 offset) {
- if (getSciVersion() <= SCI_VERSION_2_1) {
+ if (getSciVersion() < SCI_VERSION_3) {
_offset = offset;
} else {
// Store the lower 16 bits in the offset, and the 17th and 18th bits in the segment
@@ -210,12 +210,30 @@ reg_t reg_t::operator^(const reg_t right) const {
return lookForWorkaround(right, "bitwise XOR");
}
+#ifdef ENABLE_SCI32
+reg_t reg_t::operator&(int16 right) const {
+ return *this & make_reg(0, right);
+}
+
+reg_t reg_t::operator|(int16 right) const {
+ return *this | make_reg(0, right);
+}
+
+reg_t reg_t::operator^(int16 right) const {
+ return *this ^ make_reg(0, right);
+}
+#endif
+
int reg_t::cmp(const reg_t right, bool treatAsUnsigned) const {
if (getSegment() == right.getSegment()) { // can compare things in the same segment
if (treatAsUnsigned || !isNumber())
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)) {
@@ -224,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 af78bd0b84..e60f52e85c 100644
--- a/engines/sci/engine/vm_types.h
+++ b/engines/sci/engine/vm_types.h
@@ -136,6 +136,19 @@ struct reg_t {
reg_t operator|(const reg_t right) const;
reg_t operator^(const reg_t right) const;
+#ifdef ENABLE_SCI32
+ reg_t operator&(int16 right) const;
+ reg_t operator|(int16 right) const;
+ reg_t operator^(int16 right) const;
+
+ void operator&=(const reg_t &right) { *this = *this & right; }
+ void operator|=(const reg_t &right) { *this = *this | right; }
+ void operator^=(const reg_t &right) { *this = *this ^ right; }
+ void operator&=(int16 right) { *this = *this & right; }
+ void operator|=(int16 right) { *this = *this | right; }
+ void operator^=(int16 right) { *this = *this ^ right; }
+#endif
+
private:
/**
* Compares two reg_t's.
@@ -147,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 b1c002413d..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 {
@@ -38,13 +41,13 @@ struct ScancodeRow {
const char *keys;
};
-const ScancodeRow s_scancodeRows[] = {
+static const ScancodeRow scancodeAltifyRows[] = {
{ 0x10, "QWERTYUIOP[]" },
{ 0x1e, "ASDFGHJKL;'\\" },
{ 0x2c, "ZXCVBNM,./" }
};
-const byte codepagemap_88591toDOS[0x80] = {
+static const byte codePageMap88591ToDOS[0x80] = {
'?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', // 0x8x
'?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', // 0x9x
'?', 0xad, 0x9b, 0x9c, '?', 0x9d, '?', 0x9e, '?', '?', 0xa6, 0xae, 0xaa, '?', '?', '?', // 0xAx
@@ -61,7 +64,7 @@ struct SciKeyConversion {
int sciKeyNumlockOn;
};
-const SciKeyConversion keyMappings[] = {
+static const SciKeyConversion keyMappings[] = {
{ Common::KEYCODE_UP , SCI_KEY_UP , SCI_KEY_UP },
{ Common::KEYCODE_DOWN , SCI_KEY_DOWN , SCI_KEY_DOWN },
{ Common::KEYCODE_RIGHT , SCI_KEY_RIGHT , SCI_KEY_RIGHT },
@@ -94,16 +97,15 @@ const SciKeyConversion keyMappings[] = {
struct MouseEventConversion {
Common::EventType commonType;
short sciType;
- short data;
};
-const MouseEventConversion mouseEventMappings[] = {
- { Common::EVENT_LBUTTONDOWN, SCI_EVENT_MOUSE_PRESS, 1 },
- { Common::EVENT_RBUTTONDOWN, SCI_EVENT_MOUSE_PRESS, 2 },
- { Common::EVENT_MBUTTONDOWN, SCI_EVENT_MOUSE_PRESS, 3 },
- { Common::EVENT_LBUTTONUP, SCI_EVENT_MOUSE_RELEASE, 1 },
- { Common::EVENT_RBUTTONUP, SCI_EVENT_MOUSE_RELEASE, 2 },
- { Common::EVENT_MBUTTONUP, SCI_EVENT_MOUSE_RELEASE, 3 }
+static const MouseEventConversion mouseEventMappings[] = {
+ { Common::EVENT_LBUTTONDOWN, SCI_EVENT_MOUSE_PRESS },
+ { Common::EVENT_RBUTTONDOWN, SCI_EVENT_MOUSE_PRESS },
+ { Common::EVENT_MBUTTONDOWN, SCI_EVENT_MOUSE_PRESS },
+ { Common::EVENT_LBUTTONUP, SCI_EVENT_MOUSE_RELEASE },
+ { Common::EVENT_RBUTTONUP, SCI_EVENT_MOUSE_RELEASE },
+ { Common::EVENT_MBUTTONUP, SCI_EVENT_MOUSE_RELEASE }
};
EventManager::EventManager(bool fontIsExtended) : _fontIsExtended(fontIsExtended) {
@@ -117,9 +119,9 @@ static int altify(int ch) {
int row;
int c = toupper((char)ch);
- for (row = 0; row < ARRAYSIZE(s_scancodeRows); row++) {
- const char *keys = s_scancodeRows[row].keys;
- int offset = s_scancodeRows[row].offset;
+ for (row = 0; row < ARRAYSIZE(scancodeAltifyRows); row++) {
+ const char *keys = scancodeAltifyRows[row].keys;
+ int offset = scancodeAltifyRows[row].offset;
while (*keys) {
if (*keys == c)
@@ -134,8 +136,13 @@ static int altify(int ch) {
}
SciEvent EventManager::getScummVMEvent() {
- SciEvent input = { SCI_EVENT_NONE, 0, 0, 0, Common::Point(0, 0) };
- SciEvent noEvent = { SCI_EVENT_NONE, 0, 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;
@@ -156,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;
@@ -174,11 +194,50 @@ SciEvent EventManager::getScummVMEvent() {
return input;
}
+ int scummVMKeyFlags;
+
+ switch (ev.type) {
+ case Common::EVENT_KEYDOWN:
+ case Common::EVENT_KEYUP:
+ // Use keyboard modifiers directly in case this is a keyboard event
+ scummVMKeyFlags = ev.kbd.flags;
+ break;
+ default:
+ // Otherwise get them from EventManager
+ scummVMKeyFlags = em->getModifierState();
+ break;
+ }
+
+ input.modifiers =
+ ((scummVMKeyFlags & Common::KBD_ALT) ? SCI_KEYMOD_ALT : 0) |
+ ((scummVMKeyFlags & Common::KBD_CTRL) ? SCI_KEYMOD_CTRL : 0) |
+ ((scummVMKeyFlags & Common::KBD_SHIFT) ? SCI_KEYMOD_LSHIFT | SCI_KEYMOD_RSHIFT : 0);
+ // Caps lock and Scroll lock have been removed, cause we already handle upper
+ // case keys and Scroll lock doesn't seem to be used anywhere
+ //((ourModifiers & Common::KBD_CAPS) ? SCI_KEYMOD_CAPSLOCK : 0) |
+ //((ourModifiers & Common::KBD_SCRL) ? SCI_KEYMOD_SCRLOCK : 0) |
+
// Handle mouse events
for (int i = 0; i < ARRAYSIZE(mouseEventMappings); i++) {
if (mouseEventMappings[i].commonType == ev.type) {
input.type = mouseEventMappings[i].sciType;
- input.data = mouseEventMappings[i].data;
+ // Sierra passed keyboard modifiers for mouse events, too.
+
+ // Sierra also set certain modifiers within their mouse interrupt handler
+ // This whole thing was probably meant for people using a mouse, that only featured 1 button
+ // So the user was able to press Ctrl and click the mouse button to create a right click.
+ switch (ev.type) {
+ case Common::EVENT_RBUTTONDOWN: // right button
+ case Common::EVENT_RBUTTONUP:
+ input.modifiers |= (SCI_KEYMOD_RSHIFT | SCI_KEYMOD_LSHIFT); // this value was hardcoded in the mouse interrupt handler
+ break;
+ case Common::EVENT_MBUTTONDOWN: // middle button
+ case Common::EVENT_MBUTTONUP:
+ input.modifiers |= SCI_KEYMOD_CTRL; // this value was hardcoded in the mouse interrupt handler
+ break;
+ default:
+ break;
+ }
return input;
}
}
@@ -187,7 +246,7 @@ SciEvent EventManager::getScummVMEvent() {
if (ev.type != Common::EVENT_KEYDOWN)
return noEvent;
- // Check for Control-D (debug console)
+ // Check for Control-Shift-D (debug console)
if (ev.kbd.hasFlags(Common::KBD_CTRL | Common::KBD_SHIFT) && ev.kbd.keycode == Common::KEYCODE_d) {
// Open debug console
Console *con = g_sci->getSciDebugger();
@@ -197,24 +256,23 @@ SciEvent EventManager::getScummVMEvent() {
// Process keyboard events
- int modifiers = em->getModifierState();
bool numlockOn = (ev.kbd.flags & Common::KBD_NUM);
- input.data = ev.kbd.keycode;
+ Common::KeyCode scummVMKeycode = ev.kbd.keycode;
+
input.character = ev.kbd.ascii;
input.type = SCI_EVENT_KEYBOARD;
- input.modifiers =
- ((modifiers & Common::KBD_ALT) ? SCI_KEYMOD_ALT : 0) |
- ((modifiers & Common::KBD_CTRL) ? SCI_KEYMOD_CTRL : 0) |
- ((modifiers & Common::KBD_SHIFT) ? SCI_KEYMOD_LSHIFT | SCI_KEYMOD_RSHIFT : 0);
-
- // Caps lock and Scroll lock have been removed, cause we already handle upper
- // case keys ad Scroll lock doesn't seem to be used anywhere
- //((ev.kbd.flags & Common::KBD_CAPS) ? SCI_KEYMOD_CAPSLOCK : 0) |
- //((ev.kbd.flags & Common::KBD_SCRL) ? SCI_KEYMOD_SCRLOCK : 0) |
+ if (scummVMKeycode >= Common::KEYCODE_KP0 && scummVMKeycode <= Common::KEYCODE_KP9) {
+ if (!(scummVMKeyFlags & Common::KBD_NUM)) {
+ // HACK: Num-Lock not enabled
+ // We shouldn't get a valid ascii code in these cases. We fix it here, so that cursor keys
+ // on the numpad work properly.
+ input.character = 0;
+ }
+ }
- if (!(input.data & 0xFF00)) {
+ if ((input.character) && (input.character <= 0xFF)) {
// Directly accept most common keys without conversion
if ((input.character >= 0x80) && (input.character <= 0xFF)) {
// If there is no extended font, we will just clear the
@@ -228,26 +286,27 @@ SciEvent EventManager::getScummVMEvent() {
return noEvent;
// Convert 8859-1 characters to DOS (cp850/437) for
// multilingual SCI01 games
- input.character = codepagemap_88591toDOS[input.character & 0x7f];
+ input.character = codePageMap88591ToDOS[input.character & 0x7f];
}
- if (input.data == Common::KEYCODE_TAB) {
- input.character = input.data = SCI_KEY_TAB;
- if (modifiers & Common::KBD_SHIFT)
+ if (scummVMKeycode == Common::KEYCODE_TAB) {
+ input.character = SCI_KEY_TAB;
+ if (scummVMKeyFlags & Common::KBD_SHIFT)
input.character = SCI_KEY_SHIFT_TAB;
}
- if (input.data == Common::KEYCODE_DELETE)
- input.data = input.character = SCI_KEY_DELETE;
- } else if ((input.data >= Common::KEYCODE_F1) && input.data <= Common::KEYCODE_F10) {
+ if (scummVMKeycode == Common::KEYCODE_DELETE)
+ input.character = SCI_KEY_DELETE;
+ } else if ((scummVMKeycode >= Common::KEYCODE_F1) && scummVMKeycode <= Common::KEYCODE_F10) {
// SCI_K_F1 == 59 << 8
// SCI_K_SHIFT_F1 == 84 << 8
- input.character = input.data = SCI_KEY_F1 + ((input.data - Common::KEYCODE_F1)<<8);
- if (modifiers & Common::KBD_SHIFT)
- input.character = input.data + 0x1900;
+ if (!(scummVMKeyFlags & Common::KBD_SHIFT))
+ input.character = SCI_KEY_F1 + ((scummVMKeycode - Common::KEYCODE_F1)<<8);
+ else
+ input.character = SCI_KEY_SHIFT_F1 + ((scummVMKeycode - Common::KEYCODE_F1)<<8);
} else {
// Special keys that need conversion
for (int i = 0; i < ARRAYSIZE(keyMappings); i++) {
- if (keyMappings[i].scummVMKey == ev.kbd.keycode) {
- input.character = input.data = numlockOn ? keyMappings[i].sciKeyNumlockOn : keyMappings[i].sciKeyNumlockOff;
+ if (keyMappings[i].scummVMKey == scummVMKeycode) {
+ input.character = numlockOn ? keyMappings[i].sciKeyNumlockOn : keyMappings[i].sciKeyNumlockOff;
break;
}
}
@@ -256,14 +315,19 @@ SciEvent EventManager::getScummVMEvent() {
// When Ctrl AND Alt are pressed together with a regular key, Linux will give us control-key, Windows will give
// us the actual key. My opinion is that windows is right, because under DOS the keys worked the same, anyway
// we support the other case as well
- if ((modifiers & Common::KBD_ALT) && input.character > 0 && input.character < 27)
+ if ((scummVMKeyFlags & Common::KBD_ALT) && input.character > 0 && input.character < 27)
input.character += 96; // 0x01 -> 'a'
// Scancodify if appropriate
- if (modifiers & Common::KBD_ALT)
+ if (scummVMKeyFlags & Common::KBD_ALT)
input.character = altify(input.character);
- if (getSciVersion() <= SCI_VERSION_1_MIDDLE && (modifiers & Common::KBD_CTRL) && input.character > 0 && input.character < 27)
+ 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
@@ -290,8 +354,12 @@ void EventManager::updateScreen() {
}
}
-SciEvent EventManager::getSciEvent(unsigned int mask) {
- SciEvent event = { 0, 0, 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();
@@ -304,7 +372,7 @@ SciEvent EventManager::getSciEvent(unsigned int mask) {
// Search for matching event in queue
Common::List<SciEvent>::iterator iter = _events.begin();
- while (iter != _events.end() && !((*iter).type & mask))
+ while (iter != _events.end() && !(iter->type & mask))
++iter;
if (iter != _events.end()) {
@@ -326,17 +394,17 @@ SciEvent EventManager::getSciEvent(unsigned int mask) {
void SciEngine::sleep(uint32 msecs) {
uint32 time;
- const uint32 wakeup_time = g_system->getMillis() + msecs;
+ const uint32 wakeUpTime = g_system->getMillis() + msecs;
while (true) {
// let backend process events and update the screen
_eventMan->getSciEvent(SCI_EVENT_PEEK);
time = g_system->getMillis();
- if (time + 10 < wakeup_time) {
+ if (time + 10 < wakeUpTime) {
g_system->delayMillis(10);
} else {
- if (time < wakeup_time)
- g_system->delayMillis(wakeup_time - time);
+ if (time < wakeUpTime)
+ g_system->delayMillis(wakeUpTime - time);
break;
}
diff --git a/engines/sci/event.h b/engines/sci/event.h
index 82e93a9373..15a94b3e73 100644
--- a/engines/sci/event.h
+++ b/engines/sci/event.h
@@ -29,84 +29,98 @@
namespace Sci {
struct SciEvent {
- short type;
- short data;
- short modifiers;
+ uint16 type;
+ uint16 modifiers;
/**
- * For keyboard events: 'data' after applying
- * the effects of 'modifiers', e.g. if
- * type == SCI_EVT_KEYBOARD
- * data == 'a'
- * buckybits == SCI_EVM_LSHIFT
- * then
- * character == 'A'
+ * For keyboard events: the actual character of the key that was pressed
* For 'Alt', characters are interpreted by their
* PC keyboard scancodes.
*/
- short character;
+ 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*/
#define SCI_EVENT_NONE 0
-#define SCI_EVENT_MOUSE_PRESS (1<<0)
-#define SCI_EVENT_MOUSE_RELEASE (1<<1)
-#define SCI_EVENT_KEYBOARD (1<<2)
-#define SCI_EVENT_DIRECTION (1<<6)
-#define SCI_EVENT_SAID (1<<7)
+#define SCI_EVENT_MOUSE_PRESS (1 << 0)
+#define SCI_EVENT_MOUSE_RELEASE (1 << 1)
+#define SCI_EVENT_KEYBOARD (1 << 2)
+#define SCI_EVENT_DIRECTION (1 << 6)
+#define SCI_EVENT_SAID (1 << 7)
/*Fake values for other events*/
-#define SCI_EVENT_QUIT (1<<11)
-#define SCI_EVENT_PEEK (1<<15)
+#define SCI_EVENT_QUIT (1 << 11)
+#define SCI_EVENT_PEEK (1 << 15)
#define SCI_EVENT_ANY 0x7fff
/* Keycodes of special keys: */
-#define SCI_KEY_ESC 27
-#define SCI_KEY_BACKSPACE 8
-#define SCI_KEY_ENTER 13
-#define SCI_KEY_TAB '\t'
-#define SCI_KEY_SHIFT_TAB (0xf << 8)
-
-#define SCI_KEY_HOME (71 << 8) // 7
-#define SCI_KEY_UP (72 << 8) // 8
-#define SCI_KEY_PGUP (73 << 8) // 9
+#ifdef ENABLE_SCI32
+#define SCI_KEY_ETX 3
+#endif
+#define SCI_KEY_ESC 27
+#define SCI_KEY_BACKSPACE 8
+#define SCI_KEY_ENTER 13
+#define SCI_KEY_TAB '\t'
+#define SCI_KEY_SHIFT_TAB (0xf << 8)
+
+#define SCI_KEY_HOME (71 << 8) // 7
+#define SCI_KEY_UP (72 << 8) // 8
+#define SCI_KEY_PGUP (73 << 8) // 9
//
-#define SCI_KEY_LEFT (75 << 8) // 4
+#define SCI_KEY_LEFT (75 << 8) // 4
#define SCI_KEY_CENTER (76 << 8) // 5
-#define SCI_KEY_RIGHT (77 << 8) // 6
+#define SCI_KEY_RIGHT (77 << 8) // 6
//
-#define SCI_KEY_END (79 << 8) // 1
-#define SCI_KEY_DOWN (80 << 8) // 2
+#define SCI_KEY_END (79 << 8) // 1
+#define SCI_KEY_DOWN (80 << 8) // 2
#define SCI_KEY_PGDOWN (81 << 8) // 3
//
#define SCI_KEY_INSERT (82 << 8) // 0
#define SCI_KEY_DELETE (83 << 8) // .
-#define SCI_KEY_F1 (59<<8)
-#define SCI_KEY_F2 (60<<8)
-#define SCI_KEY_F3 (61<<8)
-#define SCI_KEY_F4 (62<<8)
-#define SCI_KEY_F5 (63<<8)
-#define SCI_KEY_F6 (64<<8)
-#define SCI_KEY_F7 (65<<8)
-#define SCI_KEY_F8 (66<<8)
-#define SCI_KEY_F9 (67<<8)
-#define SCI_KEY_F10 (68<<8)
+#define SCI_KEY_F1 (59 << 8)
+#define SCI_KEY_F2 (60 << 8)
+#define SCI_KEY_F3 (61 << 8)
+#define SCI_KEY_F4 (62 << 8)
+#define SCI_KEY_F5 (63 << 8)
+#define SCI_KEY_F6 (64 << 8)
+#define SCI_KEY_F7 (65 << 8)
+#define SCI_KEY_F8 (66 << 8)
+#define SCI_KEY_F9 (67 << 8)
+#define SCI_KEY_F10 (68 << 8)
+
+#define SCI_KEY_SHIFT_F1 (84 << 8)
+#define SCI_KEY_SHIFT_F2 (85 << 8)
+#define SCI_KEY_SHIFT_F3 (86 << 8)
+#define SCI_KEY_SHIFT_F4 (87 << 8)
+#define SCI_KEY_SHIFT_F5 (88 << 8)
+#define SCI_KEY_SHIFT_F6 (89 << 8)
+#define SCI_KEY_SHIFT_F7 (90 << 8)
+#define SCI_KEY_SHIFT_F8 (91 << 8)
+#define SCI_KEY_SHIFT_F9 (92 << 8)
+#define SCI_KEY_SHIFT_F10 (93 << 8)
/*Values for buckybits */
-#define SCI_KEYMOD_RSHIFT (1<<0)
-#define SCI_KEYMOD_LSHIFT (1<<1)
-#define SCI_KEYMOD_CTRL (1<<2)
-#define SCI_KEYMOD_ALT (1<<3)
-#define SCI_KEYMOD_SCRLOCK (1<<4)
-#define SCI_KEYMOD_NUMLOCK (1<<5)
-#define SCI_KEYMOD_CAPSLOCK (1<<6)
-#define SCI_KEYMOD_INSERT (1<<7)
+#define SCI_KEYMOD_RSHIFT (1 << 0)
+#define SCI_KEYMOD_LSHIFT (1 << 1)
+#define SCI_KEYMOD_CTRL (1 << 2)
+#define SCI_KEYMOD_ALT (1 << 3)
+#define SCI_KEYMOD_SCRLOCK (1 << 4)
+#define SCI_KEYMOD_NUMLOCK (1 << 5)
+#define SCI_KEYMOD_CAPSLOCK (1 << 6)
+#define SCI_KEYMOD_INSERT (1 << 7)
#define SCI_KEYMOD_NO_FOOLOCK (~(SCI_KEYMOD_SCRLOCK | SCI_KEYMOD_NUMLOCK | SCI_KEYMOD_CAPSLOCK | SCI_KEYMOD_INSERT))
#define SCI_KEYMOD_ALL 0xFF
@@ -117,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/animate.cpp b/engines/sci/graphics/animate.cpp
index 7957ed6a55..98278397b7 100644
--- a/engines/sci/graphics/animate.cpp
+++ b/engines/sci/graphics/animate.cpp
@@ -28,6 +28,7 @@
#include "sci/sci.h"
#include "sci/event.h"
#include "sci/engine/kernel.h"
+#include "sci/engine/script_patches.h"
#include "sci/engine/state.h"
#include "sci/engine/selector.h"
#include "sci/engine/vm.h"
@@ -44,8 +45,8 @@
namespace Sci {
-GfxAnimate::GfxAnimate(EngineState *state, GfxCache *cache, GfxPorts *ports, GfxPaint16 *paint16, GfxScreen *screen, GfxPalette *palette, GfxCursor *cursor, GfxTransitions *transitions)
- : _s(state), _cache(cache), _ports(ports), _paint16(paint16), _screen(screen), _palette(palette), _cursor(cursor), _transitions(transitions) {
+GfxAnimate::GfxAnimate(EngineState *state, ScriptPatcher *scriptPatcher, GfxCache *cache, GfxPorts *ports, GfxPaint16 *paint16, GfxScreen *screen, GfxPalette *palette, GfxCursor *cursor, GfxTransitions *transitions)
+ : _s(state), _scriptPatcher(scriptPatcher), _cache(cache), _ports(ports), _paint16(paint16), _screen(screen), _palette(palette), _cursor(cursor), _transitions(transitions) {
init();
}
@@ -55,16 +56,77 @@ GfxAnimate::~GfxAnimate() {
void GfxAnimate::init() {
_lastCastData.clear();
- _ignoreFastCast = false;
- // fastCast object is not found in any SCI games prior SCI1
- if (getSciVersion() <= SCI_VERSION_01)
- _ignoreFastCast = true;
- // Also if fastCast object exists at gamestartup, we can assume that the interpreter doesnt do kAnimate aborts
- // (found in Larry 1)
- if (getSciVersion() > SCI_VERSION_0_EARLY) {
- if (!_s->_segMan->findObjectByName("fastCast").isNull())
- _ignoreFastCast = true;
+ _fastCastEnabled = false;
+ if (getSciVersion() == SCI_VERSION_1_1) {
+ // Seems to have been available for all SCI1.1 games
+ _fastCastEnabled = true;
+ } else if (getSciVersion() >= SCI_VERSION_1_EARLY) {
+ // fastCast only exists for some games between SCI1 early and SCI1 late
+ // Try to detect it by code signature
+ // It's extremely important, that we only enable it for games that actually need it
+ if (detectFastCast()) {
+ _fastCastEnabled = true;
+ }
+ }
+}
+
+// Signature for fastCast detection
+static const uint16 fastCastSignature[] = {
+ SIG_MAGICDWORD,
+ 0x35, 0x00, // ldi 00
+ 0xa1, 84, // sag global[84d]
+ SIG_END
+};
+
+// Fast cast in games:
+
+// SCI1 Early:
+// KQ5 - no fastcast, LSL1 (demo) - no fastcast, Mixed Up Fairy Tales - *has fastcast*, XMas Card 1990 - no fastcast,
+// SQ4Floppy - no fastcast, Mixed Up Mother Goose - no fastcast
+//
+// SCI1 Middle:
+// LSL5 demo - no fastfast, Conquest of the Longbow demo - no fastcast, LSL1 - no fastcast,
+// Astro Chicken II - no fastcast
+//
+// SCI1 Late:
+// Castle of Dr. Brain demo - has fastcast, Castle of Dr. Brain - has fastcast,
+// Conquests of the Longbow - has fastcast, Space Quest 1 EGA - has fastcast,
+// King's Quest 5 multilingual - *NO* fastcast, Police Quest 3 demo - *NO* fastcast,
+// LSL5 multilingual - has fastcast, Police Quest 3 - has fastcast,
+// EcoQuest 1 - has fastcast, Mixed Up Fairy Tales demo - has fastcast,
+// Space Quest 4 multilingual - *NO* fastcast
+//
+// SCI1.1
+// Quest for Glory 3 demo - has fastcast, Police Quest 1 - hast fastcast, Quest for Glory 1 - has fastcast
+// Laura Bow 2 Floppy - has fastcast, Mixed Up Mother Goose - has fastcast, Quest for Glory 3 - has fastcast
+// Island of Dr. Brain - has fastcast, King's Quest 6 - has fastcast, Space Quest 5 - has fastcast
+// Hoyle 4 - has fastcast, Laura Bow 2 CD - has fastcast, Freddy Pharkas CD - has fastcast
+bool GfxAnimate::detectFastCast() {
+ SegManager *segMan = _s->_segMan;
+ const reg_t gameVMObject = g_sci->getGameObject();
+ reg_t gameSuperVMObject = segMan->getObject(gameVMObject)->getSuperClassSelector();
+ uint32 magicDWord = 0; // platform-specific BE/LE for performance
+ int magicDWordOffset = 0;
+
+ if (gameSuperVMObject.isNull()) {
+ gameSuperVMObject = gameVMObject; // Just in case. According to sci.cpp this may happen in KQ5CD, when loading saved games before r54510
+ }
+
+ Script *objectScript = segMan->getScript(gameSuperVMObject.getSegment());
+ byte *scriptData = const_cast<byte *>(objectScript->getBuf(0));
+ uint32 scriptSize = objectScript->getBufSize();
+
+ _scriptPatcher->calculateMagicDWordAndVerify("fast cast detection", fastCastSignature, true, magicDWord, magicDWordOffset);
+
+ // Signature is found for multilingual King's Quest 5 too, but it looks as if the fast cast global is never set
+ // within that game. Which means even though we detect it as having the capability, it's never actually used.
+ // The original multilingual KQ5 interpreter did have this feature disabled.
+ // Sierra probably used latest system scripts and that's why we detect it.
+ if (_scriptPatcher->findSignature(magicDWord, magicDWordOffset, fastCastSignature, "fast cast detection", scriptData, scriptSize) >= 0) {
+ // Signature found, game seems to use fast cast for kAnimate
+ return true;
}
+ return false;
}
void GfxAnimate::disposeLastCast() {
@@ -80,12 +142,14 @@ bool GfxAnimate::invoke(List *list, int argc, reg_t *argv) {
while (curNode) {
curObject = curNode->value;
- if (!_ignoreFastCast) {
+ if (_fastCastEnabled) {
// Check if the game has a fastCast object set
// if we don't abort kAnimate processing, at least in kq5 there will be animation cels drawn into speech boxes.
if (!_s->variables[VAR_GLOBAL][84].isNull()) {
- if (!strcmp(_s->_segMan->getObjectName(_s->variables[VAR_GLOBAL][84]), "fastCast"))
- return false;
+ // This normally points to an object called "fastCast",
+ // but for example in Eco Quest 1 it may also point to an object called "EventHandler" (see bug #5170)
+ // Original SCI only checked, if this global was not 0.
+ return false;
}
}
diff --git a/engines/sci/graphics/animate.h b/engines/sci/graphics/animate.h
index 6c1822c903..ac7078093c 100644
--- a/engines/sci/graphics/animate.h
+++ b/engines/sci/graphics/animate.h
@@ -87,9 +87,13 @@ class GfxView;
*/
class GfxAnimate {
public:
- GfxAnimate(EngineState *state, GfxCache *cache, GfxPorts *ports, GfxPaint16 *paint16, GfxScreen *screen, GfxPalette *palette, GfxCursor *cursor, GfxTransitions *transitions);
+ GfxAnimate(EngineState *state, ScriptPatcher *scriptPatcher, GfxCache *cache, GfxPorts *ports, GfxPaint16 *paint16, GfxScreen *screen, GfxPalette *palette, GfxCursor *cursor, GfxTransitions *transitions);
virtual ~GfxAnimate();
+ bool isFastCastEnabled() {
+ return _fastCastEnabled;
+ }
+
void disposeLastCast();
bool invoke(List *list, int argc, reg_t *argv);
void makeSortedList(List *list);
@@ -110,6 +114,7 @@ public:
private:
void init();
+ bool detectFastCast();
void addToPicSetPicNotValid();
void animateShowPic();
@@ -119,6 +124,7 @@ private:
void setNsRect(GfxView *view, AnimateList::iterator it);
EngineState *_s;
+ ScriptPatcher *_scriptPatcher;
GfxCache *_cache;
GfxPorts *_ports;
GfxPaint16 *_paint16;
@@ -130,7 +136,7 @@ private:
AnimateList _list;
AnimateArray _lastCastData;
- bool _ignoreFastCast;
+ bool _fastCastEnabled;
};
} // End of namespace Sci
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
new file mode 100644
index 0000000000..48de054a31
--- /dev/null
+++ b/engines/sci/graphics/celobj32.cpp
@@ -0,0 +1,1151 @@
+/* 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/resource.h"
+#include "sci/engine/seg_manager.h"
+#include "sci/engine/state.h"
+#include "sci/graphics/celobj32.h"
+#include "sci/graphics/frameout.h"
+#include "sci/graphics/palette32.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) {
+ const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth;
+ const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight;
+
+ for (int i = 0; i < ARRAYSIZE(_scaleTables); ++i) {
+ if (_scaleTables[i].scaleX == scaleX && _scaleTables[i].scaleY == scaleY) {
+ _activeIndex = i;
+ return;
+ }
+ }
+
+ int i = 1 - _activeIndex;
+ _activeIndex = i;
+ CelScalerTable &table = _scaleTables[i];
+
+ if (table.scaleX != scaleX) {
+ assert(screenWidth <= ARRAYSIZE(table.valuesX));
+ buildLookupTable(table.valuesX, scaleX, screenWidth);
+ table.scaleX = scaleX;
+ }
+
+ if (table.scaleY != scaleY) {
+ assert(screenHeight <= ARRAYSIZE(table.valuesY));
+ buildLookupTable(table.valuesY, scaleY, screenHeight);
+ table.scaleY = scaleY;
+ }
+}
+
+void CelScaler::buildLookupTable(int *table, const Ratio &ratio, const int size) {
+ int value = 0;
+ int remainder = 0;
+ int num = ratio.getNumerator();
+ for (int i = 0; i < size; ++i) {
+ *table++ = value;
+ remainder += ratio.getDenominator();
+ if (remainder >= num) {
+ value += remainder / num;
+ remainder %= num;
+ }
+ }
+}
+
+const CelScalerTable *CelScaler::getScalerTable(const Ratio &scaleX, const Ratio &scaleY) {
+ activateScaleTables(scaleX, scaleY);
+ return &_scaleTables[_activeIndex];
+}
+
+#pragma mark -
+#pragma mark CelObj
+bool CelObj::_drawBlackLines = false;
+
+void CelObj::init() {
+ CelObj::deinit();
+ _drawBlackLines = false;
+ _nextCacheId = 1;
+ _scaler = new CelScaler();
+ _cache = new CelCache;
+ _cache->resize(100);
+}
+
+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;
+}
+
+#pragma mark -
+#pragma mark CelObj - Scalers
+
+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, const Common::Point &scaledPosition) :
+ _row(nullptr),
+ _reader(celObj, FLIP ? celObj._width : maxWidth),
+ _lastIndex(celObj._width - 1),
+ _sourceX(scaledPosition.x),
+ _sourceY(scaledPosition.y) {}
+
+ inline void setTarget(const int16 x, const int16 y) {
+ _row = _reader.getRow(y - _sourceY);
+
+ if (FLIP) {
+#ifndef NDEBUG
+ _rowEdge = _row - 1;
+#endif
+ _row += _lastIndex - (x - _sourceX);
+ assert(_row > _rowEdge);
+ } else {
+#ifndef NDEBUG
+ _rowEdge = _row + _lastIndex + 1;
+#endif
+ _row += x - _sourceX;
+ assert(_row < _rowEdge);
+ }
+ }
+
+ inline byte read() {
+ assert(_row != _rowEdge);
+
+ if (FLIP) {
+ return *_row--;
+ } else {
+ return *_row++;
+ }
+ }
+};
+
+template<bool FLIP, typename READER>
+struct SCALER_Scale {
+#ifndef NDEBUG
+ int16 _maxX;
+#endif
+ const byte *_row;
+ READER _reader;
+ int16 _x;
+ 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) {
+ // 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;
+ }
+ }
+
+ const int16 unscaledY = (scaledPosition.y / scaleY).toInt();
+ for (int16 y = targetRect.top; y < targetRect.bottom; ++y) {
+ _valuesY[y] = table->valuesY[y] - unscaledY;
+ }
+ } else {
+ 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() {
+ 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;
+ }
+};
+
+struct READER_Compressed {
+private:
+ byte *_resource;
+ byte _buffer[1024];
+ uint32 _controlOffset;
+ uint32 _dataOffset;
+ uint32 _uncompressedDataOffset;
+ int16 _y;
+ const int16 _sourceHeight;
+ const uint8 _transparentColor;
+ const int16 _maxWidth;
+
+public:
+ READER_Compressed(const CelObj &celObj, const int16 maxWidth) :
+ _resource(celObj.getResPointer()),
+ _y(-1),
+ _sourceHeight(celObj._height),
+ _transparentColor(celObj._transparentColor),
+ _maxWidth(maxWidth) {
+ assert(maxWidth <= celObj._width);
+
+ byte *celHeader = _resource + celObj._celHeaderOffset;
+ _dataOffset = READ_SCI11ENDIAN_UINT32(celHeader + 24);
+ _uncompressedDataOffset = READ_SCI11ENDIAN_UINT32(celHeader + 28);
+ _controlOffset = READ_SCI11ENDIAN_UINT32(celHeader + 32);
+ }
+
+ 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);
+
+ // uncompressed data segment for row
+ byte *literal = _resource + _uncompressedDataOffset + READ_SCI11ENDIAN_UINT32(_resource + _controlOffset + _sourceHeight * 4 + y * 4);
+
+ uint8 length;
+ for (int16 i = 0; i < _maxWidth; i += length) {
+ byte controlByte = *row++;
+ length = controlByte;
+
+ // Run-length encoded
+ if (controlByte & 0x80) {
+ length &= 0x3F;
+ assert(i + length < (int)sizeof(_buffer));
+
+ // Fill with skip color
+ if (controlByte & 0x40) {
+ memset(_buffer + i, _transparentColor, length);
+ // Next value is fill color
+ } else {
+ memset(_buffer + i, *literal, length);
+ ++literal;
+ }
+ // Uncompressed
+ } else {
+ assert(i + length < (int)sizeof(_buffer));
+ memcpy(_buffer + i, literal, length);
+ literal += length;
+ }
+ }
+ _y = y;
+ }
+
+ return _buffer;
+ }
+};
+
+#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) {
+ *target = pixel;
+ }
+ }
+};
+
+/**
+ * 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 Common::Point &scaledPosition = screenItem._scaledPosition;
+ const Ratio &scaleX = screenItem._ratioX;
+ const Ratio &scaleY = screenItem._ratioY;
+ _drawBlackLines = screenItem._drawBlackLines;
+
+ if (_remap) {
+ // 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, targetRect, scaledPosition);
+ } else {
+ drawUncompNoFlipMap(target, targetRect, scaledPosition);
+ }
+ } else {
+ if (_drawMirrored) {
+ drawHzFlipMap(target, targetRect, scaledPosition);
+ } else {
+ drawNoFlipMap(target, targetRect, scaledPosition);
+ }
+ }
+ } else {
+ if (_compressionType == kCelCompressionNone) {
+ scaleDrawUncompMap(target, scaleX, scaleY, targetRect, scaledPosition);
+ } else {
+ scaleDrawMap(target, scaleX, scaleY, 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);
+ }
+ }
+ } else {
+ if (_compressionType == kCelCompressionNone) {
+ scaleDrawUncomp(target, scaleX, scaleY, targetRect, scaledPosition);
+ } else {
+ scaleDraw(target, scaleX, scaleY, 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);
+ }
+ }
+ } else {
+ if (_compressionType == kCelCompressionNone) {
+ scaleDrawUncompNoMD(target, scaleX, scaleY, targetRect, scaledPosition);
+ } else {
+ scaleDrawNoMD(target, scaleX, scaleY, targetRect, scaledPosition);
+ }
+ }
+ }
+
+ _drawBlackLines = false;
+}
+
+void CelObj::draw(Buffer &target, const ScreenItem &screenItem, const Common::Rect &targetRect, bool mirrorX) {
+ _drawMirrored = mirrorX;
+ draw(target, screenItem, targetRect);
+}
+
+void CelObj::draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const bool mirrorX) {
+ _drawMirrored = mirrorX;
+ Ratio square;
+ drawTo(target, targetRect, scaledPosition, square, square);
+}
+
+void CelObj::drawTo(Buffer &target, Common::Rect const &targetRect, Common::Point const &scaledPosition, Ratio const &scaleX, Ratio const &scaleY) const {
+ if (_remap) {
+ if (scaleX.isOne() && scaleY.isOne()) {
+ if (_compressionType == kCelCompressionNone) {
+ if (_drawMirrored) {
+ drawUncompHzFlipMap(target, targetRect, scaledPosition);
+ } else {
+ drawUncompNoFlipMap(target, targetRect, scaledPosition);
+ }
+ } else {
+ if (_drawMirrored) {
+ drawHzFlipMap(target, targetRect, scaledPosition);
+ } else {
+ drawNoFlipMap(target, targetRect, scaledPosition);
+ }
+ }
+ } else {
+ if (_compressionType == kCelCompressionNone) {
+ scaleDrawUncompMap(target, scaleX, scaleY, targetRect, scaledPosition);
+ } else {
+ scaleDrawMap(target, scaleX, scaleY, targetRect, scaledPosition);
+ }
+ }
+ } else {
+ if (scaleX.isOne() && scaleY.isOne()) {
+ if (_compressionType == kCelCompressionNone) {
+ if (_drawMirrored) {
+ drawUncompHzFlipNoMD(target, targetRect, scaledPosition);
+ } else {
+ drawUncompNoFlipNoMD(target, targetRect, scaledPosition);
+ }
+ } else {
+ if (_drawMirrored) {
+ drawHzFlipNoMD(target, targetRect, scaledPosition);
+ } else {
+ drawNoFlipNoMD(target, targetRect, scaledPosition);
+ }
+ }
+ } else {
+ if (_compressionType == kCelCompressionNone) {
+ scaleDrawUncompNoMD(target, scaleX, scaleY, targetRect, scaledPosition);
+ } else {
+ scaleDrawNoMD(target, scaleX, scaleY, targetRect, scaledPosition);
+ }
+ }
+ }
+}
+
+uint8 CelObj::readPixel(uint16 x, const uint16 y, bool mirrorX) const {
+ if (mirrorX) {
+ x = _width - x - 1;
+ }
+
+ if (_compressionType == kCelCompressionNone) {
+ READER_Uncompressed reader(*this, x + 1);
+ return reader.getRow(y)[x];
+ } else {
+ READER_Compressed reader(*this, x + 1);
+ return reader.getRow(y)[x];
+ }
+}
+
+void CelObj::submitPalette() const {
+ if (_hunkPaletteOffset) {
+ 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 = 0;
+
+ for (int i = 0, len = _cache->size(); i < len; ++i) {
+ CelCacheEntry &entry = (*_cache)[i];
+
+ if (entry.celObj == nullptr) {
+ if (*nextInsertIndex == -1) {
+ *nextInsertIndex = i;
+ }
+ } else if (entry.celObj->_info == celInfo) {
+ entry.id = ++_nextCacheId;
+ return i;
+ } else if (oldestId > entry.id) {
+ oldestId = entry.id;
+ oldestIndex = i;
+ }
+ }
+
+ if (*nextInsertIndex == -1) {
+ *nextInsertIndex = oldestIndex;
+ }
+
+ return -1;
+}
+
+void CelObj::putCopyInCache(const int cacheIndex) const {
+ if (cacheIndex == -1) {
+ error("Invalid cache index");
+ }
+
+ CelCacheEntry &entry = (*_cache)[cacheIndex];
+
+ if (entry.celObj != nullptr) {
+ delete entry.celObj;
+ }
+
+ entry.celObj = duplicate();
+ entry.id = ++_nextCacheId;
+}
+
+#pragma mark -
+#pragma mark CelObj - Drawing
+
+template<typename MAPPER, typename SCALER, bool DRAW_BLACK_LINES>
+struct RENDERER {
+ MAPPER &_mapper;
+ SCALER &_scaler;
+ const uint8 _skipColor;
+
+ RENDERER(MAPPER &mapper, SCALER &scaler, const uint8 skipColor) :
+ _mapper(mapper),
+ _scaler(scaler),
+ _skipColor(skipColor) {}
+
+ inline void draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
+ 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 (int16 y = 0; y < targetHeight; ++y) {
+ if (DRAW_BLACK_LINES && (y % 2) == 0) {
+ memset(targetPixel, 0, targetWidth);
+ targetPixel += targetWidth + skipStride;
+ continue;
+ }
+
+ _scaler.setTarget(targetRect.left, targetRect.top + y);
+
+ for (int16 x = 0; x < targetWidth; ++x) {
+ _mapper.draw(targetPixel++, _scaler.read(), _skipColor);
+ }
+
+ targetPixel += skipStride;
+ }
+ }
+};
+
+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(), scaledPosition);
+ RENDERER<MAPPER, SCALER, false> renderer(mapper, scaler, _transparentColor);
+ renderer.draw(target, targetRect, scaledPosition);
+}
+
+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, 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) {
+ target.fillRect(targetRect, 250);
+}
+
+void CelObj::drawHzFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
+ 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 {
+ 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 {
+ 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 {
+ 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 {
+ 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 {
+ 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 {
+ 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 {
+ 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 {
+ 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 {
+ 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 {
+ 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 {
+ 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 {
+ render<MAPPER_NoMD, SCALER_NoScale<false, READER_Compressed> >(target, targetRect, scaledPosition);
+}
+
+void CelObj::drawHzFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
+ render<MAPPER_NoMD, SCALER_NoScale<true, READER_Compressed> >(target, targetRect, scaledPosition);
+}
+
+void CelObj::drawUncompNoFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
+ render<MAPPER_NoMD, SCALER_NoScale<false, READER_Uncompressed> >(target, targetRect, scaledPosition);
+}
+
+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)
+ render<MAPPER_NoMD, SCALER_Scale<true, READER_Compressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
+ 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 {
+ if (_drawMirrored) {
+ render<MAPPER_NoMD, SCALER_Scale<true, READER_Uncompressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
+ } else {
+ render<MAPPER_NoMD, SCALER_Scale<false, READER_Uncompressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
+ }
+}
+
+#pragma mark -
+#pragma mark CelObjView
+
+CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int16 celNo) {
+ _info.type = kCelTypeView;
+ _info.resourceId = viewId;
+ _info.loopNo = loopNo;
+ _info.celNo = celNo;
+ _mirrorX = false;
+ _compressionType = kCelCompressionInvalid;
+ _transparent = true;
+
+ int cacheInsertIndex;
+ int cacheIndex = searchCache(_info, &cacheInsertIndex);
+ if (cacheIndex != -1) {
+ CelCacheEntry &entry = (*_cache)[cacheIndex];
+ 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;
+ }
+
+ // TODO: The next code should be moved to a common file that
+ // generates view resource metadata for both SCI16 and SCI32
+ // implementations
+
+ Resource *resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, viewId), false);
+
+ // NOTE: SCI2.1/SQ6 just silently returns here.
+ if (!resource) {
+ warning("View resource %d not loaded", viewId);
+ return;
+ }
+
+ byte *data = resource->data;
+
+ _scaledWidth = READ_SCI11ENDIAN_UINT16(data + 14);
+ _scaledHeight = READ_SCI11ENDIAN_UINT16(data + 16);
+
+ if (_scaledWidth == 0 || _scaledHeight == 0) {
+ byte sizeFlag = data[5];
+ if (sizeFlag == 0) {
+ _scaledWidth = kLowResX;
+ _scaledHeight = kLowResY;
+ } else if (sizeFlag == 1) {
+ _scaledWidth = 640;
+ _scaledHeight = 480;
+ } else if (sizeFlag == 2) {
+ _scaledWidth = 640;
+ _scaledHeight = 400;
+ }
+ }
+
+ uint16 loopCount = data[2];
+ if (_info.loopNo >= loopCount) {
+ _info.loopNo = loopCount - 1;
+ }
+
+ // NOTE: This is the actual check, in the actual location,
+ // from SCI engine.
+ if (loopNo < 0) {
+ error("Loop is less than 0!");
+ }
+
+ const uint16 viewHeaderSize = READ_SCI11ENDIAN_UINT16(data);
+ const uint8 loopHeaderSize = data[12];
+ const uint8 viewHeaderFieldSize = 2;
+
+ byte *loopHeader = data + viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * _info.loopNo);
+
+ if ((int8)loopHeader[0] != -1) {
+ if (loopHeader[1] == 1) {
+ _mirrorX = true;
+ }
+
+ loopHeader = data + viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * (int8)loopHeader[0]);
+ }
+
+ uint8 celCount = loopHeader[2];
+ if (_info.celNo >= celCount) {
+ _info.celNo = celCount - 1;
+ }
+
+ _hunkPaletteOffset = READ_SCI11ENDIAN_UINT32(data + 8);
+ _celHeaderOffset = READ_SCI11ENDIAN_UINT32(loopHeader + 12) + (data[13] * _info.celNo);
+
+ byte *celHeader = data + _celHeaderOffset;
+
+ _width = READ_SCI11ENDIAN_UINT16(celHeader);
+ _height = READ_SCI11ENDIAN_UINT16(celHeader + 2);
+ _displace.x = _width / 2 - (int16)READ_SCI11ENDIAN_UINT16(celHeader + 4);
+ _displace.y = _height - (int16)READ_SCI11ENDIAN_UINT16(celHeader + 6) - 1;
+ _transparentColor = celHeader[8];
+ _compressionType = (CelCompressionType)celHeader[9];
+
+ if (_compressionType != kCelCompressionNone && _compressionType != kCelCompressionRLE) {
+ error("Compression type not supported - V: %d L: %d C: %d", _info.resourceId, _info.loopNo, _info.celNo);
+ }
+
+ if (celHeader[10] & 128) {
+ // NOTE: This is correct according to SCI2.1/SQ6/DOS;
+ // the engine re-reads the byte value as a word value
+ uint16 flags = READ_SCI11ENDIAN_UINT16(celHeader + 10);
+ _transparent = flags & 1 ? true : false;
+ _remap = flags & 2 ? true : false;
+ } else if (_compressionType == kCelCompressionNone) {
+ _remap = analyzeUncompressedForRemap();
+ } else {
+ _remap = analyzeForRemap();
+ }
+
+ putCopyInCache(cacheInsertIndex);
+}
+
+bool CelObjView::analyzeUncompressedForRemap() const {
+ byte *pixels = getResPointer() + READ_SCI11ENDIAN_UINT32(getResPointer() + _celHeaderOffset + 24);
+ for (int i = 0; i < _width * _height; ++i) {
+ const byte pixel = pixels[i];
+ if (
+ pixel >= g_sci->_gfxRemap32->getStartColor() &&
+ pixel <= g_sci->_gfxRemap32->getEndColor() &&
+ pixel != _transparentColor
+ ) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CelObjView::analyzeForRemap() const {
+ 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;
+}
+
+void CelObjView::draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, bool mirrorX, const Ratio &scaleX, const Ratio &scaleY) {
+ _drawMirrored = mirrorX;
+ drawTo(target, targetRect, scaledPosition, scaleX, scaleY);
+}
+
+CelObjView *CelObjView::duplicate() const {
+ return new CelObjView(*this);
+}
+
+byte *CelObjView::getResPointer() const {
+ 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;
+ _info.loopNo = 0;
+ _info.celNo = celNo;
+ _mirrorX = false;
+ _compressionType = kCelCompressionInvalid;
+ _transparent = true;
+ _remap = false;
+
+ int cacheInsertIndex;
+ int cacheIndex = searchCache(_info, &cacheInsertIndex);
+ if (cacheIndex != -1) {
+ CelCacheEntry &entry = (*_cache)[cacheIndex];
+ 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;
+ }
+
+ Resource *resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypePic, picId), false);
+
+ // NOTE: SCI2.1/SQ6 just silently returns here.
+ if (!resource) {
+ warning("Pic resource %d not loaded", picId);
+ return;
+ }
+
+ byte *data = resource->data;
+
+ _celCount = data[2];
+
+ if (_info.celNo >= _celCount) {
+ error("Cel number %d greater than cel count %d", _info.celNo, _celCount);
+ }
+
+ _celHeaderOffset = READ_SCI11ENDIAN_UINT16(data) + (READ_SCI11ENDIAN_UINT16(data + 4) * _info.celNo);
+ _hunkPaletteOffset = READ_SCI11ENDIAN_UINT32(data + 6);
+
+ byte *celHeader = data + _celHeaderOffset;
+
+ _width = READ_SCI11ENDIAN_UINT16(celHeader);
+ _height = READ_SCI11ENDIAN_UINT16(celHeader + 2);
+ _displace.x = (int16)READ_SCI11ENDIAN_UINT16(celHeader + 4);
+ _displace.y = (int16)READ_SCI11ENDIAN_UINT16(celHeader + 6);
+ _transparentColor = celHeader[8];
+ _compressionType = (CelCompressionType)celHeader[9];
+ _priority = READ_SCI11ENDIAN_UINT16(celHeader + 36);
+ _relativePosition.x = (int16)READ_SCI11ENDIAN_UINT16(celHeader + 38);
+ _relativePosition.y = (int16)READ_SCI11ENDIAN_UINT16(celHeader + 40);
+
+ uint16 sizeFlag1 = READ_SCI11ENDIAN_UINT16(data + 10);
+ uint16 sizeFlag2 = READ_SCI11ENDIAN_UINT16(data + 12);
+
+ if (sizeFlag2) {
+ _scaledWidth = sizeFlag1;
+ _scaledHeight = sizeFlag2;
+ } else if (sizeFlag1 == 0) {
+ _scaledWidth = kLowResX;
+ _scaledHeight = kLowResY;
+ } else if (sizeFlag1 == 1) {
+ _scaledWidth = 640;
+ _scaledHeight = 480;
+ } else if (sizeFlag1 == 2) {
+ _scaledWidth = 640;
+ _scaledHeight = 400;
+ }
+
+ if (celHeader[10] & 128) {
+ // NOTE: This is correct according to SCI2.1/SQ6/DOS;
+ // the engine re-reads the byte value as a word value
+ uint16 flags = READ_SCI11ENDIAN_UINT16(celHeader + 10);
+ _transparent = flags & 1 ? true : false;
+ _remap = flags & 2 ? true : false;
+ } else {
+ _transparent = _compressionType != kCelCompressionNone ? true : analyzeUncompressedForSkip();
+
+ if (_compressionType != kCelCompressionNone && _compressionType != kCelCompressionRLE) {
+ error("Compression type not supported - P: %d C: %d", picId, celNo);
+ }
+ }
+
+ putCopyInCache(cacheInsertIndex);
+}
+
+bool CelObjPic::analyzeUncompressedForSkip() const {
+ byte *resource = getResPointer();
+ byte *pixels = resource + READ_SCI11ENDIAN_UINT32(resource + _celHeaderOffset + 24);
+ for (int i = 0; i < _width * _height; ++i) {
+ uint8 pixel = pixels[i];
+ if (pixel == _transparentColor) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void CelObjPic::draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const bool mirrorX) {
+ Ratio square;
+ _drawMirrored = mirrorX;
+ drawTo(target, targetRect, scaledPosition, square, square);
+}
+
+CelObjPic *CelObjPic::duplicate() const {
+ return new CelObjPic(*this);
+}
+
+byte *CelObjPic::getResPointer() const {
+ 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 bitmapObject) {
+ _info.type = kCelTypeMem;
+ _info.bitmap = bitmapObject;
+ _mirrorX = false;
+ _compressionType = kCelCompressionNone;
+ _celHeaderOffset = 0;
+ _transparent = true;
+
+ 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 {
+ return new CelObjMem(*this);
+}
+
+byte *CelObjMem::getResPointer() const {
+ return g_sci->getEngineState()->_segMan->getHunkPointer(_info.bitmap);
+}
+
+#pragma mark -
+#pragma mark CelObjColor
+
+CelObjColor::CelObjColor(const uint8 color, const int16 width, const int16 height) {
+ _info.type = kCelTypeColor;
+ _info.color = color;
+ _displace.x = 0;
+ _displace.y = 0;
+ _scaledWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+ _scaledHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+ _hunkPaletteOffset = 0;
+ _mirrorX = false;
+ _remap = false;
+ _width = width;
+ _height = height;
+}
+
+void CelObjColor::draw(Buffer &target, const ScreenItem &screenItem, const Common::Rect &targetRect, const bool mirrorX) {
+ // TODO: The original engine sets this flag but why? One cannot
+ // draw a solid color mirrored.
+ _drawMirrored = mirrorX;
+ draw(target, targetRect);
+}
+void CelObjColor::draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, bool mirrorX) {
+ error("Unsupported method");
+}
+void CelObjColor::draw(Buffer &target, const Common::Rect &targetRect) const {
+ target.fillRect(targetRect, _info.color);
+}
+
+CelObjColor *CelObjColor::duplicate() const {
+ return new CelObjColor(*this);
+}
+
+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
new file mode 100644
index 0000000000..eb6ce3a3c9
--- /dev/null
+++ b/engines/sci/graphics/celobj32.h
@@ -0,0 +1,607 @@
+/* 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_CELOBJ32_H
+#define SCI_GRAPHICS_CELOBJ32_H
+
+#include "common/rational.h"
+#include "common/rect.h"
+#include "sci/resource.h"
+#include "sci/engine/vm_types.h"
+
+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,
+ kCelTypeMem = 2,
+ kCelTypeColor = 3
+};
+
+enum CelCompressionType {
+ kCelCompressionNone = 0,
+ kCelCompressionRLE = 138,
+ kCelCompressionInvalid = 1000
+};
+
+/**
+ * A CelInfo32 object describes the basic properties of a
+ * cel object.
+ */
+struct CelInfo32 {
+ /**
+ * The type of the cel object.
+ */
+ CelType type;
+
+ /**
+ * For cel objects that draw from resources, the ID of
+ * the resource to load.
+ */
+ GuiResourceId resourceId;
+
+ /**
+ * For CelObjView, the loop number to draw from the
+ * view resource.
+ */
+ int16 loopNo;
+
+ /**
+ * For CelObjView and CelObjPic, the cel number to draw
+ * from the view or pic resource.
+ */
+ int16 celNo;
+
+ /**
+ * For CelObjMem, a segment register pointing to a heap
+ * resource containing headered bitmap data.
+ */
+ reg_t bitmap;
+
+ /**
+ * For CelObjColor, the fill color.
+ */
+ uint8 color;
+
+ // NOTE: In at least SCI2.1/SQ6, color is left
+ // uninitialised.
+ CelInfo32() :
+ type(kCelTypeMem),
+ resourceId(0),
+ loopNo(0),
+ celNo(0),
+ bitmap(NULL_REG) {}
+
+ // NOTE: This is the equivalence criteria used by
+ // CelObj::searchCache in at least SCI2.1/SQ6. Notably,
+ // it does not check the color field.
+ inline bool operator==(const CelInfo32 &other) {
+ return (
+ type == other.type &&
+ resourceId == other.resourceId &&
+ loopNo == other.loopNo &&
+ celNo == other.celNo &&
+ bitmap == other.bitmap
+ );
+ }
+
+ inline bool operator!=(const CelInfo32 &other) {
+ return !(*this == other);
+ }
+};
+
+class CelObj;
+struct CelCacheEntry {
+ /**
+ * A monotonically increasing cache ID used to identify
+ * the least recently used item in the cache for
+ * replacement.
+ */
+ int id;
+ CelObj *celObj;
+ CelCacheEntry() : id(0), celObj(nullptr) {}
+};
+
+typedef Common::Array<CelCacheEntry> CelCache;
+
+#pragma mark -
+#pragma mark CelScaler
+
+struct CelScalerTable {
+ /**
+ * A lookup table of indexes that should be used to find
+ * the correct column to read from the source bitmap
+ * when drawing a scaled version of the source bitmap.
+ */
+ int valuesX[1024];
+
+ /**
+ * The ratio used to generate the x-values.
+ */
+ Ratio scaleX;
+
+ /**
+ * A lookup table of indexes that should be used to find
+ * the correct row to read from a source bitmap when
+ * drawing a scaled version of the source bitmap.
+ */
+ int valuesY[1024];
+
+ /**
+ * The ratio used to generate the y-values.
+ */
+ Ratio scaleY;
+};
+
+class CelScaler {
+ /**
+ * Cached scale tables.
+ */
+ CelScalerTable _scaleTables[2];
+
+ /**
+ * The index of the most recently used scale table.
+ */
+ int _activeIndex;
+
+ /**
+ * Activates a scale table for the given X and Y ratios.
+ * If there is no table that matches the given ratios,
+ * the least most recently used table will be replaced
+ * and activated.
+ */
+ void activateScaleTables(const Ratio &scaleX, const Ratio &scaleY);
+
+ /**
+ * Builds a pixel lookup table in `table` for the given
+ * ratio. The table will be filled up to the specified
+ * size, which should be large enough to draw across the
+ * entire target buffer.
+ */
+ void buildLookupTable(int *table, const Ratio &ratio, const int size);
+
+public:
+ CelScaler() :
+ _scaleTables(),
+ _activeIndex(0) {
+ 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];
+ }
+ }
+
+ /**
+ * Retrieves scaler tables for the given X and Y ratios.
+ */
+ const CelScalerTable *getScalerTable(const Ratio &scaleX, const Ratio &scaleY);
+};
+
+#pragma mark -
+#pragma mark CelObj
+
+class ScreenItem;
+/**
+ * A cel object is the lowest-level rendering primitive in
+ * the SCI engine and draws itself directly to a target
+ * pixel buffer.
+ */
+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
+ * cel's `_mirrorX` property and the owner screen item's
+ * `_mirrorX` property.
+ */
+ bool _drawMirrored;
+
+public:
+ static CelScaler *_scaler;
+
+ /**
+ * The basic identifying information for this cel. This
+ * information effectively acts as a composite key for
+ * a cel object, and any cel object can be recreated
+ * from this data alone.
+ */
+ CelInfo32 _info;
+
+ /**
+ * The offset to the cel header for this cel within the
+ * raw resource data.
+ */
+ uint32 _celHeaderOffset;
+
+ /**
+ * The offset to the embedded palette for this cel
+ * within the raw resource data.
+ */
+ uint32 _hunkPaletteOffset;
+
+ /**
+ * The natural dimensions of the cel.
+ */
+ uint16 _width, _height;
+
+ /**
+ * TODO: Documentation
+ */
+ Common::Point _displace;
+
+ /**
+ * The dimensions of the original coordinate system for
+ * the cel. Used to scale cels from their native size
+ * to the correct size on screen.
+ *
+ * @note This is set to scriptWidth/Height for
+ * CelObjColor. For other cel objects, the value comes
+ * from the raw resource data. For text bitmaps, this is
+ * the width/height of the coordinate system used to
+ * generate the text, which also defaults to
+ * scriptWidth/Height but seems to typically be changed
+ * to more closely match the native screen resolution.
+ */
+ uint16 _scaledWidth, _scaledHeight;
+
+ /**
+ * The skip (transparent) color for the cel. When
+ * compositing, any pixels matching this color will not
+ * be copied to the buffer.
+ */
+ uint8 _transparentColor;
+
+ /**
+ * Whether or not this cel has any transparent regions.
+ * This is used for optimised drawing of non-transparent
+ * cels.
+ */
+ bool _transparent; // TODO: probably "skip"?
+
+ /**
+ * The compression type for the pixel data for this cel.
+ */
+ CelCompressionType _compressionType;
+
+ /**
+ * Whether or not this cel should be palette-remapped?
+ */
+ bool _remap;
+
+ /**
+ * If true, the cel contains pre-mirrored picture data.
+ * This value comes directly from the resource data and
+ * is XORed with the `_mirrorX` property of the owner
+ * screen item when rendering.
+ */
+ bool _mirrorX;
+
+ /**
+ * Initialises static CelObj members.
+ */
+ static void init();
+
+ /**
+ * Frees static CelObj members.
+ */
+ static void deinit();
+
+ virtual ~CelObj() {};
+
+ /**
+ * Draws the cel to the target buffer using the priority
+ * and positioning information from the given screen
+ * item. The mirroring of the cel will be unchanged from
+ * any previous call to draw.
+ */
+ void draw(Buffer &target, const ScreenItem &screenItem, const Common::Rect &targetRect) const;
+
+ /**
+ * Draws the cel to the target buffer using the priority
+ * and positioning information from the given screen
+ * item and the given mirror flag.
+ *
+ * @note In SCI engine, this function was a virtual
+ * function, but CelObjView, CelObjPic, and CelObjMem
+ * all used the same function and the compiler
+ * deduplicated the copies; we deduplicate the source by
+ * putting the implementation on CelObj instead of
+ * copying it to 3/4 of the subclasses.
+ */
+ virtual void draw(Buffer &target, const ScreenItem &screenItem, const Common::Rect &targetRect, const bool mirrorX);
+
+ /**
+ * Draws the cel to the target buffer using the
+ * positioning and mirroring information from the
+ * provided arguments.
+ *
+ * @note In SCI engine, this function was a virtual
+ * function, but CelObjView, CelObjPic, and CelObjMem
+ * all used the same function and the compiler
+ * deduplicated the copies; we deduplicate the source by
+ * putting the implementation on CelObj instead of
+ * copying it to 3/4 of the subclasses.
+ */
+ virtual void draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const bool mirrorX);
+
+ /**
+ * Draws the cel to the target buffer using the given
+ * position and scaling parameters. The mirroring of the
+ * cel will be unchanged from any previous call to draw.
+ */
+ void drawTo(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const Ratio &scaleX, const Ratio &scaleY) const;
+
+ /**
+ * Creates a copy of this cel on the free store and
+ * returns a pointer to the new object. The new cel will
+ * point to a shared copy of bitmap/resource data.
+ */
+ virtual CelObj *duplicate() const = 0;
+
+ /**
+ * Retrieves a pointer to the raw resource data for this
+ * cel. This method cannot be used with a CelObjColor.
+ */
+ virtual byte *getResPointer() const = 0;
+
+ /**
+ * Reads the pixel at the given coordinates. This method
+ * is valid only for CelObjView and CelObjPic.
+ */
+ virtual uint8 readPixel(uint16 x, uint16 y, bool mirrorX) const;
+
+ /**
+ * Submits the palette from this cel to the palette
+ * manager for integration into the master screen
+ * palette.
+ */
+ void submitPalette() const;
+
+#pragma mark -
+#pragma mark CelObj - Drawing
+private:
+ template<typename MAPPER, typename SCALER>
+ void render(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
+
+ 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;
+ void drawNoFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
+ void drawUncompNoFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
+ 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;
+ // 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;
+ void drawUncompNoFlipNoMDNoSkip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
+ void drawUncompHzFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
+ 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;
+ // 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
+protected:
+ /**
+ * A monotonically increasing cache ID used to identify
+ * the least recently used item in the cache for
+ * replacement.
+ */
+ static int _nextCacheId;
+
+ /**
+ * A cache of cel objects used to avoid reinitialisation
+ * overhead for cels with the same CelInfo32.
+ */
+ // NOTE: At least SQ6 uses a fixed cache size of 100.
+ static CelCache *_cache;
+
+ /**
+ * Searches the cel cache for a CelObj matching the
+ * provided CelInfo32. If not found, -1 is returned.
+ * nextInsertIndex will receive the index of the oldest
+ * item in the cache, which can be used to replace
+ * the oldest item with a newer item.
+ */
+ int searchCache(const CelInfo32 &celInfo, int *nextInsertIndex) const;
+
+ /**
+ * Puts a copy of this CelObj into the cache at the
+ * given cache index.
+ */
+ void putCopyInCache(int index) const;
+};
+
+#pragma mark -
+#pragma mark CelObjView
+
+/**
+ * A CelObjView is the drawing primitive for a View type
+ * resource. Each CelObjView corresponds to a single cel
+ * within a single loop of a view.
+ */
+class CelObjView : public CelObj {
+private:
+ /**
+ * Analyses resources without baked-in remap flags
+ * to determine whether or not they should be remapped.
+ */
+ bool analyzeUncompressedForRemap() const;
+
+ /**
+ * Analyses compressed resources without baked-in remap
+ * flags to determine whether or not they should be
+ * remapped.
+ */
+ bool analyzeForRemap() const;
+
+public:
+ CelObjView(const GuiResourceId viewId, const int16 loopNo, const int16 celNo);
+ virtual ~CelObjView() override {};
+
+ using CelObj::draw;
+
+ /**
+ * Draws the cel to the target buffer using the
+ * positioning, mirroring, and scaling information from
+ * the provided arguments.
+ */
+ void draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, bool mirrorX, const Ratio &scaleX, const Ratio &scaleY);
+
+ virtual CelObjView *duplicate() const override;
+ virtual byte *getResPointer() const override;
+};
+
+#pragma mark -
+#pragma mark CelObjPic
+
+/**
+ * A CelObjPic is the drawing primitive for a Picture type
+ * resource. Each CelObjPic corresponds to a single cel
+ * within a picture.
+ */
+class CelObjPic : public CelObj {
+private:
+ /**
+ * Analyses uncompressed resources without baked-in skip
+ * flags to determine whether or not they can use fast
+ * blitting.
+ */
+ bool analyzeUncompressedForSkip() const;
+
+public:
+ /**
+ * The number of cels in the original picture resource.
+ */
+ uint8 _celCount;
+
+ /**
+ * The position of this cel relative to the top-left
+ * corner of the picture.
+ */
+ Common::Point _relativePosition;
+
+ /**
+ * The z-buffer priority for this cel. Higher prorities
+ * are drawn on top of lower priorities.
+ */
+ int16 _priority;
+
+ CelObjPic(const GuiResourceId pictureId, const int16 celNo);
+ virtual ~CelObjPic() override {};
+
+ using CelObj::draw;
+ virtual void draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const bool mirrorX) override;
+
+ virtual CelObjPic *duplicate() const override;
+ virtual byte *getResPointer() const override;
+};
+
+#pragma mark -
+#pragma mark CelObjMem
+
+/**
+ * A CelObjMem is the drawing primitive for arbitrary
+ * bitmaps generated in memory. Generated bitmaps in SCI32
+ * include text & vector drawings and per-pixel screen
+ * transitions like dissolves.
+ */
+class CelObjMem : public CelObj {
+public:
+ CelObjMem(const reg_t bitmap);
+ virtual ~CelObjMem() override {};
+
+ virtual CelObjMem *duplicate() const override;
+ virtual byte *getResPointer() const override;
+};
+
+#pragma mark -
+#pragma mark CelObjColor
+
+/**
+ * A CelObjColor is the drawing primitive for fast,
+ * low-memory, flat color fills.
+ */
+class CelObjColor : public CelObj {
+public:
+ CelObjColor(const uint8 color, const int16 width, const int16 height);
+ virtual ~CelObjColor() override {};
+
+ using CelObj::draw;
+ /**
+ * Block fills the target buffer with the cel color.
+ */
+ void draw(Buffer &target, const Common::Rect &targetRect) const;
+ virtual void draw(Buffer &target, const ScreenItem &screenItem, const Common::Rect &targetRect, const bool mirrorX) override;
+ virtual void draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const bool mirrorX) override;
+
+ 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 3c2285a470..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));
@@ -112,11 +112,6 @@ void GfxCompare::kernelSetNowSeen(reg_t objectReference) {
GfxView *view = NULL;
Common::Rect celRect(0, 0);
GuiResourceId viewId = (GuiResourceId)readSelectorValue(_segMan, objectReference, SELECTOR(view));
-
- // HACK: Ignore invalid views for now (perhaps unimplemented text views?)
- if (viewId == 0xFFFF) // invalid view
- return;
-
int16 loopNo = readSelectorValue(_segMan, objectReference, SELECTOR(loop));
int16 celNo = readSelectorValue(_segMan, objectReference, SELECTOR(cel));
int16 x = (int16)readSelectorValue(_segMan, objectReference, SELECTOR(x));
@@ -126,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)
- _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) {
- _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);
}
@@ -153,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);
}
@@ -201,15 +211,9 @@ void GfxCompare::kernelBaseSetter(reg_t object) {
GuiResourceId viewId = readSelectorValue(_segMan, object, SELECTOR(view));
int16 loopNo = readSelectorValue(_segMan, object, SELECTOR(loop));
int16 celNo = readSelectorValue(_segMan, object, SELECTOR(cel));
-
- // HACK: Ignore invalid views for now (perhaps unimplemented text views?)
- if (viewId == 0xFFFF) // invalid view
- return;
-
uint16 scaleSignal = 0;
- if (getSciVersion() >= SCI_VERSION_1_1) {
+ if (getSciVersion() >= SCI_VERSION_1_1)
scaleSignal = readSelectorValue(_segMan, object, SELECTOR(scaleSignal));
- }
Common::Rect celRect;
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/controls16.cpp b/engines/sci/graphics/controls16.cpp
index e2e250cf9d..b4bd92699a 100644
--- a/engines/sci/graphics/controls16.cpp
+++ b/engines/sci/graphics/controls16.cpp
@@ -151,7 +151,7 @@ void GfxControls16::kernelTexteditChange(reg_t controlObject, reg_t eventObject)
Common::Rect rect;
if (textReference.isNull())
- error("kEditControl called on object that doesnt have a text reference");
+ error("kEditControl called on object that doesn't have a text reference");
text = _segMan->getString(textReference);
uint16 oldCursorPos = cursorPos;
diff --git a/engines/sci/graphics/controls32.cpp b/engines/sci/graphics/controls32.cpp
index 90b5cd558c..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 doesnt 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.data) {
- 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.data == 99) {
- // Control-C in earlier SCI games (SCI0 - SCI1 middle)
- // Control-C erases the whole line
- cursorPos = 0; text.clear();
- textChanged = true;
- } else if (curEvent.data > 31 && curEvent.data < 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.data);
+ 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.data, 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 1a58de073c..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;
@@ -453,6 +456,15 @@ void GfxCursor::kernelClearZoomZone() {
void GfxCursor::kernelSetZoomZone(byte multiplier, Common::Rect zone, GuiResourceId viewNum, int loopNum, int celNum, GuiResourceId picNum, byte zoomColor) {
kernelClearZoomZone();
+ // This function is a stub in the Mac version of Freddy Pharkas.
+ // This function was only used in two games (LB2 and Pharkas), but there
+ // was no version of LB2 for the Macintosh platform.
+ // CHECKME: This wasn't verified against disassembly, one might want
+ // to check against it, in case there's some leftover code in the stubbed
+ // function (although it does seem that this was completely removed).
+ if (g_sci->getPlatform() == Common::kPlatformMacintosh)
+ return;
+
_zoomMultiplier = multiplier;
if (_zoomMultiplier != 1 && _zoomMultiplier != 2 && _zoomMultiplier != 4)
diff --git a/engines/sci/graphics/cursor.h b/engines/sci/graphics/cursor.h
index c2d7998eb3..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 {
@@ -77,8 +79,18 @@ public:
*/
void kernelSetMoveZone(Common::Rect zone);
- void kernelClearZoomZone();
+ /**
+ * Creates a dynamic zoom cursor, that is used to zoom on specific parts of the screen,
+ * using a separate larger picture. This was only used by two SCI1.1 games, Laura Bow 2
+ * (for examining the glyphs), and Freddy Pharkas (for examining the prescription with
+ * the whisky glass).
+ *
+ * In the Mac version of Freddy Pharkas, this was removed completely, and the scene has
+ * been redesigned to work without this functionality. There was no version of LB2 for
+ * the Macintosh platform.
+ */
void kernelSetZoomZone(byte multiplier, Common::Rect zone, GuiResourceId viewNum, int loopNum, int celNum, GuiResourceId picNum, byte zoomColor);
+ void kernelClearZoomZone();
void kernelSetPos(Common::Point pos);
void kernelMoveCursor(Common::Point pos);
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index ccc362dc37..a7899b8d89 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -21,9 +21,10 @@
*/
#include "common/algorithm.h"
+#include "common/config-manager.h"
#include "common/events.h"
#include "common/keyboard.h"
-#include "common/list_intern.h"
+#include "common/list.h"
#include "common/str.h"
#include "common/system.h"
#include "common/textconsole.h"
@@ -41,867 +42,1717 @@
#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/palette.h"
-#include "sci/graphics/picture.h"
+#include "sci/graphics/palette32.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 all guesswork
-
-enum SciSpeciaPlanelPictureCodes {
- kPlaneTranslucent = 0xfffe, // -2
- kPlanePlainColored = 0xffff // -1
+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 }
+};
+static int16 divisionsDefaults[2][16] = {
+ /* SCI2.1early- */ { 1, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 40, 40, 101, 101 },
+ /* SCI2.1mid+ */ { 1, 20, 20, 20, 20, 10, 10, 10, 10, 20, 20, 6, 10, 101, 101, 2 }
};
+static int16 unknownCDefaults[2][16] = {
+ /* SCI2.1early- */ { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 0, 0, 0, 0 },
+ /* 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, GfxScreen *screen, GfxPalette32 *palette) :
+ _isHiRes(false),
+ _palette(palette),
+ _resMan(resMan),
+ _screen(screen),
+ _segMan(segMan),
+ _benchmarkingFinished(false),
+ _throttleFrameOut(true),
+ _showStyles(nullptr),
+ _throttleState(0),
+ // TODO: Stop using _gfxScreen
+ _currentBuffer(screen->getDisplayWidth(), screen->getDisplayHeight(), nullptr),
+ _remapOccurred(false),
+ _frameNowVisible(false),
+ _screenRect(screen->getDisplayWidth(), screen->getDisplayHeight()),
+ _overdrawThreshold(0),
+ _palMorphIsOn(false) {
+
+ _currentBuffer.setPixels(calloc(1, screen->getDisplayWidth() * screen->getDisplayHeight()));
+
+ for (int i = 0; i < 236; i += 2) {
+ _styleRanges[i] = 0;
+ _styleRanges[i + 1] = -1;
+ }
+ for (int i = 236; i < ARRAYSIZE(_styleRanges); ++i) {
+ _styleRanges[i] = 0;
+ }
+
+ // TODO: Make hires detection work uniformly across all SCI engine
+ // versions (this flag is normally passed by SCI::MakeGraphicsMgr
+ // to the GraphicsMgr constructor depending upon video configuration,
+ // so should be handled upstream based on game configuration instead
+ // of here)
+ if (getSciVersion() >= SCI_VERSION_2_1_EARLY && _resMan->detectHires()) {
+ _isHiRes = true;
+ }
-GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxCache *cache, GfxScreen *screen, GfxPalette *palette, GfxPaint32 *paint32)
- : _segMan(segMan), _resMan(resMan), _cache(cache), _screen(screen), _palette(palette), _paint32(paint32) {
+ if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
+ _dissolveSequenceSeeds = dissolveSequences[0];
+ _defaultDivisions = divisionsDefaults[0];
+ _defaultUnknownC = unknownCDefaults[0];
+ } else {
+ _dissolveSequenceSeeds = dissolveSequences[1];
+ _defaultDivisions = divisionsDefaults[1];
+ _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
+ // frameOut, and (2) functions do a very simple lookup of the
+ // plane and arithmetic with the plane's gameRect. In
+ // principle, CoordAdjuster could be reused for
+ // convertGameRectToPlaneRect, but it is not super clear yet
+ // what the benefit would be to do that.
_coordAdjuster = (GfxCoordAdjuster32 *)coordAdjuster;
- _curScrollText = -1;
- _showScrollText = false;
- _maxScrollTexts = 0;
+
+ // TODO: Script resolution is hard-coded per game;
+ // also this must be set or else the engine will crash
+ _coordAdjuster->setScriptsResolution(_currentBuffer.scriptWidth, _currentBuffer.scriptHeight);
}
GfxFrameout::~GfxFrameout() {
clear();
+ CelObj::deinit();
+ free(_currentBuffer.getPixels());
}
+void GfxFrameout::run() {
+ CelObj::init();
+ Plane::init();
+ ScreenItem::init();
+
+ // NOTE: This happens in SCI::InitPlane in the actual engine,
+ // and is a background fill plane to ensure hidden planes
+ // (planes with a priority of -1) are never drawn
+ Plane *initPlane = new Plane(Common::Rect(_currentBuffer.scriptWidth, _currentBuffer.scriptHeight));
+ initPlane->_priority = 0;
+ _planes.add(initPlane);
+}
+
+// SCI32 actually did not clear anything at all it seems on restore. The scripts actually cleared up
+// planes + screen items right before restoring. And after restoring they sync'd its internal planes list
+// as well.
void GfxFrameout::clear() {
- deletePlaneItems(NULL_REG);
_planes.clear();
- deletePlanePictures(NULL_REG);
- clearScrollTexts();
-}
-
-void GfxFrameout::clearScrollTexts() {
- _scrollTexts.clear();
- _curScrollText = -1;
-}
-
-void GfxFrameout::addScrollTextEntry(Common::String &text, reg_t kWindow, uint16 x, uint16 y, bool replace) {
- //reg_t bitmapHandle = g_sci->_gfxText32->createScrollTextBitmap(text, kWindow);
- // HACK: We set the container dimensions manually
- reg_t bitmapHandle = g_sci->_gfxText32->createScrollTextBitmap(text, kWindow, 480, 70);
- ScrollTextEntry textEntry;
- textEntry.bitmapHandle = bitmapHandle;
- textEntry.kWindow = kWindow;
- textEntry.x = x;
- textEntry.y = y;
- if (!replace || _scrollTexts.size() == 0) {
- if (_scrollTexts.size() > _maxScrollTexts) {
- _scrollTexts.remove_at(0);
- _curScrollText--;
- }
- _scrollTexts.push_back(textEntry);
- _curScrollText++;
- } else {
- _scrollTexts.pop_back();
- _scrollTexts.push_back(textEntry);
- }
+ _visiblePlanes.clear();
+ _showList.clear();
}
-void GfxFrameout::showCurrentScrollText() {
- if (!_showScrollText || _curScrollText < 0)
+// This is what Game::restore does, only needed when our ScummVM dialogs are patched in
+// It actually does one pass before actual restore deleting screen items + planes
+// And after restore it does another pass adding screen items + planes.
+// Attention: at least Space Quest 6's option plane seems to stay in memory right from the start and is not re-created.
+void GfxFrameout::syncWithScripts(bool addElements) {
+ EngineState *engineState = g_sci->getEngineState();
+ SegManager *segMan = engineState->_segMan;
+
+ // In case original save/restore dialogs are active, don't do anything
+ if (ConfMan.getBool("originalsaveload"))
return;
- uint16 size = (uint16)_scrollTexts.size();
- if (size > 0) {
- assert(_curScrollText < size);
- ScrollTextEntry textEntry = _scrollTexts[_curScrollText];
- g_sci->_gfxText32->drawScrollTextBitmap(textEntry.kWindow, textEntry.bitmapHandle, textEntry.x, textEntry.y);
- }
-}
-
-extern void showScummVMDialog(const Common::String &message);
-
-void GfxFrameout::kernelAddPlane(reg_t object) {
- PlaneEntry newPlane;
-
- if (_planes.empty()) {
- // There has to be another way for sierra sci to do this or maybe script resolution is compiled into
- // interpreter (TODO)
- uint16 scriptWidth = readSelectorValue(_segMan, object, SELECTOR(resX));
- uint16 scriptHeight = readSelectorValue(_segMan, object, SELECTOR(resY));
-
- // Phantasmagoria 2 doesn't specify a script width/height
- if (g_sci->getGameId() == GID_PHANTASMAGORIA2) {
- scriptWidth = 640;
- scriptHeight = 480;
- }
-
- assert(scriptWidth > 0 && scriptHeight > 0);
- _coordAdjuster->setScriptsResolution(scriptWidth, scriptHeight);
- }
-
- // Import of QfG character files dialog is shown in QFG4.
- // Display additional popup information before letting user use it.
- // For the SCI0-SCI1.1 version of this, check kDrawControl().
- if (g_sci->inQfGImportRoom() && !strcmp(_segMan->getObjectName(object), "DSPlane")) {
- showScummVMDialog("Characters saved inside ScummVM are shown "
- "automatically. Character files saved in the original "
- "interpreter need to be put inside ScummVM's saved games "
- "directory and a prefix needs to be added depending on which "
- "game it was saved in: 'qfg1-' for Quest for Glory 1, 'qfg2-' "
- "for Quest for Glory 2, 'qfg3-' for Quest for Glory 3. "
- "Example: 'qfg2-thief.sav'.");
- }
-
- newPlane.object = object;
- newPlane.priority = readSelectorValue(_segMan, object, SELECTOR(priority));
- newPlane.lastPriority = -1; // hidden
- newPlane.planeOffsetX = 0;
- newPlane.planeOffsetY = 0;
- newPlane.pictureId = kPlanePlainColored;
- newPlane.planePictureMirrored = false;
- newPlane.planeBack = 0;
- _planes.push_back(newPlane);
-
- kernelUpdatePlane(object);
-}
-
-void GfxFrameout::kernelUpdatePlane(reg_t object) {
- for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); ++it) {
- if (it->object == object) {
- // Read some information
- it->priority = readSelectorValue(_segMan, object, SELECTOR(priority));
- GuiResourceId lastPictureId = it->pictureId;
- it->pictureId = readSelectorValue(_segMan, object, SELECTOR(picture));
- if (lastPictureId != it->pictureId) {
- // picture got changed, load new picture
- deletePlanePictures(object);
- // Draw the plane's picture if it's not a translucent/plane colored frame
- if ((it->pictureId != kPlanePlainColored) && (it->pictureId != kPlaneTranslucent)) {
- // SQ6 gives us a bad picture number for the control menu
- if (_resMan->testResource(ResourceId(kResourceTypePic, it->pictureId)))
- addPlanePicture(object, it->pictureId, 0);
- }
- }
- it->planeRect.top = readSelectorValue(_segMan, object, SELECTOR(top));
- it->planeRect.left = readSelectorValue(_segMan, object, SELECTOR(left));
- it->planeRect.bottom = readSelectorValue(_segMan, object, SELECTOR(bottom));
- it->planeRect.right = readSelectorValue(_segMan, object, SELECTOR(right));
-
- _coordAdjuster->fromScriptToDisplay(it->planeRect.top, it->planeRect.left);
- _coordAdjuster->fromScriptToDisplay(it->planeRect.bottom, it->planeRect.right);
-
- // We get negative left in kq7 in scrolling rooms
- if (it->planeRect.left < 0) {
- it->planeOffsetX = -it->planeRect.left;
- it->planeRect.left = 0;
- } else {
- it->planeOffsetX = 0;
- }
+ // Get planes list object
+ reg_t planesListObject = engineState->variables[VAR_GLOBAL][10];
+ reg_t planesListElements = readSelector(segMan, planesListObject, SELECTOR(elements));
- if (it->planeRect.top < 0) {
- it->planeOffsetY = -it->planeRect.top;
- it->planeRect.top = 0;
- } else {
- it->planeOffsetY = 0;
- }
+ List *planesList = segMan->lookupList(planesListElements);
+ reg_t planesNodeObject = planesList->first;
- // We get bad plane-bottom in sq6
- if (it->planeRect.right > _screen->getWidth())
- it->planeRect.right = _screen->getWidth();
- if (it->planeRect.bottom > _screen->getHeight())
- it->planeRect.bottom = _screen->getHeight();
-
- it->planeClipRect = Common::Rect(it->planeRect.width(), it->planeRect.height());
- it->upscaledPlaneRect = it->planeRect;
- it->upscaledPlaneClipRect = it->planeClipRect;
- if (_screen->getUpscaledHires()) {
- _screen->adjustToUpscaledCoordinates(it->upscaledPlaneRect.top, it->upscaledPlaneRect.left);
- _screen->adjustToUpscaledCoordinates(it->upscaledPlaneRect.bottom, it->upscaledPlaneRect.right);
- _screen->adjustToUpscaledCoordinates(it->upscaledPlaneClipRect.top, it->upscaledPlaneClipRect.left);
- _screen->adjustToUpscaledCoordinates(it->upscaledPlaneClipRect.bottom, it->upscaledPlaneClipRect.right);
- }
+ // Go through all elements of planes::elements
+ while (!planesNodeObject.isNull()) {
+ Node *planesNode = segMan->lookupNode(planesNodeObject);
+ reg_t planeObject = planesNode->value;
+
+ if (addElements) {
+ // Add this plane object
+ kernelAddPlane(planeObject);
+ }
- it->planePictureMirrored = readSelectorValue(_segMan, object, SELECTOR(mirrored));
- it->planeBack = readSelectorValue(_segMan, object, SELECTOR(back));
+ reg_t planeCastsObject = readSelector(segMan, planeObject, SELECTOR(casts));
+ reg_t setListElements = readSelector(segMan, planeCastsObject, SELECTOR(elements));
- sortPlanes();
+ // Now go through all elements of plane::casts::elements
+ List *planeCastsList = segMan->lookupList(setListElements);
+ reg_t planeCastsNodeObject = planeCastsList->first;
- // Update the items in the plane
- for (FrameoutList::iterator listIterator = _screenItems.begin(); listIterator != _screenItems.end(); listIterator++) {
- reg_t itemPlane = readSelector(_segMan, (*listIterator)->object, SELECTOR(plane));
- if (object == itemPlane) {
- kernelUpdateScreenItem((*listIterator)->object);
+ while (!planeCastsNodeObject.isNull()) {
+ Node *castsNode = segMan->lookupNode(planeCastsNodeObject);
+ reg_t castsObject = castsNode->value;
+
+ reg_t castsListElements = readSelector(segMan, castsObject, SELECTOR(elements));
+
+ List *castsList = segMan->lookupList(castsListElements);
+ reg_t castNodeObject = castsList->first;
+
+ while (!castNodeObject.isNull()) {
+ Node *castNode = segMan->lookupNode(castNodeObject);
+ reg_t castObject = castNode->value;
+
+ // read selector "-info-" of this object
+ // TODO: Seems to have been changed for SCI3
+ // Do NOT use getInfoSelector in here. SCI3 games did not use infoToa, but an actual selector.
+ // Maybe that selector is just a straight copy, but it needs to get verified/checked.
+ uint16 castInfoSelector = readSelectorValue(segMan, castObject, SELECTOR(_info_));
+
+ if (castInfoSelector & kInfoFlagViewInserted) {
+ if (addElements) {
+ // Flag set, so add this screen item
+ kernelAddScreenItem(castObject);
+ } else {
+ // Flag set, so delete this screen item
+ kernelDeleteScreenItem(castObject);
+ }
}
+
+ castNodeObject = castNode->succ;
}
- return;
+ planeCastsNodeObject = castsNode->succ;
+ }
+
+ if (!addElements) {
+ // Delete this plane object
+ kernelDeletePlane(planeObject);
}
+
+ planesNodeObject = planesNode->succ;
}
- error("kUpdatePlane called on plane that wasn't added before");
}
-void GfxFrameout::kernelDeletePlane(reg_t object) {
- deletePlaneItems(object);
- deletePlanePictures(object);
+#pragma mark -
+#pragma mark Benchmarking
- for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); ++it) {
- if (it->object == object) {
- _planes.erase(it);
- Common::Rect planeRect;
- planeRect.top = readSelectorValue(_segMan, object, SELECTOR(top));
- planeRect.left = readSelectorValue(_segMan, object, SELECTOR(left));
- planeRect.bottom = readSelectorValue(_segMan, object, SELECTOR(bottom));
- planeRect.right = readSelectorValue(_segMan, object, SELECTOR(right));
+bool GfxFrameout::checkForFred(const reg_t object) {
+ const int16 viewId = readSelectorValue(_segMan, object, SELECTOR(view));
+ const SciGameId gameId = g_sci->getGameId();
- _coordAdjuster->fromScriptToDisplay(planeRect.top, planeRect.left);
- _coordAdjuster->fromScriptToDisplay(planeRect.bottom, planeRect.right);
+ if (gameId == GID_QFG4 && viewId == 9999) {
+ return true;
+ }
- // Blackout removed plane rect
- _paint32->fillRect(planeRect, 0);
- return;
- }
+ if (gameId != GID_QFG4 && viewId == -556) {
+ return true;
}
+
+ if (Common::String(_segMan->getObjectName(object)) == "fred") {
+ return true;
+ }
+
+ return false;
}
-void GfxFrameout::addPlanePicture(reg_t object, GuiResourceId pictureId, uint16 startX, uint16 startY) {
- if (pictureId == kPlanePlainColored || pictureId == kPlaneTranslucent) // sanity check
- return;
+#pragma mark -
+#pragma mark Screen items
- PlanePictureEntry newPicture;
- newPicture.object = object;
- newPicture.pictureId = pictureId;
- newPicture.picture = new GfxPicture(_resMan, _coordAdjuster, 0, _screen, _palette, pictureId, false);
- newPicture.startX = startX;
- newPicture.startY = startY;
- newPicture.pictureCels = 0;
- _planePictures.push_back(newPicture);
+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::deletePlanePictures(reg_t object) {
- PlanePictureList::iterator it = _planePictures.begin();
+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));
+// }
- while (it != _planePictures.end()) {
- if (it->object == object || object.isNull()) {
- delete it->pictureCels;
- delete it->picture;
- it = _planePictures.erase(it);
- } else {
- ++it;
- }
+ 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);
}
-// Provides the same functionality as kGraph(DrawLine)
-reg_t GfxFrameout::addPlaneLine(reg_t object, Common::Point startPoint, Common::Point endPoint, byte color, byte priority, byte control) {
- for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); ++it) {
- if (it->object == object) {
- PlaneLineEntry line;
- line.hunkId = _segMan->allocateHunkEntry("PlaneLine()", 1); // we basically use this for a unique ID
- line.startPoint = startPoint;
- line.endPoint = endPoint;
- line.color = color;
- line.priority = priority;
- line.control = control;
- it->lines.push_back(line);
- return line.hunkId;
- }
+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();
}
+}
- return NULL_REG;
+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::updatePlaneLine(reg_t object, reg_t hunkId, Common::Point startPoint, Common::Point endPoint, byte color, byte priority, byte control) {
- // Check if we're asked to update a line that was never added
- if (hunkId.isNull())
- return;
+void GfxFrameout::kernelAddScreenItem(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 && _throttleFrameOut && checkForFred(object)) {
+ _throttleFrameOut = false;
+ }
- for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); ++it) {
- if (it->object == object) {
- for (PlaneLineList::iterator it2 = it->lines.begin(); it2 != it->lines.end(); ++it2) {
- if (it2->hunkId == hunkId) {
- it2->startPoint = startPoint;
- it2->endPoint = endPoint;
- it2->color = color;
- it2->priority = priority;
- it2->control = control;
- return;
- }
- }
- }
+ const reg_t planeObject = readSelector(_segMan, object, SELECTOR(plane));
+
+ _segMan->getObject(object)->setInfoSelectorFlag(kInfoFlagViewInserted);
+
+ Plane *plane = _planes.findByObject(planeObject);
+ if (plane == nullptr) {
+ error("kAddScreenItem: 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) {
+ screenItem->update(object);
+ } else {
+ screenItem = new ScreenItem(object);
+ plane->_screenItemList.add(screenItem);
}
}
-void GfxFrameout::deletePlaneLine(reg_t object, reg_t hunkId) {
- // Check if we're asked to delete a line that was never added (happens during the intro of LSL6)
- if (hunkId.isNull())
- return;
+void GfxFrameout::kernelUpdateScreenItem(const reg_t object) {
+ const reg_t magnifierObject = readSelector(_segMan, object, SELECTOR(magnifier));
+ if (magnifierObject.isNull()) {
+ const reg_t planeObject = readSelector(_segMan, object, SELECTOR(plane));
+ Plane *plane = _planes.findByObject(planeObject);
+ if (plane == nullptr) {
+ error("kUpdateScreenItem: Plane %04x:%04x not found for screen item %04x:%04x", PRINT_REG(planeObject), PRINT_REG(object));
+ }
- for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); ++it) {
- if (it->object == object) {
- for (PlaneLineList::iterator it2 = it->lines.begin(); it2 != it->lines.end(); ++it2) {
- if (it2->hunkId == hunkId) {
- _segMan->freeHunkEntry(hunkId);
- it2 = it->lines.erase(it2);
- return;
- }
- }
+ ScreenItem *screenItem = plane->_screenItemList.findByObject(object);
+ if (screenItem == nullptr) {
+ error("kUpdateScreenItem: Screen item %04x:%04x not found in plane %04x:%04x", PRINT_REG(object), PRINT_REG(planeObject));
}
+
+ screenItem->update(object);
+ } else {
+ 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!");
}
}
-// Adapted from GfxAnimate::applyGlobalScaling()
-void GfxFrameout::applyGlobalScaling(FrameoutEntry *itemEntry, Common::Rect planeRect, int16 celHeight) {
- // Global scaling uses global var 2 and some other stuff to calculate scaleX/scaleY
- int16 maxScale = readSelectorValue(_segMan, itemEntry->object, SELECTOR(maxScale));
- int16 maxCelHeight = (maxScale * celHeight) >> 7;
- reg_t globalVar2 = g_sci->getEngineState()->variables[VAR_GLOBAL][2]; // current room object
- int16 vanishingY = readSelectorValue(_segMan, globalVar2, SELECTOR(vanishingY));
+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;
+ }
- int16 fixedPortY = planeRect.bottom - vanishingY;
- int16 fixedEntryY = itemEntry->y - vanishingY;
- if (!fixedEntryY)
- fixedEntryY = 1;
+ _segMan->getObject(object)->clearInfoSelectorFlag(kInfoFlagViewInserted);
- if ((celHeight == 0) || (fixedPortY == 0))
- error("global scaling panic");
+ const reg_t planeObject = readSelector(_segMan, object, SELECTOR(plane));
+ Plane *plane = _planes.findByObject(planeObject);
+ if (plane == nullptr) {
+ return;
+ }
- itemEntry->scaleY = (maxCelHeight * fixedEntryY) / fixedPortY;
- itemEntry->scaleY = (itemEntry->scaleY * maxScale) / celHeight;
+ ScreenItem *screenItem = plane->_screenItemList.findByObject(object);
+ if (screenItem == nullptr) {
+ return;
+ }
- // Make sure that the calculated value is sane
- if (itemEntry->scaleY < 1 /*|| itemEntry->scaleY > 128*/)
- itemEntry->scaleY = 128;
+ deleteScreenItem(*screenItem, *plane);
+}
- itemEntry->scaleX = itemEntry->scaleY;
+#pragma mark -
+#pragma mark Planes
- // and set objects scale selectors
- //writeSelectorValue(_segMan, itemEntry->object, SELECTOR(scaleX), itemEntry->scaleX);
- //writeSelectorValue(_segMan, itemEntry->object, SELECTOR(scaleY), itemEntry->scaleY);
+void GfxFrameout::kernelAddPlane(const reg_t object) {
+ Plane *plane = _planes.findByObject(object);
+ if (plane != nullptr) {
+ plane->update(object);
+ updatePlane(*plane);
+ } else {
+ plane = new Plane(object);
+ addPlane(*plane);
+ }
}
-void GfxFrameout::kernelAddScreenItem(reg_t object) {
- // Ignore invalid items
- if (!_segMan->isObject(object)) {
- warning("kernelAddScreenItem: Attempt to add an invalid object (%04x:%04x)", PRINT_REG(object));
- return;
+void GfxFrameout::kernelUpdatePlane(const reg_t object) {
+ Plane *plane = _planes.findByObject(object);
+ if (plane == nullptr) {
+ error("kUpdatePlane: Plane %04x:%04x not found", PRINT_REG(object));
}
- FrameoutEntry *itemEntry = new FrameoutEntry();
- memset(itemEntry, 0, sizeof(FrameoutEntry));
- itemEntry->object = object;
- itemEntry->givenOrderNr = _screenItems.size();
- itemEntry->visible = true;
- _screenItems.push_back(itemEntry);
+ plane->update(object);
+ updatePlane(*plane);
+}
- kernelUpdateScreenItem(object);
+void GfxFrameout::kernelDeletePlane(const reg_t object) {
+ Plane *plane = _planes.findByObject(object);
+ if (plane == nullptr) {
+ error("kDeletePlane: Plane %04x:%04x not found", PRINT_REG(object));
+ }
+
+ if (plane->_created) {
+ // NOTE: The original engine calls some `AbortPlane` function that
+ // just ends up doing this anyway so we skip the extra indirection
+ _planes.erase(plane);
+ } else {
+ plane->_created = 0;
+ plane->_deleted = g_sci->_gfxFrameout->getScreenCount();
+ }
}
-void GfxFrameout::kernelUpdateScreenItem(reg_t object) {
- // Ignore invalid items
- if (!_segMan->isObject(object)) {
- warning("kernelUpdateScreenItem: Attempt to update an invalid object (%04x:%04x)", PRINT_REG(object));
- return;
+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));
}
- FrameoutEntry *itemEntry = findScreenItem(object);
- if (!itemEntry) {
- warning("kernelUpdateScreenItem: invalid object %04x:%04x", PRINT_REG(object));
- return;
+ 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));
}
- itemEntry->viewId = readSelectorValue(_segMan, object, SELECTOR(view));
- itemEntry->loopNo = readSelectorValue(_segMan, object, SELECTOR(loop));
- itemEntry->celNo = readSelectorValue(_segMan, object, SELECTOR(cel));
- itemEntry->x = readSelectorValue(_segMan, object, SELECTOR(x));
- itemEntry->y = readSelectorValue(_segMan, object, SELECTOR(y));
- itemEntry->z = readSelectorValue(_segMan, object, SELECTOR(z));
- itemEntry->priority = readSelectorValue(_segMan, object, SELECTOR(priority));
- if (readSelectorValue(_segMan, object, SELECTOR(fixPriority)) == 0)
- itemEntry->priority = itemEntry->y;
+ plane->scrollScreenItems(deltaX, deltaY, scrollPics);
- itemEntry->signal = readSelectorValue(_segMan, object, SELECTOR(signal));
- itemEntry->scaleSignal = readSelectorValue(_segMan, object, SELECTOR(scaleSignal));
+ for (ScreenItemList::iterator it = plane->_screenItemList.begin(); it != plane->_screenItemList.end(); ++it) {
+ ScreenItem &screenItem = **it;
- if (itemEntry->scaleSignal & kScaleSignalDoScaling32) {
- itemEntry->scaleX = readSelectorValue(_segMan, object, SELECTOR(scaleX));
- itemEntry->scaleY = readSelectorValue(_segMan, object, SELECTOR(scaleY));
+ // 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();
+}
+
+void GfxFrameout::addPlane(Plane &plane) {
+ if (_planes.findByObject(plane._object) == nullptr) {
+ plane.clipScreenRect(_screenRect);
+ _planes.add(&plane);
} else {
- itemEntry->scaleX = 128;
- itemEntry->scaleY = 128;
+ plane._deleted = 0;
+ if (plane._created == 0) {
+ plane._moved = g_sci->_gfxFrameout->getScreenCount();
+ }
+ _planes.sort();
}
- itemEntry->visible = true;
+}
+
+void GfxFrameout::updatePlane(Plane &plane) {
+ // NOTE: This assertion comes from SCI engine code.
+ assert(_planes.findByObject(plane._object) == &plane);
- // Check if the entry can be hidden
- if (lookupSelector(_segMan, object, SELECTOR(visible), NULL, NULL) != kSelectorNone)
- itemEntry->visible = readSelectorValue(_segMan, object, SELECTOR(visible));
+ Plane *visiblePlane = _visiblePlanes.findByObject(plane._object);
+ plane.sync(visiblePlane, _screenRect);
+ // NOTE: updateScreenRect was originally called a second time here,
+ // but it is already called at the end of the Plane::Update call
+ // in the original engine anyway.
+
+ _planes.sort();
}
-void GfxFrameout::kernelDeleteScreenItem(reg_t object) {
- FrameoutEntry *itemEntry = findScreenItem(object);
- // If the item could not be found, it may already have been deleted
- if (!itemEntry)
- return;
+#pragma mark -
+#pragma mark Pics
+
+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) {
+ error("kAddPicAt: Plane %04x:%04x not found", PRINT_REG(planeObject));
+ }
+ plane->addPic(pictureId, Common::Point(x, y), mirrorX);
+}
+
+#pragma mark -
+#pragma mark Rendering
+
+void GfxFrameout::frameOut(const bool shouldShowBits, const Common::Rect &eraseRect) {
+// TODO: Robot
+// if (_robot != nullptr) {
+// _robot.doRobot();
+// }
+
+ // NOTE: The original engine allocated these as static arrays of 100
+ // pointers to ScreenItemList / RectList
+ ScreenItemListList screenItemLists;
+ EraseListList eraseLists;
+
+ screenItemLists.resize(_planes.size());
+ eraseLists.resize(_planes.size());
+
+ if (g_sci->_gfxRemap32->getRemapCount() > 0 && _remapOccurred) {
+ remapMarkRedraw();
+ }
+
+ calcLists(screenItemLists, eraseLists, eraseRect);
+
+ for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) {
+ list->sort();
+ }
+
+ for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) {
+ for (DrawList::iterator drawItem = list->begin(); drawItem != list->end(); ++drawItem) {
+ (*drawItem)->screenItem->getCelObj().submitPalette();
+ }
+ }
+
+ _remapOccurred = _palette->updateForFrame();
+
+ // NOTE: SCI engine set this to false on each loop through the
+ // planelist iterator below. Since that is a waste, we only set
+ // it once.
+ _frameNowVisible = false;
+
+ for (PlaneList::size_type i = 0; i < _planes.size(); ++i) {
+ drawEraseList(eraseLists[i], *_planes[i]);
+ drawScreenItemList(screenItemLists[i]);
+ }
+
+// TODO: Robot
+// if (_robot != nullptr) {
+// _robot->frameAlmostVisible();
+// }
+
+ _palette->updateHardware(!shouldShowBits);
+
+ if (shouldShowBits) {
+ showBits();
+ }
- _screenItems.remove(itemEntry);
- delete itemEntry;
+ _frameNowVisible = true;
+
+// TODO: Robot
+// if (_robot != nullptr) {
+// robot->frameNowVisible();
+// }
}
-void GfxFrameout::deletePlaneItems(reg_t planeObject) {
- FrameoutList::iterator listIterator = _screenItems.begin();
+/**
+ * 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 splitCount = 0;
+ if (r.top < other.top) {
+ Common::Rect &t = outRects[splitCount++];
+ t = r;
+ t.bottom = other.top;
+ r.top = other.top;
+ }
+
+ if (r.bottom > other.bottom) {
+ Common::Rect &t = outRects[splitCount++];
+ t = r;
+ t.top = other.bottom;
+ r.bottom = other.bottom;
+ }
+
+ if (r.left < other.left) {
+ Common::Rect &t = outRects[splitCount++];
+ t = r;
+ t.right = other.left;
+ r.left = other.left;
+ }
+
+ if (r.right > other.right) {
+ Common::Rect &t = outRects[splitCount++];
+ t = r;
+ t.left = other.right;
+ }
- while (listIterator != _screenItems.end()) {
- bool objectMatches = false;
- if (!planeObject.isNull()) {
- reg_t itemPlane = readSelector(_segMan, (*listIterator)->object, SELECTOR(plane));
- objectMatches = (planeObject == itemPlane);
+ return splitCount;
+}
+
+/**
+ * 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 {
- objectMatches = true;
+ ++splitCount;
}
+ }
+
+ if (lowerBottom != lowerMinBottom) {
+ Common::Rect &lowerRect = outRects[splitCount];
+ lowerRect.left = lowerLeft;
+ lowerRect.top = lowerMinBottom;
+ lowerRect.right = lowerRight;
+ lowerRect.bottom = lowerBottom;
- if (objectMatches) {
- FrameoutEntry *itemEntry = *listIterator;
- listIterator = _screenItems.erase(listIterator);
- delete itemEntry;
+ // Merge lower rect into middle rect if possible
+ if (lowerRect.left == middleRect.left && lowerRect.right == middleRect.right) {
+ middleRect.bottom = lowerRect.bottom;
} else {
- ++listIterator;
+ ++splitCount;
}
}
+
+ assert(splitCount <= 2);
+ return splitCount;
}
-FrameoutEntry *GfxFrameout::findScreenItem(reg_t object) {
- for (FrameoutList::iterator listIterator = _screenItems.begin(); listIterator != _screenItems.end(); listIterator++) {
- FrameoutEntry *itemEntry = *listIterator;
- if (itemEntry->object == object)
- return itemEntry;
+// 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 addedToEraseList = false;
+ bool foundTransparentPlane = false;
+
+ if (!eraseRect.isEmpty()) {
+ addedToEraseList = true;
+ eraseList.add(eraseRect);
}
- return NULL;
-}
+ 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);
-int16 GfxFrameout::kernelGetHighPlanePri() {
- sortPlanes();
- return readSelectorValue(g_sci->getEngineState()->_segMan, _planes.back().object, SELECTOR(priority));
-}
+ // NOTE: SSCI only ever checks for kPlaneTypeTransparent here, even
+ // though kPlaneTypeTransparentPicture is also a transparent plane
+ if (outerPlane->_type == kPlaneTypeTransparent) {
+ foundTransparentPlane = true;
+ }
-void GfxFrameout::kernelAddPicAt(reg_t planeObj, GuiResourceId pictureId, int16 pictureX, int16 pictureY) {
- addPlanePicture(planeObj, pictureId, pictureX, pictureY);
-}
+ if (outerPlane->_deleted) {
+ if (visiblePlane != nullptr && !visiblePlane->_screenRect.isEmpty()) {
+ eraseList.add(visiblePlane->_screenRect);
+ addedToEraseList = true;
+ }
+ ++deletedPlaneCount;
+ } 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) {
+ eraseList.add(outRects[i]);
+ }
+ }
+ addedToEraseList = 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;
+ }
+ }
+ }
-bool sortHelper(const FrameoutEntry* entry1, const FrameoutEntry* entry2) {
- if (entry1->priority == entry2->priority) {
- if (entry1->y == entry2->y)
- return (entry1->givenOrderNr < entry2->givenOrderNr);
- return (entry1->y < entry2->y);
+ 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));
+ }
+
+ const int splitCount = splitRects(rect, innerPlane._screenRect, outRects);
+ for (int i = 0; i < splitCount; ++i) {
+ eraseList.add(outRects[i]);
+ }
+
+ eraseList.erase_at(rectIndex);
+ break;
+ }
+ }
+ }
+
+ eraseList.pack();
+ }
}
- return (entry1->priority < entry2->priority);
-}
-bool planeSortHelper(const PlaneEntry &entry1, const PlaneEntry &entry2) {
- if (entry1.priority < 0)
- return true;
+ // clean up deleted planes
+ if (deletedPlaneCount) {
+ for (int planeIndex = planeCount - 1; planeIndex >= 0; --planeIndex) {
+ Plane *plane = _planes[planeIndex];
+
+ if (plane->_deleted) {
+ --plane->_deleted;
+ if (plane->_deleted <= 0) {
+ const int visiblePlaneIndex = _visiblePlanes.findIndexByObject(plane->_object);
+ if (visiblePlaneIndex != -1) {
+ _visiblePlanes.remove_at(visiblePlaneIndex);
+ }
- if (entry2.priority < 0)
- return false;
+ _planes.remove_at(planeIndex);
+ eraseLists.remove_at(planeIndex);
+ drawLists.remove_at(planeIndex);
+ }
- return entry1.priority < entry2.priority;
-}
+ if (--deletedPlaneCount <= 0) {
+ break;
+ }
+ }
+ }
+ }
+
+ // Some planes may have been deleted, so re-retrieve count
+ planeCount = _planes.size();
+
+ 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;
+ }
-void GfxFrameout::sortPlanes() {
- // First, remove any invalid planes
- for (PlaneList::iterator it = _planes.begin(); it != _planes.end();) {
- if (!_segMan->isObject(it->object))
- it = _planes.erase(it);
- else
- it++;
+ eraseList.add(outerPlane._screenRect.findIntersectingRect(visibleOuterPlane->_screenRect));
+
+ for (int innerIndex = (int)planeCount - 1; innerIndex >= 0; --innerIndex) {
+ // "inner" just refers to the inner loop
+ 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(*eraseList[rectIndex]);
+ } else {
+ eraseLists[outerIndex].add(*eraseList[rectIndex]);
+ }
+ }
+ }
+
+ eraseList.erase_at(rectIndex);
+ } else if (splitCount != -1) {
+ for (int i = 0; i < splitCount; ++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) {
+ *eraseList[rectIndex] = outerPlane._screenRect.findIntersectingRect(innerPlane._screenRect);
+
+ if (outerPlane._priority <= innerPlane._priority) {
+ eraseLists[innerIndex].add(*eraseList[rectIndex]);
+ } else {
+ eraseLists[outerIndex].add(*eraseList[rectIndex]);
+ }
+ }
+ }
+ eraseList.erase_at(rectIndex);
+ }
+ }
+ eraseList.pack();
+ }
+ }
}
- // Sort the rest of them
- Common::sort(_planes.begin(), _planes.end(), planeSortHelper);
-}
+ for (PlaneList::size_type planeIndex = 0; planeIndex < planeCount; ++planeIndex) {
+ Plane &plane = *_planes[planeIndex];
+ Plane *visiblePlane = _visiblePlanes.findByObject(plane._object);
-void GfxFrameout::showVideo() {
- bool skipVideo = false;
- RobotDecoder *videoDecoder = g_sci->_robotDecoder;
- uint16 x = videoDecoder->getPos().x;
- uint16 y = videoDecoder->getPos().y;
- uint16 screenWidth = _screen->getWidth();
- uint16 screenHeight = _screen->getHeight();
- uint16 outputWidth;
- uint16 outputHeight;
+ 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 (videoDecoder->hasDirtyPalette())
- g_system->getPaletteManager()->setPalette(videoDecoder->getPalette(), 0, 256);
+ plane.calcLists(*visiblePlane, _planes, drawLists[planeIndex], eraseLists[planeIndex]);
+ }
+ } else {
+ plane.decrementScreenItemArrayCounts(visiblePlane, false);
+ }
- while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) {
- if (videoDecoder->needsUpdate()) {
- const Graphics::Surface *frame = videoDecoder->decodeNextFrame();
- if (frame) {
- // We need to clip here
- // At least Phantasmagoria shows a 640x390 video on a 630x450 screen during the intro
- outputWidth = frame->w > screenWidth ? screenWidth : frame->w;
- outputHeight = frame->h > screenHeight ? screenHeight : frame->h;
- g_system->copyRectToScreen(frame->getPixels(), frame->pitch, x, y, outputWidth, outputHeight);
+ 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._updated) {
+ *visiblePlane = plane;
+ --plane._updated;
+ }
+ }
- if (videoDecoder->hasDirtyPalette())
- g_system->getPaletteManager()->setPalette(videoDecoder->getPalette(), 0, 256);
+ // NOTE: SSCI only looks for kPlaneTypeTransparent, not
+ // kPlaneTypeTransparentPicture
+ if (foundTransparentPlane) {
+ 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 = (int)planeIndex - 1; i >= 0; --i) {
+ _planes[i]->filterDownEraseRects(drawLists[i], eraseLists[i], eraseLists[planeIndex]);
+ }
+
+ if (eraseLists[planeIndex].size() > 0) {
+ error("Transparent plane's erase list not absorbed");
+ }
+ }
- g_system->updateScreen();
+ for (PlaneList::size_type i = planeIndex + 1; i < planeCount; ++i) {
+ if (_planes[i]->_type == kPlaneTypeTransparent) {
+ _planes[i]->filterUpDrawRects(drawLists[i], drawLists[planeIndex]);
+ }
}
}
+ }
+}
+
+void GfxFrameout::drawEraseList(const RectList &eraseList, const Plane &plane) {
+ if (plane._type != kPlaneTypeColored) {
+ return;
+ }
- 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;
+ 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) {
+ 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);
+ const ScreenItem &screenItem = *drawItem.screenItem;
+ // TODO: Remove
+// 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) {
+ 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;
+ }
+ }
+ }
+ }
+
+ if (didMerge) {
+ showList.pack();
+ }
}
+ }
- g_system->delayMillis(10);
+ mergeList.pack();
+ for (RectList::size_type i = 0; i < mergeList.size(); ++i) {
+ showList.add(*mergeList[i]);
}
}
-void GfxFrameout::createPlaneItemList(reg_t planeObject, FrameoutList &itemList) {
- // Copy screen items of the current frame to the list of items to be drawn
- for (FrameoutList::iterator listIterator = _screenItems.begin(); listIterator != _screenItems.end(); listIterator++) {
- reg_t itemPlane = readSelector(_segMan, (*listIterator)->object, SELECTOR(plane));
- if (planeObject == itemPlane) {
- kernelUpdateScreenItem((*listIterator)->object); // TODO: Why is this necessary?
- itemList.push_back(*listIterator);
+void GfxFrameout::palMorphFrameOut(const int8 *styleRanges, const ShowStyleEntry *showStyle) {
+ Palette sourcePalette(_palette->getNextPalette());
+ alterVmap(sourcePalette, sourcePalette, -1, styleRanges);
+
+ int16 prevRoom = g_sci->getEngineState()->variables[VAR_GLOBAL][12].toSint16();
+
+ Common::Rect rect(_screen->getDisplayWidth(), _screen->getDisplayHeight());
+ _showList.add(rect);
+ showBits();
+
+ // NOTE: The original engine allocated these as static arrays of 100
+ // pointers to ScreenItemList / RectList
+ ScreenItemListList screenItemLists;
+ EraseListList eraseLists;
+
+ screenItemLists.resize(_planes.size());
+ eraseLists.resize(_planes.size());
+
+ if (g_sci->_gfxRemap32->getRemapCount() > 0 && _remapOccurred) {
+ remapMarkRedraw();
+ }
+
+ calcLists(screenItemLists, eraseLists);
+ for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) {
+ list->sort();
+ }
+
+ for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) {
+ for (DrawList::iterator drawItem = list->begin(); drawItem != list->end(); ++drawItem) {
+ (*drawItem)->screenItem->getCelObj().submitPalette();
}
}
- for (PlanePictureList::iterator pictureIt = _planePictures.begin(); pictureIt != _planePictures.end(); pictureIt++) {
- if (pictureIt->object == planeObject) {
- GfxPicture *planePicture = pictureIt->picture;
- // Allocate memory for picture cels
- pictureIt->pictureCels = new FrameoutEntry[planePicture->getSci32celCount()];
+ _remapOccurred = _palette->updateForFrame();
+ _frameNowVisible = false;
- // Add following cels to the itemlist
- FrameoutEntry *picEntry = pictureIt->pictureCels;
- int planePictureCels = planePicture->getSci32celCount();
- for (int pictureCelNr = 0; pictureCelNr < planePictureCels; pictureCelNr++) {
- picEntry->celNo = pictureCelNr;
- picEntry->object = NULL_REG;
- picEntry->picture = planePicture;
- picEntry->y = planePicture->getSci32celY(pictureCelNr);
- picEntry->x = planePicture->getSci32celX(pictureCelNr);
- picEntry->picStartX = pictureIt->startX;
- picEntry->picStartY = pictureIt->startY;
- picEntry->visible = true;
+ for (PlaneList::size_type i = 0; i < _planes.size(); ++i) {
+ drawEraseList(eraseLists[i], *_planes[i]);
+ drawScreenItemList(screenItemLists[i]);
+ }
- picEntry->priority = planePicture->getSci32celPriority(pictureCelNr);
+ Palette nextPalette(_palette->getNextPalette());
- itemList.push_back(picEntry);
- picEntry++;
+ 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];
+ sourcePalette.colors[i].used = true;
+ }
+ }
+ } 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;
}
}
}
- // Now sort our itemlist
- Common::sort(itemList.begin(), itemList.end(), sortHelper);
+ _palette->submit(sourcePalette);
+ _palette->updateFFrame();
+ _palette->updateHardware();
+ alterVmap(nextPalette, sourcePalette, 1, _styleRanges);
+
+ if (showStyle && showStyle->type != kShowStyleUnknown) {
+// TODO: SCI2.1mid transition effects
+// processEffects();
+ warning("Transition %d not implemented!", showStyle->type);
+ } else {
+ showBits();
+ }
+
+ _frameNowVisible = true;
+
+ for (PlaneList::iterator plane = _planes.begin(); plane != _planes.end(); ++plane) {
+ (*plane)->_redrawAllCount = getScreenCount();
+ }
+
+ if (g_sci->_gfxRemap32->getRemapCount() > 0 && _remapOccurred) {
+ remapMarkRedraw();
+ }
+
+ calcLists(screenItemLists, eraseLists);
+ for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) {
+ list->sort();
+ }
+
+ for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) {
+ for (DrawList::iterator drawItem = list->begin(); drawItem != list->end(); ++drawItem) {
+ (*drawItem)->screenItem->getCelObj().submitPalette();
+ }
+ }
+
+ _remapOccurred = _palette->updateForFrame();
+ // NOTE: During this second loop, `_frameNowVisible = false` is
+ // inside the next loop in SCI2.1mid
+ _frameNowVisible = false;
+
+ for (PlaneList::size_type i = 0; i < _planes.size(); ++i) {
+ drawEraseList(eraseLists[i], *_planes[i]);
+ drawScreenItemList(screenItemLists[i]);
+ }
+
+ _palette->submit(nextPalette);
+ _palette->updateFFrame();
+ _palette->updateHardware(false);
+ showBits();
+
+ _frameNowVisible = true;
}
-bool GfxFrameout::isPictureOutOfView(FrameoutEntry *itemEntry, Common::Rect planeRect, int16 planeOffsetX, int16 planeOffsetY) {
- // Out of view horizontally (sanity checks)
- int16 pictureCelStartX = itemEntry->picStartX + itemEntry->x;
- int16 pictureCelEndX = pictureCelStartX + itemEntry->picture->getSci32celWidth(itemEntry->celNo);
- int16 planeStartX = planeOffsetX;
- int16 planeEndX = planeStartX + planeRect.width();
- if (pictureCelEndX < planeStartX)
- return true;
- if (pictureCelStartX > planeEndX)
- return true;
+void GfxFrameout::showBits() {
+ for (RectList::const_iterator rect = _showList.begin(); rect != _showList.end(); ++rect) {
+ Common::Rect rounded(**rect);
+ // NOTE: SCI engine used BR-inclusive rects so used slightly
+ // different masking here to ensure that the width of rects
+ // was always even.
+ rounded.left &= ~1;
+ rounded.right = (rounded.right + 1) & ~1;
+
+ // TODO:
+ // _cursor->GonnaPaint(rounded);
+ }
- // Out of view vertically (sanity checks)
- int16 pictureCelStartY = itemEntry->picStartY + itemEntry->y;
- int16 pictureCelEndY = pictureCelStartY + itemEntry->picture->getSci32celHeight(itemEntry->celNo);
- int16 planeStartY = planeOffsetY;
- int16 planeEndY = planeStartY + planeRect.height();
- if (pictureCelEndY < planeStartY)
- return true;
- if (pictureCelStartY > planeEndY)
- return true;
+ // TODO:
+ // _cursor->PaintStarting();
- return false;
+ for (RectList::const_iterator rect = _showList.begin(); rect != _showList.end(); ++rect) {
+ Common::Rect rounded(**rect);
+ // NOTE: SCI engine used BR-inclusive rects so used slightly
+ // different masking here to ensure that the width of rects
+ // was always even.
+ rounded.left &= ~1;
+ rounded.right = (rounded.right + 1) & ~1;
+
+ byte *sourceBuffer = (byte *)_currentBuffer.getPixels() + rounded.top * _currentBuffer.screenWidth + rounded.left;
+
+ g_system->copyRectToScreen(sourceBuffer, _currentBuffer.screenWidth, rounded.left, rounded.top, rounded.width(), rounded.height());
+ }
+
+ // TODO:
+ // _cursor->DonePainting();
+
+ _showList.clear();
}
-void GfxFrameout::drawPicture(FrameoutEntry *itemEntry, int16 planeOffsetX, int16 planeOffsetY, bool planePictureMirrored) {
- int16 pictureOffsetX = planeOffsetX;
- int16 pictureX = itemEntry->x;
- if ((planeOffsetX) || (itemEntry->picStartX)) {
- if (planeOffsetX <= itemEntry->picStartX) {
- pictureX += itemEntry->picStartX - planeOffsetX;
- pictureOffsetX = 0;
- } else {
- pictureOffsetX = planeOffsetX - itemEntry->picStartX;
+void GfxFrameout::alterVmap(const Palette &palette1, const Palette &palette2, const int8 style, const int8 *const styleRanges) {
+ uint8 clut[256];
+
+ for (int paletteIndex = 0; paletteIndex < ARRAYSIZE(palette1.colors); ++paletteIndex) {
+ int outerR = palette1.colors[paletteIndex].r;
+ int outerG = palette1.colors[paletteIndex].g;
+ int outerB = palette1.colors[paletteIndex].b;
+
+ if (styleRanges[paletteIndex] == style) {
+ int minDiff = 262140;
+ int minDiffIndex = paletteIndex;
+
+ for (int i = 0; i < 236; ++i) {
+ if (styleRanges[i] != style) {
+ int r = palette1.colors[i].r;
+ int g = palette1.colors[i].g;
+ int b = palette1.colors[i].b;
+ int diffSquared = (outerR - r) * (outerR - r) + (outerG - g) * (outerG - g) + (outerB - b) * (outerB - b);
+ if (diffSquared < minDiff) {
+ minDiff = diffSquared;
+ minDiffIndex = i;
+ }
+ }
+ }
+
+ clut[paletteIndex] = minDiffIndex;
}
- }
- int16 pictureOffsetY = planeOffsetY;
- int16 pictureY = itemEntry->y;
- if ((planeOffsetY) || (itemEntry->picStartY)) {
- if (planeOffsetY <= itemEntry->picStartY) {
- pictureY += itemEntry->picStartY - planeOffsetY;
- pictureOffsetY = 0;
- } else {
- pictureOffsetY = planeOffsetY - itemEntry->picStartY;
+ if (style == 1 && styleRanges[paletteIndex] == 0) {
+ int minDiff = 262140;
+ int minDiffIndex = paletteIndex;
+
+ for (int i = 0; i < 236; ++i) {
+ int r = palette2.colors[i].r;
+ int g = palette2.colors[i].g;
+ int b = palette2.colors[i].b;
+
+ int diffSquared = (outerR - r) * (outerR - r) + (outerG - g) * (outerG - g) + (outerB - b) * (outerB - b);
+ if (diffSquared < minDiff) {
+ minDiff = diffSquared;
+ minDiffIndex = i;
+ }
+ }
+
+ clut[paletteIndex] = minDiffIndex;
}
}
- itemEntry->picture->drawSci32Vga(itemEntry->celNo, pictureX, itemEntry->y, pictureOffsetX, pictureOffsetY, planePictureMirrored);
- // warning("picture cel %d %d", itemEntry->celNo, itemEntry->priority);
+ // NOTE: This is currBuffer->ptr in SCI engine
+ byte *pixels = (byte *)_currentBuffer.getPixels();
+
+ 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];
+ // 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 (
+ (styleRangeValue == 1 && styleRangeValue == style) ||
+ (styleRangeValue == 0 && style == 1)
+ ) {
+ pixels[pixelIndex] = clut[currentValue];
+ }
+ }
}
-void GfxFrameout::kernelFrameout() {
- if (g_sci->_robotDecoder->isVideoLoaded()) {
- showVideo();
+void GfxFrameout::kernelSetPalStyleRange(const uint8 fromColor, const uint8 toColor) {
+ if (toColor > fromColor) {
return;
}
- _palette->palVaryUpdate();
-
- for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); it++) {
- reg_t planeObject = it->object;
+ for (int i = fromColor; i < toColor; ++i) {
+ _styleRanges[i] = 0;
+ }
+}
- // Draw any plane lines, if they exist
- // These are drawn on invisible planes as well. (e.g. "invisiblePlane" in LSL6 hires)
- // FIXME: Lines aren't always drawn (e.g. when the narrator speaks in LSL6 hires).
- // Perhaps something is painted over them?
- for (PlaneLineList::iterator it2 = it->lines.begin(); it2 != it->lines.end(); ++it2) {
- Common::Point startPoint = it2->startPoint;
- Common::Point endPoint = it2->endPoint;
- _coordAdjuster->kernelLocalToGlobal(startPoint.x, startPoint.y, it->object);
- _coordAdjuster->kernelLocalToGlobal(endPoint.x, endPoint.y, it->object);
- _screen->drawLine(startPoint, endPoint, it2->color, it2->priority, it2->control);
+inline ShowStyleEntry * GfxFrameout::findShowStyleForPlane(const reg_t planeObj) const {
+ ShowStyleEntry *entry = _showStyles;
+ while (entry != nullptr) {
+ if (entry->plane == planeObj) {
+ break;
}
+ entry = entry->next;
+ }
- int16 planeLastPriority = it->lastPriority;
+ return entry;
+}
- // Update priority here, sq6 sets it w/o UpdatePlane
- int16 planePriority = it->priority = readSelectorValue(_segMan, planeObject, SELECTOR(priority));
+inline ShowStyleEntry *GfxFrameout::deleteShowStyleInternal(ShowStyleEntry *const showStyle) {
+ ShowStyleEntry *lastEntry = nullptr;
- it->lastPriority = planePriority;
- if (planePriority < 0) { // Plane currently not meant to be shown
- // If plane was shown before, delete plane rect
- if (planePriority != planeLastPriority)
- _paint32->fillRect(it->planeRect, 0);
- continue;
+ for (ShowStyleEntry *testEntry = _showStyles; testEntry != nullptr; testEntry = testEntry->next) {
+ if (testEntry == showStyle) {
+ break;
}
+ lastEntry = testEntry;
+ }
- // There is a race condition lurking in SQ6, which causes the game to hang in the intro, when teleporting to Polysorbate LX.
- // Since I first wrote the patch, the race has stopped occurring for me though.
- // I'll leave this for investigation later, when someone can reproduce.
- //if (it->pictureId == kPlanePlainColored) // FIXME: This is what SSCI does, and fixes the intro of LSL7, but breaks the dialogs in GK1 (adds black boxes)
- if (it->pictureId == kPlanePlainColored && (it->planeBack || g_sci->getGameId() != GID_GK1))
- _paint32->fillRect(it->planeRect, it->planeBack);
+ if (lastEntry == nullptr) {
+ _showStyles = showStyle->next;
+ lastEntry = _showStyles;
+ } else {
+ lastEntry->next = showStyle->next;
+ }
- _coordAdjuster->pictureSetDisplayArea(it->planeRect);
- // Invoking drewPicture() with an invalid picture ID in SCI32 results in
- // invalidating the palVary palette when a palVary effect is active. This
- // is quite obvious in QFG4, where the day time palette is incorrectly
- // shown when exiting the caves, and the correct night time palette
- // flashes briefly each time that kPalVaryInit is called.
- if (it->pictureId != 0xFFFF)
- _palette->drewPicture(it->pictureId);
+ delete[] showStyle->fadeColorRanges;
+ delete showStyle;
- FrameoutList itemList;
+ // TODO: Verify that this is the correct entry to return
+ // for the loop in processShowStyles to work correctly
+ return lastEntry;
+}
- createPlaneItemList(planeObject, itemList);
+// TODO: 10-argument version is only in SCI3; argc checks are currently wrong for this version
+// 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, reg_t pFadeArray, int16 divisions, const int16 blackScreen) {
+
+ bool hasDivisions = false;
+ bool hasFadeArray = false;
+
+ // 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) {
+ hasDivisions = argc > 8;
+ hasFadeArray = argc > 7;
+ } else {
+ hasDivisions = argc > 9;
+ hasFadeArray = argc > 8;
+ }
- for (FrameoutList::iterator listIterator = itemList.begin(); listIterator != itemList.end(); listIterator++) {
- FrameoutEntry *itemEntry = *listIterator;
+ bool isFadeUp;
+ int16 color;
+ if (back != -1) {
+ isFadeUp = false;
+ color = back;
+ } else {
+ isFadeUp = true;
+ color = 0;
+ }
- if (!itemEntry->visible)
- continue;
+ if ((getSciVersion() < SCI_VERSION_2_1_MIDDLE && type == 15) || type > 15) {
+ error("Illegal show style %d for plane %04x:%04x", type, PRINT_REG(planeObj));
+ }
- if (itemEntry->object.isNull()) {
- // Picture cel data
- _coordAdjuster->fromScriptToDisplay(itemEntry->y, itemEntry->x);
- _coordAdjuster->fromScriptToDisplay(itemEntry->picStartY, itemEntry->picStartX);
+ Plane *plane = _planes.findByObject(planeObj);
+ if (plane == nullptr) {
+ error("Plane %04x:%04x is not present in active planes list", PRINT_REG(planeObj));
+ }
- if (!isPictureOutOfView(itemEntry, it->planeRect, it->planeOffsetX, it->planeOffsetY))
- drawPicture(itemEntry, it->planeOffsetX, it->planeOffsetY, it->planePictureMirrored);
- } else {
- GfxView *view = (itemEntry->viewId != 0xFFFF) ? _cache->getView(itemEntry->viewId) : NULL;
- int16 dummyX = 0;
-
- if (view && view->isSci2Hires()) {
- view->adjustToUpscaledCoordinates(itemEntry->y, itemEntry->x);
- view->adjustToUpscaledCoordinates(itemEntry->z, dummyX);
- } else if (getSciVersion() >= SCI_VERSION_2_1) {
- _coordAdjuster->fromScriptToDisplay(itemEntry->y, itemEntry->x);
- _coordAdjuster->fromScriptToDisplay(itemEntry->z, dummyX);
- }
+ bool createNewEntry = true;
+ ShowStyleEntry *entry = findShowStyleForPlane(planeObj);
+ if (entry != nullptr) {
+ // TODO: SCI2.1early has different criteria for show style reuse
+ bool useExisting = true;
- // Adjust according to current scroll position
- itemEntry->x -= it->planeOffsetX;
- itemEntry->y -= it->planeOffsetY;
-
- uint16 useInsetRect = readSelectorValue(_segMan, itemEntry->object, SELECTOR(useInsetRect));
- if (useInsetRect) {
- itemEntry->celRect.top = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inTop));
- itemEntry->celRect.left = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inLeft));
- itemEntry->celRect.bottom = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inBottom));
- itemEntry->celRect.right = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inRight));
- if (view && view->isSci2Hires()) {
- view->adjustToUpscaledCoordinates(itemEntry->celRect.top, itemEntry->celRect.left);
- view->adjustToUpscaledCoordinates(itemEntry->celRect.bottom, itemEntry->celRect.right);
- }
- itemEntry->celRect.translate(itemEntry->x, itemEntry->y);
- // TODO: maybe we should clip the cels rect with this, i'm not sure
- // the only currently known usage is game menu of gk1
- } else if (view) {
- // Process global scaling, if needed.
- // TODO: Seems like SCI32 always processes global scaling for scaled objects
- // TODO: We can only process symmetrical scaling for now (i.e. same value for scaleX/scaleY)
- if ((itemEntry->scaleSignal & kScaleSignalDoScaling32) &&
- !(itemEntry->scaleSignal & kScaleSignalDisableGlobalScaling32) &&
- (itemEntry->scaleX == itemEntry->scaleY) &&
- itemEntry->scaleX != 128)
- applyGlobalScaling(itemEntry, it->planeRect, view->getHeight(itemEntry->loopNo, itemEntry->celNo));
-
- if ((itemEntry->scaleX == 128) && (itemEntry->scaleY == 128))
- view->getCelRect(itemEntry->loopNo, itemEntry->celNo,
- itemEntry->x, itemEntry->y, itemEntry->z, itemEntry->celRect);
- else
- view->getCelScaledRect(itemEntry->loopNo, itemEntry->celNo,
- itemEntry->x, itemEntry->y, itemEntry->z, itemEntry->scaleX,
- itemEntry->scaleY, itemEntry->celRect);
-
- Common::Rect nsRect = itemEntry->celRect;
- // Translate back to actual coordinate within scrollable plane
- nsRect.translate(it->planeOffsetX, it->planeOffsetY);
-
- if (g_sci->getGameId() == GID_PHANTASMAGORIA2) {
- // HACK: Some (?) objects in Phantasmagoria 2 have no NS rect. Skip them for now.
- // TODO: Remove once we figure out how Phantasmagoria 2 draws objects on screen.
- if (lookupSelector(_segMan, itemEntry->object, SELECTOR(nsLeft), NULL, NULL) != kSelectorVariable)
- continue;
- }
+ if (useExisting) {
+ useExisting = entry->divisions == (hasDivisions ? divisions : _defaultDivisions[type]) && entry->unknownC == _defaultUnknownC[type];
+ }
- if (view && view->isSci2Hires()) {
- view->adjustBackUpscaledCoordinates(nsRect.top, nsRect.left);
- view->adjustBackUpscaledCoordinates(nsRect.bottom, nsRect.right);
- g_sci->_gfxCompare->setNSRect(itemEntry->object, nsRect);
- } else if (getSciVersion() >= SCI_VERSION_2_1 && _resMan->detectHires()) {
- _coordAdjuster->fromDisplayToScript(nsRect.top, nsRect.left);
- _coordAdjuster->fromDisplayToScript(nsRect.bottom, nsRect.right);
- g_sci->_gfxCompare->setNSRect(itemEntry->object, nsRect);
- }
+ if (useExisting) {
+ createNewEntry = false;
+ isFadeUp = true;
+ entry->currentStep = 0;
+ } else {
+ isFadeUp = true;
+ color = entry->color;
+ deleteShowStyleInternal(entry/*, true*/);
+ entry = nullptr;
+ }
+ }
- // TODO: For some reason, the top left nsRect coordinates get
- // swapped in the GK1 inventory screen, investigate why.
- // This is also needed for GK1 rooms 710 and 720 (catacombs, inner and
- // outer circle), for handling the tiles and talking to Wolfgang.
- // HACK: Fix the coordinates by explicitly setting them here for GK1.
- // Also check bug #6729, for another case where this is needed.
- if (g_sci->getGameId() == GID_GK1)
- g_sci->_gfxCompare->setNSRect(itemEntry->object, nsRect);
+ if (type > 0) {
+ if (createNewEntry) {
+ entry = new ShowStyleEntry;
+ // NOTE: SCI2.1 engine tests if allocation returned a null pointer
+ // but then only avoids setting currentStep if this is so. Since
+ // this is a nonsensical approach, we do not do that here
+ entry->currentStep = 0;
+ entry->unknownC = _defaultUnknownC[type];
+ entry->processed = false;
+ entry->divisions = hasDivisions ? divisions : _defaultDivisions[type];
+ entry->plane = planeObj;
+
+ 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;
+ }
+ }
- // Don't attempt to draw sprites that are outside the visible
- // screen area. An example is the random people walking in
- // Jackson Square in GK1.
- if (itemEntry->celRect.bottom < 0 || itemEntry->celRect.top >= _screen->getDisplayHeight() ||
- itemEntry->celRect.right < 0 || itemEntry->celRect.left >= _screen->getDisplayWidth())
- continue;
-
- Common::Rect clipRect, translatedClipRect;
- clipRect = itemEntry->celRect;
-
- if (view && view->isSci2Hires()) {
- clipRect.clip(it->upscaledPlaneClipRect);
- translatedClipRect = clipRect;
- translatedClipRect.translate(it->upscaledPlaneRect.left, it->upscaledPlaneRect.top);
- } else {
- // QFG4 passes invalid rectangles when a battle is starting
- if (!clipRect.isValidRect())
- continue;
- clipRect.clip(it->planeClipRect);
- translatedClipRect = clipRect;
- translatedClipRect.translate(it->planeRect.left, it->planeRect.top);
- }
+ // NOTE: The original engine had no nullptr check and would just crash
+ // if it got to here
+ if (entry == nullptr) {
+ error("Cannot edit non-existing ShowStyle entry");
+ }
+
+ entry->fadeUp = isFadeUp;
+ entry->color = color;
+ entry->nextTick = g_sci->getTickCount();
+ entry->type = type;
+ entry->animate = animate;
+ entry->delay = (seconds * 60 + entry->divisions - 1) / entry->divisions;
+
+ if (entry->delay == 0) {
+ if (entry->fadeColorRanges != nullptr) {
+ delete[] entry->fadeColorRanges;
+ }
+ delete entry;
+ error("ShowStyle has no duration");
+ }
- if (view) {
- if (!clipRect.isEmpty()) {
- if ((itemEntry->scaleX == 128) && (itemEntry->scaleY == 128))
- view->draw(itemEntry->celRect, clipRect, translatedClipRect,
- itemEntry->loopNo, itemEntry->celNo, 255, 0, view->isSci2Hires());
- else
- view->drawScaled(itemEntry->celRect, clipRect, translatedClipRect,
- itemEntry->loopNo, itemEntry->celNo, 255, itemEntry->scaleX, itemEntry->scaleY);
+ if (frameOutNow) {
+ Common::Rect frameOutRect(0, 0);
+ frameOut(false, frameOutRect);
+ }
+
+ if (createNewEntry) {
+ // TODO: Implement SCI2.1early and SCI3
+ entry->next = _showStyles;
+ _showStyles = entry;
+ }
+ }
+}
+
+// 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
+// SCI3 implements 0, 1/3/5/7/9, 2/4/6/8/10, 11, 12/15, 13, 14
+// TODO: Sierra code needs to be replaced with code that uses the
+// computed entry->delay property instead of just counting divisors,
+// as the latter is machine-speed-dependent and leads to wrong
+// transition speeds
+void GfxFrameout::processShowStyles() {
+ uint32 now = g_sci->getTickCount();
+
+ bool continueProcessing;
+
+ // TODO: Change to bool? Engine uses inc to set the value to true,
+ // but there does not seem to be any reason to actually count how
+ // many times it was set
+ int doFrameOut;
+ do {
+ continueProcessing = false;
+ doFrameOut = 0;
+ ShowStyleEntry *showStyle = _showStyles;
+ while (showStyle != nullptr) {
+ bool retval = false;
+
+ if (!showStyle->animate) {
+ ++doFrameOut;
+ }
+
+ if (showStyle->nextTick < now || !showStyle->animate) {
+ // TODO: Different versions of SCI use different processors!
+ // This is the SQ6/KQ7/SCI2.1mid table.
+ switch (showStyle->type) {
+ case kShowStyleNone: {
+ retval = processShowStyleNone(showStyle);
+ break;
+ }
+ case kShowStyleHShutterOut:
+ case kShowStyleVShutterOut:
+ case kShowStyleWipeLeft:
+ case kShowStyleWipeUp:
+ case kShowStyleIrisOut:
+ case kShowStyleHShutterIn:
+ case kShowStyleVShutterIn:
+ case kShowStyleWipeRight:
+ case kShowStyleWipeDown:
+ case kShowStyleIrisIn:
+ case kShowStyle11:
+ case kShowStyle12:
+ case kShowStyleUnknown: {
+ retval = processShowStyleMorph(showStyle);
+ break;
+ }
+ case kShowStyleFadeOut: {
+ retval = processShowStyleFade(-1, showStyle);
+ break;
+ }
+ case kShowStyleFadeIn: {
+ retval = processShowStyleFade(1, showStyle);
+ break;
}
}
+ }
- // Draw text, if it exists
- if (lookupSelector(_segMan, itemEntry->object, SELECTOR(text), NULL, NULL) == kSelectorVariable) {
- g_sci->_gfxText32->drawTextBitmap(itemEntry->x, itemEntry->y, it->planeRect, itemEntry->object);
- }
+ if (!retval) {
+ continueProcessing = true;
}
+
+ if (retval && showStyle->processed) {
+ showStyle = deleteShowStyleInternal(showStyle);
+ } else {
+ showStyle = showStyle->next;
+ }
+ }
+
+ if (g_engine->shouldQuit()) {
+ return;
+ }
+
+ if (doFrameOut) {
+ 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);
+}
+
+bool GfxFrameout::processShowStyleNone(ShowStyleEntry *const showStyle) {
+ if (showStyle->fadeUp) {
+ _palette->setFade(100, 0, 255);
+ } else {
+ _palette->setFade(0, 0, 255);
+ }
+
+ showStyle->processed = true;
+ return true;
+}
+
+bool GfxFrameout::processShowStyleMorph(ShowStyleEntry *const showStyle) {
+ palMorphFrameOut(_styleRanges, showStyle);
+ showStyle->processed = true;
+ return true;
+}
+
+// TODO: Normalise use of 'entry' vs 'showStyle'
+bool GfxFrameout::processShowStyleFade(const int direction, ShowStyleEntry *const showStyle) {
+ bool unchanged = true;
+ if (showStyle->currentStep < showStyle->divisions) {
+ int percent;
+ if (direction <= 0) {
+ percent = showStyle->divisions - showStyle->currentStep - 1;
+ } else {
+ percent = showStyle->currentStep;
}
- for (PlanePictureList::iterator pictureIt = _planePictures.begin(); pictureIt != _planePictures.end(); pictureIt++) {
- if (pictureIt->object == planeObject) {
- delete[] pictureIt->pictureCels;
- pictureIt->pictureCels = 0;
+ percent *= 100;
+ percent /= showStyle->divisions - 1;
+
+ if (showStyle->fadeColorRangesCount > 0) {
+ for (int i = 0, len = showStyle->fadeColorRangesCount; i < len; i += 2) {
+ _palette->setFade(percent, showStyle->fadeColorRanges[i], showStyle->fadeColorRanges[i + 1]);
}
+ } else {
+ _palette->setFade(percent, 0, 255);
}
+
+ ++showStyle->currentStep;
+ showStyle->nextTick += showStyle->delay;
+ unchanged = false;
}
- showCurrentScrollText();
+ if (showStyle->currentStep >= showStyle->divisions && unchanged) {
+ if (direction > 0) {
+ showStyle->processed = true;
+ }
- _screen->copyToScreen();
+ return true;
+ }
- g_sci->getEngineState()->_throttleTrigger = true;
+ return false;
}
-void GfxFrameout::printPlaneList(Console *con) {
- for (PlaneList::const_iterator it = _planes.begin(); it != _planes.end(); ++it) {
- PlaneEntry p = *it;
- Common::String curPlaneName = _segMan->getObjectName(p.object);
- Common::Rect r = p.upscaledPlaneRect;
- Common::Rect cr = p.upscaledPlaneClipRect;
-
- con->debugPrintf("%04x:%04x (%s): prio %d, lastprio %d, offsetX %d, offsetY %d, pic %d, mirror %d, back %d\n",
- PRINT_REG(p.object), curPlaneName.c_str(),
- (int16)p.priority, (int16)p.lastPriority,
- p.planeOffsetX, p.planeOffsetY, p.pictureId,
- p.planePictureMirrored, p.planeBack);
- con->debugPrintf(" rect: (%d, %d, %d, %d), clip rect: (%d, %d, %d, %d)\n",
- r.left, r.top, r.right, r.bottom,
- cr.left, cr.top, cr.right, cr.bottom);
-
- if (p.pictureId != 0xffff && p.pictureId != 0xfffe) {
- con->debugPrintf("Pictures:\n");
-
- for (PlanePictureList::iterator pictureIt = _planePictures.begin(); pictureIt != _planePictures.end(); pictureIt++) {
- if (pictureIt->object == p.object) {
- con->debugPrintf(" Picture %d: x %d, y %d\n", pictureIt->pictureId, pictureIt->startX, pictureIt->startY);
- }
- }
+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();
+// }
+
+ frameOut(shouldShowBits);
+ }
+
+ throttle();
+}
+
+void GfxFrameout::throttle() {
+ if (_throttleFrameOut) {
+ uint8 throttleTime;
+ if (_throttleState == 2) {
+ throttleTime = 17;
+ _throttleState = 0;
+ } else {
+ throttleTime = 16;
+ ++_throttleState;
}
+
+ g_sci->getEngineState()->speedThrottler(throttleTime);
+ g_sci->getEngineState()->_throttleTrigger = true;
+ }
+}
+
+#pragma mark -
+#pragma mark Mouse cursor
+
+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);
+ }
+
+ 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));
}
-void GfxFrameout::printPlaneItemList(Console *con, reg_t planeObject) {
- for (FrameoutList::iterator listIterator = _screenItems.begin(); listIterator != _screenItems.end(); listIterator++) {
- FrameoutEntry *e = *listIterator;
- reg_t itemPlane = readSelector(_segMan, e->object, SELECTOR(plane));
+bool GfxFrameout::isOnMe(const ScreenItem &screenItem, const Plane &plane, const Common::Point &position, const bool checkPixel) const {
- if (planeObject == itemPlane) {
- Common::String curItemName = _segMan->getObjectName(e->object);
- Common::Rect icr = e->celRect;
- GuiResourceId picId = e->picture ? e->picture->getResourceId() : 0;
+ 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 (!screenItem._screenRect.contains(scaledPosition)) {
+ return false;
+ }
- con->debugPrintf("%d: %04x:%04x (%s), view %d, loop %d, cel %d, x %d, y %d, z %d, "
- "signal %d, scale signal %d, scaleX %d, scaleY %d, rect (%d, %d, %d, %d), "
- "pic %d, picX %d, picY %d, visible %d\n",
- e->givenOrderNr, PRINT_REG(e->object), curItemName.c_str(),
- e->viewId, e->loopNo, e->celNo, e->x, e->y, e->z,
- e->signal, e->scaleSignal, e->scaleX, e->scaleY,
- icr.left, icr.top, icr.right, icr.bottom,
- picId, e->picStartX, e->picStartY, e->visible);
+ if (checkPixel) {
+ CelObj &celObj = screenItem.getCelObj();
+
+ bool mirrorX = screenItem._mirrorX ^ celObj._mirrorX;
+
+ scaledPosition.x -= screenItem._scaledPosition.x;
+ scaledPosition.y -= screenItem._scaledPosition.y;
+
+ mulru(scaledPosition, Ratio(celObj._scaledWidth, _currentBuffer.screenWidth), Ratio(celObj._scaledHeight, _currentBuffer.screenHeight));
+
+ 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;
}
+
+ uint8 pixel = celObj.readPixel(scaledPosition.x, scaledPosition.y, mirrorX);
+ return pixel != celObj._transparentColor;
+ }
+
+ return true;
+}
+
+void GfxFrameout::kernelSetNowSeen(const reg_t screenItemObject) const {
+ const reg_t planeObject = readSelector(_segMan, screenItemObject, SELECTOR(plane));
+
+ 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 *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));
+ }
+
+ 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);
+}
+
+void GfxFrameout::remapMarkRedraw() {
+ for (PlaneList::const_iterator it = _planes.begin(); it != _planes.end(); ++it) {
+ Plane *p = *it;
+ p->remapMarkRedraw();
+ }
+}
+
+#pragma mark -
+#pragma mark Debugging
+
+void GfxFrameout::printPlaneListInternal(Console *con, const PlaneList &planeList) const {
+ for (PlaneList::const_iterator it = planeList.begin(); it != planeList.end(); ++it) {
+ Plane *p = *it;
+ p->printDebugInfo(con);
}
}
+void GfxFrameout::printPlaneList(Console *con) const {
+ printPlaneListInternal(con, _planes);
+}
+
+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);
+
+ if (p == nullptr) {
+ con->debugPrintf("Plane does not exist");
+ return;
+ }
+
+ 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 e0c60f92c1..99658ede6a 100644
--- a/engines/sci/graphics/frameout.h
+++ b/engines/sci/graphics/frameout.h
@@ -23,157 +23,488 @@
#ifndef SCI_GRAPHICS_FRAMEOUT_H
#define SCI_GRAPHICS_FRAMEOUT_H
-namespace Sci {
+#include "sci/graphics/plane32.h"
+#include "sci/graphics/screen_item32.h"
-class GfxPicture;
+namespace Sci {
+// TODO: Don't do this this way
+int splitRects(Common::Rect r, const Common::Rect &other, Common::Rect(&outRects)[4]);
-struct PlaneLineEntry {
- reg_t hunkId;
- Common::Point startPoint;
- Common::Point endPoint;
- byte color;
- byte priority;
- byte control;
+// TODO: Verify display styles and adjust names appropriately for
+// types 1 through 12 & 15 (others are correct)
+// Names should be:
+// * VShutterIn, VShutterOut
+// * HShutterIn, HShutterOut
+// * WipeLeft, WipeRight, WipeDown, WipeUp
+// * PixelDissolve
+// * ShutDown and Kill? (and Plain and Fade?)
+enum ShowStyleType /* : uint8 */ {
+ kShowStyleNone = 0,
+ kShowStyleHShutterOut = 1,
+ kShowStyleHShutterIn = 2,
+ kShowStyleVShutterOut = 3,
+ kShowStyleVShutterIn = 4,
+ kShowStyleWipeLeft = 5,
+ kShowStyleWipeRight = 6,
+ kShowStyleWipeUp = 7,
+ kShowStyleWipeDown = 8,
+ kShowStyleIrisOut = 9,
+ kShowStyleIrisIn = 10,
+ kShowStyle11 = 11,
+ kShowStyle12 = 12,
+ kShowStyleFadeOut = 13,
+ kShowStyleFadeIn = 14,
+ // TODO: Only in SCI3
+ kShowStyleUnknown = 15
};
-typedef Common::List<PlaneLineEntry> PlaneLineList;
-
-struct PlaneEntry {
- reg_t object;
- int16 priority;
- int16 lastPriority;
- int16 planeOffsetX;
- int16 planeOffsetY;
- GuiResourceId pictureId;
- Common::Rect planeRect;
- Common::Rect planeClipRect;
- Common::Rect upscaledPlaneRect;
- Common::Rect upscaledPlaneClipRect;
- bool planePictureMirrored;
- byte planeBack;
- PlaneLineList lines;
-};
+/**
+ * Show styles represent transitions applied to draw planes.
+ * One show style per plane can be active at a time.
+ */
+struct ShowStyleEntry {
+ /**
+ * The ID of the plane this show style belongs to.
+ * In SCI2.1mid (at least SQ6), per-plane transitions
+ * were removed and a single plane ID is used.
+ */
+ reg_t plane;
-typedef Common::List<PlaneEntry> PlaneList;
-
-struct FrameoutEntry {
- uint16 givenOrderNr;
- reg_t object;
- GuiResourceId viewId;
- int16 loopNo;
- int16 celNo;
- int16 x, y, z;
- int16 priority;
- uint16 signal;
- uint16 scaleSignal;
- int16 scaleX;
- int16 scaleY;
- Common::Rect celRect;
- GfxPicture *picture;
- int16 picStartX;
- int16 picStartY;
- bool visible;
-};
+ /**
+ * The type of the transition.
+ */
+ ShowStyleType type;
-typedef Common::List<FrameoutEntry *> FrameoutList;
+ // TODO: This name is probably incorrect
+ bool fadeUp;
-struct PlanePictureEntry {
- reg_t object;
- int16 startX;
- int16 startY;
- GuiResourceId pictureId;
- GfxPicture *picture;
- FrameoutEntry *pictureCels; // temporary
-};
+ /**
+ * The number of steps for the show style.
+ */
+ int16 divisions;
-typedef Common::List<PlanePictureEntry> PlanePictureList;
+ // NOTE: This property exists from SCI2 through at least
+ // SCI2.1mid but is never used in the actual processing
+ // of the styles?
+ int unknownC;
-struct ScrollTextEntry {
- reg_t bitmapHandle;
- reg_t kWindow;
- uint16 x;
- uint16 y;
-};
+ /**
+ * The color used by transitions that draw CelObjColor
+ * screen items. -1 for transitions that do not draw
+ * screen items.
+ */
+ int16 color;
+
+ // TODO: Probably uint32
+ // TODO: This field probably should be used in order to
+ // provide time-accurate processing of show styles. In the
+ // actual SCI engine (at least 2–2.1mid) it appears that
+ // style transitions are drawn “as fast as possibleâ€, one
+ // step per loop, even though this delay field exists
+ int delay;
+
+ // TODO: Probably bool, but never seems to be true?
+ int animate;
+
+ /**
+ * The wall time at which the next step of the animation
+ * should execute.
+ */
+ uint32 nextTick;
-typedef Common::Array<ScrollTextEntry> ScrollTextList;
+ /**
+ * During playback of the show style, the current step
+ * (out of divisions).
+ */
+ int currentStep;
-enum ViewScaleSignals32 {
- kScaleSignalDoScaling32 = 0x0001, // enables scaling when drawing that cel (involves scaleX and scaleY)
- kScaleSignalUnk1 = 0x0002, // unknown
- kScaleSignalDisableGlobalScaling32 = 0x0004
+ /**
+ * The next show style.
+ */
+ ShowStyleEntry *next;
+
+ /**
+ * Whether or not this style has finished running and
+ * is ready for disposal.
+ */
+ bool processed;
+
+ //
+ // Engine specific properties for SCI2.1mid through SCI3
+ //
+
+ /**
+ * The number of entries in the fadeColorRanges array.
+ */
+ uint8 fadeColorRangesCount;
+
+ /**
+ * A pointer to an dynamically sized array of palette
+ * indexes, in the order [ fromColor, toColor, ... ].
+ * Only colors within this range are transitioned.
+ */
+ uint16 *fadeColorRanges;
};
-class GfxCache;
+typedef Common::Array<DrawList> ScreenItemListList;
+typedef Common::Array<RectList> EraseListList;
+
class GfxCoordAdjuster32;
-class GfxPaint32;
-class GfxPalette;
class GfxScreen;
/**
- * Frameout class, kFrameout and relevant functions for SCI32 games
+ * Frameout class, kFrameout and relevant functions for SCI32 games.
+ * Roughly equivalent to GraphicsMgr in the actual SCI engine.
*/
class GfxFrameout {
+private:
+ bool _isHiRes;
+ GfxCoordAdjuster32 *_coordAdjuster;
+ GfxPalette32 *_palette;
+ ResourceManager *_resMan;
+ GfxScreen *_screen;
+ SegManager *_segMan;
+
public:
- GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxCache *cache, GfxScreen *screen, GfxPalette *palette, GfxPaint32 *paint32);
+ GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxScreen *screen, GfxPalette32 *palette);
~GfxFrameout();
- void kernelAddPlane(reg_t object);
- void kernelUpdatePlane(reg_t object);
- void kernelDeletePlane(reg_t object);
- void applyGlobalScaling(FrameoutEntry *itemEntry, Common::Rect planeRect, int16 celHeight);
- void kernelAddScreenItem(reg_t object);
- void kernelUpdateScreenItem(reg_t object);
- void kernelDeleteScreenItem(reg_t object);
- void deletePlaneItems(reg_t planeObject);
- FrameoutEntry *findScreenItem(reg_t object);
- int16 kernelGetHighPlanePri();
- void kernelAddPicAt(reg_t planeObj, GuiResourceId pictureId, int16 pictureX, int16 pictureY);
- void kernelFrameout();
-
- void addPlanePicture(reg_t object, GuiResourceId pictureId, uint16 startX, uint16 startY = 0);
- void deletePlanePictures(reg_t object);
- reg_t addPlaneLine(reg_t object, Common::Point startPoint, Common::Point endPoint, byte color, byte priority, byte control);
- void updatePlaneLine(reg_t object, reg_t hunkId, Common::Point startPoint, Common::Point endPoint, byte color, byte priority, byte control);
- void deletePlaneLine(reg_t object, reg_t hunkId);
void clear();
+ void syncWithScripts(bool addElements); // this is what Game::restore does, only needed when our ScummVM dialogs are patched in
+ void run();
- // Scroll text functions
- void addScrollTextEntry(Common::String &text, reg_t kWindow, uint16 x, uint16 y, bool replace);
- void showCurrentScrollText();
- void initScrollText(uint16 maxItems) { _maxScrollTexts = maxItems; }
- void clearScrollTexts();
- void firstScrollText() { if (_scrollTexts.size() > 0) _curScrollText = 0; }
- void lastScrollText() { if (_scrollTexts.size() > 0) _curScrollText = _scrollTexts.size() - 1; }
- void prevScrollText() { if (_curScrollText > 0) _curScrollText--; }
- void nextScrollText() { if (_curScrollText + 1 < (uint16)_scrollTexts.size()) _curScrollText++; }
- void toggleScrollText(bool show) { _showScrollText = show; }
+#pragma mark -
+#pragma mark Benchmarking
+private:
+ /**
+ * Optimization to avoid the more expensive object name
+ * comparision on every call to kAddScreenItem and
+ * kRemoveScreenItem.
+ */
+ bool _benchmarkingFinished;
- void printPlaneList(Console *con);
- void printPlaneItemList(Console *con, reg_t planeObject);
+ /**
+ * 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 showVideo();
- void createPlaneItemList(reg_t planeObject, FrameoutList &itemList);
- bool isPictureOutOfView(FrameoutEntry *itemEntry, Common::Rect planeRect, int16 planeOffsetX, int16 planeOffsetY);
- void drawPicture(FrameoutEntry *itemEntry, int16 planeOffsetX, int16 planeOffsetY, bool planePictureMirrored);
+ void remapMarkRedraw();
- SegManager *_segMan;
- ResourceManager *_resMan;
- GfxCoordAdjuster32 *_coordAdjuster;
- GfxCache *_cache;
- GfxPalette *_palette;
- GfxScreen *_screen;
- GfxPaint32 *_paint32;
+public:
+ /**
+ * Adds a screen item.
+ */
+ void addScreenItem(ScreenItem &screenItem) const;
+
+ /**
+ * Updates a screen item.
+ */
+ void updateScreenItem(ScreenItem &screenItem) const;
- FrameoutList _screenItems;
+ /**
+ * 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
+private:
+ /**
+ * The list of planes (i.e. layers) that have been added
+ * to the screen.
+ *
+ * @note This field is on `GraphicsMgr.screen` in SCI
+ * engine.
+ */
PlaneList _planes;
- PlanePictureList _planePictures;
- ScrollTextList _scrollTexts;
- int16 _curScrollText;
- bool _showScrollText;
- uint16 _maxScrollTexts;
- void sortPlanes();
+ /**
+ * 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
+ * already exists within the current plane list.
+ *
+ * @note This method is on Screen in SCI engine, but it
+ * is only ever called on `GraphicsMgr.screen`.
+ */
+ void addPlane(Plane &plane);
+
+ /**
+ * 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 deletePlane(Plane &plane);
+
+ 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 -
+#pragma mark Pics
+public:
+ void kernelAddPicAt(const reg_t planeObject, const GuiResourceId pictureId, const int16 pictureX, const int16 pictureY, const bool mirrorX);
+
+#pragma mark -
+
+ // TODO: Remap-related?
+ void kernelSetPalStyleRange(const uint8 fromColor, const uint8 toColor);
+
+#pragma mark -
+#pragma mark Transitions
+private:
+ int *_dissolveSequenceSeeds;
+ int16 *_defaultDivisions;
+ int16 *_defaultUnknownC;
+
+ /**
+ * TODO: Documentation
+ */
+ ShowStyleEntry *_showStyles;
+
+ inline ShowStyleEntry *findShowStyleForPlane(const reg_t planeObj) const;
+ inline ShowStyleEntry *deleteShowStyleInternal(ShowStyleEntry *const showStyle);
+ void processShowStyles();
+ bool processShowStyleNone(ShowStyleEntry *showStyle);
+ bool processShowStyleMorph(ShowStyleEntry *showStyle);
+ bool processShowStyleFade(const int direction, ShowStyleEntry *showStyle);
+
+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, 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];
+
+ /**
+ * The internal display pixel buffer. During frameOut,
+ * this buffer is drawn into according to the draw and
+ * erase rects calculated by `calcLists`, then drawn out
+ * to the hardware surface according to the `_showList`
+ * rects (which are also calculated by `calcLists`).
+ */
+ Buffer _currentBuffer;
+
+ /**
+ * 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;
+
+ /**
+ * Whether or not the data in the current buffer is what
+ * is visible to the user. During rendering updates,
+ * this flag is set to false.
+ */
+ bool _frameNowVisible;
+
+ /**
+ * TODO: Document
+ * TODO: Depending upon if the engine ever modifies this
+ * rect, it may be stupid to store it separately instead
+ * of just getting width/height from GfxScreen.
+ *
+ * @note This field is on `GraphicsMgr.screen` in SCI
+ * engine.
+ */
+ Common::Rect _screenRect;
+
+ /**
+ * A list of rectangles, in display coordinates, that
+ * represent portions of the internal screen buffer that
+ * should be drawn to the hardware display surface.
+ *
+ * @note This field is on `GraphicsMgr.screen` in SCI
+ * engine.
+ */
+ RectList _showList;
+
+ /**
+ * The amount of extra overdraw that is acceptable when
+ * merging two show list rectangles together into a
+ * single larger rectangle.
+ *
+ * @note This field is on `GraphicsMgr.screen` in SCI
+ * engine.
+ */
+ int _overdrawThreshold;
+
+ /**
+ * A list of planes that are currently drawn to the
+ * hardware display surface. Used to calculate
+ * differences in plane properties between the last
+ * frame and current frame.
+ *
+ * @note This field is on `GraphicsMgr.visibleScreen` in
+ * SCI engine.
+ */
+ PlaneList _visiblePlanes;
+
+ /**
+ * Calculates the location and dimensions of dirty rects
+ * 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 &eraseRect = Common::Rect());
+
+ /**
+ * Erases the areas in the given erase list from the
+ * visible screen buffer by filling them with the color
+ * from the corresponding plane. This is an optimisation
+ * for colored-type planes only; other plane types have
+ * to be redrawn from pixel data.
+ */
+ void drawEraseList(const RectList &eraseList, const Plane &plane);
+
+ /**
+ * Draws all screen items from the given draw list to
+ * the visible screen buffer.
+ */
+ void drawScreenItemList(const DrawList &screenItemList);
+
+ /**
+ * 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
+ * blit operations.
+ */
+ void mergeToShowList(const Common::Rect &drawRect, RectList &showList, const int overdrawThreshold);
+
+ /**
+ * TODO: Documentation
+ */
+ void palMorphFrameOut(const int8 *styleRanges, const ShowStyleEntry *showStyle);
+
+ /**
+ * Writes the internal frame buffer out to hardware and
+ * clears the show list.
+ */
+ void showBits();
+
+public:
+ /**
+ * Whether palMorphFrameOut should be used instead of
+ * frameOut for rendering. Used by kMorphOn to
+ * explicitly enable palMorphFrameOut for one frame.
+ */
+ bool _palMorphIsOn;
+
+ inline const Buffer &getCurrentBuffer() const {
+ return _currentBuffer;
+ }
+
+ 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
+ * new palette indexes based on matched style ranges.
+ */
+ void alterVmap(const Palette &palette1, const Palette &palette2, const int8 style, const int8 *const styleRanges);
+
+ // 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,
+ // SQ6/DOS, SQ6/Win, and Phant2/Win, this function simply returns 1. If
+ // you know of any game/environment where this function returns some
+ // value other than 1, or if you used to work at Sierra and can explain
+ // why this is a thing (and if anyone needs to care about it), please
+ // open a ticket!!
+ inline int getScreenCount() const {
+ return 1;
+ };
+
+#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
+public:
+ void printPlaneList(Console *con) const;
+ 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 4889f12bd2..3fcc83c5e2 100644
--- a/engines/sci/graphics/helpers.h
+++ b/engines/sci/graphics/helpers.h
@@ -26,6 +26,11 @@
#include "common/endian.h" // for READ_LE_UINT16
#include "common/rect.h"
#include "common/serializer.h"
+#ifdef ENABLE_SCI32
+#include "common/rational.h"
+#include "graphics/pixelformat.h"
+#include "graphics/surface.h"
+#endif
#include "sci/engine/vm_types.h"
namespace Sci {
@@ -45,6 +50,9 @@ typedef int16 TextAlignment;
#define PORTS_FIRSTWINDOWID 2
#define PORTS_FIRSTSCRIPTWINDOWID 3
+#ifdef ENABLE_SCI32
+#define PRINT_RECT(x) (x).left,(x).top,(x).right,(x).bottom
+#endif
struct Port {
uint16 id;
@@ -118,9 +126,120 @@ struct Window : public Port, public Common::Serializable {
}
};
+#ifdef ENABLE_SCI32
+/**
+ * Multiplies a rectangle by two ratios with default
+ * rounding. Modifies the rect directly.
+ */
+inline void mul(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 * ratioX).toInt();
+ rect.bottom = (rect.bottom * ratioY).toInt();
+}
+
+/**
+ * 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, 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 - extra;
+}
+
+/**
+ * Multiplies a point by two rational numbers for X and Y,
+ * rounding up to the nearest whole number. Modifies the
+ * point directly.
+ */
+inline void mulru(Common::Point &point, const Common::Rational &ratioX, const Common::Rational &ratioY) {
+ point.x = mulru(point.x, ratioX);
+ point.y = mulru(point.y, ratioY);
+}
+
+/**
+ * Multiplies a point by two rational numbers for X and Y,
+ * rounding up to the nearest whole number. Modifies the
+ * rect directly.
+ */
+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 - 1, ratioX, extra) + 1;
+ rect.bottom = mulru(rect.bottom - 1, ratioY, extra) + 1;
+}
+
+struct Buffer : public Graphics::Surface {
+ uint16 screenWidth;
+ uint16 screenHeight;
+ 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),
+ // TODO: These values are not correct for all games. Script
+ // dimensions were hard-coded per game in the original
+ // interpreter. Search all games for their internal script
+ // dimensions and set appropriately. (This code does not
+ // appear to exist at all in SCI3, which uses 640x480.)
+ scriptWidth(320),
+ scriptHeight(200) {
+ init(width, height, width, pix, Graphics::PixelFormat::createFormatCLUT8());
+ }
+
+ void clear(const uint8 value) {
+ memset(pixels, value, w * h);
+ }
+
+ inline uint8 *getAddress(const uint16 x, const uint16 y) {
+ return (uint8 *)getBasePtr(x, y);
+ }
+
+ inline uint8 *getAddressSimRes(const uint16 x, const uint16 y) {
+ return (uint8*)pixels + (y * w * screenHeight / scriptHeight) + (x * screenWidth / scriptWidth);
+ }
+
+ bool isNull() {
+ return pixels == nullptr;
+ }
+};
+#endif
+
struct Color {
byte used;
byte r, g, b;
+
+#ifdef ENABLE_SCI32
+ bool operator==(const Color &other) const {
+ return used == other.used && r == other.r && g == other.g && b == other.b;
+ }
+ inline bool operator!=(const Color &other) const {
+ return !operator==(other);
+ }
+#endif
};
struct Palette {
@@ -128,6 +247,21 @@ struct Palette {
uint32 timestamp;
Color colors[256];
byte intensity[256];
+
+#ifdef ENABLE_SCI32
+ bool operator==(const Palette &other) const {
+ for (int i = 0; i < ARRAYSIZE(colors); ++i) {
+ if (colors[i] != other.colors[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ inline bool operator!=(const Palette &other) const {
+ return !(*this == other);
+ }
+#endif
};
struct PalSchedule {
diff --git a/engines/sci/graphics/lists32.h b/engines/sci/graphics/lists32.h
new file mode 100644
index 0000000000..4f74c77325
--- /dev/null
+++ b/engines/sci/graphics/lists32.h
@@ -0,0 +1,192 @@
+/* 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_LISTS32_H
+#define SCI_GRAPHICS_LISTS32_H
+
+#include "common/array.h"
+
+namespace Sci {
+
+/**
+ * StablePointerArray holds pointers in a fixed-size array
+ * that maintains position of erased items until `pack` is
+ * called. It is used by DrawList, RectList, and
+ * ScreenItemList. StablePointerArray takes ownership of
+ * all pointers that are passed to it and deletes them when
+ * calling `erase` or when destroying the
+ * StablePointerArray.
+ */
+template<class T, uint N>
+class StablePointerArray {
+ uint _size;
+ T *_items[N];
+
+public:
+ typedef T **iterator;
+ typedef T *const *const_iterator;
+ typedef T *value_type;
+ typedef uint size_type;
+
+ StablePointerArray() : _size(0), _items() {}
+ StablePointerArray(const StablePointerArray &other) : _size(other._size) {
+ for (size_type i = 0; i < _size; ++i) {
+ if (other._items[i] == nullptr) {
+ _items[i] = nullptr;
+ } else {
+ _items[i] = new T(*other._items[i]);
+ }
+ }
+ }
+ ~StablePointerArray() {
+ for (size_type i = 0; i < _size; ++i) {
+ delete _items[i];
+ }
+ }
+
+ void operator=(const StablePointerArray &other) {
+ clear();
+ _size = other._size;
+ for (size_type i = 0; i < _size; ++i) {
+ if (other._items[i] == nullptr) {
+ _items[i] = nullptr;
+ } else {
+ _items[i] = new T(*other._items[i]);
+ }
+ }
+ }
+
+ T *const &operator[](size_type index) const {
+ assert(index < _size);
+ return _items[index];
+ }
+
+ T *&operator[](size_type index) {
+ assert(index < _size);
+ return _items[index];
+ }
+
+ /**
+ * Adds a new pointer to the array.
+ */
+ void add(T *item) {
+ assert(_size < N);
+ _items[_size++] = item;
+ }
+
+ iterator begin() {
+ return _items;
+ }
+
+ const_iterator begin() const {
+ return _items;
+ }
+
+ void clear() {
+ for (size_type i = 0; i < _size; ++i) {
+ delete _items[i];
+ _items[i] = nullptr;
+ }
+
+ _size = 0;
+ }
+
+ iterator end() {
+ return _items + _size;
+ }
+
+ const_iterator end() const {
+ return _items + _size;
+ }
+
+ /**
+ * Erases the object pointed to by the given iterator.
+ */
+ void erase(T *item) {
+ for (iterator it = begin(); it != end(); ++it) {
+ if (*it == item) {
+ delete *it;
+ *it = nullptr;
+ break;
+ }
+ }
+ }
+
+ /**
+ * Erases the object pointed to by the given iterator.
+ */
+ void erase(iterator &it) {
+ assert(it >= _items && it < _items + _size);
+ delete *it;
+ *it = nullptr;
+ }
+
+ /**
+ * Erases the object pointed to at the given index.
+ */
+ void erase_at(size_type index) {
+ assert(index < _size);
+
+ delete _items[index];
+ _items[index] = nullptr;
+ }
+
+ /**
+ * Removes freed pointers from the pointer list.
+ */
+ size_type pack() {
+ iterator freePtr = begin();
+ size_type newSize = 0;
+
+ for (iterator it = begin(), last = end(); it != last; ++it) {
+ if (*it != nullptr) {
+ *freePtr = *it;
+ ++freePtr;
+ ++newSize;
+ }
+ }
+
+ _size = newSize;
+ return newSize;
+ }
+
+ /**
+ * The number of populated slots in the array. The size
+ * of the array will only go down once `pack` is called.
+ */
+ size_type size() const {
+ return _size;
+ }
+};
+
+template<typename T>
+class FindByObject {
+ const reg_t &_object;
+public:
+ FindByObject(const reg_t &object) : _object(object) {}
+ bool operator()(const T entry) const {
+ return entry && entry->_object == _object;
+ }
+};
+
+} // End of namespace Sci
+#endif
diff --git a/engines/sci/graphics/maciconbar.cpp b/engines/sci/graphics/maciconbar.cpp
index 8e2e12b7bd..e10b9fddbf 100644
--- a/engines/sci/graphics/maciconbar.cpp
+++ b/engines/sci/graphics/maciconbar.cpp
@@ -234,7 +234,7 @@ void GfxMacIconBar::remapColors(Graphics::Surface *surf, const byte *palette) {
byte g = palette[color * 3 + 1];
byte b = palette[color * 3 + 2];
- *pixels++ = g_sci->_gfxPalette->findMacIconBarColor(r, g, b);
+ *pixels++ = g_sci->_gfxPalette16->findMacIconBarColor(r, g, b);
}
}
diff --git a/engines/sci/graphics/menu.cpp b/engines/sci/graphics/menu.cpp
index 8e8c1d64c2..eb3f5888c7 100644
--- a/engines/sci/graphics/menu.cpp
+++ b/engines/sci/graphics/menu.cpp
@@ -424,8 +424,12 @@ reg_t GfxMenu::kernelSelect(reg_t eventObject, bool pauseSound) {
default:
while (itemIterator != itemEnd) {
itemEntry = *itemIterator;
+ // Sierra actually did not check the modifier, they only checked the ascii code
+ // Which is why for example pressing Ctrl-I and Shift-Ctrl-I both brought up the inventory in QfG1
+ // We still check the modifier, but we need to isolate the lower byte, because of a keyboard
+ // driver bug (see engine/kevent.cpp / kGetEvent)
if (itemEntry->keyPress == keyPress &&
- itemEntry->keyModifier == keyModifier &&
+ itemEntry->keyModifier == (keyModifier & 0xFF) &&
itemEntry->enabled)
break;
itemIterator++;
@@ -743,7 +747,7 @@ GuiMenuItemEntry *GfxMenu::interactiveWithKeyboard() {
// - sierra didn't wrap around when changing item id
// - sierra allowed item id to be 0, which didn't make any sense
do {
- switch (curEvent.data) {
+ switch (curEvent.character) {
case SCI_KEY_ESC:
_curMenuId = curItemEntry->menuId; _curItemId = curItemEntry->id;
return NULL;
@@ -772,10 +776,10 @@ GuiMenuItemEntry *GfxMenu::interactiveWithKeyboard() {
newMenuId = newItemEntry->menuId; newItemId = newItemEntry->id;
// if we do this step again because of a separator line -> don't repeat left/right, but go down
- switch (curEvent.data) {
+ switch (curEvent.character) {
case SCI_KEY_LEFT:
case SCI_KEY_RIGHT:
- curEvent.data = SCI_KEY_DOWN;
+ curEvent.character = SCI_KEY_DOWN;
}
}
} while (newItemEntry->separatorLine);
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 59abef5550..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"
@@ -86,10 +87,6 @@ GfxPalette::GfxPalette(ResourceManager *resMan, GfxScreen *screen)
_macClut = 0;
loadMacIconBarPalette();
-#ifdef ENABLE_SCI32
- _clutTable = 0;
-#endif
-
switch (_resMan->getViewType()) {
case kViewEga:
_totalScreenColors = 16;
@@ -107,9 +104,6 @@ GfxPalette::GfxPalette(ResourceManager *resMan, GfxScreen *screen)
default:
error("GfxPalette: Unknown view type");
}
-
- _remapOn = false;
- resetRemapping();
}
GfxPalette::~GfxPalette() {
@@ -117,10 +111,6 @@ GfxPalette::~GfxPalette() {
palVaryRemoveTimer();
delete[] _macClut;
-
-#ifdef ENABLE_SCI32
- unloadClut();
-#endif
}
bool GfxPalette::isMerging() {
@@ -144,7 +134,7 @@ void GfxPalette::setDefault() {
#define SCI_PAL_FORMAT_CONSTANT 1
#define SCI_PAL_FORMAT_VARIABLE 0
-void GfxPalette::createFromData(byte *data, int bytesLeft, Palette *paletteOut) {
+void GfxPalette::createFromData(byte *data, int bytesLeft, Palette *paletteOut) const {
int palFormat = 0;
int palOffset = 0;
int palColorStart = 0;
@@ -318,7 +308,7 @@ void GfxPalette::set(Palette *newPalette, bool force, bool forceRealMerge) {
uint32 systime = _sysPalette.timestamp;
if (force || newPalette->timestamp != systime) {
- // SCI1.1+ doesnt do real merging anymore, but simply copying over the used colors from other palettes
+ // SCI1.1+ doesn't do real merging anymore, but simply copying over the used colors from other palettes
// There are some games with inbetween SCI1.1 interpreters, use real merging for them (e.g. laura bow 2 demo)
if ((forceRealMerge) || (_useMerging))
_sysPaletteChanged |= merge(newPalette, force, forceRealMerge);
@@ -344,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;
@@ -597,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);
}
@@ -658,7 +568,7 @@ bool GfxPalette::kernelAnimate(byte fromColor, byte toColor, int speed) {
Color col;
//byte colorNr;
int16 colorCount;
- uint32 now = g_system->getMillis() * 60 / 1000;
+ uint32 now = g_sci->getTickCount();
// search for sheduled animations with the same 'from' value
// schedule animation...
@@ -983,7 +893,7 @@ void GfxPalette::palVaryProcess(int signal, bool setPalette) {
_palVaryResourceId = -1;
// Calculate inbetween palette
- Sci::Color inbetween;
+ Color inbetween;
int16 color;
for (int colorNr = 1; colorNr < 255; colorNr++) {
inbetween.used = _sysPalette.colors[colorNr].used;
@@ -994,7 +904,7 @@ void GfxPalette::palVaryProcess(int signal, bool setPalette) {
color = _palVaryTargetPalette.colors[colorNr].b - _palVaryOriginPalette.colors[colorNr].b;
inbetween.b = ((color * _palVaryStep) / 64) + _palVaryOriginPalette.colors[colorNr].b;
- if (memcmp(&inbetween, &_sysPalette.colors[colorNr], sizeof(Sci::Color))) {
+ if (memcmp(&inbetween, &_sysPalette.colors[colorNr], sizeof(Color))) {
_sysPalette.colors[colorNr] = inbetween;
_sysPaletteChanged = true;
}
@@ -1087,58 +997,4 @@ bool GfxPalette::colorIsFromMacClut(byte index) {
return index != 0 && _macClut && (_macClut[index * 3] != 0 || _macClut[index * 3 + 1] != 0 || _macClut[index * 3 + 2] != 0);
}
-#ifdef ENABLE_SCI32
-
-bool GfxPalette::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.
-
- unloadClut();
-
- Common::String filename = Common::String::format("%d.clu", clutId);
- Common::File clut;
-
- if (!clut.open(filename) || clut.size() != 0x10000 + 236 * 3)
- return false;
-
- // Read in the lookup table
- // It maps each RGB565 color to a palette index
- _clutTable = new byte[0x10000];
- clut.read(_clutTable, 0x10000);
-
- Palette pal;
- memset(&pal, 0, sizeof(Palette));
-
- // Setup 1:1 mapping
- for (int i = 0; i < 256; i++) {
- pal.mapping[i] = i;
- }
-
- // Now load in the palette
- for (int i = 1; i <= 236; i++) {
- pal.colors[i].used = 1;
- pal.colors[i].r = clut.readByte();
- pal.colors[i].g = clut.readByte();
- pal.colors[i].b = clut.readByte();
- }
-
- set(&pal, true);
- setOnScreen();
- return true;
-}
-
-byte GfxPalette::matchClutColor(uint16 color) {
- // Match a color in RGB565 format to a palette index based on the loaded CLUT
- assert(_clutTable);
- return _clutTable[color];
-}
-
-void GfxPalette::unloadClut() {
- // This will only unload the actual table, but not reset any palette
- delete[] _clutTable;
- _clutTable = 0;
-}
-
-#endif
-
} // End of namespace Sci
diff --git a/engines/sci/graphics/palette.h b/engines/sci/graphics/palette.h
index 500a45eccf..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
*/
@@ -53,7 +47,7 @@ public:
bool isUsing16bitColorMatch();
void setDefault();
- void createFromData(byte *data, int bytesLeft, Palette *paletteOut);
+ void createFromData(byte *data, int bytesLeft, Palette *paletteOut) const;
bool setAmiga();
void modifyAmigaPalette(byte *data);
void setEGA();
@@ -64,15 +58,6 @@ public:
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();
@@ -104,19 +89,13 @@ 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);
bool colorIsFromMacClut(byte index);
-#ifdef ENABLE_SCI32
- bool loadClut(uint16 clutId);
- byte matchClutColor(uint16 color);
- void unloadClut();
-#endif
-
-private:
+protected:
void palVaryInit();
void palVaryInstallTimer();
void palVaryRemoveTimer();
@@ -144,18 +123,8 @@ private:
int _palVarySignal;
uint16 _totalScreenColors;
- bool _remapOn;
- ColorRemappingType _remappingType[256];
- byte _remappingByPercent[256];
- byte _remappingByRange[256];
- uint16 _remappingPercentToSet;
-
void loadMacIconBarPalette();
byte *_macClut;
-
-#ifdef ENABLE_SCI32
- byte *_clutTable;
-#endif
};
} // End of namespace Sci
diff --git a/engines/sci/graphics/palette32.cpp b/engines/sci/graphics/palette32.cpp
new file mode 100644
index 0000000000..2a98c237b0
--- /dev/null
+++ b/engines/sci/graphics/palette32.cpp
@@ -0,0 +1,841 @@
+/* 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 "common/system.h"
+#include "graphics/palette.h"
+
+#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 {
+
+#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),
+ _needsUpdate(false),
+ _currentPalette(),
+ _sourcePalette(),
+ _nextPalette(),
+ // Clut
+ _clutTable(nullptr),
+ // Palette varying
+ _varyStartPalette(nullptr),
+ _varyTargetPalette(nullptr),
+ _varyFromColor(0),
+ _varyToColor(255),
+ _varyLastTick(0),
+ _varyTime(0),
+ _varyDirection(0),
+ _varyTargetPercent(0),
+ _varyNumTimesPaused(0),
+ // Palette cycling
+ _cyclers(),
+ _cycleMap() {
+ _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) {
+ // 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];
+ }
+ }
+}
+
+void GfxPalette32::submit(const Palette &palette) {
+ const Palette oldSourcePalette(_sourcePalette);
+ mergePaletteInternal(&_sourcePalette, &palette);
+
+ if (!_needsUpdate && _sourcePalette != oldSourcePalette) {
+ ++_version;
+ _needsUpdate = true;
+ }
+}
+
+void GfxPalette32::submit(HunkPalette &hunkPalette) {
+ if (hunkPalette.getVersion() == _version) {
+ return;
+ }
+
+ const Palette oldSourcePalette(_sourcePalette);
+ const Palette palette = hunkPalette.toPalette();
+ mergePaletteInternal(&_sourcePalette, &palette);
+
+ if (!_needsUpdate && oldSourcePalette != _sourcePalette) {
+ ++_version;
+ _needsUpdate = true;
+ }
+
+ hunkPalette.setVersion(_version);
+}
+
+bool GfxPalette32::loadPalette(const GuiResourceId resourceId) {
+ Resource *palResource = _resMan->findResource(ResourceId(kResourceTypePalette, resourceId), false);
+
+ if (!palResource) {
+ return false;
+ }
+
+ HunkPalette palette(palResource->data);
+ submit(palette);
+ return true;
+}
+
+int16 GfxPalette32::matchColor(const uint8 r, const uint8 g, const uint8 b) {
+ int16 bestIndex = 0;
+ int bestDifference = 0xFFFFF;
+ int difference;
+
+ for (int i = 0, channelDifference; i < g_sci->_gfxRemap32->getStartColor(); ++i) {
+ difference = _currentPalette.colors[i].r - r;
+ difference *= difference;
+ if (bestDifference <= difference) {
+ continue;
+ }
+
+ channelDifference = _currentPalette.colors[i].g - g;
+ difference += channelDifference * channelDifference;
+ if (bestDifference <= difference) {
+ continue;
+ }
+
+ channelDifference = _currentPalette.colors[i].b - b;
+ difference += channelDifference * channelDifference;
+ if (bestDifference <= difference) {
+ continue;
+ }
+ bestDifference = difference;
+ bestIndex = i;
+ }
+
+ return bestIndex;
+}
+
+bool GfxPalette32::updateForFrame() {
+ applyAll();
+ _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];
+ }
+ _needsUpdate = false;
+ g_sci->_gfxRemap32->remapAllTables(_nextPalette != _currentPalette);
+}
+
+void GfxPalette32::updateHardware(const bool updateScreen) {
+ if (_currentPalette == _nextPalette) {
+ return;
+ }
+
+ byte bpal[3 * 256];
+
+ 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
+
+ // 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);
+ if (updateScreen) {
+ g_sci->getEventManager()->updateScreen();
+ }
+}
+
+void GfxPalette32::applyAll() {
+ applyVary();
+ applyCycles();
+ applyFade();
+}
+
+#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.
+
+ unloadClut();
+
+ Common::String filename = Common::String::format("%d.clu", clutId);
+ Common::File clut;
+
+ if (!clut.open(filename) || clut.size() != 0x10000 + 236 * 3)
+ return false;
+
+ // Read in the lookup table
+ // It maps each RGB565 color to a palette index
+ _clutTable = new byte[0x10000];
+ clut.read(_clutTable, 0x10000);
+
+ Palette pal;
+ memset(&pal, 0, sizeof(Palette));
+
+ // Setup 1:1 mapping
+ for (int i = 0; i < 256; i++) {
+ pal.mapping[i] = i;
+ }
+
+ // Now load in the palette
+ for (int i = 1; i <= 236; i++) {
+ pal.colors[i].used = 1;
+ pal.colors[i].r = clut.readByte();
+ pal.colors[i].g = clut.readByte();
+ pal.colors[i].b = clut.readByte();
+ }
+
+ set(&pal, true);
+ setOnScreen();
+ return true;
+}
+
+byte GfxPalette32::matchClutColor(uint16 color) {
+ // Match a color in RGB565 format to a palette index based on the loaded CLUT
+ assert(_clutTable);
+ return _clutTable[color];
+}
+
+void GfxPalette32::unloadClut() {
+ // This will only unload the actual table, but not reset any palette
+ delete[] _clutTable;
+ _clutTable = nullptr;
+}
+#endif
+
+#pragma mark -
+#pragma mark Varying
+
+inline Palette GfxPalette32::getPaletteFromResourceInternal(const GuiResourceId resourceId) const {
+ Resource *palResource = _resMan->findResource(ResourceId(kResourceTypePalette, resourceId), false);
+
+ if (!palResource) {
+ error("Could not load vary palette %d", resourceId);
+ }
+
+ HunkPalette rawPalette(palResource->data);
+ return rawPalette.toPalette();
+}
+
+inline void GfxPalette32::setVaryTimeInternal(const int16 percent, const int time) {
+ _varyLastTick = g_sci->getTickCount();
+ if (!time || _varyPercent == percent) {
+ _varyDirection = 0;
+ _varyTargetPercent = _varyPercent = percent;
+ } else {
+ _varyTime = time / (percent - _varyPercent);
+ _varyTargetPercent = percent;
+
+ if (_varyTime > 0) {
+ _varyDirection = 1;
+ } else if (_varyTime < 0) {
+ _varyDirection = -1;
+ _varyTime = -_varyTime;
+ } else {
+ _varyDirection = 0;
+ _varyTargetPercent = _varyPercent = percent;
+ }
+ }
+}
+
+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);
+}
+
+void GfxPalette32::kernelPalVaryMergeTarget(GuiResourceId paletteId) {
+ Palette palette = getPaletteFromResourceInternal(paletteId);
+ mergeTarget(&palette);
+}
+
+void GfxPalette32::kernelPalVarySetTarget(GuiResourceId paletteId) {
+ Palette palette = getPaletteFromResourceInternal(paletteId);
+ setTarget(&palette);
+}
+
+void GfxPalette32::kernelPalVarySetStart(GuiResourceId paletteId) {
+ Palette palette = getPaletteFromResourceInternal(paletteId);
+ setStart(&palette);
+}
+
+void GfxPalette32::kernelPalVaryMergeStart(GuiResourceId paletteId) {
+ Palette palette = getPaletteFromResourceInternal(paletteId);
+ mergeStart(&palette);
+}
+
+void GfxPalette32::kernelPalVaryPause(bool pause) {
+ if (pause) {
+ varyPause();
+ } else {
+ varyOn();
+ }
+}
+
+void GfxPalette32::setVary(const Palette *const target, const int16 percent, const int time, const int16 fromColor, const int16 toColor) {
+ setTarget(target);
+ setVaryTimeInternal(percent, time);
+
+ if (fromColor > -1) {
+ _varyFromColor = fromColor;
+ }
+ if (toColor > -1) {
+ assert(toColor < 256);
+ _varyToColor = toColor;
+ }
+}
+
+void GfxPalette32::setVaryPercent(const int16 percent, const int time, const int16 fromColor, const int16 fromColorAlternate) {
+ if (_varyTargetPalette != nullptr) {
+ setVaryTimeInternal(percent, time);
+ }
+
+ // This looks like a mistake in the actual SCI engine (both SQ6 and Lighthouse);
+ // the values are always hardcoded to -1 in kPalVary, so this code can never
+ // actually be executed
+ if (fromColor > -1) {
+ _varyFromColor = fromColor;
+ }
+ if (fromColorAlternate > -1) {
+ _varyFromColor = fromColorAlternate;
+ }
+}
+
+int16 GfxPalette32::getVaryPercent() const {
+ return ABS(_varyPercent);
+}
+
+void GfxPalette32::varyOff() {
+ _varyNumTimesPaused = 0;
+ _varyPercent = _varyTargetPercent = 0;
+ _varyFromColor = 0;
+ _varyToColor = 255;
+ _varyDirection = 0;
+
+ if (_varyTargetPalette != nullptr) {
+ delete _varyTargetPalette;
+ _varyTargetPalette = nullptr;
+ }
+
+ if (_varyStartPalette != nullptr) {
+ delete _varyStartPalette;
+ _varyStartPalette = nullptr;
+ }
+}
+
+void GfxPalette32::mergeTarget(const Palette *const palette) {
+ if (_varyTargetPalette != nullptr) {
+ mergePaletteInternal(_varyTargetPalette, palette);
+ } else {
+ _varyTargetPalette = new Palette(*palette);
+ }
+}
+
+void GfxPalette32::varyPause() {
+ _varyDirection = 0;
+ ++_varyNumTimesPaused;
+}
+
+void GfxPalette32::varyOn() {
+ if (_varyNumTimesPaused > 0) {
+ --_varyNumTimesPaused;
+ }
+
+ if (_varyTargetPalette != nullptr && _varyNumTimesPaused == 0 && _varyPercent != _varyTargetPercent) {
+ if (_varyTime == 0) {
+ _varyPercent = _varyTargetPercent;
+ } else if (_varyTargetPercent < _varyPercent) {
+ _varyDirection = -1;
+ } else {
+ _varyDirection = 1;
+ }
+ }
+}
+
+void GfxPalette32::setVaryTime(const int time) {
+ if (_varyTargetPalette == nullptr) {
+ return;
+ }
+
+ setVaryTimeInternal(_varyTargetPercent, time);
+}
+
+void GfxPalette32::setTarget(const Palette *const palette) {
+ if (_varyTargetPalette != nullptr) {
+ delete _varyTargetPalette;
+ }
+
+ _varyTargetPalette = new Palette(*palette);
+}
+
+void GfxPalette32::setStart(const Palette *const palette) {
+ if (_varyStartPalette != nullptr) {
+ delete _varyStartPalette;
+ }
+
+ _varyStartPalette = new Palette(*palette);
+}
+
+void GfxPalette32::mergeStart(const Palette *const palette) {
+ if (_varyStartPalette != nullptr) {
+ mergePaletteInternal(_varyStartPalette, palette);
+ } else {
+ _varyStartPalette = new Palette(*palette);
+ }
+}
+
+void GfxPalette32::applyVary() {
+ while (g_sci->getTickCount() - _varyLastTick > (uint32)_varyTime && _varyDirection != 0) {
+ _varyLastTick += _varyTime;
+
+ if (_varyPercent == _varyTargetPercent) {
+ _varyDirection = 0;
+ }
+
+ _varyPercent += _varyDirection;
+ }
+
+ if (_varyPercent == 0 || _varyTargetPalette == nullptr) {
+ for (int i = 0, len = ARRAYSIZE(_nextPalette.colors); i < len; ++i) {
+ if (_varyStartPalette != nullptr && i >= _varyFromColor && i <= _varyToColor) {
+ _nextPalette.colors[i] = _varyStartPalette->colors[i];
+ } else {
+ _nextPalette.colors[i] = _sourcePalette.colors[i];
+ }
+ }
+ } else {
+ for (int i = 0, len = ARRAYSIZE(_nextPalette.colors); i < len; ++i) {
+ if (i >= _varyFromColor && i <= _varyToColor) {
+ Color targetColor = _varyTargetPalette->colors[i];
+ Color sourceColor;
+
+ if (_varyStartPalette != nullptr) {
+ sourceColor = _varyStartPalette->colors[i];
+ } else {
+ sourceColor = _sourcePalette.colors[i];
+ }
+
+ Color computedColor;
+
+ int color;
+ color = targetColor.r - sourceColor.r;
+ computedColor.r = ((color * _varyPercent) / 100) + sourceColor.r;
+ color = targetColor.g - sourceColor.g;
+ computedColor.g = ((color * _varyPercent) / 100) + sourceColor.g;
+ color = targetColor.b - sourceColor.b;
+ computedColor.b = ((color * _varyPercent) / 100) + sourceColor.b;
+ computedColor.used = sourceColor.used;
+
+ _nextPalette.colors[i] = computedColor;
+ }
+ else {
+ _nextPalette.colors[i] = _sourcePalette.colors[i];
+ }
+ }
+ }
+}
+
+#pragma mark -
+#pragma mark Cycling
+
+inline void GfxPalette32::clearCycleMap(const uint16 fromColor, const uint16 numColorsToClear) {
+ bool *mapEntry = _cycleMap + fromColor;
+ const bool *lastEntry = _cycleMap + numColorsToClear;
+ while (mapEntry < lastEntry) {
+ *mapEntry++ = false;
+ }
+}
+
+inline void GfxPalette32::setCycleMap(const uint16 fromColor, const uint16 numColorsToSet) {
+ bool *mapEntry = _cycleMap + fromColor;
+ const bool *lastEntry = _cycleMap + numColorsToSet;
+ while (mapEntry < lastEntry) {
+ if (*mapEntry != false) {
+ error("Cycles intersect");
+ }
+ *mapEntry++ = true;
+ }
+}
+
+inline PalCycler *GfxPalette32::getCycler(const uint16 fromColor) {
+ const int numCyclers = ARRAYSIZE(_cyclers);
+
+ for (int cyclerIndex = 0; cyclerIndex < numCyclers; ++cyclerIndex) {
+ PalCycler *cycler = _cyclers[cyclerIndex];
+ if (cycler != nullptr && cycler->fromColor == fromColor) {
+ return cycler;
+ }
+ }
+
+ return nullptr;
+}
+
+inline void doCycleInternal(PalCycler *cycler, const int16 speed) {
+ int16 currentCycle = cycler->currentCycle;
+ const uint16 numColorsToCycle = cycler->numColorsToCycle;
+
+ if (cycler->direction == 0) {
+ currentCycle = (currentCycle - (speed % numColorsToCycle)) + numColorsToCycle;
+ } else {
+ currentCycle = currentCycle + speed;
+ }
+
+ cycler->currentCycle = (uint8) (currentCycle % numColorsToCycle);
+}
+
+void GfxPalette32::setCycle(const uint8 fromColor, const uint8 toColor, const int16 direction, const int16 delay) {
+ assert(fromColor < toColor);
+
+ int cyclerIndex;
+ const int numCyclers = ARRAYSIZE(_cyclers);
+
+ PalCycler *cycler = getCycler(fromColor);
+
+ if (cycler != nullptr) {
+ clearCycleMap(fromColor, cycler->numColorsToCycle);
+ } else {
+ for (cyclerIndex = 0; cyclerIndex < numCyclers; ++cyclerIndex) {
+ if (_cyclers[cyclerIndex] == nullptr) {
+ cycler = new PalCycler;
+ _cyclers[cyclerIndex] = cycler;
+ break;
+ }
+ }
+ }
+
+ // 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) {
+ const uint32 now = g_sci->getTickCount();
+ uint32 minUpdateDelta = 0xFFFFFFFF;
+
+ for (cyclerIndex = 0; cyclerIndex < numCyclers; ++cyclerIndex) {
+ PalCycler *candidate = _cyclers[cyclerIndex];
+
+ const uint32 updateDelta = now - candidate->lastUpdateTick;
+ if (updateDelta < minUpdateDelta) {
+ minUpdateDelta = updateDelta;
+ cycler = candidate;
+ }
+ }
+
+ clearCycleMap(cycler->fromColor, cycler->numColorsToCycle);
+ }
+
+ const uint16 numColorsToCycle = 1 + ((uint8) toColor) - fromColor;
+ cycler->fromColor = (uint8) fromColor;
+ cycler->numColorsToCycle = (uint8) numColorsToCycle;
+ cycler->currentCycle = (uint8) fromColor;
+ cycler->direction = direction < 0 ? PalCycleBackward : PalCycleForward;
+ cycler->delay = delay;
+ cycler->lastUpdateTick = g_sci->getTickCount();
+ cycler->numTimesPaused = 0;
+
+ setCycleMap(fromColor, numColorsToCycle);
+}
+
+void GfxPalette32::doCycle(const uint8 fromColor, const int16 speed) {
+ PalCycler *cycler = getCycler(fromColor);
+ if (cycler != nullptr) {
+ cycler->lastUpdateTick = g_sci->getTickCount();
+ doCycleInternal(cycler, speed);
+ }
+}
+
+void GfxPalette32::cycleOn(const uint8 fromColor) {
+ PalCycler *cycler = getCycler(fromColor);
+ if (cycler != nullptr && cycler->numTimesPaused > 0) {
+ --cycler->numTimesPaused;
+ }
+}
+
+void GfxPalette32::cyclePause(const uint8 fromColor) {
+ PalCycler *cycler = getCycler(fromColor);
+ if (cycler != nullptr) {
+ ++cycler->numTimesPaused;
+ }
+}
+
+void GfxPalette32::cycleAllOn() {
+ for (int i = 0, len = ARRAYSIZE(_cyclers); i < len; ++i) {
+ PalCycler *cycler = _cyclers[i];
+ if (cycler != nullptr && cycler->numTimesPaused > 0) {
+ --cycler->numTimesPaused;
+ }
+ }
+}
+
+void GfxPalette32::cycleAllPause() {
+ // 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) {
+ // This seems odd, because currentCycle is 0..numColorsPerCycle,
+ // but fromColor is 0..255. When applyAllCycles runs, the values
+ // end up back in range
+ cycler->currentCycle = cycler->fromColor;
+ }
+ }
+
+ applyAllCycles();
+
+ for (int i = 0, len = ARRAYSIZE(_cyclers); i < len; ++i) {
+ PalCycler *cycler = _cyclers[i];
+ if (cycler != nullptr) {
+ ++cycler->numTimesPaused;
+ }
+ }
+}
+
+void GfxPalette32::cycleOff(const uint8 fromColor) {
+ for (int i = 0, len = ARRAYSIZE(_cyclers); i < len; ++i) {
+ PalCycler *cycler = _cyclers[i];
+ if (cycler != nullptr && cycler->fromColor == fromColor) {
+ clearCycleMap(fromColor, cycler->numColorsToCycle);
+ delete cycler;
+ _cyclers[i] = nullptr;
+ break;
+ }
+ }
+}
+
+void GfxPalette32::cycleAllOff() {
+ for (int i = 0, len = ARRAYSIZE(_cyclers); i < len; ++i) {
+ PalCycler *cycler = _cyclers[i];
+ if (cycler != nullptr) {
+ clearCycleMap(cycler->fromColor, cycler->numColorsToCycle);
+ delete cycler;
+ _cyclers[i] = nullptr;
+ }
+ }
+}
+
+void GfxPalette32::applyAllCycles() {
+ Color paletteCopy[256];
+ memcpy(paletteCopy, _nextPalette.colors, sizeof(Color) * 256);
+
+ for (int cyclerIndex = 0, numCyclers = ARRAYSIZE(_cyclers); cyclerIndex < numCyclers; ++cyclerIndex) {
+ PalCycler *cycler = _cyclers[cyclerIndex];
+ if (cycler != nullptr) {
+ cycler->currentCycle = (uint8) ((((int) cycler->currentCycle) + 1) % cycler->numColorsToCycle);
+ // Disassembly was not fully evaluated to verify this is exactly the same
+ // as the code from applyCycles, but it appeared to be at a glance
+ for (int j = 0; j < cycler->numColorsToCycle; j++) {
+ _nextPalette.colors[cycler->fromColor + j] = paletteCopy[cycler->fromColor + (cycler->currentCycle + j) % cycler->numColorsToCycle];
+ }
+ }
+ }
+}
+
+void GfxPalette32::applyCycles() {
+ Color paletteCopy[256];
+ memcpy(paletteCopy, _nextPalette.colors, sizeof(Color) * 256);
+
+ for (int i = 0, len = ARRAYSIZE(_cyclers); i < len; ++i) {
+ PalCycler *cycler = _cyclers[i];
+ if (cycler == nullptr) {
+ continue;
+ }
+
+ if (cycler->delay != 0 && cycler->numTimesPaused == 0) {
+ while ((cycler->delay + cycler->lastUpdateTick) < g_sci->getTickCount()) {
+ doCycleInternal(cycler, 1);
+ cycler->lastUpdateTick += cycler->delay;
+ }
+ }
+
+ for (int j = 0; j < cycler->numColorsToCycle; j++) {
+ _nextPalette.colors[cycler->fromColor + j] = paletteCopy[cycler->fromColor + (cycler->currentCycle + j) % cycler->numColorsToCycle];
+ }
+ }
+}
+
+#pragma mark -
+#pragma mark Fading
+
+// NOTE: There are some game scripts (like SQ6 Sierra logo and main menu) that call
+// setFade with numColorsToFade set to 256, but other parts of the engine like
+// processShowStyleNone use 255 instead of 256. It is not clear if this is because
+// 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(uint16 percent, uint8 fromColor, uint16 numColorsToFade) {
+ if (fromColor > numColorsToFade) {
+ return;
+ }
+
+ assert(numColorsToFade <= ARRAYSIZE(_fadeTable));
+
+ for (int i = fromColor; i < numColorsToFade; i++)
+ _fadeTable[i] = percent;
+}
+
+void GfxPalette32::fadeOff() {
+ setFade(100, 0, 256);
+}
+
+void GfxPalette32::applyFade() {
+ for (int i = 0; i < ARRAYSIZE(_fadeTable); ++i) {
+ if (_fadeTable[i] == 100)
+ continue;
+
+ Color &color = _nextPalette.colors[i];
+
+ 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
new file mode 100644
index 0000000000..dc2158022f
--- /dev/null
+++ b/engines/sci/graphics/palette32.h
@@ -0,0 +1,411 @@
+/* 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_PALETTE32_H
+#define SCI_GRAPHICS_PALETTE32_H
+
+#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
+};
+
+struct PalCycler {
+ /**
+ * The color index of the palette cycler. This value is effectively used as the ID for the
+ * cycler.
+ */
+ uint8 fromColor;
+
+ /**
+ * The number of palette slots which are cycled by the palette cycler.
+ */
+ uint16 numColorsToCycle;
+
+ /**
+ * The position of the cursor in its cycle.
+ */
+ uint8 currentCycle;
+
+ /**
+ * The direction of the cycler.
+ */
+ PalCyclerDirection direction;
+
+ /**
+ * The cycle tick at the last time the cycler’s currentCycle was updated.
+ * 795 days of game time ought to be enough for everyone? :)
+ */
+ uint32 lastUpdateTick;
+
+ /**
+ * The amount of time in ticks each cycle should take to complete. In other words,
+ * the higher the delay, the slower the cycle animation. If delay is 0, the cycler
+ * does not automatically cycle and needs to be pumped manually with DoCycle.
+ */
+ int16 delay;
+
+ /**
+ * The number of times this cycler has been paused.
+ */
+ uint16 numTimesPaused;
+};
+
+class GfxPalette32 {
+public:
+ GfxPalette32(ResourceManager *resMan);
+ ~GfxPalette32();
+
+private:
+ ResourceManager *_resMan;
+
+ /**
+ * The palette revision version. Increments once per game
+ * loop that changes the source palette.
+ */
+ uint32 _version;
+
+ /**
+ * Whether or not the hardware palette needs updating.
+ */
+ bool _needsUpdate;
+
+ /**
+ * The currently displayed palette.
+ */
+ Palette _currentPalette;
+
+ /**
+ * The unmodified source palette loaded by kPalette. Additional
+ * palette entries may be mixed into the source palette by
+ * CelObj objects, which contain their own palettes.
+ */
+ Palette _sourcePalette;
+
+ /**
+ * The palette to be used when the hardware is next updated.
+ * On update, _nextPalette is transferred to _currentPalette.
+ */
+ Palette _nextPalette;
+
+ bool createPaletteFromResourceInternal(const GuiResourceId paletteId, Palette *const out) const;
+ Palette getPaletteFromResourceInternal(const GuiResourceId paletteId) const;
+
+public:
+ void saveLoadWithSerializer(Common::Serializer &s);
+ inline const Palette &getNextPalette() const { return _nextPalette; };
+ inline const Palette &getCurrentPalette() const { return _currentPalette; };
+
+ /**
+ * 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(const Palette &palette);
+ void submit(HunkPalette &palette);
+
+ bool updateForFrame();
+ void updateFFrame();
+ void updateHardware(const bool updateScreen = true);
+ void applyAll();
+
+#pragma mark -
+#pragma mark Color look-up
+private:
+ /**
+ * An optional lookup table used to remap RGB565 colors to a palette
+ * index. Used by Phantasmagoria 2 in 8-bit color environments.
+ */
+ byte *_clutTable;
+
+public:
+ bool loadClut(uint16 clutId);
+ byte matchClutColor(uint16 color);
+ void unloadClut();
+
+#pragma mark -
+#pragma mark Varying
+private:
+ /**
+ * An optional palette used to describe the source colors used
+ * in a palette vary operation. If this palette is not specified,
+ * sourcePalette is used instead.
+ */
+ Palette *_varyStartPalette;
+
+ /**
+ * An optional palette used to describe the target colors used
+ * in a palette vary operation.
+ */
+ Palette *_varyTargetPalette;
+
+ /**
+ * The minimum palette index that has been varied from the
+ * source palette. 0–255
+ */
+ uint8 _varyFromColor;
+
+ /**
+ * The maximum palette index that is has been varied from the
+ * source palette. 0-255
+ */
+ uint8 _varyToColor;
+
+ /**
+ * The tick at the last time the palette vary was updated.
+ */
+ uint32 _varyLastTick;
+
+ /**
+ * The amount of time to elapse, in ticks, between each cycle
+ * of a palette vary animation.
+ */
+ int _varyTime;
+
+ /**
+ * The direction of change: -1, 0, or 1.
+ */
+ int16 _varyDirection;
+
+ /**
+ * The amount, in percent, that the vary color is currently
+ * blended into the source color.
+ */
+ int16 _varyPercent;
+
+ /**
+ * The target amount that a vary color will be blended into
+ * the source color.
+ */
+ int16 _varyTargetPercent;
+
+ /**
+ * The number of time palette varying has been paused.
+ */
+ uint16 _varyNumTimesPaused;
+
+public:
+ void kernelPalVarySet(const GuiResourceId paletteId, const int16 percent, const int time, const int16 fromColor, const int16 toColor);
+ void kernelPalVaryMergeTarget(const GuiResourceId paletteId);
+ void kernelPalVarySetTarget(const GuiResourceId paletteId);
+ void kernelPalVarySetStart(const GuiResourceId paletteId);
+ void kernelPalVaryMergeStart(const GuiResourceId paletteId);
+ 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);
+ int16 getVaryPercent() const;
+ void varyOff();
+ void mergeTarget(const Palette *const palette);
+ void varyPause();
+ void varyOn();
+ void setVaryTime(const int time);
+ void setTarget(const Palette *const palette);
+ void setStart(const Palette *const palette);
+ void mergeStart(const Palette *const palette);
+ void setVaryTimeInternal(const int16 percent, const int time);
+ void applyVary();
+
+#pragma mark -
+#pragma mark Cycling
+private:
+ // SQ6 defines 10 cyclers
+ PalCycler *_cyclers[10];
+
+ /**
+ * The cycle map is used to detect overlapping cyclers.
+ * 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);
+ inline void setCycleMap(uint16 fromColor, uint16 numColorsToClear);
+ inline PalCycler *getCycler(uint16 fromColor);
+
+public:
+ void setCycle(const uint8 fromColor, const uint8 toColor, const int16 direction, const int16 delay);
+ void doCycle(const uint8 fromColor, const int16 speed);
+ void cycleOn(const uint8 fromColor);
+ void cyclePause(const uint8 fromColor);
+ void cycleAllOn();
+ void cycleAllPause();
+ void cycleOff(const uint8 fromColor);
+ void cycleAllOff();
+ void applyAllCycles();
+ void applyCycles();
+ inline const bool *getCycleMap() const { return _cycleMap; }
+
+#pragma mark -
+#pragma mark Fading
+private:
+ /**
+ * The fade table records the expected intensity level of each pixel
+ * in the palette that will be displayed on the next frame.
+ */
+ uint16 _fadeTable[256];
+
+public:
+ /**
+ * 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/picture.cpp b/engines/sci/graphics/picture.cpp
index d7ef84dc1e..2eab391afd 100644
--- a/engines/sci/graphics/picture.cpp
+++ b/engines/sci/graphics/picture.cpp
@@ -209,12 +209,12 @@ void GfxPicture::drawSci32Vga(int16 celNo, int16 drawX, int16 drawY, int16 pictu
}
// Header
- // [headerSize:WORD] [celCount:BYTE] [Unknown:BYTE] [Unknown:WORD] [paletteOffset:DWORD] [Unknown:DWORD]
+ // 0[headerSize:WORD] 2[celCount:BYTE] 3[Unknown:BYTE] 4[celHeaderSize:WORD] 6[paletteOffset:DWORD] 10[Unknown:WORD] 12[Unknown:WORD]
// cel-header follow afterwards, each is 42 bytes
// Cel-Header
- // [width:WORD] [height:WORD] [displaceX:WORD] [displaceY:WORD] [clearColor:BYTE] [compressed:BYTE]
+ // 0[width:WORD] 2[height:WORD] 4[displaceX:WORD] 6[displaceY:WORD] 8[clearColor:BYTE] 9[compressed:BYTE]
// offset 10-23 is unknown
- // [rleOffset:DWORD] [literalOffset:DWORD] [Unknown:WORD] [Unknown:WORD] [priority:WORD] [relativeXpos:WORD] [relativeYpos:WORD]
+ // 24[rleOffset:DWORD] 28[literalOffset:DWORD] 32[Unknown:WORD] 34[Unknown:WORD] 36[priority:WORD] 38[relativeXpos:WORD] 40[relativeYpos:WORD]
cel_headerPos += 42 * celNo;
diff --git a/engines/sci/graphics/picture.h b/engines/sci/graphics/picture.h
index 2404f99b41..942fa0f107 100644
--- a/engines/sci/graphics/picture.h
+++ b/engines/sci/graphics/picture.h
@@ -38,6 +38,9 @@ enum {
class GfxPorts;
class GfxScreen;
class GfxPalette;
+class GfxCoordAdjuster;
+class ResourceManager;
+class Resource;
/**
* Picture class, handles loading and displaying of picture resources
diff --git a/engines/sci/graphics/plane32.cpp b/engines/sci/graphics/plane32.cpp
new file mode 100644
index 0000000000..aa629e4081
--- /dev/null
+++ b/engines/sci/graphics/plane32.cpp
@@ -0,0 +1,951 @@
+/* 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/console.h"
+#include "sci/engine/kernel.h"
+#include "sci/engine/selector.h"
+#include "sci/engine/state.h"
+#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"
+
+namespace Sci {
+#pragma mark DrawList
+void DrawList::add(ScreenItem *screenItem, const Common::Rect &rect) {
+ DrawItem *drawItem = new DrawItem;
+ drawItem->screenItem = screenItem;
+ drawItem->rect = rect;
+ DrawListBase::add(drawItem);
+}
+
+#pragma mark -
+#pragma mark Plane
+uint16 Plane::_nextObjectId = 20000;
+
+Plane::Plane(const Common::Rect &gameRect, PlanePictureCodes pictureId) :
+_pictureId(pictureId),
+_mirrored(false),
+_type(kPlaneTypeColored),
+_back(0),
+_priorityChanged(0),
+_object(make_reg(0, _nextObjectId++)),
+_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);
+ setType();
+ _screenRect = _planeRect;
+}
+
+Plane::Plane(reg_t object) :
+_type(kPlaneTypeColored),
+_priorityChanged(false),
+_object(object),
+_redrawAllCount(g_sci->_gfxFrameout->getScreenCount()),
+_created(g_sci->_gfxFrameout->getScreenCount()),
+_updated(0),
+_deleted(0),
+_moved(0) {
+ SegManager *segMan = g_sci->getEngineState()->_segMan;
+ _vanishingPoint.x = readSelectorValue(segMan, object, SELECTOR(vanishingX));
+ _vanishingPoint.y = readSelectorValue(segMan, object, SELECTOR(vanishingY));
+
+ _gameRect.left = readSelectorValue(segMan, object, SELECTOR(inLeft));
+ _gameRect.top = readSelectorValue(segMan, object, SELECTOR(inTop));
+ _gameRect.right = readSelectorValue(segMan, object, SELECTOR(inRight)) + 1;
+ _gameRect.bottom = readSelectorValue(segMan, object, SELECTOR(inBottom)) + 1;
+ convertGameRectToPlaneRect();
+
+ _back = readSelectorValue(segMan, object, SELECTOR(back));
+ _priority = readSelectorValue(segMan, object, SELECTOR(priority));
+ _pictureId = readSelectorValue(segMan, object, SELECTOR(picture));
+ setType();
+
+ _mirrored = readSelectorValue(segMan, object, SELECTOR(mirrored));
+ _screenRect = _planeRect;
+ changePic();
+}
+
+Plane::Plane(const Plane &other) :
+_pictureId(other._pictureId),
+_mirrored(other._mirrored),
+_type(other._type),
+_back(other._back),
+_object(other._object),
+_priority(other._priority),
+_planeRect(other._planeRect),
+_gameRect(other._gameRect),
+_screenRect(other._screenRect),
+_screenItemList(other._screenItemList) {}
+
+void Plane::operator=(const Plane &other) {
+ _gameRect = other._gameRect;
+ _planeRect = other._planeRect;
+ _vanishingPoint = other._vanishingPoint;
+ _pictureId = other._pictureId;
+ _type = other._type;
+ _mirrored = other._mirrored;
+ _priority = other._priority;
+ _back = other._back;
+ _screenRect = other._screenRect;
+ _priorityChanged = other._priorityChanged;
+}
+
+void Plane::init() {
+ _nextObjectId = 20000;
+}
+
+void Plane::convertGameRectToPlaneRect() {
+ 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;
+
+ const Ratio ratioX = Ratio(screenWidth, scriptWidth);
+ const Ratio ratioY = Ratio(screenHeight, scriptHeight);
+
+ _planeRect = _gameRect;
+ mulru(_planeRect, ratioX, ratioY, 1);
+}
+
+void Plane::printDebugInfo(Console *con) const {
+ Common::String name;
+
+ if (_object.isNumber()) {
+ name = "-scummvm-";
+ } else {
+ name = g_sci->getEngineState()->_segMan->getObjectName(_object);
+ }
+
+ con->debugPrintf("%04x:%04x (%s): type %d, prio %d, pic %d, mirror %d, back %d\n",
+ PRINT_REG(_object),
+ name.c_str(),
+ _type,
+ _priority,
+ _pictureId,
+ _mirrored,
+ _back
+ );
+ con->debugPrintf(" game rect: (%d, %d, %d, %d), plane rect: (%d, %d, %d, %d)\n screen rect: (%d, %d, %d, %d)\n",
+ PRINT_RECT(_gameRect),
+ PRINT_RECT(_planeRect),
+ PRINT_RECT(_screenRect)
+ );
+ con->debugPrintf(" # screen items: %d\n", _screenItemList.size());
+}
+
+#pragma mark -
+#pragma mark Plane - Pic
+
+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->_fixedPriority = true;
+ if (position != nullptr) {
+ screenItem->_position = *position + celObj->_relativePosition;
+ } else {
+ screenItem->_position = celObj->_relativePosition;
+ }
+ _screenItemList.add(screenItem);
+
+ delete screenItem->_celObj;
+ screenItem->_celObj = celObj;
+ }
+ _type = transparent ? kPlaneTypeTransparentPicture : kPlaneTypePicture;
+}
+
+void Plane::addPic(const GuiResourceId pictureId, const Common::Point &position, const bool mirrorX) {
+ deletePic(pictureId);
+ addPicInternal(pictureId, &position, mirrorX);
+ // NOTE: In SCI engine this method returned the pictureId of the
+ // plane, but this return value was never used
+}
+
+void Plane::changePic() {
+ _pictureChanged = false;
+
+ if (_type != kPlaneTypePicture && _type != kPlaneTypeTransparentPicture) {
+ return;
+ }
+
+ addPicInternal(_pictureId, nullptr, _mirrored);
+}
+
+void Plane::deletePic(const GuiResourceId pictureId) {
+ for (ScreenItemList::iterator it = _screenItemList.begin(); it != _screenItemList.end(); ++it) {
+ ScreenItem *screenItem = *it;
+ if (screenItem->_pictureId == pictureId) {
+ screenItem->_created = 0;
+ screenItem->_updated = 0;
+ screenItem->_deleted = g_sci->_gfxFrameout->getScreenCount();
+ }
+ }
+}
+
+void Plane::deletePic(const GuiResourceId oldPictureId, const GuiResourceId newPictureId) {
+ deletePic(oldPictureId);
+ _pictureId = newPictureId;
+}
+
+void Plane::deleteAllPics() {
+ for (ScreenItemList::iterator it = _screenItemList.begin(); it != _screenItemList.end(); ++it) {
+ ScreenItem *screenItem = *it;
+ if (screenItem != nullptr && screenItem->_celInfo.type == kCelTypePic) {
+ if (screenItem->_created == 0) {
+ screenItem->_created = 0;
+ screenItem->_updated = 0;
+ screenItem->_deleted = g_sci->_gfxFrameout->getScreenCount();
+ } else {
+ _screenItemList.erase(it);
+ }
+ }
+ }
+
+ _screenItemList.pack();
+}
+
+#pragma mark -
+#pragma mark Plane - Rendering
+
+void Plane::breakDrawListByPlanes(DrawList &drawList, const PlaneList &planeList) const {
+ 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 = 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);
+ break;
+ }
+ }
+ }
+ }
+ drawList.pack();
+}
+
+void Plane::breakEraseListByPlanes(RectList &eraseList, const PlaneList &planeList) const {
+ 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 = 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);
+ break;
+ }
+ }
+ }
+ }
+ eraseList.pack();
+}
+
+void Plane::calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList &drawList, RectList &eraseList) {
+ 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;
+ }
+
+ // 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) {
+ visibleItem = visiblePlane._screenItemList[i];
+ }
+
+ // 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);
+ }
+ }
+ }
+
+ 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 {
+ 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 (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);
+ }
+ }
+ }
+ }
+
+ // Remove parts of eraselist/drawlist that are covered by other planes
+ breakEraseListByPlanes(eraseList, planeList);
+ breakDrawListByPlanes(drawList, planeList);
+
+ // 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 pictureDrawn = false;
+ bool screenItemDrawn = false;
+
+ 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 (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) {
+ mergeToDrawList(j, intersection, drawList);
+ }
+ screenItemDrawn = true;
+ }
+ } else {
+ if (!item->_updated && !item->_created) {
+ mergeToDrawList(j, intersection, drawList);
+ }
+ if (item->_celInfo.type == kCelTypePic) {
+ pictureDrawn = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ _screenItemList.unsort();
+ } else {
+ // 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 (
+ item != nullptr &&
+ !item->_created && !item->_updated && !item->_deleted &&
+ rect.intersects(item->_screenRect)
+ ) {
+ drawList.add(item, rect.findIntersectingRect(item->_screenRect));
+ }
+ }
+ }
+ }
+
+ if (g_sci->_gfxRemap32->getRemapCount() == 0) {
+ // Add all items that overlap with items in the drawlist and have higher
+ // 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);
+ }
+ }
+ }
+ }
+ }
+
+ decrementScreenItemArrayCounts(&visiblePlane, false);
+}
+
+void Plane::decrementScreenItemArrayCounts(Plane *visiblePlane, const bool forceUpdate) {
+ const ScreenItemList::size_type screenItemCount = _screenItemList.size();
+ for (ScreenItemList::size_type i = 0; i < screenItemCount; ++i) {
+ ScreenItem *item = _screenItemList[i];
+
+ if (item != nullptr) {
+ // update item in visiblePlane if item is updated
+ if (
+ item->_updated ||
+ (
+ forceUpdate &&
+ visiblePlane != nullptr &&
+ visiblePlane->_screenItemList.findByObject(item->_object) != nullptr
+ )
+ ) {
+ *visiblePlane->_screenItemList[i] = *item;
+ }
+
+ if (item->_updated) {
+ item->_updated--;
+ }
+
+ // create new item in visiblePlane if item was added
+ if (item->_created) {
+ item->_created--;
+ if (visiblePlane != nullptr) {
+ visiblePlane->_screenItemList.add(new ScreenItem(*item));
+ }
+ }
+
+ // delete item from both planes if it was deleted
+ if (item->_deleted) {
+ item->_deleted--;
+ if (!item->_deleted) {
+ 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 &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 < 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 outRects[4];
+ const Common::Rect &r2 = *higherEraseList[i];
+ int splitCount = splitRects(r2, r, outRects);
+ if (splitCount > 0) {
+ while (splitCount--) {
+ higherEraseList.add(outRects[splitCount]);
+ }
+ }
+ higherEraseList.erase_at(i);
+ }
+ }
+
+ higherEraseList.pack();
+ }
+}
+
+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, 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 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);
+
+ for (RectList::size_type i = 0; i < mergeList.size(); ++i) {
+ r = *mergeList[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 splitCount = splitRects(r, drawItem.rect, outRects);
+ if (splitCount != -1) {
+ while (splitCount--) {
+ mergeList.add(outRects[splitCount]);
+ }
+
+ mergeList.erase_at(i);
+
+ // proceed to the next rect
+ r = *mergeList[++i];
+ }
+ }
+ }
+ }
+
+ mergeList.pack();
+
+ for (RectList::size_type i = 0; i < mergeList.size(); ++i) {
+ drawList.add(&item, *mergeList[i]);
+ }
+}
+
+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 < mergeList.size(); ++i) {
+ r = *mergeList[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 outRects[4];
+ int splitCount = splitRects(r, eraseRect, outRects);
+ if (splitCount != -1) {
+ while (splitCount--) {
+ mergeList.add(outRects[splitCount]);
+ }
+
+ mergeList.erase_at(i);
+
+ // proceed to the next rect
+ r = *mergeList[++i];
+ }
+ }
+ }
+
+ mergeList.pack();
+
+ 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) {
+ 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);
+ }
+ }
+ }
+
+ eraseList.clear();
+
+ if (!_screenRect.isEmpty() && _type != kPlaneTypePicture && _type != kPlaneTypeOpaque) {
+ eraseList.add(_screenRect);
+ }
+ breakEraseListByPlanes(eraseList, planeList);
+ breakDrawListByPlanes(drawList, planeList);
+ --_redrawAllCount;
+ decrementScreenItemArrayCounts(visiblePlane, true);
+}
+
+void Plane::setType() {
+ switch (_pictureId) {
+ case kPlanePicColored:
+ _type = kPlaneTypeColored;
+ break;
+ case kPlanePicTransparent:
+ _type = kPlaneTypeTransparent;
+ break;
+ case kPlanePicOpaque:
+ _type = kPlaneTypeOpaque;
+ break;
+ case kPlanePicTransparentPicture:
+ _type = kPlaneTypeTransparentPicture;
+ break;
+ default:
+ if (_type != kPlaneTypeTransparentPicture) {
+ _type = kPlaneTypePicture;
+ }
+ break;
+ }
+}
+
+void Plane::sync(const Plane *other, const Common::Rect &screenRect) {
+ if (other == nullptr) {
+ if (_pictureChanged) {
+ deleteAllPics();
+ setType();
+ changePic();
+ _redrawAllCount = g_sci->_gfxFrameout->getScreenCount();
+ } else {
+ setType();
+ }
+ } else {
+ if (
+ _planeRect.top != other->_planeRect.top ||
+ _planeRect.left != other->_planeRect.left ||
+ _planeRect.right > other->_planeRect.right ||
+ _planeRect.bottom > other->_planeRect.bottom
+ ) {
+ // the plane moved or got larger
+ _redrawAllCount = g_sci->_gfxFrameout->getScreenCount();
+ _moved = g_sci->_gfxFrameout->getScreenCount();
+ } else if (_planeRect != other->_planeRect) {
+ // the plane got smaller
+ _moved = g_sci->_gfxFrameout->getScreenCount();
+ }
+
+ if (_priority != other->_priority) {
+ _priorityChanged = g_sci->_gfxFrameout->getScreenCount();
+ }
+
+ if (_pictureId != other->_pictureId || _mirrored != other->_mirrored || _pictureChanged) {
+ deleteAllPics();
+ setType();
+ changePic();
+ _redrawAllCount = g_sci->_gfxFrameout->getScreenCount();
+ }
+
+ if (_back != other->_back) {
+ _redrawAllCount = g_sci->_gfxFrameout->getScreenCount();
+ }
+ }
+
+ _deleted = 0;
+ if (_created == 0) {
+ _updated = g_sci->_gfxFrameout->getScreenCount();
+ }
+
+ convertGameRectToPlaneRect();
+ _screenRect = _planeRect;
+ // NOTE: screenRect originally was retrieved through globals
+ // instead of being passed into the function
+ clipScreenRect(screenRect);
+}
+
+void Plane::update(const reg_t object) {
+ SegManager *segMan = g_sci->getEngineState()->_segMan;
+ _vanishingPoint.x = readSelectorValue(segMan, object, SELECTOR(vanishingX));
+ _vanishingPoint.y = readSelectorValue(segMan, object, SELECTOR(vanishingY));
+ _gameRect.left = readSelectorValue(segMan, object, SELECTOR(inLeft));
+ _gameRect.top = readSelectorValue(segMan, object, SELECTOR(inTop));
+ _gameRect.right = readSelectorValue(segMan, object, SELECTOR(inRight)) + 1;
+ _gameRect.bottom = readSelectorValue(segMan, object, SELECTOR(inBottom)) + 1;
+ convertGameRectToPlaneRect();
+
+ _priority = readSelectorValue(segMan, object, SELECTOR(priority));
+ GuiResourceId pictureId = readSelectorValue(segMan, object, SELECTOR(picture));
+ if (_pictureId != pictureId) {
+ _pictureId = pictureId;
+ _pictureChanged = true;
+ }
+
+ _mirrored = readSelectorValue(segMan, object, SELECTOR(mirrored));
+ _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;
+ }
+
+ PlaneListBase::clear();
+}
+
+void PlaneList::erase(Plane *plane) {
+ for (iterator it = begin(); it != end(); ++it) {
+ if (*it == plane) {
+ erase(it);
+ break;
+ }
+ }
+}
+
+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) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+Plane *PlaneList::findByObject(const reg_t object) const {
+ const_iterator planeIt = Common::find_if(begin(), end(), FindByObject<Plane *>(object));
+
+ if (planeIt == end()) {
+ return nullptr;
+ }
+
+ return *planeIt;
+}
+
+int16 PlaneList::getTopPlanePriority() const {
+ if (size() > 0) {
+ return (*this)[size() - 1]->_priority;
+ }
+
+ return 0;
+}
+
+int16 PlaneList::getTopSciPlanePriority() const {
+ int16 priority = 0;
+
+ for (const_iterator it = begin(); it != end(); ++it) {
+ if ((*it)->_priority >= 10000) {
+ break;
+ }
+
+ priority = (*it)->_priority;
+ }
+
+ return priority;
+}
+
+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
new file mode 100644
index 0000000000..3981a2b319
--- /dev/null
+++ b/engines/sci/graphics/plane32.h
@@ -0,0 +1,531 @@
+/* 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_PLANE32_H
+#define SCI_GRAPHICS_PLANE32_H
+
+#include "common/array.h"
+#include "common/rect.h"
+#include "sci/engine/vm_types.h"
+#include "sci/graphics/helpers.h"
+#include "sci/graphics/lists32.h"
+#include "sci/graphics/screen_item32.h"
+
+namespace Sci {
+enum PlaneType {
+ kPlaneTypeColored = 0,
+ kPlaneTypePicture = 1,
+ kPlaneTypeTransparent = 2,
+ kPlaneTypeOpaque = 3,
+ kPlaneTypeTransparentPicture = 4
+};
+
+enum PlanePictureCodes {
+ // NOTE: Any value at or below 65531 means the plane
+ // is a kPlaneTypePicture.
+ kPlanePic = 65531,
+ kPlanePicTransparentPicture = 65532,
+ kPlanePicOpaque = 65533,
+ kPlanePicTransparent = 65534,
+ kPlanePicColored = 65535
+};
+
+#pragma mark -
+#pragma mark RectList
+
+typedef StablePointerArray<Common::Rect, 200> RectListBase;
+class RectList : public RectListBase {
+public:
+ void add(const Common::Rect &rect) {
+ RectListBase::add(new Common::Rect(rect));
+ }
+};
+
+#pragma mark -
+#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 {
+ return *screenItem < *other.screenItem;
+ }
+};
+
+typedef StablePointerArray<DrawItem, 250> DrawListBase;
+class DrawList : public DrawListBase {
+private:
+ inline static bool sortHelper(const DrawItem *a, const DrawItem *b) {
+ return *a < *b;
+ }
+public:
+ void add(ScreenItem *screenItem, const Common::Rect &rect);
+ inline void sort() {
+ pack();
+ Common::sort(begin(), end(), sortHelper);
+ }
+};
+
+class PlaneList;
+
+#pragma mark -
+#pragma mark Plane
+
+/**
+ * A plane is a grouped layer of screen items.
+ */
+class Plane {
+private:
+ /**
+ * A serial used for planes that are generated inside
+ * the graphics engine, rather than the interpreter.
+ */
+ static uint16 _nextObjectId;
+
+ /**
+ * 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
+ * PlanePictureCodes, in which case the plane becomes a
+ * non-picture plane.
+ */
+ GuiResourceId _pictureId;
+
+ /**
+ * Whether or not the contents of picture planes should
+ * be drawn horizontally mirrored. Only applies to
+ * planes of type kPlaneTypePicture.
+ */
+ bool _mirrored;
+
+ /**
+ * Whether the picture ID for this plane has changed.
+ * This flag is set when the plane is created or updated
+ * from a VM object, and is cleared when the plane is
+ * synchronised to another plane (which calls
+ * changePic).
+ */
+ bool _pictureChanged;
+
+ /**
+ * Converts the dimensions of the game rect used by
+ * scripts to the dimensions of the plane rect used to
+ * render content to the screen. Coordinates with
+ * remainders are rounded up to the next whole pixel.
+ */
+ void convertGameRectToPlaneRect();
+
+ /**
+ * Sets the type of the plane according to its assigned
+ * picture resource ID.
+ */
+ void setType();
+
+public:
+ /**
+ * The type of the plane.
+ */
+ PlaneType _type;
+
+ /**
+ * The color to use when erasing the plane. Only
+ * applies to planes of type kPlaneTypeColored.
+ */
+ byte _back;
+
+ /**
+ * Whether the priority of this plane has changed.
+ * This flag is set when the plane is updated from
+ * another plane and cleared when draw list calculation
+ * occurs.
+ */
+ int _priorityChanged;
+
+ /**
+ * A handle to the VM object corresponding to this
+ * plane. Some planes are generated purely within the
+ * graphics engine and have a numeric object value.
+ */
+ reg_t _object;
+
+ /**
+ * The rendering priority of the plane. Higher
+ * priorities are drawn above lower priorities.
+ */
+ int16 _priority;
+
+ /**
+ * 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;
+
+ /**
+ * Flags indicating the state of the plane.
+ * - `created` is set when the plane is first created,
+ * either from a VM object or from within the engine
+ * itself
+ * - `updated` is set when the plane is updated from
+ * another plane and the two planes' `planeRect`s do
+ * not match
+ * - `deleted` is set when the plane is deleted by a
+ * kernel call
+ * - `moved` is set when the plane has been moved or
+ * resized
+ */
+ int _created, _updated, _deleted, _moved;
+
+ /**
+ * The vanishing point for the plane. Used when
+ * automatically calculating the correct scaling of the
+ * plane's screen items according to their position.
+ */
+ Common::Point _vanishingPoint;
+
+ /**
+ * The position & dimensions of the plane in screen
+ * coordinates. This rect is not clipped to the screen,
+ * so may include coordinates that are offscreen.
+ */
+ Common::Rect _planeRect;
+
+ /**
+ * The position & dimensions of the plane in game script
+ * coordinates.
+ */
+ Common::Rect _gameRect;
+
+ /**
+ * The position & dimensions of the plane in screen
+ * coordinates. This rect is clipped to the screen.
+ */
+ Common::Rect _screenRect;
+
+ /**
+ * The list of screen items grouped within this plane.
+ */
+ ScreenItemList _screenItemList;
+
+public:
+ /**
+ * Initialises static Plane members.
+ */
+ static void init();
+
+ // 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 {
+ if (_priority < other._priority) {
+ return true;
+ }
+
+ if (_priority == other._priority) {
+ return _object < other._object;
+ }
+
+ return false;
+ }
+
+ /**
+ * Clips the screen rect of this plane to fit within the
+ * given screen rect.
+ */
+ inline void clipScreenRect(const Common::Rect &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;
+ _screenRect.top = 0;
+ _screenRect.right = 0;
+ _screenRect.bottom = 0;
+ }
+ }
+
+ void printDebugInfo(Console *con) const;
+
+ /**
+ * Compares the properties of the current plane against
+ * the properties of the `other` plane (which is the
+ * corresponding plane from the visible plane list) to
+ * discover which properties have been changed on this
+ * plane by a call to `update(reg_t)`.
+ *
+ * @note This method was originally called UpdatePlane
+ * in SCI engine.
+ */
+ void sync(const Plane *other, const Common::Rect &screenRect);
+
+ /**
+ * Updates the plane to match the state of the plane
+ * object from the virtual machine.
+ *
+ * @note This method was originally called UpdatePlane
+ * in SCI engine.
+ */
+ 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:
+ /**
+ * Adds all cels from the specified picture resource to
+ * the plane as screen items. If a position is provided,
+ * the screen items will be given that position;
+ * otherwise, the default relative positions for each
+ * cel will be taken from the picture resource data.
+ */
+ inline void addPicInternal(const GuiResourceId pictureId, const Common::Point *position, const bool mirrorX);
+
+ /**
+ * Marks all screen items to be deleted that are within
+ * this plane and match the given picture ID.
+ */
+ void deletePic(const GuiResourceId pictureId);
+
+ /**
+ * Marks all screen items to be deleted that are within
+ * this plane and match the given picture ID, then sets
+ * the picture ID of the plane to the new picture ID
+ * without adding any screen items.
+ */
+ void deletePic(const GuiResourceId oldPictureId, const GuiResourceId newPictureId);
+
+ /**
+ * Marks all screen items to be deleted that are within
+ * this plane and are picture cels.
+ */
+ void deleteAllPics();
+
+public:
+ /**
+ * Marks all existing screen items matching the current
+ * picture to be deleted, then adds all cels from the
+ * new picture resource to the plane at the given
+ * position.
+ */
+ 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 higher-priority, non-transparent, intersecting
+ * planes.
+ */
+ void breakDrawListByPlanes(DrawList &drawList, const PlaneList &planeList) const;
+
+ /**
+ * 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;
+
+ /**
+ * 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;
+
+ /**
+ * 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 &eraseList) const;
+
+public:
+ /**
+ * Calculates the location and dimensions of dirty rects
+ * of the screen items in this plane and adds them to
+ * the given draw and erase lists, and synchronises this
+ * plane's list of screen items to the given visible
+ * plane.
+ */
+ void calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList &drawList, RectList &eraseList);
+
+ /**
+ * 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);
+
+ /**
+ * 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 filterDownEraseRects(DrawList &drawList, RectList &eraseList, RectList &higherEraseList) 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 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 &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 -
+#pragma mark PlaneList
+
+typedef Common::Array<Plane *> PlaneListBase;
+class PlaneList : public PlaneListBase {
+private:
+ inline static bool sortHelper(const Plane *a, const Plane *b) {
+ return *a < *b;
+ }
+
+ using PlaneListBase::push_back;
+
+public:
+ // A method for finding the index of a plane inside a
+ // PlaneList is used because entries in the main plane
+ // list and visible plane list of GfxFrameout are
+ // synchronised by index
+ int findIndexByObject(const reg_t object) const;
+ Plane *findByObject(const reg_t object) const;
+
+ /**
+ * Gets the priority of the top plane in the plane list.
+ */
+ int16 getTopPlanePriority() const;
+
+ /**
+ * Gets the priority of the top plane in the plane list
+ * created by a game script.
+ */
+ int16 getTopSciPlanePriority() const;
+
+ void add(Plane *plane);
+ void clear();
+ 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/portrait.cpp b/engines/sci/graphics/portrait.cpp
index cb425f3be9..045a923569 100644
--- a/engines/sci/graphics/portrait.cpp
+++ b/engines/sci/graphics/portrait.cpp
@@ -316,7 +316,7 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint
g_sci->getEngineState()->wait(1);
curEvent = _event->getSciEvent(SCI_EVENT_ANY);
if (curEvent.type == SCI_EVENT_MOUSE_PRESS ||
- (curEvent.type == SCI_EVENT_KEYBOARD && curEvent.data == SCI_KEY_ESC) ||
+ (curEvent.type == SCI_EVENT_KEYBOARD && curEvent.character == SCI_KEY_ESC) ||
g_sci->getEngineState()->abortScriptProcessing == kAbortQuitGame ||
g_sci->getEngineState()->_delayedRestoreGame)
userAbort = true;
@@ -339,7 +339,7 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint
g_sci->getEngineState()->wait(1);
curEvent = _event->getSciEvent(SCI_EVENT_ANY);
if (curEvent.type == SCI_EVENT_MOUSE_PRESS ||
- (curEvent.type == SCI_EVENT_KEYBOARD && curEvent.data == SCI_KEY_ESC) ||
+ (curEvent.type == SCI_EVENT_KEYBOARD && curEvent.character == SCI_KEY_ESC) ||
g_sci->getEngineState()->abortScriptProcessing == kAbortQuitGame)
userAbort = true;
curPosition = _audio->getAudioPosition();
diff --git a/engines/sci/graphics/ports.cpp b/engines/sci/graphics/ports.cpp
index bcc991081e..0d00ce01e6 100644
--- a/engines/sci/graphics/ports.cpp
+++ b/engines/sci/graphics/ports.cpp
@@ -717,8 +717,10 @@ void GfxPorts::kernelGraphAdjustPriority(int top, int bottom) {
}
byte GfxPorts::kernelCoordinateToPriority(int16 y) {
- if (y < _priorityTop)
- return _priorityBands[_priorityTop];
+ if (y < 0) // Sierra did not check this, we do for safety reasons
+ return _priorityBands[0];
+ // do NOT check for _priorityTop in here. Sierra never did that and it would cause
+ // at least priority issues in room 54 of lsl2 (airplane)
if (y > _priorityBottom)
return _priorityBands[_priorityBottom];
return _priorityBands[y];
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.cpp b/engines/sci/graphics/screen.cpp
index ca5b5b3b8c..c977a93817 100644
--- a/engines/sci/graphics/screen.cpp
+++ b/engines/sci/graphics/screen.cpp
@@ -50,12 +50,14 @@ GfxScreen::GfxScreen(ResourceManager *resMan) : _resMan(resMan) {
// to provide that under DOS as well, but as gk1/floppy does support
// upscaled hires scriptswise, but doesn't actually have the hires content
// we need to limit it to platform windows.
- if (g_sci->getPlatform() == Common::kPlatformWindows) {
+ if ((g_sci->getPlatform() == Common::kPlatformWindows) || (g_sci->forceHiresGraphics())) {
if (g_sci->getGameId() == GID_KQ6)
_upscaledHires = GFX_SCREEN_UPSCALED_640x440;
#ifdef ENABLE_SCI32
if (g_sci->getGameId() == GID_GK1)
_upscaledHires = GFX_SCREEN_UPSCALED_640x480;
+ if (g_sci->getGameId() == GID_PQ4)
+ _upscaledHires = GFX_SCREEN_UPSCALED_640x480;
#endif
}
@@ -212,36 +214,6 @@ GfxScreen::GfxScreen(ResourceManager *resMan) : _resMan(resMan) {
error("Unknown SCI1.1 Mac game");
} else
initGraphics(_displayWidth, _displayHeight, _displayWidth > 320);
-
- // Initialize code pointers
- _vectorAdjustCoordinatePtr = &GfxScreen::vectorAdjustCoordinateNOP;
- _vectorAdjustLineCoordinatesPtr = &GfxScreen::vectorAdjustLineCoordinatesNOP;
- _vectorIsFillMatchPtr = &GfxScreen::vectorIsFillMatchNormal;
- _vectorPutPixelPtr = &GfxScreen::putPixelNormal;
- _vectorPutLinePixelPtr = &GfxScreen::putPixel;
- _vectorGetPixelPtr = &GfxScreen::getPixelNormal;
- _putPixelPtr = &GfxScreen::putPixelNormal;
- _getPixelPtr = &GfxScreen::getPixelNormal;
-
- switch (_upscaledHires) {
- case GFX_SCREEN_UPSCALED_480x300:
- _vectorAdjustCoordinatePtr = &GfxScreen::vectorAdjustCoordinate480x300Mac;
- _vectorAdjustLineCoordinatesPtr = &GfxScreen::vectorAdjustLineCoordinates480x300Mac;
- // vectorPutPixel -> we already adjust coordinates for vector code, that's why we can set pixels directly
- // vectorGetPixel -> see vectorPutPixel
- _vectorPutLinePixelPtr = &GfxScreen::vectorPutLinePixel480x300Mac;
- _putPixelPtr = &GfxScreen::putPixelAllUpscaled;
- _getPixelPtr = &GfxScreen::getPixelUpscaled;
- break;
- case GFX_SCREEN_UPSCALED_640x400:
- case GFX_SCREEN_UPSCALED_640x440:
- case GFX_SCREEN_UPSCALED_640x480:
- _vectorPutPixelPtr = &GfxScreen::putPixelDisplayUpscaled;
- _putPixelPtr = &GfxScreen::putPixelDisplayUpscaled;
- break;
- case GFX_SCREEN_UPSCALED_DISABLED:
- break;
- }
}
GfxScreen::~GfxScreen() {
@@ -268,17 +240,26 @@ void GfxScreen::copyToScreen() {
}
void GfxScreen::copyFromScreen(byte *buffer) {
- // TODO this ignores the pitch
Graphics::Surface *screen = g_system->lockScreen();
- memcpy(buffer, screen->getPixels(), _displayPixels);
+
+ if (screen->pitch == _displayWidth) {
+ memcpy(buffer, screen->getPixels(), _displayPixels);
+ } else {
+ const byte *src = (const byte *)screen->getPixels();
+ uint height = _displayHeight;
+
+ while (height--) {
+ memcpy(buffer, src, _displayWidth);
+ buffer += _displayWidth;
+ src += screen->pitch;
+ }
+ }
+
g_system->unlockScreen();
}
void GfxScreen::kernelSyncWithFramebuffer() {
- // TODO this ignores the pitch
- Graphics::Surface *screen = g_system->lockScreen();
- memcpy(_displayScreen, screen->getPixels(), _displayPixels);
- g_system->unlockScreen();
+ copyFromScreen(_displayScreen);
}
void GfxScreen::copyRectToScreen(const Common::Rect &rect) {
@@ -323,40 +304,68 @@ byte GfxScreen::getDrawingMask(byte color, byte prio, byte control) {
return flag;
}
-void GfxScreen::vectorAdjustCoordinateNOP(int16 *x, int16 *y) {
+void GfxScreen::vectorAdjustLineCoordinates(int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control) {
+ switch (_upscaledHires) {
+ case GFX_SCREEN_UPSCALED_480x300: {
+ int16 displayLeft = (*left * 3) / 2;
+ int16 displayRight = (*right * 3) / 2;
+ int16 displayTop = (*top * 3) / 2;
+ int16 displayBottom = (*bottom * 3) / 2;
+
+ if (displayLeft < displayRight) {
+ // one more pixel to the left, one more pixel to the right
+ if (displayLeft > 0)
+ vectorPutLinePixel(displayLeft - 1, displayTop, drawMask, color, priority, control);
+ vectorPutLinePixel(displayRight + 1, displayBottom, drawMask, color, priority, control);
+ } else if (displayLeft > displayRight) {
+ if (displayRight > 0)
+ vectorPutLinePixel(displayRight - 1, displayBottom, drawMask, color, priority, control);
+ vectorPutLinePixel(displayLeft + 1, displayTop, drawMask, color, priority, control);
+ }
+ *left = displayLeft;
+ *top = displayTop;
+ *right = displayRight;
+ *bottom = displayBottom;
+ break;
+ }
+ default:
+ break;
+ }
}
-void GfxScreen::vectorAdjustCoordinate480x300Mac(int16 *x, int16 *y) {
- *x = _upscaledWidthMapping[*x];
- *y = _upscaledHeightMapping[*y];
+// This is called from vector drawing to put a pixel at a certain location
+void GfxScreen::vectorPutLinePixel(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) {
+ if (_upscaledHires == GFX_SCREEN_UPSCALED_480x300) {
+ vectorPutLinePixel480x300(x, y, drawMask, color, priority, control);
+ return;
+ }
+
+ // For anything else forward to the regular putPixel
+ putPixel(x, y, drawMask, color, priority, control);
}
-void GfxScreen::vectorAdjustLineCoordinatesNOP(int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control) {
+// Special 480x300 Mac putPixel for vector line drawing, also draws an additional pixel below the actual one
+void GfxScreen::vectorPutLinePixel480x300(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) {
+ int offset = y * _width + x;
+
+ if (drawMask & GFX_SCREEN_MASK_VISUAL) {
+ // also set pixel below actual pixel
+ _visualScreen[offset] = color;
+ _visualScreen[offset + _width] = color;
+ _displayScreen[offset] = color;
+ _displayScreen[offset + _displayWidth] = color;
+ }
+ if (drawMask & GFX_SCREEN_MASK_PRIORITY) {
+ _priorityScreen[offset] = priority;
+ _priorityScreen[offset + _width] = priority;
+ }
+ if (drawMask & GFX_SCREEN_MASK_CONTROL) {
+ _controlScreen[offset] = control;
+ _controlScreen[offset + _width] = control;
+ }
}
-void GfxScreen::vectorAdjustLineCoordinates480x300Mac(int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control) {
- int16 displayLeft = _upscaledWidthMapping[*left];
- int16 displayRight = _upscaledWidthMapping[*right];
- int16 displayTop = _upscaledHeightMapping[*top];
- int16 displayBottom = _upscaledHeightMapping[*bottom];
-
- if (displayLeft < displayRight) {
- // one more pixel to the left, one more pixel to the right
- if (displayLeft > 0)
- vectorPutLinePixel(displayLeft - 1, displayTop, drawMask, color, priority, control);
- vectorPutLinePixel(displayRight + 1, displayBottom, drawMask, color, priority, control);
- } else if (displayLeft > displayRight) {
- if (displayRight > 0)
- vectorPutLinePixel(displayRight - 1, displayBottom, drawMask, color, priority, control);
- vectorPutLinePixel(displayLeft + 1, displayTop, drawMask, color, priority, control);
- }
- *left = displayLeft;
- *top = displayTop;
- *right = displayRight;
- *bottom = displayBottom;
-}
-
-byte GfxScreen::vectorIsFillMatchNormal(int16 x, int16 y, byte screenMask, byte checkForColor, byte checkForPriority, byte checkForControl, bool isEGA) {
+byte GfxScreen::vectorIsFillMatch(int16 x, int16 y, byte screenMask, byte checkForColor, byte checkForPriority, byte checkForControl, bool isEGA) {
int offset = y * _width + x;
byte match = 0;
@@ -386,132 +395,6 @@ byte GfxScreen::vectorIsFillMatchNormal(int16 x, int16 y, byte screenMask, byte
return match;
}
-// Special 480x300 Mac putPixel for vector line drawing, also draws an additional pixel below the actual one
-void GfxScreen::vectorPutLinePixel480x300Mac(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) {
- int offset = y * _width + x;
-
- if (drawMask & GFX_SCREEN_MASK_VISUAL) {
- _visualScreen[offset] = color;
- _visualScreen[offset + _width] = color;
- _displayScreen[offset] = color;
- // also set pixel below actual pixel
- _displayScreen[offset + _displayWidth] = color;
- }
- if (drawMask & GFX_SCREEN_MASK_PRIORITY) {
- _priorityScreen[offset] = priority;
- _priorityScreen[offset + _width] = priority;
- }
- if (drawMask & GFX_SCREEN_MASK_CONTROL) {
- _controlScreen[offset] = control;
- _controlScreen[offset + _width] = control;
- }
-}
-
-// Directly sets a pixel on various screens, display is not upscaled
-void GfxScreen::putPixelNormal(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) {
- int offset = y * _width + x;
-
- if (drawMask & GFX_SCREEN_MASK_VISUAL) {
- _visualScreen[offset] = color;
- _displayScreen[offset] = color;
- }
- if (drawMask & GFX_SCREEN_MASK_PRIORITY)
- _priorityScreen[offset] = priority;
- if (drawMask & GFX_SCREEN_MASK_CONTROL)
- _controlScreen[offset] = control;
-}
-
-// Directly sets a pixel on various screens, display IS upscaled
-void GfxScreen::putPixelDisplayUpscaled(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) {
- int offset = y * _width + x;
-
- if (drawMask & GFX_SCREEN_MASK_VISUAL) {
- _visualScreen[offset] = color;
- putScaledPixelOnScreen(_displayScreen, x, y, color);
- }
- if (drawMask & GFX_SCREEN_MASK_PRIORITY)
- _priorityScreen[offset] = priority;
- if (drawMask & GFX_SCREEN_MASK_CONTROL)
- _controlScreen[offset] = control;
-}
-
-// Directly sets a pixel on various screens, ALL screens ARE upscaled
-void GfxScreen::putPixelAllUpscaled(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) {
- if (drawMask & GFX_SCREEN_MASK_VISUAL) {
- putScaledPixelOnScreen(_visualScreen, x, y, color);
- putScaledPixelOnScreen(_displayScreen, x, y, color);
- }
- if (drawMask & GFX_SCREEN_MASK_PRIORITY)
- putScaledPixelOnScreen(_priorityScreen, x, y, priority);
- if (drawMask & GFX_SCREEN_MASK_CONTROL)
- putScaledPixelOnScreen(_controlScreen, x, y, control);
-}
-
-/**
- * This is used to put font pixels onto the screen - we adjust differently, so that we won't
- * do triple pixel lines in any case on upscaled hires. That way the font will not get distorted
- * Sierra SCI didn't do this
- */
-void GfxScreen::putFontPixel(int16 startingY, int16 x, int16 y, byte color) {
- int16 actualY = startingY + y;
- if (_fontIsUpscaled) {
- // Do not scale ourselves, but put it on the display directly
- putPixelOnDisplay(x, actualY, color);
- } else {
- int offset = actualY * _width + x;
-
- _visualScreen[offset] = color;
- switch (_upscaledHires) {
- case GFX_SCREEN_UPSCALED_DISABLED:
- _displayScreen[offset] = color;
- break;
- case GFX_SCREEN_UPSCALED_640x400:
- case GFX_SCREEN_UPSCALED_640x440:
- case GFX_SCREEN_UPSCALED_640x480: {
- // to 1-> 4 pixels upscaling for all of those, so that fonts won't look weird
- int displayOffset = (_upscaledHeightMapping[startingY] + y * 2) * _displayWidth + x * 2;
- _displayScreen[displayOffset] = color;
- _displayScreen[displayOffset + 1] = color;
- displayOffset += _displayWidth;
- _displayScreen[displayOffset] = color;
- _displayScreen[displayOffset + 1] = color;
- break;
- }
- default:
- putScaledPixelOnScreen(_displayScreen, x, actualY, color);
- break;
- }
- }
-}
-
-/**
- * This will just change a pixel directly on displayscreen. It is supposed to be
- * only used on upscaled-Hires games where hires content needs to get drawn ONTO
- * the upscaled display screen (like japanese fonts, hires portraits, etc.).
- */
-void GfxScreen::putPixelOnDisplay(int16 x, int16 y, byte color) {
- int offset = y * _displayWidth + x;
- _displayScreen[offset] = color;
-}
-
-//void GfxScreen::putScaledPixelOnDisplay(int16 x, int16 y, byte color) {
-//}
-
-void GfxScreen::putScaledPixelOnScreen(byte *screen, int16 x, int16 y, byte data) {
- int displayOffset = _upscaledHeightMapping[y] * _displayWidth + _upscaledWidthMapping[x];
- int heightOffsetBreak = (_upscaledHeightMapping[y + 1] - _upscaledHeightMapping[y]) * _displayWidth;
- int heightOffset = 0;
- int widthOffsetBreak = _upscaledWidthMapping[x + 1] - _upscaledWidthMapping[x];
- do {
- int widthOffset = 0;
- do {
- screen[displayOffset + heightOffset + widthOffset] = data;
- widthOffset++;
- } while (widthOffset != widthOffsetBreak);
- heightOffset += _displayWidth;
- } while (heightOffset != heightOffsetBreak);
-}
-
/**
* Sierra's Bresenham line drawing.
* WARNING: Do not replace this with Graphics::drawLine(), as this causes issues
@@ -593,16 +476,6 @@ void GfxScreen::putKanjiChar(Graphics::FontSJIS *commonFont, int16 x, int16 y, u
commonFont->drawChar(displayPtr, chr, _displayWidth, 1, color, 0, -1, -1);
}
-byte GfxScreen::getPixelNormal(byte *screen, int16 x, int16 y) {
- return screen[y * _width + x];
-}
-
-byte GfxScreen::getPixelUpscaled(byte *screen, int16 x, int16 y) {
- int16 mappedX = _upscaledWidthMapping[x];
- int16 mappedY = _upscaledHeightMapping[y];
- return screen[mappedY * _width + mappedX];
-}
-
int GfxScreen::bitsGetDataSize(Common::Rect rect, byte mask) {
int byteCount = sizeof(rect) + sizeof(mask);
int pixels = rect.width() * rect.height();
@@ -613,7 +486,7 @@ int GfxScreen::bitsGetDataSize(Common::Rect rect, byte mask) {
} else {
int rectHeight = _upscaledHeightMapping[rect.bottom] - _upscaledHeightMapping[rect.top];
int rectWidth = _upscaledWidthMapping[rect.right] - _upscaledWidthMapping[rect.left];
- byteCount += rectHeight * rect.width() * rectWidth; // _displayScreen (upscaled hires)
+ byteCount += rectHeight * rectWidth; // _displayScreen (upscaled hires)
}
}
if (mask & GFX_SCREEN_MASK_PRIORITY) {
@@ -627,7 +500,6 @@ int GfxScreen::bitsGetDataSize(Common::Rect rect, byte mask) {
error("bitsGetDataSize() called w/o being in upscaled hires mode");
byteCount += pixels; // _displayScreen (coordinates actually are given to us for hires displayScreen)
}
-
return byteCount;
}
@@ -794,7 +666,7 @@ void GfxScreen::dither(bool addToFlag) {
*displayPtr = color;
break;
default:
- putScaledPixelOnScreen(_displayScreen, x, y, color);
+ putScaledPixelOnDisplay(x, y, color);
break;
}
*visualPtr = color;
@@ -826,7 +698,7 @@ void GfxScreen::dither(bool addToFlag) {
*displayPtr = ditheredColor;
break;
default:
- putScaledPixelOnScreen(_displayScreen, x, y, ditheredColor);
+ putScaledPixelOnDisplay(x, y, ditheredColor);
break;
}
color = ((x^y) & 1) ? color >> 4 : color & 0x0F;
diff --git a/engines/sci/graphics/screen.h b/engines/sci/graphics/screen.h
index 1c946ef02f..65416252f6 100644
--- a/engines/sci/graphics/screen.h
+++ b/engines/sci/graphics/screen.h
@@ -76,6 +76,11 @@ public:
byte getColorWhite() { return _colorWhite; }
byte getColorDefaultVectorData() { return _colorDefaultVectorData; }
+#ifdef ENABLE_SCI32
+ byte *getDisplayScreen() { return _displayScreen; }
+ byte *getPriorityScreen() { return _priorityScreen; }
+#endif
+
void clearForRestoreGame();
void copyToScreen();
void copyFromScreen(byte *buffer);
@@ -84,51 +89,16 @@ public:
void copyDisplayRectToScreen(const Common::Rect &rect);
void copyRectToScreen(const Common::Rect &rect, int16 x, int16 y);
- // calls to code pointers
- void inline vectorAdjustCoordinate (int16 *x, int16 *y) {
- (this->*_vectorAdjustCoordinatePtr)(x, y);
- }
- void inline vectorAdjustLineCoordinates (int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control) {
- (this->*_vectorAdjustLineCoordinatesPtr)(left, top, right, bottom, drawMask, color, priority, control);
- }
- byte inline vectorIsFillMatch (int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con, bool isEGA) {
- return (this->*_vectorIsFillMatchPtr)(x, y, screenMask, t_color, t_pri, t_con, isEGA);
- }
- void inline vectorPutPixel(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) {
- (this->*_vectorPutPixelPtr)(x, y, drawMask, color, priority, control);
- }
- void inline vectorPutLinePixel(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) {
- (this->*_vectorPutLinePixelPtr)(x, y, drawMask, color, priority, control);
- }
- byte inline vectorGetVisual(int16 x, int16 y) {
- return (this->*_vectorGetPixelPtr)(_visualScreen, x, y);
- }
- byte inline vectorGetPriority(int16 x, int16 y) {
- return (this->*_vectorGetPixelPtr)(_priorityScreen, x, y);
- }
- byte inline vectorGetControl(int16 x, int16 y) {
- return (this->*_vectorGetPixelPtr)(_controlScreen, x, y);
- }
-
-
- void inline putPixel(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) {
- (this->*_putPixelPtr)(x, y, drawMask, color, priority, control);
- }
+ // Vector drawing
+private:
+ void vectorPutLinePixel(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control);
+ void vectorPutLinePixel480x300(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control);
- byte inline getVisual(int16 x, int16 y) {
- return (this->*_getPixelPtr)(_visualScreen, x, y);
- }
- byte inline getPriority(int16 x, int16 y) {
- return (this->*_getPixelPtr)(_priorityScreen, x, y);
- }
- byte inline getControl(int16 x, int16 y) {
- return (this->*_getPixelPtr)(_controlScreen, x, y);
- }
+public:
+ void vectorAdjustLineCoordinates(int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control);
+ byte vectorIsFillMatch(int16 x, int16 y, byte screenMask, byte checkForColor, byte checkForPriority, byte checkForControl, bool isEGA);
byte getDrawingMask(byte color, byte prio, byte control);
- //void putPixel(int16 x, int16 y, byte drawMask, byte color, byte prio, byte control);
- void putFontPixel(int16 startingY, int16 x, int16 y, byte color);
- void putPixelOnDisplay(int16 x, int16 y, byte color);
void drawLine(Common::Point startPoint, Common::Point endPoint, byte color, byte prio, byte control);
void drawLine(int16 left, int16 top, int16 right, int16 bottom, byte color, byte prio, byte control) {
drawLine(Common::Point(left, top), Common::Point(right, bottom), color, prio, control);
@@ -206,8 +176,8 @@ private:
byte *_controlScreen;
/**
- * This screen is the one that is actually displayed to the user. It may be
- * 640x400 for japanese SCI1 games. SCI0 games may be undithered in here.
+ * This screen is the one, where pixels are copied out of into the frame buffer.
+ * It may be 640x400 for japanese SCI1 games. SCI0 games may be undithered in here.
* Only read from this buffer for Save/ShowBits usage.
*/
byte *_displayScreen;
@@ -215,8 +185,8 @@ private:
ResourceManager *_resMan;
/**
- * Pointer to the currently active screen (changing it only required for
- * debug purposes).
+ * Pointer to the currently active screen (changing only required for
+ * debug purposes, to show for example the priority screen).
*/
byte *_activeScreen;
@@ -239,38 +209,241 @@ private:
*/
bool _fontIsUpscaled;
- // dynamic code
- void (GfxScreen::*_vectorAdjustCoordinatePtr) (int16 *x, int16 *y);
- void vectorAdjustCoordinateNOP (int16 *x, int16 *y);
- void vectorAdjustCoordinate480x300Mac (int16 *x, int16 *y);
- void (GfxScreen::*_vectorAdjustLineCoordinatesPtr) (int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control);
- void vectorAdjustLineCoordinatesNOP (int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control);
- void vectorAdjustLineCoordinates480x300Mac (int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control);
-
- byte (GfxScreen::*_vectorIsFillMatchPtr) (int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con, bool isEGA);
- byte vectorIsFillMatchNormal (int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con, bool isEGA);
- byte vectorIsFillMatch480x300Mac (int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con, bool isEGA);
+ // pixel related code, in header so that it can be inlined for performance
+public:
+ void putPixel(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) {
+ if (_upscaledHires == GFX_SCREEN_UPSCALED_480x300) {
+ putPixel480x300(x, y, drawMask, color, priority, control);
+ return;
+ }
+
+ // Set pixel for visual, priority and control map directly, those are not upscaled
+ int offset = y * _width + x;
+
+ if (drawMask & GFX_SCREEN_MASK_VISUAL) {
+ _visualScreen[offset] = color;
+
+ int displayOffset = 0;
+
+ switch (_upscaledHires) {
+ case GFX_SCREEN_UPSCALED_DISABLED:
+ displayOffset = offset;
+ _displayScreen[displayOffset] = color;
+ break;
+
+ case GFX_SCREEN_UPSCALED_640x400:
+ case GFX_SCREEN_UPSCALED_640x440:
+ case GFX_SCREEN_UPSCALED_640x480:
+ putScaledPixelOnDisplay(x, y, color);
+ break;
+ default:
+ break;
+ }
+ }
+ if (drawMask & GFX_SCREEN_MASK_PRIORITY) {
+ _priorityScreen[offset] = priority;
+ }
+ if (drawMask & GFX_SCREEN_MASK_CONTROL) {
+ _controlScreen[offset] = control;
+ }
+ }
- void (GfxScreen::*_vectorPutPixelPtr) (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control);
- void vectorPutPixel480x300Mac (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control);
+ void putPixel480x300(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) {
+ int offset = ((y * 3) / 2 * _width) + ((x * 3) / 2);
+
+ // All maps are upscaled
+ // TODO: figure out, what Sierra exactly did on Mac for these games
+ if (drawMask & GFX_SCREEN_MASK_VISUAL) {
+ putPixel480x300Worker(x, y, offset, _visualScreen, color);
+ putPixel480x300Worker(x, y, offset, _displayScreen, color);
+ }
+ if (drawMask & GFX_SCREEN_MASK_PRIORITY) {
+ putPixel480x300Worker(x, y, offset, _priorityScreen, priority);
+ }
+ if (drawMask & GFX_SCREEN_MASK_CONTROL) {
+ putPixel480x300Worker(x, y, offset, _controlScreen, control);
+ }
+ }
+ void putPixel480x300Worker(int16 x, int16 y, int offset, byte *screen, byte byteToSet) {
+ screen[offset] = byteToSet;
+ if (x & 1)
+ screen[offset + 1] = byteToSet;
+ if (y & 1)
+ screen[offset + _width] = byteToSet;
+ if ((x & 1) && (y & 1))
+ screen[offset + _width + 1] = byteToSet;
+ }
- void (GfxScreen::*_vectorPutLinePixelPtr) (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control);
- void vectorPutLinePixel480x300Mac (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control);
+ // This is called from vector drawing to put a pixel at a certain location
+ void vectorPutPixel(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) {
+ switch (_upscaledHires) {
+ case GFX_SCREEN_UPSCALED_640x400:
+ case GFX_SCREEN_UPSCALED_640x440:
+ case GFX_SCREEN_UPSCALED_640x480:
+ // For regular upscaled modes forward to the regular putPixel
+ putPixel(x, y, drawMask, color, priority, control);
+ return;
+ break;
+
+ default:
+ break;
+ }
+
+ // For non-upscaled mode and 480x300 Mac put pixels directly
+ int offset = y * _width + x;
+
+ if (drawMask & GFX_SCREEN_MASK_VISUAL) {
+ _visualScreen[offset] = color;
+ _displayScreen[offset] = color;
+ }
+ if (drawMask & GFX_SCREEN_MASK_PRIORITY) {
+ _priorityScreen[offset] = priority;
+ }
+ if (drawMask & GFX_SCREEN_MASK_CONTROL) {
+ _controlScreen[offset] = control;
+ }
+ }
- byte (GfxScreen::*_vectorGetPixelPtr) (byte *screen, int16 x, int16 y);
+ /**
+ * This will just change a pixel directly on displayscreen. It is supposed to be
+ * only used on upscaled-Hires games where hires content needs to get drawn ONTO
+ * the upscaled display screen (like japanese fonts, hires portraits, etc.).
+ */
+ void putPixelOnDisplay(int16 x, int16 y, byte color) {
+ int offset = y * _displayWidth + x;
+ _displayScreen[offset] = color;
+ }
- void (GfxScreen::*_putPixelPtr) (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control);
- void putPixelNormal (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control);
- void putPixelDisplayUpscaled (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control);
- void putPixelAllUpscaled (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control);
+ // Upscales a pixel and puts it on display screen only
+ void putScaledPixelOnDisplay(int16 x, int16 y, byte color) {
+ int displayOffset = 0;
+
+ switch (_upscaledHires) {
+ case GFX_SCREEN_UPSCALED_640x400:
+ displayOffset = (y * 2) * _displayWidth + x * 2; // straight 1 pixel -> 2 mapping
+
+ _displayScreen[displayOffset] = color;
+ _displayScreen[displayOffset + 1] = color;
+ _displayScreen[displayOffset + _displayWidth] = color;
+ _displayScreen[displayOffset + _displayWidth + 1] = color;
+ break;
+
+ case GFX_SCREEN_UPSCALED_640x440: {
+ int16 startY = (y * 11) / 5;
+ int16 endY = ((y + 1) * 11) / 5;
+ displayOffset = (startY * _displayWidth) + x * 2;
+
+ for (int16 curY = startY; curY < endY; curY++) {
+ _displayScreen[displayOffset] = color;
+ _displayScreen[displayOffset + 1] = color;
+ displayOffset += _displayWidth;
+ }
+ break;
+ }
+ case GFX_SCREEN_UPSCALED_640x480: {
+ int16 startY = (y * 12) / 5;
+ int16 endY = ((y + 1) * 12) / 5;
+ displayOffset = (startY * _displayWidth) + x * 2;
+
+ for (int16 curY = startY; curY < endY; curY++) {
+ _displayScreen[displayOffset] = color;
+ _displayScreen[displayOffset + 1] = color;
+ displayOffset += _displayWidth;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
- byte (GfxScreen::*_getPixelPtr) (byte *screen, int16 x, int16 y);
- byte getPixelNormal (byte *screen, int16 x, int16 y);
- byte getPixelUpscaled (byte *screen, int16 x, int16 y);
+ /**
+ * This is used to put font pixels onto the screen - we adjust differently, so that we won't
+ * do triple pixel lines in any case on upscaled hires. That way the font will not get distorted
+ * Sierra SCI didn't do this
+ */
+ void putFontPixel(int16 startingY, int16 x, int16 y, byte color) {
+ int16 actualY = startingY + y;
+ if (_fontIsUpscaled) {
+ // Do not scale ourselves, but put it on the display directly
+ putPixelOnDisplay(x, actualY, color);
+ } else {
+ int offset = actualY * _width + x;
+
+ _visualScreen[offset] = color;
+ switch (_upscaledHires) {
+ case GFX_SCREEN_UPSCALED_DISABLED:
+ _displayScreen[offset] = color;
+ break;
+ case GFX_SCREEN_UPSCALED_640x400:
+ case GFX_SCREEN_UPSCALED_640x440:
+ case GFX_SCREEN_UPSCALED_640x480: {
+ // to 1-> 4 pixels upscaling for all of those, so that fonts won't look weird
+ int displayOffset = (_upscaledHeightMapping[startingY] + y * 2) * _displayWidth + x * 2;
+ _displayScreen[displayOffset] = color;
+ _displayScreen[displayOffset + 1] = color;
+ displayOffset += _displayWidth;
+ _displayScreen[displayOffset] = color;
+ _displayScreen[displayOffset + 1] = color;
+ break;
+ }
+ default:
+ putScaledPixelOnDisplay(x, actualY, color);
+ break;
+ }
+ }
+ }
- // pixel helper
- void putScaledPixelOnScreen(byte *screen, int16 x, int16 y, byte color);
+ byte getPixel(byte *screen, int16 x, int16 y) {
+ switch (_upscaledHires) {
+ case GFX_SCREEN_UPSCALED_480x300: {
+ int offset = ((y * 3) / 2) * _width + ((y * 3) / 2);
+
+ return screen[offset];
+ break;
+ }
+ default:
+ break;
+ }
+ return screen[y * _width + x];
+ }
+
+ byte getVisual(int16 x, int16 y) {
+ return getPixel(_visualScreen, x, y);
+ }
+ byte getPriority(int16 x, int16 y) {
+ return getPixel(_priorityScreen, x, y);
+ }
+ byte getControl(int16 x, int16 y) {
+ return getPixel(_controlScreen, x, y);
+ }
+
+ // Vector related public code - in here, so that it can be inlined
+ byte vectorGetPixel(byte *screen, int16 x, int16 y) {
+ return screen[y * _width + x];
+ }
+
+ byte vectorGetVisual(int16 x, int16 y) {
+ return vectorGetPixel(_visualScreen, x, y);
+ }
+ byte vectorGetPriority(int16 x, int16 y) {
+ return vectorGetPixel(_priorityScreen, x, y);
+ }
+ byte vectorGetControl(int16 x, int16 y) {
+ return vectorGetPixel(_controlScreen, x, y);
+ }
+
+ void vectorAdjustCoordinate(int16 *x, int16 *y) {
+ switch (_upscaledHires) {
+ case GFX_SCREEN_UPSCALED_480x300:
+ *x = (*x * 3) / 2;
+ *y = (*y * 3) / 2;
+ break;
+ default:
+ break;
+ }
+ }
};
} // End of namespace Sci
diff --git a/engines/sci/graphics/screen_item32.cpp b/engines/sci/graphics/screen_item32.cpp
new file mode 100644
index 0000000000..7383dc222e
--- /dev/null
+++ b/engines/sci/graphics/screen_item32.cpp
@@ -0,0 +1,743 @@
+/* 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/console.h"
+#include "sci/resource.h"
+#include "sci/engine/kernel.h"
+#include "sci/engine/selector.h"
+#include "sci/engine/state.h"
+#include "sci/graphics/celobj32.h"
+#include "sci/graphics/frameout.h"
+#include "sci/graphics/screen_item32.h"
+#include "sci/graphics/view.h"
+
+namespace Sci {
+#pragma mark ScreenItem
+
+uint16 ScreenItem::_nextObjectId = 20000;
+
+ScreenItem::ScreenItem(const reg_t object) :
+_celObj(nullptr),
+_object(object),
+_pictureId(-1),
+_created(g_sci->_gfxFrameout->getScreenCount()),
+_updated(0),
+_deleted(0),
+_mirrorX(false),
+_drawBlackLines(false) {
+ SegManager *segMan = g_sci->getEngineState()->_segMan;
+
+ setFromObject(segMan, object, true, true);
+ _plane = readSelector(segMan, object, SELECTOR(plane));
+}
+
+ScreenItem::ScreenItem(const reg_t plane, const CelInfo32 &celInfo) :
+_plane(plane),
+_useInsetRect(false),
+_z(0),
+_celInfo(celInfo),
+_celObj(nullptr),
+_fixedPriority(false),
+_position(0, 0),
+_object(make_reg(0, _nextObjectId++)),
+_pictureId(-1),
+_created(g_sci->_gfxFrameout->getScreenCount()),
+_updated(0),
+_deleted(0),
+_mirrorX(false),
+_drawBlackLines(false) {}
+
+ScreenItem::ScreenItem(const reg_t plane, const CelInfo32 &celInfo, const Common::Rect &rect) :
+_plane(plane),
+_useInsetRect(false),
+_z(0),
+_celInfo(celInfo),
+_celObj(nullptr),
+_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),
+_drawBlackLines(false) {
+ if (celInfo.type == kCelTypeColor) {
+ _insetRect = rect;
+ }
+}
+
+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),
+_fixedPriority(false),
+_position(position),
+_object(make_reg(0, _nextObjectId++)),
+_pictureId(-1),
+_created(g_sci->_gfxFrameout->getScreenCount()),
+_updated(0),
+_deleted(0),
+_mirrorX(false),
+_drawBlackLines(false) {}
+
+ScreenItem::ScreenItem(const ScreenItem &other) :
+_plane(other._plane),
+_scale(other._scale),
+_useInsetRect(other._useInsetRect),
+_celInfo(other._celInfo),
+_celObj(nullptr),
+_object(other._object),
+_mirrorX(other._mirrorX),
+_scaledPosition(other._scaledPosition),
+_screenRect(other._screenRect),
+_drawBlackLines(other._drawBlackLines) {
+ if (other._useInsetRect) {
+ _insetRect = other._insetRect;
+ }
+}
+
+void ScreenItem::operator=(const ScreenItem &other) {
+ // 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;
+ if (other._useInsetRect) {
+ _insetRect = other._insetRect;
+ }
+ _scale = other._scale;
+ _scaledPosition = other._scaledPosition;
+ _drawBlackLines = other._drawBlackLines;
+}
+
+ScreenItem::~ScreenItem() {
+ delete _celObj;
+}
+
+void ScreenItem::init() {
+ _nextObjectId = 20000;
+}
+
+void ScreenItem::setFromObject(SegManager *segMan, const reg_t object, const bool updateCel, const bool updateBitmap) {
+ _position.x = readSelectorValue(segMan, object, SELECTOR(x));
+ _position.y = readSelectorValue(segMan, object, SELECTOR(y));
+ _scale.x = readSelectorValue(segMan, object, SELECTOR(scaleX));
+ _scale.y = readSelectorValue(segMan, object, SELECTOR(scaleY));
+ _scale.max = readSelectorValue(segMan, object, SELECTOR(maxScale));
+ _scale.signal = (ScaleSignals32)(readSelectorValue(segMan, object, SELECTOR(scaleSignal)) & 3);
+
+ if (updateCel) {
+ _celInfo.resourceId = (GuiResourceId)readSelectorValue(segMan, object, SELECTOR(view));
+ _celInfo.loopNo = readSelectorValue(segMan, object, SELECTOR(loop));
+ _celInfo.celNo = readSelectorValue(segMan, object, SELECTOR(cel));
+
+ if (_celInfo.resourceId <= kPlanePic) {
+ // TODO: Enhance GfxView or ResourceManager to allow
+ // metadata for resources to be retrieved once, from a
+ // single location
+ Resource *view = g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, _celInfo.resourceId), false);
+ if (!view) {
+ error("Failed to load resource %d", _celInfo.resourceId);
+ }
+
+ // NOTE: +2 because the header size field itself is excluded from
+ // the header size in the data
+ const uint16 headerSize = READ_SCI11ENDIAN_UINT16(view->data) + 2;
+ const uint8 loopCount = view->data[2];
+ const uint8 loopSize = view->data[12];
+
+ if (_celInfo.loopNo >= loopCount) {
+ const int maxLoopNo = loopCount - 1;
+ _celInfo.loopNo = maxLoopNo;
+ writeSelectorValue(segMan, object, SELECTOR(loop), maxLoopNo);
+ }
+
+ byte *loopData = view->data + headerSize + (_celInfo.loopNo * loopSize);
+ const int8 seekEntry = loopData[0];
+ if (seekEntry != -1) {
+ loopData = view->data + headerSize + (seekEntry * loopSize);
+ }
+ const uint8 celCount = loopData[2];
+ if (_celInfo.celNo >= celCount) {
+ const int maxCelNo = celCount - 1;
+ _celInfo.celNo = maxCelNo;
+ writeSelectorValue(segMan, object, SELECTOR(cel), maxCelNo);
+ }
+ }
+ }
+
+ if (updateBitmap) {
+ const reg_t bitmap = readSelector(segMan, object, SELECTOR(bitmap));
+ if (!bitmap.isNull()) {
+ _celInfo.bitmap = bitmap;
+ _celInfo.type = kCelTypeMem;
+ } else {
+ _celInfo.bitmap = NULL_REG;
+ _celInfo.type = kCelTypeView;
+ }
+ }
+
+ if (updateCel || updateBitmap) {
+ delete _celObj;
+ _celObj = nullptr;
+ }
+
+ if (readSelectorValue(segMan, object, SELECTOR(fixPriority))) {
+ _fixedPriority = true;
+ _priority = readSelectorValue(segMan, object, SELECTOR(priority));
+ } else {
+ _fixedPriority = false;
+ writeSelectorValue(segMan, object, SELECTOR(priority), _position.y);
+ }
+
+ _z = readSelectorValue(segMan, object, SELECTOR(z));
+ _position.y -= _z;
+
+ if (readSelectorValue(segMan, object, SELECTOR(useInsetRect))) {
+ _useInsetRect = true;
+ _insetRect.left = readSelectorValue(segMan, object, SELECTOR(inLeft));
+ _insetRect.top = readSelectorValue(segMan, object, SELECTOR(inTop));
+ _insetRect.right = readSelectorValue(segMan, object, SELECTOR(inRight)) + 1;
+ _insetRect.bottom = readSelectorValue(segMan, object, SELECTOR(inBottom)) + 1;
+ } else {
+ _useInsetRect = false;
+ }
+
+ segMan->getObject(object)->clearInfoSelectorFlag(kInfoFlagViewVisible);
+}
+
+void ScreenItem::calcRects(const Plane &plane) {
+ const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+ const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+ const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth;
+ const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight;
+
+ const CelObj &celObj = getCelObj();
+
+ Common::Rect celRect(celObj._width, celObj._height);
+ if (_useInsetRect) {
+ if (_insetRect.intersects(celRect)) {
+ _insetRect.clip(celRect);
+ } else {
+ _insetRect = Common::Rect();
+ }
+ } else {
+ _insetRect = celRect;
+ }
+
+ 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() && scaleY.getNumerator()) {
+ _screenItemRect = _insetRect;
+
+ 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) {
+ const Ratio scriptToCelX(celObj._scaledWidth, scriptWidth);
+ const Ratio scriptToCelY(celObj._scaledHeight, scriptHeight);
+ mulru(_screenItemRect, scriptToCelX, scriptToCelY, 0);
+
+ if (_screenItemRect.intersects(celRect)) {
+ _screenItemRect.clip(celRect);
+ } else {
+ _screenItemRect = Common::Rect();
+ }
+ }
+
+ 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 (!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;
+ }
+ }
+
+ displaceX = (displaceX * scaleX).toInt();
+ displaceY = (displaceY * scaleY).toInt();
+ }
+
+ mulinc(_screenItemRect, celToScreenX, celToScreenY);
+ displaceX = (displaceX * celToScreenX).toInt();
+ displaceY = (displaceY * celToScreenY).toInt();
+
+ 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 * scriptToScreenX).toInt() - displaceX;
+ _scaledPosition.y = (_position.y * scriptToScreenY).toInt() - displaceY;
+ }
+
+ _screenItemRect.translate(_scaledPosition.x, _scaledPosition.y);
+
+ if (_mirrorX != celObj._mirrorX && _celInfo.type == kCelTypePic) {
+ Common::Rect temp(_insetRect);
+
+ if (!scaleX.isOne()) {
+ mulinc(temp, scaleX, 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);
+
+ // TODO: This is weird.
+ int deltaX = plane._planeRect.width() - temp.right - 1 - temp.left;
+
+ _scaledPosition.x += deltaX;
+ _screenItemRect.translate(deltaX, 0);
+ }
+
+ _scaledPosition.x += plane._planeRect.left;
+ _scaledPosition.y += plane._planeRect.top;
+ _screenItemRect.translate(plane._planeRect.left, plane._planeRect.top);
+
+ _ratioX = scaleX * celToScreenX;
+ _ratioY = scaleY * celToScreenY;
+ } else {
+ // low resolution coordinates
+
+ int displaceX = celObj._displace.x;
+ if (_mirrorX != celObj._mirrorX && _celInfo.type != kCelTypePic) {
+ displaceX = celObj._width - celObj._displace.x - 1;
+ }
+
+ 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
+ // why this is the only one that reduces the BR corner
+ _screenItemRect.right -= 1;
+ _screenItemRect.bottom -= 1;
+ }
+
+ _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) {
+ Common::Rect temp(_insetRect);
+
+ if (!scaleX.isOne()) {
+ mulinc(temp, scaleX, Ratio());
+ temp.right -= 1;
+ }
+
+ CelObjPic *celObjPic = dynamic_cast<CelObjPic *>(_celObj);
+ 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.
+ int deltaX = plane._gameRect.width() - temp.right - 1 - temp.left;
+
+ _scaledPosition.x += deltaX;
+ _screenItemRect.translate(deltaX, 0);
+ }
+
+ _scaledPosition.x += plane._gameRect.left;
+ _scaledPosition.y += plane._gameRect.top;
+ _screenItemRect.translate(plane._gameRect.left, plane._gameRect.top);
+
+ if (celObj._scaledWidth != screenWidth || celObj._scaledHeight != screenHeight) {
+ mulru(_scaledPosition, celToScreenX, celToScreenY);
+ mulru(_screenItemRect, celToScreenX, celToScreenY, 1);
+ }
+
+ _ratioX = scaleX * celToScreenX;
+ _ratioY = scaleY * celToScreenY;
+ }
+
+ _screenRect = _screenItemRect;
+
+ if (_screenRect.intersects(plane._screenRect)) {
+ _screenRect.clip(plane._screenRect);
+ } else {
+ _screenRect.right = 0;
+ _screenRect.bottom = 0;
+ _screenRect.left = 0;
+ _screenRect.top = 0;
+ }
+
+ if (!_fixedPriority) {
+ _priority = _z + _position.y;
+ }
+ } else {
+ _screenRect.left = 0;
+ _screenRect.top = 0;
+ _screenRect.right = 0;
+ _screenRect.bottom = 0;
+ }
+}
+
+CelObj &ScreenItem::getCelObj() const {
+ if (_celObj == nullptr) {
+ switch (_celInfo.type) {
+ case kCelTypeView:
+ _celObj = new CelObjView(_celInfo.resourceId, _celInfo.loopNo, _celInfo.celNo);
+ break;
+ case kCelTypePic:
+ error("Internal error, pic screen item with no cel.");
+ break;
+ case kCelTypeMem:
+ _celObj = new CelObjMem(_celInfo.bitmap);
+ break;
+ case kCelTypeColor:
+ _celObj = new CelObjColor(_celInfo.color, _insetRect.width(), _insetRect.height());
+ break;
+ }
+ }
+
+ return *_celObj;
+}
+
+void ScreenItem::printDebugInfo(Console *con) const {
+ 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,
+ _position.x,
+ _position.y,
+ _z,
+ _scaledPosition.x,
+ _scaledPosition.y,
+ _created | (_updated << 1) | (_deleted << 2)
+ );
+ con->debugPrintf(" screen rect (%d, %d, %d, %d)\n", PRINT_RECT(_screenRect));
+ if (_useInsetRect) {
+ con->debugPrintf(" inset rect: (%d, %d, %d, %d)\n", PRINT_RECT(_insetRect));
+ }
+
+ Common::String celType;
+ switch (_celInfo.type) {
+ case kCelTypePic:
+ celType = "pic";
+ break;
+ case kCelTypeView:
+ celType = "view";
+ break;
+ case kCelTypeColor:
+ celType = "color";
+ break;
+ case kCelTypeMem:
+ celType = "mem";
+ break;
+ }
+
+ con->debugPrintf(" type: %s, res %d, loop %d, cel %d, bitmap %04x:%04x, color: %d\n",
+ celType.c_str(),
+ _celInfo.resourceId,
+ _celInfo.loopNo,
+ _celInfo.celNo,
+ PRINT_REG(_celInfo.bitmap),
+ _celInfo.color
+ );
+ if (_celObj != nullptr) {
+ con->debugPrintf(" width %d, height %d, scaledWidth %d, scaledHeight %d\n",
+ _celObj->_width,
+ _celObj->_height,
+ _celObj->_scaledWidth,
+ _celObj->_scaledHeight
+ );
+ }
+}
+
+void ScreenItem::update(const reg_t object) {
+ SegManager *segMan = g_sci->getEngineState()->_segMan;
+
+ const GuiResourceId view = readSelectorValue(segMan, object, SELECTOR(view));
+ const int16 loopNo = readSelectorValue(segMan, object, SELECTOR(loop));
+ const int16 celNo = readSelectorValue(segMan, object, SELECTOR(cel));
+
+ const bool updateCel = (
+ _celInfo.resourceId != view ||
+ _celInfo.loopNo != loopNo ||
+ _celInfo.celNo != celNo
+ );
+
+ const bool updateBitmap = !readSelector(segMan, object, SELECTOR(bitmap)).isNull();
+
+ setFromObject(segMan, object, updateCel, updateBitmap);
+
+ if (!_created) {
+ _updated = g_sci->_gfxFrameout->getScreenCount();
+ }
+
+ _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 {
+ const_iterator screenItemIt = Common::find_if(begin(), end(), FindByObject<ScreenItem *>(object));
+
+ if (screenItemIt == end()) {
+ return nullptr;
+ }
+
+ return *screenItemIt;
+}
+void ScreenItemList::sort() {
+ if (size() < 2) {
+ return;
+ }
+
+ for (size_type i = 0; i < size(); ++i) {
+ _unsorted[i] = i;
+ }
+
+ 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) {
+ 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
new file mode 100644
index 0000000000..3d9d5ef3d7
--- /dev/null
+++ b/engines/sci/graphics/screen_item32.h
@@ -0,0 +1,326 @@
+/* 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_SCREEN_ITEM32_H
+#define SCI_GRAPHICS_SCREEN_ITEM32_H
+
+#include "common/rect.h"
+#include "sci/graphics/celobj32.h"
+#include "sci/graphics/lists32.h"
+
+namespace Sci {
+
+enum ScaleSignals32 {
+ kScaleSignalNone = 0,
+ kScaleSignalDoScaling32 = 1, // enables scaling when drawing that cel (involves scaleX and scaleY)
+ kScaleSignalUseVanishingPoint = 2,
+ // TODO: Is this actually a thing? I have not seen it and
+ // the original engine masks &3 where it uses scale signals.
+ kScaleSignalDisableGlobalScaling32 = 4
+};
+
+struct ScaleInfo {
+ int x, y, max;
+ ScaleSignals32 signal;
+ ScaleInfo() : x(128), y(128), max(100), signal(kScaleSignalNone) {}
+};
+
+class CelObj;
+class Plane;
+class SegManager;
+
+#pragma mark -
+#pragma mark ScreenItem
+
+/**
+ * A ScreenItem is the engine-side representation of a
+ * game script View.
+ */
+class ScreenItem {
+private:
+ /**
+ * A serial used for screen items that are generated
+ * inside the graphics engine, rather than the
+ * interpreter.
+ */
+ static uint16 _nextObjectId;
+
+public:
+ /**
+ * The parent plane of this screen item.
+ */
+ reg_t _plane;
+
+ /**
+ * Scaling data used to calculate the final screen
+ * dimensions of the screen item as well as the scaling
+ * ratios used when drawing the item to screen.
+ */
+ ScaleInfo _scale;
+
+private:
+ /**
+ * The position & dimensions of the screen item in
+ * screen coordinates. This rect includes the offset
+ * of the parent plane, but is not clipped to the
+ * screen, so may include coordinates that are
+ * offscreen.
+ */
+ Common::Rect _screenItemRect;
+
+ /**
+ * 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;
+
+ /**
+ * 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;
+
+ /**
+ * The z-index of the screen item in pseudo-3D space.
+ * Higher values are drawn on top of lower values.
+ */
+ int _z;
+
+ /**
+ * Sets the common properties of a screen item that must
+ * be set both during creation and update of a screen
+ * item.
+ */
+ void setFromObject(SegManager *segMan, const reg_t object, const bool updateCel, const bool updateBitmap);
+
+public:
+ /**
+ * A descriptor for the cel object represented by the
+ * screen item.
+ */
+ CelInfo32 _celInfo;
+
+ /**
+ * The cel object used to actually render the screen
+ * item. This member is populated by calling
+ * `getCelObj`.
+ */
+ 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 _fixedPriority;
+
+ /**
+ * The rendering priority of the screen item, relative
+ * only to the other screen items within the same plane.
+ * Higher priorities are drawn above lower priorities.
+ */
+ int16 _priority;
+
+ /**
+ * The top-left corner of the screen item, in game
+ * script coordinates, relative to the parent plane.
+ */
+ Common::Point _position;
+
+ /**
+ * The associated View script object that was
+ * used to create the ScreenItem, or a numeric
+ * value in the case of a ScreenItem that was
+ * generated outside of the VM.
+ */
+ reg_t _object;
+
+ /**
+ * For screen items representing picture resources,
+ * the resource ID of the picture.
+ */
+ GuiResourceId _pictureId;
+
+ /**
+ * Flags indicating the state of the screen item.
+ * - `created` is set when the screen item is first
+ * created, either from a VM object or from within the
+ * engine itself
+ * - `updated` is set when `created` is not already set
+ * and the screen item is updated from a VM object
+ * - `deleted` is set by the parent plane, if the parent
+ * plane is a pic type and its picture resource ID has
+ * changed
+ */
+ int _created, _updated, _deleted;
+
+ /**
+ * For screen items that represent picture cels, this
+ * value is set to match the `_mirrorX` property of the
+ * parent plane and indicates that the cel should be
+ * drawn horizontally mirrored. For final drawing, it is
+ * XORed with the `_mirrorX` property of the cel object.
+ * The cel object's `_mirrorX` property comes from the
+ * resource data itself.
+ */
+ bool _mirrorX;
+
+ /**
+ * The scaling ratios to use when drawing this screen
+ * item. These values are calculated according to the
+ * scale info whenever the screen item is updated.
+ */
+ Ratio _ratioX, _ratioY;
+
+ /**
+ * The top-left corner of the screen item, in screen
+ * coordinates.
+ */
+ Common::Point _scaledPosition;
+
+ /**
+ * The position & dimensions of the screen item in
+ * screen coordinates. This rect includes the offset of
+ * the parent plane and is clipped to the screen.
+ */
+ 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();
+
+ 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::Point &position, const ScaleInfo &scaleInfo);
+ ScreenItem(const ScreenItem &other);
+ ~ScreenItem();
+ void operator=(const ScreenItem &);
+
+ 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;
+ }
+ }
+
+ 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;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Calculates the dimensions and scaling parameters for
+ * the screen item, using the given plane as the parent
+ * plane for screen rect positioning.
+ *
+ * @note This method was called Update in SCI engine.
+ */
+ void calcRects(const Plane &plane);
+
+ /**
+ * Retrieves the corresponding cel object for this
+ * screen item. If a cel object does not already exist,
+ * one will be created and assigned.
+ */
+ CelObj &getCelObj() const;
+
+ void printDebugInfo(Console *con) const;
+
+ /**
+ * Updates the properties of the screen item from a
+ * 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 -
+#pragma mark ScreenItemList
+
+typedef StablePointerArray<ScreenItem, 250> ScreenItemListBase;
+class ScreenItemList : public ScreenItemListBase {
+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/text16.cpp b/engines/sci/graphics/text16.cpp
index f463dff4b1..b0f2c52791 100644
--- a/engines/sci/graphics/text16.cpp
+++ b/engines/sci/graphics/text16.cpp
@@ -83,8 +83,7 @@ void GfxText16::ClearChar(int16 chr) {
}
// This internal function gets called as soon as a '|' is found in a text. It
-// will process the encountered code and set new font/set color. We only support
-// one-digit codes currently, don't know if multi-digit codes are possible.
+// will process the encountered code and set new font/set color.
// Returns textcode character count.
int16 GfxText16::CodeProcessing(const char *&text, GuiResourceId orgFontId, int16 orgPenColor, bool doingDrawing) {
const char *textCode = text;
@@ -99,10 +98,8 @@ int16 GfxText16::CodeProcessing(const char *&text, GuiResourceId orgFontId, int1
// c -> sets textColor to current port pen color
// cX -> sets textColor to _textColors[X-1]
curCode = textCode[0];
- curCodeParm = textCode[1];
- if (Common::isDigit(curCodeParm)) {
- curCodeParm -= '0';
- } else {
+ curCodeParm = strtol(textCode+1, NULL, 10);
+ if (!Common::isDigit(textCode[1])) {
curCodeParm = -1;
}
switch (curCode) {
@@ -144,12 +141,41 @@ int16 GfxText16::CodeProcessing(const char *&text, GuiResourceId orgFontId, int1
}
// Has actually punctuation and characters in it, that may not be the first in a line
+// SCI1 didn't check for exclamation nor question marks, us checking for those too shouldn't be bad
static const uint16 text16_shiftJIS_punctuation[] = {
+ 0x4181, 0x4281, 0x7681, 0x7881, 0x4981, 0x4881, 0
+};
+
+// Table from Quest for Glory 1 PC-98 (SCI01)
+// has pronunciation and small combining form characters on top (details right after this table)
+static const uint16 text16_shiftJIS_punctuation_SCI01[] = {
0x9F82, 0xA182, 0xA382, 0xA582, 0xA782, 0xC182, 0xE182, 0xE382, 0xE582, 0xEC82, 0x4083, 0x4283,
0x4483, 0x4683, 0x4883, 0x6283, 0x8383, 0x8583, 0x8783, 0x8E83, 0x9583, 0x9683, 0x5B81, 0x4181,
0x4281, 0x7681, 0x7881, 0x4981, 0x4881, 0
};
+// Police Quest 2 (SCI0) only checked for: 0x4181, 0x4281, 0x7681, 0x7881, 0x4981, 0x4881
+// Castle of Dr. Brain/King's Quest 5/Space Quest 4 (SCI1) only checked for: 0x4181, 0x4281, 0x7681, 0x7881
+
+// SCI0/SCI01/SCI1:
+// 0x4181 -> comma, 0x4281 -> period / full stop
+// 0x7681 -> ending quotation mark, 0x7881 -> secondary quotation mark
+
+// SCI0/SCI01:
+// 0x4981 -> exclamation mark, 0x4881 -> question mark
+
+// SCI01 (Quest for Glory only):
+// 0x9F82, 0xA182, 0xA382, 0xA582, 0xA782 -> specifies vowel part of prev. hiragana char or pronunciation/extension of vowel
+// 0xC182 -> pronunciation
+// 0xE182, 0xE382, 0xE582, 0xEC82 -> small combining form of hiragana
+// 0x4083, 0x4283, 0x4483, 0x4683, 0x4883 -> small combining form of katagana
+// 0x6283 -> glottal stop / sokuon
+// 0x8383, 0x8583 0x8783, 0x8E83 -> small combining form of katagana
+// 0x9583 -> combining form
+// 0x9683 -> abbreviation for the kanji (ka), the counter for months, places or provisions
+// 0x5b81 -> low line / underscore (full width)
+
+
// return max # of chars to fit maxwidth with full words, does not include
// breaking space
// Also adjusts text pointer to the new position for the caller
@@ -201,9 +227,10 @@ int16 GfxText16::GetLongest(const char *&textPtr, int16 maxWidth, GuiResourceId
}
// it's meant to pass through here
case 0xA:
- case 0x9781: // this one is used by SQ4/japanese as line break as well
+ case 0x9781: // this one is used by SQ4/japanese as line break as well (was added for SCI1/PC98)
curCharCount++; textPtr++;
if (curChar > 0xFF) {
+ // skip another byte in case char is double-byte (PC-98)
curCharCount++; textPtr++;
}
// and it's also meant to pass through here
@@ -261,17 +288,27 @@ int16 GfxText16::GetLongest(const char *&textPtr, int16 maxWidth, GuiResourceId
// But it also checked, if the current character is not inside a punctuation table and it even
// went backwards in case it found multiple ones inside that table.
+ // Note: PQ2 PC-98 only went back 1 character and not multiple ones
uint nonBreakingPos = 0;
+ const uint16 *punctuationTable;
+
+ if (getSciVersion() != SCI_VERSION_01) {
+ punctuationTable = text16_shiftJIS_punctuation;
+ } else {
+ // Quest for Glory 1 PC-98 only
+ punctuationTable = text16_shiftJIS_punctuation_SCI01;
+ }
+
while (1) {
// Look up if character shouldn't be the first on a new line
nonBreakingPos = 0;
- while (text16_shiftJIS_punctuation[nonBreakingPos]) {
- if (text16_shiftJIS_punctuation[nonBreakingPos] == curChar)
+ while (punctuationTable[nonBreakingPos]) {
+ if (punctuationTable[nonBreakingPos] == curChar)
break;
nonBreakingPos++;
}
- if (!text16_shiftJIS_punctuation[nonBreakingPos]) {
+ if (!punctuationTable[nonBreakingPos]) {
// character is fine
break;
}
@@ -285,6 +322,14 @@ int16 GfxText16::GetLongest(const char *&textPtr, int16 maxWidth, GuiResourceId
error("Non double byte while seeking back");
curChar |= (*(const byte *)(textPtr + 1)) << 8;
}
+
+ if (curChar == 0x4081) {
+ // Skip over alphabetic double-byte space
+ // This was introduced for SCI1
+ // Happens in Castle of Dr. Brain PC-98 in room 120, when looking inside the mirror
+ // (game mentions Mixed Up Fairy Tales and uses English letters for that)
+ textPtr += 2;
+ }
}
// We split the word in that case
diff --git a/engines/sci/graphics/text32.cpp b/engines/sci/graphics/text32.cpp
index 56ce73e8fa..277e6e93d0 100644
--- a/engines/sci/graphics/text32.cpp
+++ b/engines/sci/graphics/text32.cpp
@@ -29,363 +29,691 @@
#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"
#include "sci/graphics/screen.h"
#include "sci/graphics/text32.h"
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) :
+ _segMan(segMan),
+ _cache(fonts),
+ // 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;
+ }
+ }
-#define SCI_TEXT32_ALIGNMENT_RIGHT -1
-#define SCI_TEXT32_ALIGNMENT_CENTER 1
-#define SCI_TEXT32_ALIGNMENT_LEFT 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) {
-GfxText32::GfxText32(SegManager *segMan, GfxCache *fonts, GfxScreen *screen)
- : _segMan(segMan), _cache(fonts), _screen(screen) {
-}
+ _borderColor = borderColor;
+ _text = text;
+ _textRect = rect;
+ _width = width;
+ _height = height;
+ _foreColor = foreColor;
+ _backColor = backColor;
+ _skipColor = skipColor;
+ _alignment = alignment;
+ _dimmed = dimmed;
-GfxText32::~GfxText32() {
-}
+ setFont(fontId);
-reg_t GfxText32::createScrollTextBitmap(Common::String text, reg_t textObject, uint16 maxWidth, uint16 maxHeight, reg_t prevHunk) {
- return createTextBitmapInternal(text, textObject, maxWidth, maxHeight, prevHunk);
+ if (doScaling) {
+ int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+ int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
-}
-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));
+ Ratio scaleX(_scaledWidth, scriptWidth);
+ Ratio scaleY(_scaledHeight, scriptHeight);
- Common::String text = _segMan->getString(stringObject);
+ _width = (_width * scaleX).toInt();
+ _height = (_height * scaleY).toInt();
+ mulinc(_textRect, scaleX, scaleY);
+ }
- return createTextBitmapInternal(text, textObject, maxWidth, maxHeight, prevHunk);
-}
+ // _textRect represents where text is drawn inside the
+ // bitmap; clipRect is the entire bitmap
+ Common::Rect bitmapRect(_width, _height);
-reg_t GfxText32::createTextBitmapInternal(Common::String &text, reg_t textObject, uint16 maxWidth, uint16 maxHeight, reg_t prevHunk) {
- // HACK: The character offsets of the up and down arrow buttons are off by one
- // in GK1, for some unknown reason. Fix them here.
- if (text.size() == 1 && (text[0] == 29 || text[0] == 30)) {
- text.setChar(text[0] + 1, 0);
- }
- 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();
+ if (_textRect.intersects(bitmapRect)) {
+ _textRect.clip(bitmapRect);
+ } else {
+ _textRect = Common::Rect();
}
- int entrySize = width * height + BITMAP_HEADER_SIZE;
- reg_t memoryId = NULL_REG;
- if (prevHunk.isNull()) {
- memoryId = _segMan->allocateHunkEntry("TextBitmap()", entrySize);
+ BitmapResource bitmap(_segMan, _width, _height, _skipColor, 0, 0, _scaledWidth, _scaledHeight, 0, false);
+ _bitmap = bitmap.getObject();
- // 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;
+ erase(bitmapRect, false);
+
+ if (_borderColor > -1) {
+ drawFrame(bitmapRect, 1, _borderColor, false);
}
- byte *memoryPtr = _segMan->getHunkPointer(memoryId);
- if (prevHunk.isNull())
- memset(memoryPtr, 0, BITMAP_HEADER_SIZE);
+ drawTextBox();
+ return _bitmap;
+}
- byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE;
- memset(bitmap, backColor, width * height);
+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;
- // Save totalWidth, totalHeight
- WRITE_LE_UINT16(memoryPtr, width);
- WRITE_LE_UINT16(memoryPtr + 2, height);
+ setFont(fontId);
- 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;
+ int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+ int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
- // Calculate total text height
- while (*txt) {
- charCount = GetLongest(txt, width, font);
- if (charCount == 0)
- break;
+ mulinc(_textRect, Ratio(_scaledWidth, scriptWidth), Ratio(_scaledHeight, scriptHeight));
- Width(txt, 0, (int16)strlen(txt), fontId, textWidth, textHeight, true);
+ CelObjView view(celInfo.resourceId, celInfo.loopNo, celInfo.celNo);
+ _skipColor = view._transparentColor;
+ _width = view._width * _scaledWidth / view._scaledWidth;
+ _height = view._height * _scaledHeight / view._scaledHeight;
- totalHeight += textHeight;
- txt += charCount;
- while (*txt == ' ')
- txt++; // skip over breaking spaces
+ Common::Rect bitmapRect(_width, _height);
+ if (_textRect.intersects(bitmapRect)) {
+ _textRect.clip(bitmapRect);
+ } else {
+ _textRect = Common::Rect();
}
- 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 SCI_TEXT32_ALIGNMENT_RIGHT:
- offsetX = width - textWidth;
- break;
- case SCI_TEXT32_ALIGNMENT_CENTER:
- // Center text both horizontally and vertically
- offsetX = (width - textWidth) / 2;
- offsetY = (height - totalHeight) / 2;
- break;
- case SCI_TEXT32_ALIGNMENT_LEFT:
- offsetX = 0;
- break;
-
- default:
- warning("Invalid alignment %d used in TextBox()", alignment);
- }
+ 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.
+
+ _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));
- 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;
+ 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);
}
- }
- curX = 0;
- curY += font->getHeight();
- txt += charCount;
- while (*txt == ' ')
- txt++; // skip over breaking spaces
+ drawTextBox();
+ }
}
- return memoryId;
+ return _bitmap;
}
-void GfxText32::disposeTextBitmap(reg_t hunkId) {
- _segMan->freeHunkEntry(hunkId);
+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::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);
+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) + rect.top * _width + rect.left;
+
+ // NOTE: Not fully disassembled, but this should be right
+ 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::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));
+void GfxText32::drawChar(const char charIndex) {
+ byte *bitmap = _segMan->getHunkPointer(_bitmap);
+ byte *pixels = bitmap + READ_SCI11ENDIAN_UINT32(bitmap + 28);
- drawTextBitmapInternal(x, y, planeRect, textObject, hunkId);*/
+ _font->drawToBuffer(charIndex, _drawPosition.y, _drawPosition.x, _foreColor, _dimmed, pixels, _width, _height);
+ _drawPosition.x += _font->getCharWidth(charIndex);
+}
- // HACK: we pretty much ignore the plane rect and x, y...
- drawTextBitmapInternal(0, 0, Common::Rect(20, 390, 600, 460), textObject, hunkId);
+uint16 GfxText32::getCharWidth(const char charIndex, const bool doScaling) const {
+ uint16 width = _font->getCharWidth(charIndex);
+ if (doScaling) {
+ width = scaleUpWidth(width);
+ }
+ return width;
}
-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())
+void GfxText32::drawTextBox() {
+ if (_text.size() == 0) {
return;
+ }
- // Negative coordinates indicate that text shouldn't be displayed
- if (x < 0 || y < 0)
- return;
+ const char *text = _text.c_str();
+ const char *sourceText = text;
+ int16 textRectWidth = _textRect.width();
+ _drawPosition.y = _textRect.top;
+ uint charIndex = 0;
- byte *memoryPtr = _segMan->getHunkPointer(hunkId);
+ if (g_sci->getGameId() == GID_SQ6 || g_sci->getGameId() == GID_MOTHERGOOSEHIRES) {
+ if (getLongest(&charIndex, textRectWidth) == 0) {
+ error("DrawTextBox GetLongest=0");
+ }
+ }
- 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;
+ charIndex = 0;
+ uint nextCharIndex = 0;
+ while (*text != '\0') {
+ _drawPosition.x = _textRect.left;
+
+ uint length = getLongest(&nextCharIndex, textRectWidth);
+ int16 textWidth = getTextWidth(charIndex, length);
+
+ 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();
}
+}
- byte *surface = memoryPtr + BITMAP_HEADER_SIZE;
+void GfxText32::drawTextBox(const Common::String &text) {
+ _text = text;
+ drawTextBox();
+}
+
+void GfxText32::drawText(const uint index, uint length) {
+ assert(index + length <= _text.size());
+
+ // 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++;
+
+ if (currentChar == '|') {
+ const char controlChar = *text++;
+ --length;
- 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);
+ 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);
+ }
+ }
- // 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();
+ while (length > 0 && *text != '|') {
+ ++text;
+ --length;
+ }
+ if (length > 0) {
+ ++text;
+ --length;
+ }
+ } else {
+ drawChar(currentChar);
+ }
+ }
+}
+
+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);
+ }
+
+ byte *bitmapData = _segMan->getHunkPointer(bitmap);
+
+ // 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);
}
- bool translucent = (skipColor == -1 && backColor == -1);
+ // NOTE: Actual engine just added the bitmap header size hardcoded here
+ byte *pixel = bitmapData + READ_SCI11ENDIAN_UINT32(bitmapData + 28) + bitmapStride * targetRect.top + targetRect.left;
+
+ 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;
+ }
- 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);
+ ++pixel;
}
+
+ pixel += stride;
}
}
-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;
+uint GfxText32::getLongest(uint *charIndex, const int16 width) {
+ assert(width > 0);
+
+ uint testLength = 0;
+ uint length = 0;
+
+ const uint initialCharIndex = *charIndex;
+
+ // The index of the next word after the last word break
+ uint lastWordBreakIndex = *charIndex;
+
+ const char *text = _text.c_str() + *charIndex;
+
+ char currentChar;
+ while ((currentChar = *text++) != '\0') {
+ // NOTE: In the original engine, the font, color, and alignment were
+ // reset here to their initial values
+
+ // 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;
+ }
+
+ // 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;
+ }
+
+ // 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;
+ }
+
+ // NOTE: In the original engine, the values of _fontId, _foreColor,
+ // and _alignment were stored for use in the return path mentioned
+ // just above here
+
+ // 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;
+ }
+
+ // In the middle of a line, keep processing
+ ++*charIndex;
+ ++testLength;
+
+ // NOTE: In the original engine, the font, color, and alignment were
+ // reset here to their initial values
+
+ // 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;
}
- if (width + font->getCharWidth(curChar) > maxWidth)
- break;
- width += font->getCharWidth(curChar);
- curCharCount++;
}
- return maxChars;
+ // 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;
}
-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 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;
+ }
+ }
+
+ return width;
}
-void GfxText32::StringWidth(const char *str, GuiResourceId fontId, int16 &textWidth, int16 &textHeight) {
- Width(str, 0, (int16)strlen(str), fontId, textWidth, textHeight, true);
+int16 GfxText32::getTextWidth(const Common::String &text, const uint index, const uint length) {
+ _text = text;
+ return scaleUpWidth(getTextWidth(index, length));
}
-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;
+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;
+
+ 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;
}
-int16 GfxText32::Size(Common::Rect &rect, const char *text, GuiResourceId fontId, int16 maxWidth) {
- int16 charCount;
- int16 maxTextWidth = 0, textWidth;
- int16 totalHeight = 0, textHeight;
+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);
+}
- // Adjust maxWidth if we're using an upscaled font
- if (_screen->fontIsUpscaled())
- maxWidth = maxWidth * _screen->getDisplayWidth() / _screen->getWidth();
+int16 GfxText32::getStringWidth(const Common::String &text) {
+ return getTextWidth(text, 0, 10000);
+}
- rect.top = rect.left = 0;
- GfxFont *font = _cache->getFont(fontId);
+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;
- if (maxWidth < 0) { // force output as single line
- StringWidth(text, fontId, textWidth, textHeight);
- rect.bottom = textHeight;
- rect.right = textWidth;
+ Common::Rect scaledRect(textRect);
+ if (doScaling) {
+ mulinc(scaledRect, Ratio(_scaledWidth, scriptWidth), Ratio(_scaledHeight, scriptHeight));
+ }
+
+ Common::String oldText = _text;
+ _text = text;
+
+ 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);
}
- // Adjust the width/height if we're using an upscaled font
- // for the scripts
- if (_screen->fontIsUpscaled()) {
- rect.right = rect.right * _screen->getWidth() / _screen->getDisplayWidth();
- rect.bottom = rect.bottom * _screen->getHeight() / _screen->getDisplayHeight();
+ 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++;
+ }
+
+ 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;
}
- return rect.right;
+ //_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 7ba7df50e4..a61760dd87 100644
--- a/engines/sci/graphics/text32.h
+++ b/engines/sci/graphics/text32.h
@@ -23,34 +23,462 @@
#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 {
+ 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));\
+}
+
/**
- * Text32 class, handles text calculation and displaying of text for SCI2, SCI21 and SCI3 games
+ * A convenience class for creating and modifying in-memory
+ * bitmaps.
*/
-class GfxText32 {
+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:
- GfxText32(SegManager *segMan, GfxCache *fonts, GfxScreen *screen);
- ~GfxText32();
- 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);
+ /**
+ * 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));
+ }
- void kernelTextSize(const char *text, int16 font, int16 maxWidth, int16 *textWidth, int16 *textHeight);
+ _buffer = Buffer(getWidth(), getHeight(), getPixels());
+ }
-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);
+ /**
+ * 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
+ * nearly the same as SCI16, which means this class behaves
+ * similarly. Notably, GfxText32 maintains drawing
+ * parameters across multiple calls.
+ */
+class GfxText32 {
+private:
SegManager *_segMan;
GfxCache *_cache;
- GfxScreen *_screen;
+
+ /**
+ * The resource ID of the default font used by the game.
+ *
+ * @todo Check all SCI32 games to learn what their
+ * default font is.
+ */
+ static int16 _defaultFontId;
+
+ /**
+ * 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;
+
+ /**
+ * The color used to draw text.
+ */
+ uint8 _foreColor;
+
+ /**
+ * The background color of the text box.
+ */
+ uint8 _backColor;
+
+ /**
+ * The transparent color of the text box. Used when
+ * compositing the bitmap onto the screen.
+ */
+ uint8 _skipColor;
+
+ /**
+ * The rect where the text is drawn within the bitmap.
+ * This rect is clipped to the dimensions of the bitmap.
+ */
+ Common::Rect _textRect;
+
+ /**
+ * The text being drawn to the currently active text
+ * bitmap.
+ */
+ Common::String _text;
+
+ /**
+ * The font being used to draw the text.
+ */
+ GuiResourceId _fontId;
+
+ /**
+ * The color of the text box border.
+ */
+ int16 _borderColor;
+
+ /**
+ * TODO: Document
+ */
+ bool _dimmed;
+
+ /**
+ * The text alignment for the drawn text.
+ */
+ TextAlign _alignment;
+
+ /**
+ * The position of the text draw cursor.
+ */
+ 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);
+
+ /**
+ * 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.
+ */
+ uint getLongest(uint *charIndex, const int16 maxWidth);
+
+ /**
+ * Gets the pixel width of a substring of the currently
+ * loaded text, without scaling.
+ */
+ int16 getTextWidth(const uint index, uint length) const;
+
+ inline Common::Rect scaleRect(const Common::Rect &rect) {
+ Common::Rect scaledRect(rect);
+ int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+ int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+ Ratio scaleX(_scaledWidth, scriptWidth);
+ Ratio scaleY(_scaledHeight, scriptHeight);
+ mulinc(scaledRect, scaleX, scaleY);
+ return scaledRect;
+ }
+
+public:
+ 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. Static since it was global in SSCI.
+ */
+ static int16 _scaledWidth;
+
+ /**
+ * The size of the y-dimension of the coordinate system
+ * used by the text renderer. Static since it was global in SSCI.
+ */
+ static int16 _scaledHeight;
+
+ /**
+ * 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;
+
+ /**
+ * 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);
+
+ /**
+ * 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);
+
+ inline int scaleUpWidth(int value) const {
+ const int scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+ return (value * scriptWidth + _scaledWidth - 1) / _scaledWidth;
+ }
+
+ inline int scaleUpHeight(int value) const {
+ const int scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+ return (value * scriptHeight + _scaledHeight - 1) / _scaledHeight;
+ }
+
+ /**
+ * Draws the text to the bitmap.
+ */
+ void drawTextBox();
+
+ /**
+ * 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 da61ecf4c3..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"
@@ -356,7 +357,7 @@ void GfxView::initData(GuiResourceId resourceId) {
for (loopNo = 0; loopNo < _loopCount; loopNo++)
for (celNo = 0; celNo < _loop[loopNo].celCount; celNo++)
_screen->adjustBackUpscaledCoordinates(_loop[loopNo].cel[celNo].scriptWidth, _loop[loopNo].cel[celNo].scriptHeight, _sci2ScaleRes);
- } else if (getSciVersion() == SCI_VERSION_2_1) {
+ } else if ((getSciVersion() >= SCI_VERSION_2_1_EARLY) && (getSciVersion() <= SCI_VERSION_2_1_LATE)) {
for (loopNo = 0; loopNo < _loopCount; loopNo++)
for (celNo = 0; celNo < _loop[loopNo].celCount; celNo++)
_coordAdjuster->fromDisplayToScript(_loop[loopNo].cel[celNo].scriptHeight, _loop[loopNo].cel[celNo].scriptWidth);
@@ -833,19 +834,6 @@ void GfxView::draw(const Common::Rect &rect, const Common::Rect &clipRect, const
bitmap += (clipRect.top - rect.top) * celWidth + (clipRect.left - rect.left);
- // WORKAROUND: EcoQuest French and German draw the fish and anemone sprites
- // with priority 15 in scene 440. Afterwards, a dialog is shown on top of
- // these sprites with priority 15 as well. This is undefined behavior
- // actually, as the sprites and dialog share the same priority, so in our
- // implementation the sprites get drawn incorrectly on top of the dialog.
- // Perhaps this worked by mistake in SSCI because of subtle differences in
- // how sprites are drawn. We compensate for this by resetting the priority
- // of all sprites that have a priority of 15 in scene 440 to priority 14,
- // so that the speech bubble can be drawn correctly on top of them. Fixes
- // bug #3040625.
- if (g_sci->getGameId() == GID_ECOQUEST && g_sci->getEngineState()->currentRoomNumber() == 440 && priority == 15)
- priority = 14;
-
if (!_EGAmapping) {
for (y = 0; y < height; y++, bitmap += celWidth) {
for (x = 0; x < width; x++) {
@@ -855,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
@@ -970,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);
}
}
}
@@ -989,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 33392e3b42..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 \
@@ -81,10 +82,18 @@ MODULE_OBJS := \
ifdef ENABLE_SCI32
MODULE_OBJS += \
engine/kgraphics32.o \
+ graphics/celobj32.o \
graphics/controls32.o \
graphics/frameout.o \
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 10740a8b7b..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"
@@ -82,8 +85,12 @@ const char *getSciVersionDesc(SciVersion version) {
return "SCI1.1";
case SCI_VERSION_2:
return "SCI2";
- case SCI_VERSION_2_1:
- return "SCI2.1";
+ case SCI_VERSION_2_1_EARLY:
+ return "Early SCI2.1";
+ case SCI_VERSION_2_1_MIDDLE:
+ return "Middle SCI2.1";
+ case SCI_VERSION_2_1_LATE:
+ return "Late SCI2.1";
case SCI_VERSION_3:
return "SCI3";
default:
@@ -217,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();
}
@@ -225,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;
@@ -303,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)
@@ -561,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) {
@@ -583,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??");
@@ -861,6 +872,7 @@ ResourceManager::ResourceManager() {
}
void ResourceManager::init() {
+ _maxMemoryLRU = 256 * 1024; // 256KiB
_memoryLocked = 0;
_memoryLRU = 0;
_LRU.clear();
@@ -914,6 +926,14 @@ void ResourceManager::init() {
debugC(1, kDebugLevelResMan, "resMan: Detected %s", getSciVersionDesc(getSciVersion()));
+ // Resources in SCI32 games are significantly larger than SCI16
+ // games and can cause immediate exhaustion of the LRU resource
+ // cache, leading to constant decompression of picture resources
+ // and making the renderer very slow.
+ if (getSciVersion() >= SCI_VERSION_2) {
+ _maxMemoryLRU = 2048 * 1024; // 2MiB
+ }
+
switch (_viewType) {
case kViewEga:
debugC(1, kDebugLevelResMan, "resMan: Detected EGA graphic resources");
@@ -931,35 +951,14 @@ void ResourceManager::init() {
debugC(1, kDebugLevelResMan, "resMan: Detected SCI1.1 VGA graphic resources");
break;
default:
-#ifdef ENABLE_SCI32
- error("resMan: Couldn't determine view type");
-#else
- if (getSciVersion() >= SCI_VERSION_2) {
- // SCI support isn't built in, thus the view type won't be determined for
- // SCI2+ games. This will be handled further up, so throw no error here
- } else {
- error("resMan: Couldn't determine view type");
- }
-#endif
+ // Throw a warning, but do not error out here, because this is called from the
+ // fallback detector, and the user could be pointing to a folder with a non-SCI
+ // game, but with SCI-like file names (e.g. Pinball Creep)
+ warning("resMan: Couldn't determine view type");
+ break;
}
}
-void ResourceManager::initForDetection() {
- assert(!g_sci);
-
- _memoryLocked = 0;
- _memoryLRU = 0;
- _LRU.clear();
- _resMap.clear();
- _audioMapSCI1 = NULL;
-
- _mapVersion = detectMapVersion();
- _volVersion = detectVolVersion();
-
- scanNewSources();
- detectSciVersion();
-}
-
ResourceManager::~ResourceManager() {
// freeing resources
ResourceMap::iterator itr = _resMap.begin();
@@ -994,9 +993,9 @@ void ResourceManager::addToLRU(Resource *res) {
_LRU.push_front(res);
_memoryLRU += res->size;
#if SCI_VERBOSE_RESMAN
- debug("Adding %s.%03d (%d bytes) to lru control: %d bytes total",
- getResourceTypeName(res->type), res->number, res->size,
- mgr->_memoryLRU);
+ debug("Adding %s (%d bytes) to lru control: %d bytes total",
+ res->_id.toString().c_str(), res->size,
+ _memoryLRU);
#endif
res->_status = kResStatusEnqueued;
}
@@ -1019,13 +1018,13 @@ void ResourceManager::printLRU() {
}
void ResourceManager::freeOldResources() {
- while (MAX_MEMORY < _memoryLRU) {
+ while (_maxMemoryLRU < _memoryLRU) {
assert(!_LRU.empty());
Resource *goner = *_LRU.reverse_begin();
removeFromLRU(goner);
goner->unalloc();
#ifdef SCI_VERBOSE_RESMAN
- debug("resMan-debug: LRU: Freeing %s.%03d (%d bytes)", getResourceTypeName(goner->type), goner->number, goner->size);
+ debug("resMan-debug: LRU: Freeing %s (%d bytes)", goner->_id.toString().c_str(), goner->size);
#endif
}
}
@@ -1052,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.
@@ -1361,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;
@@ -1369,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;
}
@@ -1379,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;
}
@@ -1403,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;
}
@@ -1450,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();
@@ -2121,6 +2137,79 @@ ViewType ResourceManager::detectViewType() {
return kViewUnknown;
}
+// to detect selector "wordFail" in LE vocab resource
+static const byte detectSci21EarlySignature[] = {
+ 10, // size of signature
+ 0x08, 0x00, 'w', 'o', 'r', 'd', 'F', 'a', 'i', 'l'
+};
+
+// to detect selector "wordFail" in BE vocab resource (SCI2.1 Early)
+static const byte detectSci21EarlyBESignature[] = {
+ 10, // size of signature
+ 0x00, 0x08, 'w', 'o', 'r', 'd', 'F', 'a', 'i', 'l'
+};
+
+// to detect new kString calling to detect SCI2.1 Late
+static const byte detectSci21NewStringSignature[] = {
+ 8, // size of signature
+ 0x78, // push1
+ 0x78, // push1
+ 0x39, 0x09, // pushi 09
+ 0x59, 0x01, // rest 01
+ 0x43, 0x5c, // callk String
+};
+
+bool ResourceManager::checkResourceDataForSignature(Resource *resource, const byte *signature) {
+ byte signatureSize = *signature;
+ const byte *resourceData = resource->data;
+
+ signature++; // skip over size byte
+ if (signatureSize < 4)
+ error("resource signature is too small, internal error");
+ if (signatureSize > resource->size)
+ return false;
+
+ const uint32 signatureDWord = *((const uint32 *)signature);
+ signature += 4; signatureSize -= 4;
+
+ const uint32 searchLimit = resource->size - signatureSize + 1;
+ uint32 DWordOffset = 0;
+ while (DWordOffset < searchLimit) {
+ if (signatureDWord == READ_UINT32(resourceData + DWordOffset)) {
+ // magic DWORD found, check if the rest matches as well
+ uint32 offset = DWordOffset + 4;
+ uint32 signaturePos = 0;
+ while (signaturePos < signatureSize) {
+ if (resourceData[offset] != signature[signaturePos])
+ break;
+ offset++;
+ signaturePos++;
+ }
+ if (signaturePos >= signatureSize)
+ return true; // signature found
+ }
+ DWordOffset++;
+ }
+ return false;
+}
+
+bool ResourceManager::checkResourceForSignatures(ResourceType resourceType, uint16 resourceNr, const byte *signature1, const byte *signature2) {
+ Resource *resource = findResource(ResourceId(resourceType, resourceNr), false);
+
+ if (resource) {
+ // resource found and loaded, check for signatures
+ if (signature1) {
+ if (checkResourceDataForSignature(resource, signature1))
+ return true;
+ }
+ if (signature2) {
+ if (checkResourceDataForSignature(resource, signature2))
+ return true;
+ }
+ }
+ return false;
+}
+
void ResourceManager::detectSciVersion() {
// We use the view compression to set a preliminary s_sciVersion for the sake of getResourceInfo
// Pretend we have a SCI0 game
@@ -2180,31 +2269,52 @@ void ResourceManager::detectSciVersion() {
// no Mac SCI2 games. Yes, that means that GK1 Mac is SCI2.1 and not SCI2.
// TODO: Decide between SCI2.1 and SCI3
- if (res)
- s_sciVersion = SCI_VERSION_2_1;
- else
+ if (res) {
+ s_sciVersion = SCI_VERSION_2_1_EARLY; // we check for SCI2.1 specifics a bit later
+ } else {
s_sciVersion = SCI_VERSION_1_1;
- return;
+ return;
+ }
}
// Handle SCI32 versions here
- if (_volVersion >= kResVersionSci2) {
- Common::List<ResourceId> heaps = listResources(kResourceTypeHeap);
- bool hasHeapResources = !heaps.empty();
-
- // SCI2.1/3 and SCI1 Late resource maps are the same, except that
- // SCI1 Late resource maps have the resource types or'd with
- // 0x80. We differentiate between SCI2 and SCI2.1/3 based on that.
- if (_mapVersion == kResVersionSci1Late) {
- s_sciVersion = SCI_VERSION_2;
- return;
- } else if (hasHeapResources) {
- s_sciVersion = SCI_VERSION_2_1;
+ if (s_sciVersion != SCI_VERSION_2_1_EARLY) {
+ if (_volVersion >= kResVersionSci2) {
+ Common::List<ResourceId> heaps = listResources(kResourceTypeHeap);
+ bool hasHeapResources = !heaps.empty();
+
+ // SCI2.1/3 and SCI1 Late resource maps are the same, except that
+ // SCI1 Late resource maps have the resource types or'd with
+ // 0x80. We differentiate between SCI2 and SCI2.1/3 based on that.
+ if (_mapVersion == kResVersionSci1Late) {
+ s_sciVersion = SCI_VERSION_2;
+ return;
+ } else if (hasHeapResources) {
+ s_sciVersion = SCI_VERSION_2_1_EARLY; // exact SCI2.1 version is checked a bit later
+ } else {
+ s_sciVersion = SCI_VERSION_3;
+ return;
+ }
+ }
+ }
+
+ if (s_sciVersion == SCI_VERSION_2_1_EARLY) {
+ // we only know that it's SCI2.1, not which exact version it is
+
+ // check, if selector "wordFail" inside vocab 997 exists, if it does it's SCI2.1 Early
+ if ((checkResourceForSignatures(kResourceTypeVocab, 997, detectSci21EarlySignature, detectSci21EarlyBESignature))) {
+ // found -> it is SCI2.1 early
return;
- } else {
- s_sciVersion = SCI_VERSION_3;
+ }
+
+ s_sciVersion = SCI_VERSION_2_1_MIDDLE;
+ if (checkResourceForSignatures(kResourceTypeScript, 64918, detectSci21NewStringSignature, nullptr)) {
+ // new kString call detected, it's SCI2.1 late
+ // TODO: this call seems to be different on Mac
+ s_sciVersion = SCI_VERSION_2_1_LATE;
return;
}
+ return;
}
// Check for transitive SCI1/SCI1.1 games, like PQ1 here
@@ -2376,7 +2486,9 @@ bool ResourceManager::hasOldScriptHeader() {
Resource *res = findResource(ResourceId(kResourceTypeScript, 0), 0);
if (!res) {
- error("resMan: Failed to find script.000");
+ // Script 0 missing -> corrupted / non-SCI resource files.
+ // Don't error out here, because this might have been called
+ // from the fallback detector
return false;
}
@@ -2537,7 +2649,7 @@ reg_t ResourceManager::findGameObject(bool addSci11ScriptOffset) {
int16 offset = !isSci11Mac() ? READ_LE_UINT16(offsetPtr) : READ_BE_UINT16(offsetPtr);
return make_reg(1, offset);
- } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
+ } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
offsetPtr = script->data + 4 + 2 + 2;
// In SCI1.1 - SCI2.1, the heap is appended at the end of the script,
@@ -2565,7 +2677,7 @@ Common::String ResourceManager::findSierraGameId() {
if (getSciVersion() < SCI_VERSION_1_1) {
heap = findResource(ResourceId(kResourceTypeScript, 0), false);
- } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
+ } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
heap = findResource(ResourceId(kResourceTypeHeap, 0), false);
nameSelector += 5;
} else if (getSciVersion() == SCI_VERSION_3) {
@@ -2581,7 +2693,9 @@ Common::String ResourceManager::findSierraGameId() {
return "";
// Seek to the name selector of the first export
- byte *seeker = heap->data + READ_UINT16(heap->data + gameObjectOffset + nameSelector * 2);
+ byte *offsetPtr = heap->data + gameObjectOffset + nameSelector * 2;
+ uint16 offset = !isSci11Mac() ? READ_LE_UINT16(offsetPtr) : READ_BE_UINT16(offsetPtr);
+ byte *seeker = heap->data + offset;
Common::String sierraId;
sierraId += (const char *)seeker;
diff --git a/engines/sci/resource.h b/engines/sci/resource.h
index ef48998b04..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
@@ -315,11 +326,6 @@ public:
void init();
/**
- * Similar to the function above, only called from the fallback detector
- */
- void initForDetection();
-
- /**
* Adds all of the resource files for a game
*/
int addAppropriateSources();
@@ -426,9 +432,7 @@ protected:
// Note: maxMemory will not be interpreted as a hard limit, only as a restriction
// for resources which are not explicitly locked. However, a warning will be
// issued whenever this limit is exceeded.
- enum {
- MAX_MEMORY = 256 * 1024 // 256KB
- };
+ int _maxMemoryLRU;
ViewType _viewType; // Used to determine if the game has EGA or VGA graphics
Common::List<ResourceSource *> _sources;
@@ -559,6 +563,8 @@ protected:
ViewType detectViewType();
bool hasSci0Voc999();
bool hasSci1Voc900();
+ bool checkResourceDataForSignature(Resource *resource, const byte *signature);
+ bool checkResourceForSignatures(ResourceType resourceType, uint16 resourceNr, const byte *signature1, const byte *signature2);
void detectSciVersion();
};
diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp
index 3a43774492..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);
@@ -637,7 +637,7 @@ SoundResource::SoundResource(uint32 resourceNr, ResourceManager *resMan, SciVers
case SCI_VERSION_1_EARLY:
case SCI_VERSION_1_LATE:
- case SCI_VERSION_2_1:
+ case SCI_VERSION_2_1_EARLY:
data = resource->data;
// Count # of tracks
_trackCount = 0;
@@ -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 668ad053cc..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,13 +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/text32.h"
+#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/video32.h"
+#include "sci/sound/audio32.h"
+// TODO: Move this to video32
#include "sci/video/robot_decoder.h"
#endif
@@ -84,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;
@@ -94,6 +106,8 @@ SciEngine::SciEngine(OSystem *syst, const ADGameDescription *desc, SciGameId gam
_console = 0;
_opcode_formats = 0;
+ _forceHiresGraphics = false;
+
// Set up the engine specific debug levels
DebugMan.addDebugChannel(kDebugLevelError, "Error", "Script error debugging");
DebugMan.addDebugChannel(kDebugLevelNodes, "Lists", "Lists and nodes debugging");
@@ -154,25 +168,35 @@ SciEngine::~SciEngine() {
#ifdef ENABLE_SCI32
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 _gfxPalette;
+ delete _gfxPalette16;
+ delete _gfxRemap16;
delete _gfxCursor;
delete _gfxScreen;
delete _audio;
+ delete _sync;
delete _soundCmd;
delete _kernel;
delete _vocabulary;
@@ -194,12 +218,6 @@ SciEngine::~SciEngine() {
extern void showScummVMDialog(const Common::String &message);
Common::Error SciEngine::run() {
- // Assign default values to the config manager, in case settings are missing
- ConfMan.registerDefault("originalsaveload", "false");
- ConfMan.registerDefault("native_fb01", "false");
- ConfMan.registerDefault("windows_cursors", "false"); // Windows cursors for KQ6 Windows
- ConfMan.registerDefault("silver_cursors", "false"); // Silver cursors for SQ4 CD
-
_resMan = new ResourceManager();
assert(_resMan);
_resMan->addAppropriateSources();
@@ -224,6 +242,32 @@ Common::Error SciEngine::run() {
_scriptPatcher = new ScriptPatcher();
SegManager *segMan = new SegManager(_resMan, _scriptPatcher);
+ // Read user option for hires graphics
+ // Only show/selectable for:
+ // - King's Quest 6 CD
+ // - King's Quest 6 CD demo
+ // - Gabriel Knight 1 CD
+ // - Police Quest 4 CD
+ // TODO: Check, if Gabriel Knight 1 floppy supports high resolution
+ // TODO: Check, if Gabriel Knight 1 on Mac supports high resolution
+ switch (getPlatform()) {
+ case Common::kPlatformDOS:
+ case Common::kPlatformWindows:
+ // Only DOS+Windows
+ switch (_gameId) {
+ case GID_KQ6:
+ case GID_GK1:
+ case GID_PQ4:
+ if (isCD())
+ _forceHiresGraphics = ConfMan.getBool("enable_high_resolution_graphics");
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ };
+
// Initialize the game screen
_gfxScreen = new GfxScreen(_resMan);
_gfxScreen->enableUndithering(ConfMan.getBool("disable_dithering"));
@@ -237,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);
@@ -284,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.
@@ -311,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".
@@ -497,7 +565,7 @@ void SciEngine::patchGameSaveRestore() {
byte kernelIdSave = 0;
switch (_gameId) {
- case GID_HOYLE1: // gets confused, although the game doesnt support saving/restoring at all
+ case GID_HOYLE1: // gets confused, although the game doesn't support saving/restoring at all
case GID_HOYLE2: // gets confused, see hoyle1
case GID_JONES: // gets confused, when we patch us in, the game is only able to save to 1 slot, so hooking is not required
case GID_MOTHERGOOSE: // mother goose EGA saves/restores directly and has no save/restore dialogs
@@ -544,17 +612,29 @@ void SciEngine::patchGameSaveRestore() {
}
}
+ const Object *patchObjectSave = nullptr;
+
+ if (getSciVersion() < SCI_VERSION_2) {
+ // Patch gameobject ::save for now for SCI0 - SCI1.1
+ // TODO: It seems this was never adjusted to superclass, but adjusting it now may cause
+ // issues with some game. Needs to get checked and then possibly changed.
+ patchObjectSave = gameObject;
+ } else {
+ // Patch superclass ::save for SCI32
+ patchObjectSave = gameSuperObject;
+ }
+
// Search for gameobject ::save, if there is one patch that one too
- uint16 gameObjectMethodCount = gameObject->getMethodCount();
- for (uint16 methodNr = 0; methodNr < gameObjectMethodCount; methodNr++) {
- uint16 selectorId = gameObject->getFuncSelector(methodNr);
+ uint16 patchObjectMethodCount = patchObjectSave->getMethodCount();
+ for (uint16 methodNr = 0; methodNr < patchObjectMethodCount; methodNr++) {
+ uint16 selectorId = patchObjectSave->getFuncSelector(methodNr);
Common::String methodName = _kernel->getSelectorName(selectorId);
if (methodName == "save") {
if (_gameId != GID_FAIRYTALES) { // Fairy Tales saves automatically without a dialog
if (kernelIdSave != kernelIdRestore)
- patchGameSaveRestoreCode(segMan, gameObject->getFunction(methodNr), kernelIdSave);
+ patchGameSaveRestoreCode(segMan, patchObjectSave->getFunction(methodNr), kernelIdSave);
else
- patchGameSaveRestoreCodeSci21(segMan, gameObject->getFunction(methodNr), kernelIdSave, false);
+ patchGameSaveRestoreCodeSci21(segMan, patchObjectSave->getFunction(methodNr), kernelIdSave, false);
}
break;
}
@@ -618,9 +698,9 @@ void SciEngine::initGraphics() {
_gfxCursor = 0;
_gfxMacIconBar = 0;
_gfxMenu = 0;
- _gfxPaint = 0;
_gfxPaint16 = 0;
- _gfxPalette = 0;
+ _gfxPalette16 = 0;
+ _gfxRemap16 = 0;
_gfxPorts = 0;
_gfxText16 = 0;
_gfxTransitions = 0;
@@ -630,14 +710,28 @@ void SciEngine::initGraphics() {
_robotDecoder = 0;
_gfxFrameout = 0;
_gfxPaint32 = 0;
+ _gfxPalette32 = 0;
+ _gfxRemap32 = 0;
#endif
if (hasMacIconBar())
_gfxMacIconBar = new GfxMacIconBar();
- _gfxPalette = new GfxPalette(_resMan, _gfxScreen);
- _gfxCache = new GfxCache(_resMan, _gfxScreen, _gfxPalette);
- _gfxCursor = new GfxCursor(_resMan, _gfxPalette, _gfxScreen);
+#ifdef ENABLE_SCI32
+ if (getSciVersion() >= SCI_VERSION_2) {
+ _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
+
+ _gfxCache = new GfxCache(_resMan, _gfxScreen, _gfxPalette16);
+ _gfxCursor = new GfxCursor(_resMan, _gfxPalette16, _gfxScreen);
#ifdef ENABLE_SCI32
if (getSciVersion() >= SCI_VERSION_2) {
@@ -645,12 +739,12 @@ 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, _gfxPalette);
- _gfxPaint = _gfxPaint32;
- _gfxText32 = new GfxText32(_gamestate->_segMan, _gfxCache, _gfxScreen);
- _gfxControls32 = new GfxControls32(_gamestate->_segMan, _gfxCache, _gfxText32);
+ _gfxPaint32 = new GfxPaint32(_gamestate->_segMan);
_robotDecoder = new RobotDecoder(getPlatform() == Common::kPlatformMacintosh);
- _gfxFrameout = new GfxFrameout(_gamestate->_segMan, _resMan, _gfxCoordAdjuster, _gfxCache, _gfxScreen, _gfxPalette, _gfxPaint32);
+ _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 {
#endif
// SCI0-SCI1.1 graphic objects creation
@@ -658,10 +752,9 @@ void SciEngine::initGraphics() {
_gfxCoordAdjuster = new GfxCoordAdjuster16(_gfxPorts);
_gfxCursor->init(_gfxCoordAdjuster, _eventMan);
_gfxCompare = new GfxCompare(_gamestate->_segMan, _gfxCache, _gfxScreen, _gfxCoordAdjuster);
- _gfxTransitions = new GfxTransitions(_gfxScreen, _gfxPalette);
- _gfxPaint16 = new GfxPaint16(_resMan, _gamestate->_segMan, _gfxCache, _gfxPorts, _gfxCoordAdjuster, _gfxScreen, _gfxPalette, _gfxTransitions, _audio);
- _gfxPaint = _gfxPaint16;
- _gfxAnimate = new GfxAnimate(_gamestate, _gfxCache, _gfxPorts, _gfxPaint16, _gfxScreen, _gfxPalette, _gfxCursor, _gfxTransitions);
+ _gfxTransitions = new GfxTransitions(_gfxScreen, _gfxPalette16);
+ _gfxPaint16 = new GfxPaint16(_resMan, _gamestate->_segMan, _gfxCache, _gfxPorts, _gfxCoordAdjuster, _gfxScreen, _gfxPalette16, _gfxTransitions, _audio);
+ _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);
_gfxMenu = new GfxMenu(_eventMan, _gamestate->_segMan, _gfxPorts, _gfxPaint16, _gfxText16, _gfxScreen, _gfxCursor);
@@ -675,8 +768,10 @@ void SciEngine::initGraphics() {
}
#endif
- // Set default (EGA, amiga or resource 999) palette
- _gfxPalette->setDefault();
+ if (getSciVersion() < SCI_VERSION_2) {
+ // Set default (EGA, amiga or resource 999) palette
+ _gfxPalette16->setDefault();
+ }
}
void SciEngine::initStackBaseWithSelector(Selector selector) {
@@ -742,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();
}
@@ -777,7 +875,7 @@ Console *SciEngine::getSciDebugger() {
}
const char *SciEngine::getGameIdStr() const {
- return _gameDescription->gameid;
+ return _gameDescription->gameId;
}
Common::Language SciEngine::getLanguage() const {
@@ -796,6 +894,10 @@ bool SciEngine::isCD() const {
return _gameDescription->flags & ADGF_CD;
}
+bool SciEngine::forceHiresGraphics() const {
+ return _forceHiresGraphics;
+}
+
bool SciEngine::isBE() const{
switch(_gameDescription->platform) {
case Common::kPlatformAmiga:
@@ -816,7 +918,7 @@ Common::String SciEngine::getSavegameName(int nr) const {
}
Common::String SciEngine::getSavegamePattern() const {
- return _targetName + ".???";
+ return _targetName + ".###";
}
Common::String SciEngine::getFilePrefix() const {
@@ -834,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
@@ -850,12 +956,30 @@ int SciEngine::inQfGImportRoom() const {
void SciEngine::setLauncherLanguage() {
if (_gameDescription->flags & ADGF_ADDENGLISH) {
// If game is multilingual
- if (Common::parseLanguage(ConfMan.get("language")) == Common::EN_ANY) {
+ Common::Language chosenLanguage = Common::parseLanguage(ConfMan.get("language"));
+ uint16 languageToSet = 0;
+
+ switch (chosenLanguage) {
+ case Common::EN_ANY:
// and English was selected as language
- if (SELECTOR(printLang) != -1) // set text language to English
- writeSelectorValue(_gamestate->_segMan, _gameObjectAddress, SELECTOR(printLang), K_LANG_ENGLISH);
- if (SELECTOR(parseLang) != -1) // and set parser language to English as well
- writeSelectorValue(_gamestate->_segMan, _gameObjectAddress, SELECTOR(parseLang), K_LANG_ENGLISH);
+ languageToSet = K_LANG_ENGLISH;
+ break;
+ case Common::JA_JPN: {
+ // Set Japanese for FM-Towns games
+ // KQ5 on FM-Towns has no initial language set
+ if (g_sci->getPlatform() == Common::kPlatformFMTowns) {
+ languageToSet = K_LANG_JAPANESE;
+ }
+ }
+ default:
+ break;
+ }
+
+ if (languageToSet) {
+ if (SELECTOR(printLang) != -1) // set text language
+ writeSelectorValue(_gamestate->_segMan, _gameObjectAddress, SELECTOR(printLang), languageToSet);
+ if (SELECTOR(parseLang) != -1) // and set parser language as well
+ writeSelectorValue(_gamestate->_segMan, _gameObjectAddress, SELECTOR(parseLang), languageToSet);
}
}
}
@@ -892,29 +1016,79 @@ bool SciEngine::speechAndSubtitlesEnabled() {
}
void SciEngine::syncIngameAudioOptions() {
- // Sync the in-game speech/subtitles settings for SCI1.1 CD games
- if (isCD() && getSciVersion() == SCI_VERSION_1_1) {
- bool subtitlesOn = ConfMan.getBool("subtitles");
- bool speechOn = !ConfMan.getBool("speech_mute");
+ bool useGlobal90 = false;
- if (subtitlesOn && !speechOn) {
- _gamestate->variables[VAR_GLOBAL][90] = make_reg(0, 1); // subtitles
- } else if (!subtitlesOn && speechOn) {
- _gamestate->variables[VAR_GLOBAL][90] = make_reg(0, 2); // speech
- } else if (subtitlesOn && speechOn) {
- // Is it a game that supports simultaneous speech and subtitles?
+ // Sync the in-game speech/subtitles settings for SCI1.1 CD games
+ if (isCD()) {
+ switch (getSciVersion()) {
+ case SCI_VERSION_1_1:
+ // All SCI1.1 CD games use global 90
+ useGlobal90 = true;
+ break;
+#ifdef ENABLE_SCI32
+ case SCI_VERSION_2:
+ case SCI_VERSION_2_1_EARLY:
+ case SCI_VERSION_2_1_MIDDLE:
+ case SCI_VERSION_2_1_LATE:
+ // Only use global 90 for some specific games, not all SCI32 games used this method
switch (_gameId) {
- case GID_SQ4:
- case GID_FREDDYPHARKAS:
- case GID_ECOQUEST:
- case GID_LSL6:
- case GID_LAURABOW2:
- case GID_KQ6:
- _gamestate->variables[VAR_GLOBAL][90] = make_reg(0, 3); // speech + subtitles
+ case GID_KQ7: // SCI2.1
+ case GID_GK1: // SCI2
+ case GID_GK2: // SCI2.1
+ case GID_SQ6: // SCI2.1
+ case GID_TORIN: // SCI2.1
+ case GID_QFG4: // SCI2.1
+ useGlobal90 = true;
+ break;
+ case GID_LSL6: // SCI2.1
+ // TODO: Uses gameFlags array
break;
+ // TODO: Unknown at the moment:
+ // Shivers - seems not to use global 90
+ // Police Quest: SWAT - unable to check
+ // Police Quest 4 - unable to check
+ // Mixed Up Mother Goose - unable to check
+ // Phantasmagoria - seems to use global 90, unable to check for subtitles atm
default:
- // Game does not support speech and subtitles, set it to speech
+ return;
+ }
+ break;
+#endif // ENABLE_SCI32
+ default:
+ return;
+ }
+
+ bool subtitlesOn = ConfMan.getBool("subtitles");
+ bool speechOn = !ConfMan.getBool("speech_mute");
+
+ if (useGlobal90) {
+ if (subtitlesOn && !speechOn) {
+ _gamestate->variables[VAR_GLOBAL][90] = make_reg(0, 1); // subtitles
+ } else if (!subtitlesOn && speechOn) {
_gamestate->variables[VAR_GLOBAL][90] = make_reg(0, 2); // speech
+ } else if (subtitlesOn && speechOn) {
+ // Is it a game that supports simultaneous speech and subtitles?
+ switch (_gameId) {
+ case GID_SQ4:
+ case GID_FREDDYPHARKAS:
+ case GID_ECOQUEST:
+ case GID_LSL6:
+ case GID_LAURABOW2:
+ case GID_KQ6:
+#ifdef ENABLE_SCI32
+ // Unsure about Gabriel Knight 2
+ case GID_KQ7: // SCI2.1
+ case GID_GK1: // SCI2
+ case GID_SQ6: // SCI2.1, SQ6 seems to always use subtitles anyway
+ case GID_TORIN: // SCI2.1
+ case GID_QFG4: // SCI2.1
+#endif // ENABLE_SCI32
+ _gamestate->variables[VAR_GLOBAL][90] = make_reg(0, 3); // speech + subtitles
+ break;
+ default:
+ // Game does not support speech and subtitles, set it to speech
+ _gamestate->variables[VAR_GLOBAL][90] = make_reg(0, 2); // speech
+ }
}
}
}
@@ -978,4 +1152,10 @@ void SciEngine::loadMacExecutable() {
}
}
+uint32 SciEngine::getTickCount() {
+ return g_engine->getTotalPlayTime() * 60 / 1000;
+}
+void SciEngine::setTickCount(const uint32 ticks) {
+ return g_engine->setTotalPlayTime(ticks * 1000 / 60);
+}
} // End of namespace Sci
diff --git a/engines/sci/sci.h b/engines/sci/sci.h
index c6813aa07c..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,10 +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;
@@ -77,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
@@ -127,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,
@@ -164,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
@@ -200,7 +211,9 @@ 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, // GK2, KQ7, LSL6 hires, 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
};
@@ -233,6 +246,8 @@ public:
bool canLoadGameStateCurrently();
bool canSaveGameStateCurrently();
void syncSoundSettings();
+ uint32 getTickCount();
+ void setTickCount(const uint32 ticks);
/**
* Syncs the audio options of the ScummVM launcher (speech, subtitles or
@@ -264,6 +279,7 @@ public:
Common::Platform getPlatform() const;
bool isDemo() const;
bool isCD() const;
+ bool forceHiresGraphics() const;
/** Returns true if the game's original platform is big-endian. */
bool isBE() const;
@@ -276,7 +292,7 @@ public:
inline EngineState *getEngineState() const { return _gamestate; }
inline Vocabulary *getVocabulary() const { return _vocabulary; }
inline EventManager *getEventManager() const { return _eventMan; }
- inline reg_t getGameObject() const { return _gameObjectAddress; }
+ inline reg_t getGameObject() const { return _gameObjectAddress; } // Gets the game object VM address
Common::RandomSource &getRNG() { return _rng; }
@@ -291,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.
@@ -341,8 +359,10 @@ public:
GfxCoordAdjuster *_gfxCoordAdjuster;
GfxCursor *_gfxCursor;
GfxMenu *_gfxMenu; // Menu for 16-bit gfx
- GfxPalette *_gfxPalette;
- GfxPaint *_gfxPaint;
+ GfxPalette *_gfxPalette16;
+ GfxPalette32 *_gfxPalette32; // Palette for 32-bit gfx
+ 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
@@ -353,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;
@@ -416,6 +439,7 @@ private:
Console *_console;
Common::RandomSource _rng;
Common::MacResManager _macExecutable;
+ bool _forceHiresGraphics; // user-option for GK1, KQ6, PQ4
};
@@ -445,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 fb9a3f17b9..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();
@@ -79,15 +78,23 @@ void AudioPlayer::handleFanmadeSciAudio(reg_t sciAudioObject, SegManager *segMan
Common::String command = segMan->getString(commandReg);
if (command == "play" || command == "playx") {
-#ifdef USE_MAD
reg_t fileNameReg = readSelector(segMan, sciAudioObject, kernel->findSelector("fileName"));
Common::String fileName = segMan->getString(fileNameReg);
- int16 loopCount = (int16)readSelectorValue(segMan, sciAudioObject, kernel->findSelector("loopCount"));
- // When loopCount is -1, we treat it as infinite looping, else no looping is done.
- // This is observed by game scripts, which can set loopCount to all sorts of random values.
+ reg_t loopCountReg = readSelector(segMan, sciAudioObject, kernel->findSelector("loopCount"));
+ Common::String loopCountStr = segMan->getString(loopCountReg);
+ int16 loopCount = atoi(loopCountStr.c_str());
+
// Adjust loopCount for ScummVM's LoopingAudioStream semantics
- loopCount = (loopCount == -1) ? 0 : 1;
+ if (loopCount == -1) {
+ loopCount = 0; // loop endlessly
+ } else if (loopCount >= 0) {
+ // sciAudio loopCount == 0 -> play 1 time -> ScummVM's loopCount should be 1
+ // sciAudio loopCount == 1 -> play 2 times -> ScummVM's loopCount should be 2
+ loopCount++;
+ } else {
+ loopCount = 1; // play once in case the value makes no sense
+ }
// Determine sound type
Audio::Mixer::SoundType soundType = Audio::Mixer::kSFXSoundType;
@@ -96,20 +103,51 @@ void AudioPlayer::handleFanmadeSciAudio(reg_t sciAudioObject, SegManager *segMan
else if (fileName.hasPrefix("speech"))
soundType = Audio::Mixer::kSpeechSoundType;
- Common::File *sciAudio = new Common::File();
+ // Determine compression
+ uint32 audioCompressionType = 0;
+ if ((fileName.hasSuffix(".mp3")) || (fileName.hasSuffix(".sciAudio")) || (fileName.hasSuffix(".sciaudio"))) {
+ audioCompressionType = MKTAG('M','P','3',' ');
+ } else if (fileName.hasSuffix(".wav")) {
+ audioCompressionType = MKTAG('W','A','V',' ');
+ } else if (fileName.hasSuffix(".aiff")) {
+ audioCompressionType = MKTAG('A','I','F','F');
+ } else {
+ error("sciAudio: unsupported file type");
+ }
+
+ Common::File *sciAudioFile = new Common::File();
// Replace backwards slashes
for (uint i = 0; i < fileName.size(); i++) {
if (fileName[i] == '\\')
fileName.setChar('/', i);
}
- sciAudio->open("sciAudio/" + fileName);
+ sciAudioFile->open("sciAudio/" + fileName);
+
+ Audio::RewindableAudioStream *audioStream = nullptr;
- Audio::SeekableAudioStream *audioStream = Audio::makeMP3Stream(sciAudio, DisposeAfterUse::YES);
+ switch (audioCompressionType) {
+ case MKTAG('M','P','3',' '):
+#ifdef USE_MAD
+ audioStream = Audio::makeMP3Stream(sciAudioFile, DisposeAfterUse::YES);
+#endif
+ break;
+ case MKTAG('W','A','V',' '):
+ audioStream = Audio::makeWAVStream(sciAudioFile, DisposeAfterUse::YES);
+ break;
+ case MKTAG('A','I','F','F'):
+ audioStream = Audio::makeAIFFStream(sciAudioFile, DisposeAfterUse::YES);
+ break;
+ default:
+ break;
+ }
+
+ if (!audioStream) {
+ error("sciAudio: requested compression not compiled into ScummVM");
+ }
// We only support one audio handle
_mixer->playStream(soundType, &_audioHandle,
Audio::makeLoopingAudioStream((Audio::RewindableAudioStream *)audioStream, loopCount));
-#endif
} else if (command == "stop") {
_mixer->stopHandle(_audioHandle);
} else {
@@ -215,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)
- 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);
@@ -434,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 baf85de74c..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"
@@ -1019,7 +1019,7 @@ int MidiPlayer_Midi::open(ResourceManager *resMan) {
if (!isMt32GmPatch(res->data, res->size)) {
mapMt32ToGm(res->data, res->size);
} else {
- if (getSciVersion() <= SCI_VERSION_2_1) {
+ if (getSciVersion() < SCI_VERSION_3) {
error("MT-32 patch has wrong type");
} else {
// Happens in the SCI3 interactive demo of Lighthouse
diff --git a/engines/sci/sound/midiparser_sci.cpp b/engines/sci/sound/midiparser_sci.cpp
index 9f0d8d150f..21f95f17e0 100644
--- a/engines/sci/sound/midiparser_sci.cpp
+++ b/engines/sci/sound/midiparser_sci.cpp
@@ -717,7 +717,7 @@ bool MidiParser_SCI::processEvent(const EventInfo &info, bool fireEvents) {
break;
case SCI_VERSION_1_EARLY:
case SCI_VERSION_1_LATE:
- case SCI_VERSION_2_1:
+ case SCI_VERSION_2_1_EARLY:
inc = 1;
break;
default:
@@ -862,7 +862,7 @@ void MidiParser_SCI::setMasterVolume(byte masterVolume) {
case SCI_VERSION_1_EARLY:
case SCI_VERSION_1_LATE:
- case SCI_VERSION_2_1:
+ case SCI_VERSION_2_1_EARLY:
// directly set master volume (global volume is merged with channel volumes)
((MidiPlayer *)_driver)->setVolume(masterVolume);
break;
@@ -887,7 +887,7 @@ void MidiParser_SCI::setVolume(byte volume) {
case SCI_VERSION_1_EARLY:
case SCI_VERSION_1_LATE:
- case SCI_VERSION_2_1:
+ case SCI_VERSION_2_1_EARLY:
// Send previous channel volumes again to actually update the volume
for (int i = 0; i < 15; i++)
if (_channelRemap[i] != -1)
diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp
index dca73c3f51..487d30e840 100644
--- a/engines/sci/sound/music.cpp
+++ b/engines/sci/sound/music.cpp
@@ -73,7 +73,7 @@ void SciMusic::init() {
// Default to MIDI in SCI2.1+ games, as many don't have AdLib support.
// Also, default to MIDI for Windows versions of SCI1.1 games, as their
// soundtrack is written for GM.
- if (getSciVersion() >= SCI_VERSION_2_1 || g_sci->_features->useAltWinGMSound())
+ if (getSciVersion() >= SCI_VERSION_2_1_EARLY || g_sci->_features->useAltWinGMSound())
deviceFlags |= MDT_PREFER_GM;
// Currently our CMS implementation only supports SCI1(.1)
@@ -131,6 +131,12 @@ void SciMusic::init() {
// HACK: The Fun Seeker's Guide demo doesn't have patch 3 and the version
// of the Adlib driver (adl.drv) that it includes is unsupported. That demo
// doesn't have any sound anyway, so this shouldn't be fatal.
+ } else if (g_sci->getGameId() == GID_MOTHERGOOSEHIRES) {
+ // HACK: Mixed-Up Mother Goose Deluxe does not seem to use synthesized music,
+ // so just set a default tempo (for fading)
+ // TODO: Review this
+ _dwTempo = 1000000 / 250;
+ warning("Temporary music hack for MUMG Deluxe");
} else {
error("Failed to initialize sound driver");
}
@@ -206,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);
}
}
@@ -341,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);
@@ -466,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
@@ -544,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) {
@@ -566,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();
@@ -608,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();
@@ -679,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
@@ -807,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/sci/util.cpp b/engines/sci/util.cpp
index 3a9ed9ca69..ccec41a1ab 100644
--- a/engines/sci/util.cpp
+++ b/engines/sci/util.cpp
@@ -49,7 +49,7 @@ uint16 READ_SCI11ENDIAN_UINT16(const void *ptr) {
}
uint16 READ_SCI32ENDIAN_UINT16(const void *ptr) {
- if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2_1)
+ if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2_1_EARLY)
return READ_BE_UINT16(ptr);
else
return READ_LE_UINT16(ptr);
@@ -69,4 +69,13 @@ void WRITE_SCI11ENDIAN_UINT16(void *ptr, uint16 val) {
WRITE_LE_UINT16(ptr, val);
}
+#ifdef ENABLE_SCI32
+void WRITE_SCI11ENDIAN_UINT32(void *ptr, uint32 val) {
+ if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_1_1)
+ WRITE_BE_UINT32(ptr, val);
+ else
+ WRITE_LE_UINT32(ptr, val);
+}
+#endif
+
} // End of namespace Sci
diff --git a/engines/sci/util.h b/engines/sci/util.h
index 378030939c..b0fee5151e 100644
--- a/engines/sci/util.h
+++ b/engines/sci/util.h
@@ -37,6 +37,9 @@ void WRITE_SCIENDIAN_UINT16(void *ptr, uint16 val);
uint16 READ_SCI11ENDIAN_UINT16(const void *ptr);
uint32 READ_SCI11ENDIAN_UINT32(const void *ptr);
void WRITE_SCI11ENDIAN_UINT16(void *ptr, uint16 val);
+#ifdef ENABLE_SCI32
+void WRITE_SCI11ENDIAN_UINT32(void *ptr, uint32 val);
+#endif
// Wrappers for reading integer values in resources that are
// LE in SCI1.1 Mac, but BE in SCI32 Mac
diff --git a/engines/scumm/POTFILES b/engines/scumm/POTFILES
index 6d10537d3c..039aa16755 100644
--- a/engines/scumm/POTFILES
+++ b/engines/scumm/POTFILES
@@ -1,5 +1,7 @@
+engines/scumm/detection.cpp
engines/scumm/dialogs.cpp
engines/scumm/help.cpp
+engines/scumm/input.cpp
engines/scumm/scumm.cpp
engines/scumm/players/player_v3m.cpp
engines/scumm/players/player_v5m.cpp
diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp
index 0d7ea39ec2..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 occured.. 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 3a0cd15637..a1e92a9950 100644
--- a/engines/scumm/charset-fontdata.cpp
+++ b/engines/scumm/charset-fontdata.cpp
@@ -484,6 +484,73 @@ static const byte spanishCharsetDataV2[] = {
126, 10,
};
+// Russian MM font.
+static const byte russCharsetDataV2[] = {
+ 60, 234,
+ 62, 158,
+ 65, 128,
+ 66, 129,
+ 67, 150,
+ 68, 132,
+ 69, 133,
+ 70, 148,
+ 71, 131,
+ 72, 149,
+ 73, 136,
+ 74, 137,
+ 75, 138,
+ 76, 139,
+ 77, 140,
+ 78, 141,
+ 79, 142,
+ 80, 143,
+ 81, 159,
+ 82, 144,
+ 83, 145,
+ 84, 146,
+ 85, 147,
+ 86, 134,
+ 87, 130,
+ 88, 156,
+ 89, 155,
+ 90, 135,
+ 91, 152,
+ 92, 157,
+ 93, 153,
+ 94, 151,
+ 96, 238,
+ 97, 160,
+ 98, 161,
+ 99, 230,
+ 100, 164,
+ 101, 165,
+ 102, 228,
+ 103, 163,
+ 104, 229,
+ 105, 168,
+ 106, 169,
+ 107, 170,
+ 108, 171,
+ 109, 172,
+ 110, 173,
+ 111, 174,
+ 112, 175,
+ 113, 239,
+ 114, 224,
+ 115, 225,
+ 116, 226,
+ 117, 227,
+ 118, 166,
+ 119, 162,
+ 120, 236,
+ 121, 235,
+ 122, 167,
+ 123, 232,
+ 124, 237,
+ 125, 233,
+ 126, 231,
+};
+
// Special characters
static const byte specialCharsetData[] = {
0x18, 0x3e, 0x60, 0x3c, 0x06, 0x7c, 0x18, 0x00,
@@ -524,49 +591,59 @@ 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:
- _fontPtr = russianCharsetDataV2;
+ if (((_vm->_game.id == GID_MANIAC) || (_vm->_game.id == GID_ZAK)) && (_vm->_game.version == 2)) {
+ replacementMap = russCharsetDataV2;
+ replacementChars = sizeof(russCharsetDataV2) / 2;
+ replacementData = russianCharsetDataV2;
+ } else {
+ _fontPtr = russianCharsetDataV2;
+ }
break;
default:
_fontPtr = englishCharsetDataV2;
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];
- 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 45647c9bed..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 {
@@ -1268,10 +1275,9 @@ SaveStateList ScummMetaEngine::listSaves(const char *target) const {
Common::StringArray filenames;
Common::String saveDesc;
Common::String pattern = target;
- pattern += ".s??";
+ pattern += ".s##";
filenames = saveFileMan->listSavefiles(pattern);
- sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
SaveStateList saveList;
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
@@ -1288,6 +1294,8 @@ SaveStateList ScummMetaEngine::listSaves(const char *target) const {
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
@@ -1328,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 c22525b6f2..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"},
@@ -308,6 +304,8 @@ void HelpDialog::reflowLayout() {
int16 x, y;
uint16 w, h;
+ assert(lineHeight);
+
g_gui.xmlEval()->getWidgetData("ScummHelp.HelpText", x, y, w, h);
// Make sure than we don't have more lines than what we can fit
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/puttrace.cpp b/engines/scumm/he/logic/puttrace.cpp
index 1c3317b131..ba62c118fe 100644
--- a/engines/scumm/he/logic/puttrace.cpp
+++ b/engines/scumm/he/logic/puttrace.cpp
@@ -256,7 +256,7 @@ int32 LogicHErace::op_1102(int32 *args) {
}
int32 LogicHErace::op_1103(int32 *args) {
- double angle = args[0] / args[1] * DEG2RAD;
+ double angle = (double)args[0] / (double)args[1] * DEG2RAD;
writeScummVar(108, (int32)(sin(angle) * args[2]));
writeScummVar(109, (int32)(cos(angle) * args[2]));
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 a78aff96f8..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;
@@ -636,7 +642,7 @@ void SoundHE::playHESound(int soundID, int heOffset, int heChannel, int heFlags)
if (heFlags & 1) {
_heChannel[heChannel].timer = 0;
} else {
- _heChannel[heChannel].timer = size * 1000 / rate;
+ _heChannel[heChannel].timer = size * 1000 / (rate * blockAlign);
}
_mixer->stopHandle(_heSoundChannels[heChannel]);
@@ -658,7 +664,7 @@ void SoundHE::playHESound(int soundID, int heOffset, int heChannel, int heFlags)
_heChannel[heChannel].rate = rate;
if (_heChannel[heChannel].timer)
- _heChannel[heChannel].timer = size * 1000 / rate;
+ _heChannel[heChannel].timer = size * 1000 / (rate * blockAlign);
// makeADPCMStream returns a stream in native endianness, but RawMemoryStream
// defaults to big endian. If we're on a little endian system, set the LE flag.
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.cpp b/engines/scumm/imuse_digi/dimuse_track.cpp
index b7abdd074e..28ad64670c 100644
--- a/engines/scumm/imuse_digi/dimuse_track.cpp
+++ b/engines/scumm/imuse_digi/dimuse_track.cpp
@@ -352,9 +352,9 @@ Track *IMuseDigital::cloneToFadeOutTrack(Track *track, int fadeDelay) {
// leaving bug number for now #1635361
ImuseDigiSndMgr::SoundDesc *soundDesc = _sound->cloneSound(track->soundDesc);
if (!soundDesc) {
- // it fail load open old song after switch to diffrent CDs
+ // it fail load open old song after switch to different CDs
// so gave up
- error("Game not supported while playing on 2 diffrent CDs");
+ error("Game not supported while playing on 2 different CDs");
}
track->soundDesc = soundDesc;
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 86048af57c..6ef7e4d7f4 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -23,9 +23,8 @@
#include "common/config-manager.h"
#include "common/events.h"
#include "common/system.h"
-
-#include "gui/message.h"
-#include "gui/gui-manager.h"
+#include "common/translation.h"
+#include "audio/mixer.h"
#include "scumm/debugger.h"
#include "scumm/dialogs.h"
@@ -129,6 +128,14 @@ void ScummEngine::parseEvent(Common::Event event) {
_debugger->attach();
} else if (event.kbd.hasFlags(Common::KBD_CTRL) && event.kbd.keycode == Common::KEYCODE_s) {
_res->resourceStats();
+ } else if (event.kbd.hasFlags(Common::KBD_ALT) && event.kbd.keycode == Common::KEYCODE_x) {
+ // TODO: Some SCUMM games quit when Alt-x is pressed. However, not
+ // all of them seem to exhibit this behavior. LordHoto found that
+ // the Loom manual does not mention this hotkey. On the other hand
+ // the Sam&Max manual mentions that Alt-x does so on "most"
+ // platforms. We should really check which games exhibit this
+ // behavior and only use it for them.
+ quitGame();
} else {
// Normal key press, pass on to the game.
_keyPressed = event.kbd;
@@ -568,9 +575,9 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
lastKeyHit.hasFlags(Common::KBD_CTRL)) {
_snapScroll ^= 1;
if (_snapScroll) {
- messageDialog("Snap scroll on");
+ messageDialog(_("Snap scroll on"));
} else {
- messageDialog("Snap scroll off");
+ messageDialog(_("Snap scroll off"));
}
if (VAR_CAMERA_FAST_X != 0xFF)
@@ -583,7 +590,7 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
vol--;
// Display the music volume
- ValueDisplayDialog dlg("Music volume: ", 0, 16, vol, ']', '[');
+ ValueDisplayDialog dlg(_("Music volume: "), 0, 16, vol, ']', '[');
vol = runDialog(dlg);
vol *= 16;
@@ -600,7 +607,7 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
_defaultTalkDelay++;
// Display the talk speed
- ValueDisplayDialog dlg("Subtitle speed: ", 0, 9, 9 - _defaultTalkDelay, '+', '-');
+ ValueDisplayDialog dlg(_("Subtitle speed: "), 0, 9, 9 - _defaultTalkDelay, '+', '-');
_defaultTalkDelay = 9 - runDialog(dlg);
// Save the new talkspeed value to ConfMan
diff --git a/engines/scumm/insane/insane.cpp b/engines/scumm/insane/insane.cpp
index b3e9a0e699..f0bbab53e6 100644
--- a/engines/scumm/insane/insane.cpp
+++ b/engines/scumm/insane/insane.cpp
@@ -1406,7 +1406,7 @@ int32 Insane::smush_setupSanWithFlu(const char *filename, int32 setupsan2, int32
int32 offset;
debugC(DEBUG_INSANE, "smush_setupSanWithFlu(%s, %d, %d, %d, %d, %p, %d)", filename, setupsan2,
- step1, step2, setupsan1, fluPtr, numFrames);
+ step1, step2, setupsan1, (void *)fluPtr, numFrames);
_smush_setupsan1 = setupsan1;
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_towns.cpp b/engines/scumm/players/player_towns.cpp
index 5b8ca04021..d540fc4f6b 100644
--- a/engines/scumm/players/player_towns.cpp
+++ b/engines/scumm/players/player_towns.cpp
@@ -202,23 +202,24 @@ Player_Towns_v1::Player_Towns_v1(ScummEngine *vm, Audio::Mixer *mixer) : Player_
memset(_soundOverride, 0, _numSoundMax * sizeof(SoundOvrParameters));
}
- _driver = new TownsEuphonyDriver(mixer);
+ _player = new EuphonyPlayer(mixer);
+ _intf = new TownsAudioInterface(mixer, 0);
}
Player_Towns_v1::~Player_Towns_v1() {
- delete _driver;
+ delete _intf;
+ delete _player;
delete[] _soundOverride;
}
bool Player_Towns_v1::init() {
- if (!_driver)
+ if (!_player)
return false;
- if (!_driver->init())
+ if (!_player->init())
return false;
- _driver->reserveSoundEffectChannels(8);
- _intf = _driver->intf();
+ _player->driver()->reserveSoundEffectChannels(8);
// Treat all 6 fm channels and all 8 pcm channels as sound effect channels
// since music seems to exist as CD audio only in the games which use this
@@ -231,7 +232,7 @@ bool Player_Towns_v1::init() {
}
void Player_Towns_v1::setMusicVolume(int vol) {
- _driver->setMusicVolume(vol);
+ _player->driver()->setMusicVolume(vol);
}
void Player_Towns_v1::startSound(int sound) {
@@ -254,7 +255,9 @@ void Player_Towns_v1::startSound(int sound) {
uint16 len = READ_LE_UINT16(ptr) + 2;
playPcmTrack(sound, ptr + 6, velocity, 64, note ? note : (len > 50 ? ptr[50] : 60), READ_LE_UINT16(ptr + 10));
- } else if (type == 1) {
+ // WORKAROUND for bug #1873 INDY3 FMTOWNS: Music in Venice is distorted
+ // The resource for sound 40 accidently sets the sound type to 255 instead of 1.
+ } else if (type == 1 || (_vm->_game.id == GID_INDY3 && sound == 40)) {
playEuphonyTrack(sound, ptr + 6);
} else if (type == 2) {
@@ -275,7 +278,7 @@ void Player_Towns_v1::stopSound(int sound) {
if (sound != 0 && sound == _eupCurrentSound) {
_eupCurrentSound = 0;
_eupLooping = false;
- _driver->stopParser();
+ _player->stop();
}
stopPcmTrack(sound);
@@ -288,7 +291,7 @@ void Player_Towns_v1::stopAllSounds() {
_eupCurrentSound = 0;
_eupLooping = false;
- _driver->stopParser();
+ _player->stop();
stopPcmTrack(0);
}
@@ -297,7 +300,7 @@ int Player_Towns_v1::getSoundStatus(int sound) const {
if (sound == _cdaCurrentSound)
return _vm->_sound->pollCD();
if (sound == _eupCurrentSound)
- return _driver->parserIsPlaying() ? 1 : 0;
+ return _player->isPlaying() ? 1 : 0;
return Player_Towns::getSoundStatus(sound);
}
@@ -306,7 +309,7 @@ int32 Player_Towns_v1::doCommand(int numargs, int args[]) {
switch (args[0]) {
case 2:
- _driver->intf()->callback(73, 0);
+ _player->driver()->cdaToggle(0);
break;
case 3:
@@ -344,7 +347,7 @@ int32 Player_Towns_v1::doCommand(int numargs, int args[]) {
void Player_Towns_v1::setVolumeCD(int left, int right) {
_cdaVolLeft = left & 0xff;
_cdaVolRight = right & 0xff;
- _driver->setOutputVolume(1, left >> 1, right >> 1);
+ _player->driver()->setOutputVolume(1, left >> 1, right >> 1);
}
void Player_Towns_v1::setSoundVolume(int sound, int left, int right) {
@@ -373,7 +376,7 @@ void Player_Towns_v1::saveLoadWithSerializer(Serializer *ser) {
ser->saveLoadEntries(this, cdEntries);
- if (!_eupLooping && !_driver->parserIsPlaying())
+ if (!_eupLooping && !_player->isPlaying())
_eupCurrentSound = 0;
static const SaveLoadEntry eupEntries[] = {
@@ -409,7 +412,9 @@ void Player_Towns_v1::restoreAfterLoad() {
if (_vm->_game.version != 3)
ptr += 2;
- if (ptr[7] == 1) {
+ // WORKAROUND for bug #1873 INDY3 FMTOWNS: Music in Venice is distorted
+ // The resource for sound 40 accidently sets the sound type to 255 instead of 1.
+ if (ptr[7] == 1 || (_vm->_game.id == GID_INDY3 && _eupCurrentSound == 40)) {
setSoundVolume(_eupCurrentSound, _eupVolLeft, _eupVolRight);
playEuphonyTrack(_eupCurrentSound, ptr);
}
@@ -439,10 +444,10 @@ void Player_Towns_v1::restartLoopingSounds() {
c++;
}
- _driver->playSoundEffect(i + 0x3f, _pcmCurrentSound[i].note, _pcmCurrentSound[i].velo, ptr);
+ _player->driver()->playSoundEffect(i + 0x3f, _pcmCurrentSound[i].note, _pcmCurrentSound[i].velo, ptr);
}
- _driver->intf()->callback(73, 1);
+ _player->driver()->cdaToggle(1);
}
void Player_Towns_v1::startSoundEx(int sound, int velo, int pan, int note) {
@@ -492,9 +497,9 @@ void Player_Towns_v1::stopSoundSuspendLooping(int sound) {
} else {
for (int i = 1; i < 9; i++) {
if (sound == _pcmCurrentSound[i].index) {
- if (!_driver->soundEffectIsPlaying(i + 0x3f))
+ if (!_player->driver()->soundEffectIsPlaying(i + 0x3f))
continue;
- _driver->stopSoundEffect(i + 0x3f);
+ _player->driver()->stopSoundEffect(i + 0x3f);
if (_pcmCurrentSound[i].looping)
_pcmCurrentSound[i].paused = 1;
else
@@ -510,23 +515,23 @@ void Player_Towns_v1::playEuphonyTrack(int sound, const uint8 *data) {
const uint8 *trackData = src + 150;
for (int i = 0; i < 32; i++)
- _driver->configChan_enable(i, *src++);
+ _player->configPart_enable(i, *src++);
for (int i = 0; i < 32; i++)
- _driver->configChan_setMode(i, 0xff);
+ _player->configPart_setType(i, 0xff);
for (int i = 0; i < 32; i++)
- _driver->configChan_remap(i, *src++);
+ _player->configPart_remap(i, *src++);
for (int i = 0; i < 32; i++)
- _driver->configChan_adjustVolume(i, *src++);
+ _player->configPart_adjustVolume(i, *src++);
for (int i = 0; i < 32; i++)
- _driver->configChan_setTranspose(i, *src++);
+ _player->configPart_setTranspose(i, *src++);
src += 8;
for (int i = 0; i < 6; i++)
- _driver->assignChannel(i, *src++);
+ _player->driver()->assignPartToChannel(i, *src++);
for (int i = 0; i < data[14]; i++) {
- _driver->loadInstrument(i, i, pos + i * 48);
- _driver->intf()->callback(4, i, i);
+ _player->driver()->loadInstrument(i, i, pos + i * 48);
+ _player->driver()->setInstrument(i, i);
}
_eupVolLeft = _soundOverride[sound].vLeft;
@@ -537,18 +542,18 @@ void Player_Towns_v1::playEuphonyTrack(int sound, const uint8 *data) {
lvl >>= 2;
for (int i = 0; i < 6; i++)
- _driver->chanVolume(i, lvl);
+ _player->driver()->channelVolume(i, lvl);
uint32 trackSize = READ_LE_UINT32(src);
src += 4;
uint8 startTick = *src++;
- _driver->setMusicTempo(*src++);
- _driver->startMusicTrack(trackData, trackSize, startTick);
+ _player->setTempo(*src++);
+ _player->startTrack(trackData, trackSize, startTick);
_eupLooping = (*src != 1) ? 1 : 0;
- _driver->setMusicLoop(_eupLooping != 0);
- _driver->continueParsing();
+ _player->setLoopStatus(_eupLooping != 0);
+ _player->resume();
_eupCurrentSound = sound;
}
diff --git a/engines/scumm/players/player_towns.h b/engines/scumm/players/player_towns.h
index 3736524ee2..576d17e392 100644
--- a/engines/scumm/players/player_towns.h
+++ b/engines/scumm/players/player_towns.h
@@ -104,8 +104,6 @@ public:
void saveLoadWithSerializer(Serializer *ser);
void restoreAfterLoad();
- TownsEuphonyDriver *driver() { return _driver; }
-
private:
void restartLoopingSounds();
void startSoundEx(int sound, int velo, int pan, int note);
@@ -137,7 +135,7 @@ private:
uint8 _cdaCurrentSoundTemp;
uint8 _cdaNumLoopsTemp;
- TownsEuphonyDriver *_driver;
+ EuphonyPlayer *_player;
};
class Player_Towns_v2 : public Player_Towns {
diff --git a/engines/scumm/players/player_v2.cpp b/engines/scumm/players/player_v2.cpp
index f0aaa4a3be..c7ebd8abff 100644
--- a/engines/scumm/players/player_v2.cpp
+++ b/engines/scumm/players/player_v2.cpp
@@ -77,7 +77,7 @@ void Player_V2::setMusicVolume (int vol) {
vol = 255;
/* scale to int16, FIXME: find best value */
- double out = vol * 128 / 3;
+ double out = vol * 128.0 / 3.0;
/* build volume table (2dB per step) */
for (int i = 0; i < 15; i++) {
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_v4a.cpp b/engines/scumm/players/player_v4a.cpp
index bd8ce3f7ad..58f53a6d7f 100644
--- a/engines/scumm/players/player_v4a.cpp
+++ b/engines/scumm/players/player_v4a.cpp
@@ -174,7 +174,7 @@ int Player_V4A::getMusicTimer() {
return 2000;
if (_musicId) {
// The titlesong (and a few others) is running with ~70 ticks per second and the scale seems to be based on that.
- // The Game itself doesnt get the timing from the Tfmx Player however, so we just use the elapsed time
+ // The Game itself doesn't get the timing from the Tfmx Player however, so we just use the elapsed time
// 357 ~ 1000 * 25 * (1 / 70)
return _mixer->getSoundElapsedTime(_musicHandle) / 357;
}
@@ -183,7 +183,7 @@ int Player_V4A::getMusicTimer() {
int Player_V4A::getSoundStatus(int nr) const {
// For music the game queues a variable the Tfmx Player sets through a special command.
- // For sfx there seems to be no way to queue them, and the game doesnt try to.
+ // For sfx there seems to be no way to queue them, and the game doesn't try to.
return (nr == _musicId) ? _signal : 0;
}
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/resource.cpp b/engines/scumm/resource.cpp
index d4e4f43d5c..5456ae4f8f 100644
--- a/engines/scumm/resource.cpp
+++ b/engines/scumm/resource.cpp
@@ -748,7 +748,7 @@ byte *ScummEngine::getResourceAddress(ResType type, ResId idx) {
_res->setResourceCounter(type, idx, 1);
- debugC(DEBUG_RESOURCE, "getResourceAddress(%s,%d) == %p", nameOfResType(type), idx, ptr);
+ debugC(DEBUG_RESOURCE, "getResourceAddress(%s,%d) == %p", nameOfResType(type), idx, (void *)ptr);
return ptr;
}
diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp
index e5673c1803..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();
@@ -1303,7 +1305,7 @@ void ScummEngine::saveOrLoad(Serializer *s) {
if (hasTownsData) {
// Skip FM-Towns specific data
- for (int i = 69 * sizeof(uint8) + 44 * sizeof(int16); i; i--)
+ for (i = 69 * sizeof(uint8) + 44 * sizeof(int16); i; i--)
s->loadByte();
}
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/script_v2.cpp b/engines/scumm/script_v2.cpp
index a7ec2e644f..88c26f8c9e 100644
--- a/engines/scumm/script_v2.cpp
+++ b/engines/scumm/script_v2.cpp
@@ -963,6 +963,7 @@ void ScummEngine_v2::drawPreposition(int index) {
{ " ", " dans", " avec", " sur", " <" }, // French
{ " ", " in", " con", " su", " a" }, // Italian
{ " ", " en", " con", " en", " a" }, // Spanish
+ { " ", " \x7f", " \x7f", " na", " \x7f" },// Russian
};
int lang;
switch (_language) {
@@ -978,6 +979,9 @@ void ScummEngine_v2::drawPreposition(int index) {
case Common::ES_ESP:
lang = 4;
break;
+ case Common::RU_RUS:
+ lang = 5;
+ break;
default:
lang = 0; // Default to english
}
diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h
index a836cf12bc..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 Sun Jun 28 03:19:52 2015
+ This file was generated by the md5table tool on Sat Apr 30 14:24:41 2016
DO NOT EDIT MANUALLY!
*/
@@ -115,7 +115,7 @@ static const MD5Table md5table[] = {
{ "2108d83dcf09f8adb4bc524669c8cf51", "PuttTime", "HE 99", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "21a6592322f92550f144f68a8a4e685e", "dig", "", "", -1, Common::FR_FRA, Common::kPlatformMacintosh },
{ "21abe302e1b1e2b66d6f5c12e241ebfd", "freddicove", "unenc", "Unencrypted", -1, Common::RU_RUS, Common::kPlatformWindows },
- { "2232b0b9411575b1f9961713ebc9de61", "balloon", "HE 80", "", -1, Common::NL_NLD, Common::kPlatformWindows },
+ { "2232b0b9411575b1f9961713ebc9de61", "balloon", "HE 80", "", 12800, Common::NL_NLD, Common::kPlatformWindows },
{ "225e18566e810c634bf7de63e7568e3e", "mustard", "", "", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "22c7432dc97a821fcfccd480e93e3911", "spyfox2", "", "Mini Game", 14689, Common::NL_NLD, Common::kPlatformWindows },
{ "22c9eb04455440131ffc157aeb8d40a8", "fbear", "HE 70", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows },
@@ -168,7 +168,7 @@ static const MD5Table md5table[] = {
{ "36a6750e03fb505fc19fc2bf3e4dbe91", "pajama2", "", "Demo", 58749, Common::EN_ANY, Common::kPlatformUnknown },
{ "3769b56c9a22f5521d74525ee459f88d", "puttrace", "HE 99", "Demo", 13108, Common::DE_DEU, Common::kPlatformWindows },
{ "3785fd25f7e02b5782bfc5072d8f77c8", "spyfox2", "", "", -1, Common::IT_ITA, Common::kPlatformUnknown },
- { "37aed3f91c1ef959e0bd265f9b13781f", "pajama", "HE 100", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown },
+ { "37aed3f91c1ef959e0bd265f9b13781f", "pajama", "HE 100", "Updated", 66599, Common::EN_ANY, Common::kPlatformUnknown },
{ "37f56ceb13e401a7ac7d9e6b37fecaf7", "loom", "EGA", "EGA", 5748, Common::EN_ANY, Common::kPlatformDOS },
{ "37ff1b308999c4cca7319edfcc1280a0", "puttputt", "HE 70", "Demo", 8269, Common::EN_ANY, Common::kPlatformWindows },
{ "3824e60cdf639d22f6df92a03dc4b131", "fbear", "HE 62", "", 7732, Common::EN_ANY, Common::kPlatformDOS },
@@ -179,15 +179,17 @@ static const MD5Table md5table[] = {
{ "39fd6db10d0222d817025c4d3346e3b4", "farm", "", "Demo", -1, Common::EN_ANY, Common::kPlatformMacintosh },
{ "3a03dab514e4038df192d8a8de469788", "atlantis", "Floppy", "Floppy", -1, Common::EN_ANY, Common::kPlatformAmiga },
{ "3a0c35f3c147b98a2bdf8d400cfc4ab5", "indy3", "FM-TOWNS", "", -1, Common::JA_JPN, Common::kPlatformFMTowns },
- { "3a3e592b074f595489f7f11e150c398d", "puttzoo", "HE 99", "Updated", -1, Common::EN_USA, Common::kPlatformWindows },
+ { "3a3e592b074f595489f7f11e150c398d", "puttzoo", "HE 99", "Updated", -1, Common::EN_ANY, Common::kPlatformWindows },
{ "3a5d13675e9a23aedac0bac7730f0ac1", "samnmax", "", "CD", 228446581, Common::FR_FRA, Common::kPlatformMacintosh },
{ "3a5ec90d556d4920976c5578bfbfaf79", "maniac", "NES", "", -1, Common::DE_DEU, Common::kPlatformNES },
+ { "3a988de37118873ad129246b452909c0", "maniac", "V2 Demo", "V2 Demo", 1988, Common::RU_RUS, Common::kPlatformDOS },
{ "3ae7f002d9256b8bdf76aaf8a3a069f8", "freddi", "HE 100", "", 34837, Common::EN_GRB, Common::kPlatformWii },
{ "3af61c5edf8e15b43dbafd285b2e9777", "puttcircus", "", "Demo", -1, Common::HE_ISR, Common::kPlatformWindows },
{ "3b301b7892f883ce42ab4be6a274fea6", "samnmax", "Floppy", "Floppy", -1, Common::EN_ANY, Common::kPlatformDOS },
{ "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 },
@@ -236,7 +238,7 @@ static const MD5Table md5table[] = {
{ "4f138ac6f9b2ac5a41bc68b2c3296064", "freddi4", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformWindows },
{ "4f1d6f8b38343dba405472538b5037ed", "fbear", "HE 62", "", 7717, Common::EN_ANY, Common::kPlatformDOS },
{ "4f267a901719623de7dde83e47d5b474", "atlantis", "Floppy", "Floppy", -1, Common::DE_DEU, Common::kPlatformAmiga },
- { "4f580a021eee026f3b4589e17d130d78", "freddi4", "", "", -1, Common::UNK_LANG, Common::kPlatformUnknown },
+ { "4f580a021eee026f3b4589e17d130d78", "freddi4", "", "", 44190, Common::UNK_LANG, Common::kPlatformUnknown },
{ "4fa6870d9bc8c313b65d54b1da5a1891", "pajama", "", "", -1, Common::NL_NLD, Common::kPlatformUnknown },
{ "4fbbe9f64b8bc547503a379a301183ce", "tentacle", "", "CD", -1, Common::IT_ITA, Common::kPlatformUnknown },
{ "4fe6a2e8df3c4536b278fdd2fbcb181e", "pajama3", "", "Mini Game", 13911, Common::EN_ANY, Common::kPlatformWindows },
@@ -244,11 +246,11 @@ static const MD5Table md5table[] = {
{ "507bb360688dc4180fdf0d7597352a69", "freddi", "HE 73", "", 26402, Common::SE_SWE, Common::kPlatformWindows },
{ "50b831f11b8c4b83784cf81f4dcc69ea", "spyfox", "HE 101", "", -1, Common::EN_ANY, Common::kPlatformWii },
{ "50fcdc982a25063b78ad46bf389b8e8d", "tentacle", "Floppy", "Floppy", -1, Common::IT_ITA, Common::kPlatformDOS },
- { "51305e929e330e24a75a0351c8f9975e", "freddi2", "HE 99", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown },
+ { "51305e929e330e24a75a0351c8f9975e", "freddi2", "HE 99", "Updated", -1, Common::EN_ANY, Common::kPlatformUnknown },
{ "513f91a9dbe8d5490b39e56a3ac5bbdf", "pajama2", "HE 98.5", "", -1, Common::NL_NLD, Common::kPlatformUnknown },
{ "5262a27afcaee04e5c4900220bd463e7", "PuttsFunShop", "", "", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "52a4bae0746a11d7b1e8554e91a6645c", "zak", "V2", "V2", -1, Common::FR_FRA, Common::kPlatformDOS },
- { "53e94115b55dd51d4b8ff0871aa1df1e", "spyfox", "", "Demo", 20103, Common::EN_ANY, Common::kPlatformUnknown },
+ { "53e94115b55dd51d4b8ff0871aa1df1e", "spyfox", "", "Demo", 20103, Common::EN_USA, Common::kPlatformUnknown },
{ "54a936ad06161ff7bfefcb96200f7bff", "monkey", "VGA", "VGA Demo", 7617, Common::EN_ANY, Common::kPlatformAmiga },
{ "55518cd73cf9c6d23ea29c51ee06bdfe", "ft", "", "", -1, Common::IT_ITA, Common::kPlatformUnknown },
{ "55e4cc866ff9046824e1c638ba2b8c7f", "ft", "", "Akella", -1, Common::RU_RUS, Common::kPlatformUnknown },
@@ -264,7 +266,7 @@ static const MD5Table md5table[] = {
{ "58436e634f4fae1d9973591c2ffa1fcb", "spyfox", "HE 99", "Updated", -1, Common::EN_ANY, Common::kPlatformUnknown },
{ "589601b676c98b1c0c987bc031ab68b3", "chase", "HE 95", "", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "58fdf4c7ad13540a734e18f8584cad89", "puttzoo", "", "", -1, Common::EN_ANY, Common::kPlatformMacintosh },
- { "590e6546aacd0d374b7f3a4f53013ab1", "freddicove", "", "", -1, Common::UNK_LANG, Common::kPlatformUnknown },
+ { "590e6546aacd0d374b7f3a4f53013ab1", "freddicove", "", "", 41165, Common::UNK_LANG, Common::kPlatformUnknown },
{ "59d5cfcc5e672a6e07baae01328b918b", "PuttTime", "HE 90", "Demo", -1, Common::FR_FRA, Common::kPlatformUnknown },
{ "5a35e36fd777e9c37a49c5b2faca52f9", "loom", "EGA", "EGA Demo", 6108, Common::EN_ANY, Common::kPlatformDOS },
{ "5b08000a9c47b2887df6506ac767ca68", "fbear", "HE 62", "", -1, Common::EN_ANY, Common::kPlatform3DO },
@@ -287,7 +289,8 @@ static const MD5Table md5table[] = {
{ "6271130f440066830eca9056c1d7926f", "water", "HE 80", "", -1, Common::RU_RUS, Common::kPlatformWindows },
{ "62b8c16b6db226ba95aaa8be73f9885c", "indy3", "EGA", "EGA", -1, Common::ES_ESP, Common::kPlatformAmiga },
{ "632d2fddb8ba97723fa15334763ae857", "thinker1", "", "", 33270, Common::EN_ANY, Common::kPlatformWindows },
- { "63fdcdc95cdeea00060883aed38e5504", "PuttTime", "HE 85", "", -1, Common::EN_ANY, Common::kPlatformUnknown },
+ { "63fdcdc95cdeea00060883aed38e5504", "PuttTime", "HE 85", "", 62582, Common::EN_USA, Common::kPlatformUnknown },
+ { "64a22be96d679018696e5c8d3ca8b71d", "freddi", "HE 73", "", 26375, Common::JA_JPN, Common::kPlatformWindows },
{ "6508fd55530e6915507e1cc37f7f045d", "indy3", "EGA", "EGA", -1, Common::EN_ANY, Common::kPlatformDOS },
{ "65563295c3a06493351870f20a1630cf", "spyozon", "HE CUP", "Preview", 5235008, Common::UNK_LANG, Common::kPlatformUnknown },
{ "659942b9a6b519f123a13cca3c333a13", "jungle", "", "", -1, Common::EN_ANY, Common::kPlatformMacintosh },
@@ -295,7 +298,7 @@ static const MD5Table md5table[] = {
{ "66236cd1aec24e1d4aff4c4cc93b7e18", "indy3", "EGA", "EGA", -1, Common::FR_FRA, Common::kPlatformDOS },
{ "663743c03ae0c007f3d665cf631c0e6b", "puttrace", "HE 99", "Demo", 13135, Common::DE_DEU, Common::kPlatformUnknown },
{ "66fd5ff9a810dfeb6d6bdada18221140", "monkey", "VGA", "VGA", -1, Common::IT_ITA, Common::kPlatformDOS },
- { "672dec94b82f7f0877ebb5b5cf7f4bc1", "pajama", "", "", -1, Common::EN_USA, Common::kPlatformUnknown },
+ { "672dec94b82f7f0877ebb5b5cf7f4bc1", "pajama", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown },
{ "675d71151e9b5a968c8ce46d9fbf4cbf", "zak", "V2", "V2", 1916, Common::EN_ANY, Common::kPlatformDOS },
{ "679855cf61932f9bf995c8f3677380ed", "pajama3", "", "Demo", -1, Common::FR_FRA, Common::kPlatformWindows },
{ "68155a6bf082221525f431c2cbdac8ab", "SamsFunShop", "", "", -1, Common::EN_USA, Common::kPlatformUnknown },
@@ -379,7 +382,7 @@ static const MD5Table md5table[] = {
{ "822807c3cd3b43a925cab2767ca6b453", "BluesTreasureHunt", "", "Disc 1", -1, Common::EN_ANY, Common::kPlatformUnknown },
{ "8299d9b8a1b0e7b881bae7a9971dc5e2", "zak", "V2", "Demo", 1916, Common::EN_ANY, Common::kPlatformAtariST },
{ "82e5e24720cb85a2b662bea6b625cad9", "BluesTreasureHunt", "", "Disc 2", -1, Common::EN_ANY, Common::kPlatformWindows },
- { "8368f552b1e3eba559f8d559bcc4cadb", "freddi3", "", "", -1, Common::UNK_LANG, Common::kPlatformUnknown },
+ { "8368f552b1e3eba559f8d559bcc4cadb", "freddi3", "", "", 55959, Common::UNK_LANG, Common::kPlatformUnknown },
{ "839a658f7d22de00787ebc945348cdb6", "dog", "", "", 19681, Common::DE_DEU, Common::kPlatformWindows },
{ "83cedbe26aa8b58988e984e3d34cac8e", "freddi3", "HE 99", "", -1, Common::DE_DEU, Common::kPlatformUnknown },
{ "83e7a9205567dceb456ee35eeaf26ffa", "pajama3", "", "", -1, Common::IT_ITA, Common::kPlatformUnknown },
@@ -411,7 +414,7 @@ static const MD5Table md5table[] = {
{ "8e9417564f33790815445b2136efa667", "atlantis", "", "CD", 11915, Common::JA_JPN, Common::kPlatformMacintosh },
{ "8e9830a6f2702be5b22c8fa0a6aaf977", "freddi2", "HE 80", "", 65305, Common::NL_NLD, Common::kPlatformUnknown },
{ "8eb84cee9b429314c7f0bdcf560723eb", "monkey", "FM-TOWNS", "", 9925, Common::EN_ANY, Common::kPlatformFMTowns },
- { "8ee63cafb1fe9d62aa0d5a23117e70e7", "freddi2", "HE 100", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown },
+ { "8ee63cafb1fe9d62aa0d5a23117e70e7", "freddi2", "HE 100", "Updated", -1, Common::EN_ANY, Common::kPlatformUnknown },
{ "8f345db2f3f5a25ed6305001957e6f72", "freddicove", "HE 100", "", 41182, Common::NL_NLD, Common::kPlatformUnknown },
{ "8f3758ff98c9c5d78e5d635222cad026", "atlantis", "Floppy", "Floppy", -1, Common::IT_ITA, Common::kPlatformDOS },
{ "8fec68383202d38c0d25e9e3b757c5df", "comi", "Demo", "Demo", 18041, Common::UNK_LANG, Common::kPlatformWindows },
@@ -451,7 +454,7 @@ static const MD5Table md5table[] = {
{ "9c143c5905055d5df7a0f014ab379aee", "puttmoon", "HE 70", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows },
{ "9c92eeaf517a31b7221ec2546ab669fd", "puttmoon", "HE 70", "", -1, Common::EN_ANY, Common::kPlatformWindows },
{ "9cdd327c1034c046cb595d251c44da2f", "chase", "HE 95", "", -1, Common::RU_RUS, Common::kPlatformWindows },
- { "9d4ab3e0e1d1ebc6ba8a6a4c470ed184", "spyfox", "HE 100", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown },
+ { "9d4ab3e0e1d1ebc6ba8a6a4c470ed184", "spyfox", "HE 100", "Demo", 15943, Common::EN_USA, Common::kPlatformUnknown },
{ "9d7b67be003fea60be4dcbd193611936", "ft", "Demo", "Demo", 11164, Common::EN_ANY, Common::kPlatformMacintosh },
{ "9dc02577bf50d4cfaf3de3fbac06fbe2", "puttmoon", "", "", -1, Common::EN_ANY, Common::kPlatformMacintosh },
{ "9e5e0fb43bd22f4628719b7501adb717", "monkey", "No AdLib", "EGA", -1, Common::FR_FRA, Common::kPlatformAtariST },
@@ -464,7 +467,7 @@ static const MD5Table md5table[] = {
{ "a15d6e1e2c52bbd0ff7fa6b63ab7f796", "indy3", "Steam", "Steam", 680340, Common::EN_ANY, Common::kPlatformMacintosh },
{ "a194f15f51ee62badab74b9e7da97693", "baseball2001", "", "Demo", 20507, Common::EN_ANY, Common::kPlatformUnknown },
{ "a197a87ae77f3b3333f09a7a2c448fe2", "freddi", "HE 99", "Updated", -1, Common::EN_ANY, Common::kPlatformWindows },
- { "a22af0ad0e3126d19d22707b0267a37d", "balloon", "HE 80", "", -1, Common::NL_NLD, Common::kPlatformWindows },
+ { "a22af0ad0e3126d19d22707b0267a37d", "balloon", "HE 80", "", 12800, Common::NL_NLD, Common::kPlatformWindows },
{ "a2386da005672cbd5136f4f27a626c5f", "farm", "HE 73", "", 87061, Common::NL_NLD, Common::kPlatformWindows },
{ "a28135a7ade38cc0208b04507c46efd1", "spyfox", "HE 99", "", -1, Common::DE_DEU, Common::kPlatformUnknown },
{ "a2bb6aa0537402c1b3c2ea899ccef64b", "lost", "HE 99", "Demo", 15540, Common::EN_ANY, Common::kPlatformWindows },
@@ -472,14 +475,15 @@ static const MD5Table md5table[] = {
{ "a336134914eaab4892d35625aa15ad1d", "freddi4", "HE 99", "", -1, Common::RU_RUS, Common::kPlatformWindows },
{ "a525c1753c1db5011c00417da37887ef", "PuttTime", "HE 100", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "a561d2e2413cc1c71d5a1bf87bf493ea", "lost", "HE 100", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown },
- { "a56a05c6b865b9956639f8c51269e5ab", "balloon", "HE 80", "", -1, Common::NL_NLD, Common::kPlatformMacintosh },
+ { "a56a05c6b865b9956639f8c51269e5ab", "balloon", "HE 80", "", 12800, Common::NL_NLD, Common::kPlatformMacintosh },
{ "a56e8d9d4281c53c3f63c9bd22a59e21", "catalog", "HE CUP", "Preview", 10978342, Common::EN_ANY, Common::kPlatformUnknown },
{ "a570381b028972d891052ee1e51dc011", "maniac", "V2", "V2", 1988, Common::EN_ANY, Common::kPlatformAtariST },
{ "a59a438cb182124c30c4447d8ed469e9", "freddi", "HE 100", "", 34837, Common::NB_NOR, Common::kPlatformWii },
{ "a5c5388da9bf0e6662fdca8813a79d13", "farm", "", "", 86962, Common::EN_ANY, Common::kPlatformWindows },
{ "a654fb60c3b67d6317a7894ffd9f25c5", "pajama3", "", "Demo", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "a71014c53a6d18c66ef2ea0ee42328e9", "PuttTime", "HE 99", "Mini Game", 18458, Common::NL_NLD, Common::kPlatformWindows },
- { "a7cacad9c40c4dc9e1812abf6c8af9d5", "puttcircus", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown },
+ { "a77d0efbe786ea7f490c2021dbfa3f2f", "zak", "V2", "V2", -1, Common::RU_RUS, Common::kPlatformDOS },
+ { "a7cacad9c40c4dc9e1812abf6c8af9d5", "puttcircus", "", "Demo", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "a85856675429fe88051744f755b72f93", "farm", "HE 73", "", -1, Common::EN_ANY, Common::kPlatformWindows },
{ "a86f9c49355579c30d4a55b477c0d869", "baseball2001", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown },
{ "a8fcc3084ad5e3e569722755f205b1ef", "pajama3", "", "Mini Game", 13911, Common::DE_DEU, Common::kPlatformWindows },
@@ -493,7 +497,7 @@ static const MD5Table md5table[] = {
{ "aaa587701cde7e74692c68c1024b85eb", "puttrace", "HE 99", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown },
{ "aaa7f36a253f277dd29dd1c051b0e4b9", "indy3", "No AdLib", "EGA", -1, Common::DE_DEU, Common::kPlatformAtariST },
{ "aad201302286c1cfee92321cd406e427", "dig", "Steam", "Steam", 811008, Common::EN_ANY, Common::kPlatformWindows },
- { "ab0693e9324cfcf498fdcbb12acf8bb4", "puttcircus", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown },
+ { "ab0693e9324cfcf498fdcbb12acf8bb4", "puttcircus", "", "", 36655, Common::EN_USA, Common::kPlatformUnknown },
{ "ac1642b6edfb8521ca03760126f1c250", "tentacle", "", "Demo", -1, Common::DE_DEU, Common::kPlatformDOS },
{ "ac62d50e39492ee3738b4e83a5ac780f", "freddi2", "HE 80", "", -1, Common::NL_NLD, Common::kPlatformWindows },
{ "acad97ab1c6fc2a5b2d98abf6db4a190", "tentacle", "Floppy", "Floppy", -1, Common::EN_ANY, Common::kPlatformUnknown },
@@ -528,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 },
@@ -613,7 +618,7 @@ static const MD5Table md5table[] = {
{ "debe337f73d660e951ece7c1f1c81add", "zak", "V2", "V2", -1, Common::EN_ANY, Common::kPlatformDOS },
{ "defb8cb9ec4b0f91acfb6b61c6129ad9", "PuttTime", "HE 99", "", -1, Common::RU_RUS, Common::kPlatformWindows },
{ "df03ee021aa9b81d90cab9c26da07614", "indy3", "EGA", "EGA", -1, Common::IT_ITA, Common::kPlatformAmiga },
- { "df047cc4792150f601290357566d36a6", "freddi", "HE 90", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown },
+ { "df047cc4792150f601290357566d36a6", "freddi", "HE 90", "Updated", -1, Common::EN_ANY, Common::kPlatformUnknown },
{ "e01acc8c12ef44e8f778fe87e5f90f4e", "fbpack", "", "", -1, Common::EN_ANY, Common::kPlatform3DO },
{ "e03ed1474ec14de78359970e0457a820", "freddi4", "HE 99", "Demo", -1, Common::EN_GRB, Common::kPlatformWindows },
{ "e144f5f49d9241d2a9dee2576b3d09cb", "airport", "", "Demo", 51152, Common::EN_ANY, Common::kPlatformWindows },
@@ -626,7 +631,7 @@ static const MD5Table md5table[] = {
{ "e534d29afb3c6e0ee9dc3d53c5956714", "atlantis", "Floppy", "Floppy", -1, Common::DE_DEU, Common::kPlatformAmiga },
{ "e5563c8358443c4352fcddf7402a5e0a", "pajama2", "HE 98.5", "", -1, Common::FR_FRA, Common::kPlatformWindows },
{ "e5c112140ad6574997de033a8e2a2964", "readtime", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown },
- { "e62056ba675ad65d8854ab3c5ad4b3c0", "spyfox2", "", "Mini Game", 14689, Common::EN_ANY, Common::kPlatformWindows },
+ { "e62056ba675ad65d8854ab3c5ad4b3c0", "spyfox2", "", "Mini Game", 14689, Common::EN_GRB, Common::kPlatformWindows },
{ "e63a0b9249b5ca4cc4d3ac34305ae360", "freddi", "HE 99", "", -1, Common::NB_NOR, Common::kPlatformWindows },
{ "e689bdf67f98b1d760ce4487ec0e8d06", "indy3", "EGA", "EGA", -1, Common::FR_FRA, Common::kPlatformAmiga },
{ "e6cd81b25ab1453a8a6d3482118c391e", "pass", "", "", 7857, Common::EN_ANY, Common::kPlatformDOS },
@@ -639,8 +644,9 @@ static const MD5Table md5table[] = {
{ "e98b982ceaf9d253d730bde8903233d6", "monkey", "EGA", "EGA", -1, Common::DE_DEU, Common::kPlatformDOS },
{ "eae95b2b3546d8ba86ae1d397c383253", "dog", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown },
{ "eb700bb73ca1cc44a1ad5e4b1a4bdeaf", "indy3", "EGA", "EGA", 5361, Common::DE_DEU, Common::kPlatformDOS },
- { "ebd0b2c8a387f18887282afe6cad894a", "spyozon", "", "Demo", 15317, Common::EN_ANY, Common::kPlatformUnknown },
+ { "ebd0b2c8a387f18887282afe6cad894a", "spyozon", "", "Demo", 15317, Common::EN_USA, Common::kPlatformUnknown },
{ "ebd324dcf06a4c49e1ba5c231eee1060", "freddi4", "HE 99", "Demo", -1, Common::EN_USA, Common::kPlatformUnknown },
+ { "ebdd2fbc995a321605375dc57766db79", "dig", "", "With Subtitles", 16304, Common::RU_RUS, Common::kPlatformUnknown },
{ "ecc4340c2b801f5af8da4e00c0e432d9", "puttcircus", "", "", -1, Common::NL_NLD, Common::kPlatformUnknown },
{ "ed2b074bc3166087a747acb2a3c6abb0", "freddi3", "HE 98.5", "Demo", -1, Common::DE_DEU, Common::kPlatformUnknown },
{ "ed361270102e355afe5236954216aba2", "lost", "", "", -1, Common::EN_USA, Common::kPlatformUnknown },
@@ -659,13 +665,15 @@ static const MD5Table md5table[] = {
{ "f06e66fd45b2f8b0f4a2833ff4476050", "fbpack", "", "", -1, Common::HE_ISR, Common::kPlatformDOS },
{ "f08145577e4f13584cc90b3d6e9caa55", "pajama3", "", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown },
{ "f0ccc12a8704bf57706b42a37f877128", "tentacle", "Floppy", "Floppy", -1, Common::EN_ANY, Common::kPlatformDOS },
+ { "f0d294891b813d3dcc525b89bc318815", "maniac", "V2", "V2", 1988, Common::RU_RUS, Common::kPlatformDOS },
{ "f1b0e0d587b85052de5534a3847e68fe", "water", "HE 99", "Updated", -1, Common::EN_ANY, Common::kPlatformUnknown },
{ "f237bf8a5ef9af78b2a6a4f3901da341", "pajama", "", "Demo", 18354, Common::EN_ANY, Common::kPlatformUnknown },
{ "f27b1ba0eadaf2a6617b2b58192d1dbf", "samnmax", "Floppy", "Floppy", -1, Common::DE_DEU, Common::kPlatformDOS },
- { "f2ec78e50bdc63b70044e9758be10914", "spyfox", "HE 98.5", "Demo", -1, Common::NL_NLD, Common::kPlatformMacintosh },
+ { "f2ec78e50bdc63b70044e9758be10914", "spyfox", "HE 98.5", "Demo", 20141, Common::NL_NLD, Common::kPlatformMacintosh },
{ "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 },
@@ -680,7 +688,7 @@ static const MD5Table md5table[] = {
{ "fb66aa42de21675116346213f176a366", "monkey", "VGA", "VGA", -1, Common::IT_ITA, Common::kPlatformAmiga },
{ "fbb697d89d2beca87360a145f467bdae", "PuttTime", "HE 90", "Demo", -1, Common::DE_DEU, Common::kPlatformUnknown },
{ "fbbbb38a81fc9d6a61d509278390a290", "farm", "HE 73", "", -1, Common::EN_ANY, Common::kPlatformMacintosh },
- { "fbdd947d21e8f5bac6d6f7a316af1c5a", "spyfox", "", "Demo", 15693, Common::EN_ANY, Common::kPlatformUnknown },
+ { "fbdd947d21e8f5bac6d6f7a316af1c5a", "spyfox", "", "Demo", 15693, Common::EN_USA, Common::kPlatformUnknown },
{ "fc53ce0e5f6562b1c1e1b4b8203acafb", "samnmax", "Floppy", "Floppy", -1, Common::ES_ESP, Common::kPlatformDOS },
{ "fc6b6148e80d67939d9a18697c0f626a", "monkey", "EGA", "EGA", 8367, Common::DE_DEU, Common::kPlatformDOS },
{ "fc8d197a22146e74766e9cb0cfcaf1da", "freddi2", "HE 80", "Demo", 27298, Common::EN_ANY, Common::kPlatformUnknown },
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_v4.h b/engines/scumm/scumm_v4.h
index 28f619ceaa..a008023ff9 100644
--- a/engines/scumm/scumm_v4.h
+++ b/engines/scumm/scumm_v4.h
@@ -35,7 +35,7 @@ class ScummEngine_v4 : public ScummEngine_v5 {
public:
/**
- * Prepared savegame used by the orginal save/load dialog.
+ * Prepared savegame used by the original save/load dialog.
* Must be valid as long as the savescreen is active. As we are not
* notified when the savescreen is closed, memory is only freed on a game
* reset, at the destruction of the engine or when the original save/load
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/imuse_channel.cpp b/engines/scumm/smush/imuse_channel.cpp
index 461aff962e..24cb03fbfb 100644
--- a/engines/scumm/smush/imuse_channel.cpp
+++ b/engines/scumm/smush/imuse_channel.cpp
@@ -156,7 +156,7 @@ void ImuseChannel::decode() {
_sbufferSize -= remaining_size;
} else {
debugC(DEBUG_SMUSH, "impossible ! : %p, %d, %d, %p(%d), %p(%d, %d)",
- (const void *)this, _dataSize, _inData, _tbuffer, _tbufferSize, _sbuffer, _sbufferSize, _srbufferSize);
+ (const void *)this, _dataSize, _inData, (void *)_tbuffer, _tbufferSize, (void *)_sbuffer, _sbufferSize, _srbufferSize);
byte *old = _tbuffer;
int new_size = remaining_size + _tbufferSize;
_tbuffer = (byte *)malloc(new_size);
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 84d2b37f96..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++;
}
@@ -240,7 +247,7 @@ void Sound::playSound(int soundID) {
// mentioned in the bug report above; in case it is, I put a check here.
assert(soundID == 39);
- // The samplerate is copied from the sound resouce 39 of the PC CD/VGA
+ // The samplerate is copied from the sound resource 39 of the PC CD/VGA
// version of Monkey Island.
// Read info from the header
@@ -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/POTFILES b/engines/sherlock/POTFILES
new file mode 100644
index 0000000000..b9f1c1249f
--- /dev/null
+++ b/engines/sherlock/POTFILES
@@ -0,0 +1,3 @@
+engines/sherlock/detection.cpp
+engines/sherlock/scalpel/scalpel.cpp
+engines/sherlock/tattoo/widget_files.cpp
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/configure.engine b/engines/sherlock/configure.engine
index a56129a8f0..fd1c354e78 100644
--- a/engines/sherlock/configure.engine
+++ b/engines/sherlock/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 sherlock "The Lost Files of Sherlock Holmes" no
+add_engine sherlock "The Lost Files of Sherlock Holmes" yes
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/decompress.cpp b/engines/sherlock/decompress.cpp
deleted file mode 100644
index 8e02da3212..0000000000
--- a/engines/sherlock/decompress.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#include "sherlock/decompress.h"
-
-namespace Sherlock {
-
-/**
- * Decompresses an LZW compressed resource. If no outSize is specified, it will
- * decompress the entire resource. If, however, an explicit size is specified,
- * then it means we're already within a resource, and only want to decompress
- * part of it.
- */
-Common::SeekableReadStream *decompressLZ(Common::SeekableReadStream &source, int32 outSize) {
- if (outSize == -1) {
- source.seek(5);
- outSize = source.readSint32LE();
- }
-
- byte lzWindow[4096];
- uint16 lzWindowPos;
- uint16 cmd;
-
- byte *outBuffer = new byte[outSize];
- byte *outBufferEnd = outBuffer + outSize;
- Common::MemoryReadStream *outS = new Common::MemoryReadStream(outBuffer, outSize, DisposeAfterUse::YES);
-
- memset(lzWindow, 0xFF, 0xFEE);
- lzWindowPos = 0xFEE;
- cmd = 0;
-
- do {
- cmd >>= 1;
- if (!(cmd & 0x100))
- cmd = source.readByte() | 0xFF00;
-
- if (cmd & 1) {
- byte literal = source.readByte();
- *outBuffer++ = literal;
- lzWindow[lzWindowPos] = literal;
- lzWindowPos = (lzWindowPos + 1) & 0x0FFF;
- } else {
- int copyPos, copyLen;
- copyPos = source.readByte();
- copyLen = source.readByte();
- copyPos = copyPos | ((copyLen & 0xF0) << 4);
- copyLen = (copyLen & 0x0F) + 3;
- while (copyLen--) {
- byte literal = lzWindow[copyPos];
- copyPos = (copyPos + 1) & 0x0FFF;
- *outBuffer++ = literal;
- lzWindow[lzWindowPos] = literal;
- lzWindowPos = (lzWindowPos + 1) & 0x0FFF;
- }
- }
- } while (outBuffer < outBufferEnd);
-
- return outS;
-}
-
-
-/**
- * Decompresses a Rose Tattoo resource
- *
-Common::SeekableReadStream *decompress32(Common::SeekableReadStream &source, int32 outSize) {
- if (outSize == -1) {
- outSize = source.readSint32LE();
- }
-
- byte lzWindow[8192];
- byte *outBuffer = new byte[outSize];
- byte *outBufferEnd = outBuffer + outSize;
- Common::MemoryReadStream *outS = new Common::MemoryReadStream(outBuffer, outSize, DisposeAfterUse::YES);
-
- memset(lzWindow, 0xFF, 8192);
- int lzWindowPos = 0xFEE;
- int cmd = 0;
-
- do {
- cmd >>= 1;
- if (!(cmd & 0x100))
- cmd = source.readByte() | 0xFF00;
-
- if (cmd & 1) {
- byte literal = source.readByte();
- *outBuffer++ = literal;
- lzWindow[lzWindowPos] = literal;
- lzWindowPos = (lzWindowPos + 1) & 0x0FFF;
- } else {
- int copyPos, copyLen;
- copyPos = source.readByte();
- copyLen = source.readByte();
- copyPos = copyPos | ((copyLen & 0xF0) << 4);
- copyLen = (copyLen & 0x0F) + 3;
- while (copyLen--) {
- byte literal = lzWindow[copyPos];
- copyPos = (copyPos + 1) & 0x0FFF;
- *outBuffer++ = literal;
- lzWindow[lzWindowPos] = literal;
- lzWindowPos = (lzWindowPos + 1) & 0x0FFF;
- }
- }
- } while (outBuffer < outBufferEnd);
-
- return outS;
-}
-*/
-
-} // namespace Sherlock
diff --git a/engines/sherlock/detection_tables.h b/engines/sherlock/detection_tables.h
index d028c4af6c..ce6eafcaca 100644
--- a/engines/sherlock/detection_tables.h
+++ b/engines/sherlock/detection_tables.h
@@ -32,7 +32,7 @@ static const SherlockGameDescription gameDescriptions[] = {
AD_ENTRY1s("talk.lib", "ad0c4d6865edf15da4e9204c08815875", 238928),
Common::EN_ANY,
Common::kPlatformDOS,
- ADGF_TESTING,
+ ADGF_NO_FLAGS,
GUIO6(GUIO_NOSPEECH, GAMEOPTION_ORIGINAL_SAVES, GAMEOPTION_FADE_STYLE, GAMEOPTION_HELP_STYLE,
GAMEOPTION_PORTRAITS_ON, GAMEOPTION_WINDOW_STYLE)
},
@@ -50,7 +50,7 @@ static const SherlockGameDescription gameDescriptions[] = {
AD_LISTEND},
Common::DE_DEU,
Common::kPlatformDOS,
- ADGF_TESTING,
+ ADGF_NO_FLAGS,
GUIO6(GUIO_NOSPEECH, GAMEOPTION_ORIGINAL_SAVES, GAMEOPTION_FADE_STYLE, GAMEOPTION_HELP_STYLE,
GAMEOPTION_PORTRAITS_ON, GAMEOPTION_WINDOW_STYLE)
},
@@ -68,7 +68,7 @@ static const SherlockGameDescription gameDescriptions[] = {
AD_LISTEND},
Common::DE_DEU,
Common::kPlatformDOS,
- ADGF_TESTING,
+ ADGF_NO_FLAGS,
GUIO6(GUIO_NOSPEECH, GAMEOPTION_ORIGINAL_SAVES, GAMEOPTION_FADE_STYLE, GAMEOPTION_HELP_STYLE,
GAMEOPTION_PORTRAITS_ON, GAMEOPTION_WINDOW_STYLE)
},
@@ -86,7 +86,7 @@ static const SherlockGameDescription gameDescriptions[] = {
AD_LISTEND },
Common::DE_DEU,
Common::kPlatformDOS,
- ADGF_TESTING,
+ ADGF_NO_FLAGS,
GUIO6(GUIO_NOSPEECH, GAMEOPTION_ORIGINAL_SAVES, GAMEOPTION_FADE_STYLE, GAMEOPTION_HELP_STYLE,
GAMEOPTION_PORTRAITS_ON, GAMEOPTION_WINDOW_STYLE)
},
@@ -104,7 +104,7 @@ static const SherlockGameDescription gameDescriptions[] = {
AD_LISTEND},
Common::ES_ESP,
Common::kPlatformDOS,
- ADGF_TESTING,
+ ADGF_NO_FLAGS,
GUIO6(GUIO_NOSPEECH, GAMEOPTION_ORIGINAL_SAVES, GAMEOPTION_FADE_STYLE, GAMEOPTION_HELP_STYLE,
GAMEOPTION_PORTRAITS_ON, GAMEOPTION_WINDOW_STYLE)
},
@@ -134,7 +134,7 @@ static const SherlockGameDescription gameDescriptions[] = {
AD_ENTRY1s("talk.lib", "dbdc8a20c96900aa7e4d02f3fe8a274c", 121102),
Common::EN_ANY,
Common::kPlatformDOS,
- ADGF_TESTING | ADGF_DEMO,
+ ADGF_DEMO,
GUIO1(GUIO_NOSPEECH)
},
GType_SerratedScalpel,
@@ -149,7 +149,7 @@ static const SherlockGameDescription gameDescriptions[] = {
AD_ENTRY1s("music.lib", "ec19a09b7fef6fd90b1ab812ce6e9739", 38563),
Common::EN_ANY,
Common::kPlatformDOS,
- ADGF_TESTING | ADGF_DEMO,
+ ADGF_DEMO,
GUIO1(GUIO_NOSPEECH)
},
GType_SerratedScalpel,
@@ -162,9 +162,9 @@ static const SherlockGameDescription gameDescriptions[] = {
"rosetattoo",
"CD",
AD_ENTRY1s("talk.lib", "22e8e6406dd2fbbb238c9898928df42e", 770756),
- Common::EN_ANY,
+ Common::FR_FRA,
Common::kPlatformDOS,
- ADGF_TESTING,
+ ADGF_NO_FLAGS,
GUIO3(GAMEOPTION_ORIGINAL_SAVES, GAMEOPTION_HELP_STYLE, GAMEOPTION_TRANSPARENT_WINDOWS)
},
GType_RoseTattoo
@@ -179,7 +179,7 @@ static const SherlockGameDescription gameDescriptions[] = {
AD_ENTRY1s("talk.lib", "9639a756b0993ebd71cb5f4d8b78b2dc", 765134),
Common::EN_ANY,
Common::kPlatformDOS,
- ADGF_TESTING,
+ ADGF_NO_FLAGS,
GUIO3(GAMEOPTION_ORIGINAL_SAVES, GAMEOPTION_HELP_STYLE, GAMEOPTION_TRANSPARENT_WINDOWS)
},
GType_RoseTattoo,
@@ -194,7 +194,7 @@ static const SherlockGameDescription gameDescriptions[] = {
AD_ENTRY1s("talk.lib", "5027aa72f0d263ed3b1c764a6c397911", 873864),
Common::DE_DEU,
Common::kPlatformDOS,
- ADGF_TESTING,
+ ADGF_NO_FLAGS,
GUIO3(GAMEOPTION_ORIGINAL_SAVES, GAMEOPTION_HELP_STYLE, GAMEOPTION_TRANSPARENT_WINDOWS)
},
GType_RoseTattoo,
@@ -209,7 +209,7 @@ static const SherlockGameDescription gameDescriptions[] = {
AD_ENTRY1s("talk.lib", "4f3ccf50e1012445624569cd605d7449", 783713),
Common::ES_ESP,
Common::kPlatformDOS,
- ADGF_TESTING,
+ ADGF_NO_FLAGS,
GUIO3(GAMEOPTION_ORIGINAL_SAVES, GAMEOPTION_HELP_STYLE, GAMEOPTION_TRANSPARENT_WINDOWS)
},
GType_RoseTattoo,
diff --git a/engines/sherlock/events.cpp b/engines/sherlock/events.cpp
index c6a223b6d9..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() {
@@ -263,6 +263,10 @@ void Events::setFrameRate(int newRate) {
_frameRate = newRate;
}
+void Events::toggleSpeed() {
+ _frameRate = (_frameRate == GAME_FRAME_RATE) ? GAME_FRAME_RATE * 2 : GAME_FRAME_RATE;
+}
+
bool Events::checkForNextFrameCounter() {
// Check for next game frame
uint32 milli = g_system->getMillis();
@@ -346,7 +350,8 @@ bool Events::delay(uint32 time, bool interruptable) {
g_system->delayMillis(time);
bool result = !(interruptable && (kbHit() || _pressed || _vm->shouldQuit()));
- clearEvents();
+ if (interruptable)
+ clearEvents();
return result;
} else {
// For long periods go into a loop where we delay by 10ms at a time and then
diff --git a/engines/sherlock/events.h b/engines/sherlock/events.h
index e13ef18822..711804dfdf 100644
--- a/engines/sherlock/events.h
+++ b/engines/sherlock/events.h
@@ -149,6 +149,11 @@ public:
void setFrameRate(int newRate);
/**
+ * Toggle between standard game speed and an "extra fast" mode
+ */
+ void toggleSpeed();
+
+ /**
* Return the current game frame number
*/
uint32 getFrameCounter() const { return _frameCounter; }
diff --git a/engines/sherlock/fixed_text.cpp b/engines/sherlock/fixed_text.cpp
index cbee944120..4679fe58b8 100644
--- a/engines/sherlock/fixed_text.cpp
+++ b/engines/sherlock/fixed_text.cpp
@@ -27,6 +27,183 @@
namespace Sherlock {
+static const char *const fixedJournalTextEN[] = {
+ // Holmes asked/said...
+ "Holmes asked me, ",
+ "Holmes asked the Inspector, ",
+ "Holmes asked %s, ",
+ "Holmes said to me, ",
+ "Holmes said to the Inspector, ",
+ "Holmes said to %s, ",
+ // I asked/said...
+ "I replied, ",
+ "The reply was, ",
+ // Holmes/I/The Inspector/Person asked/said (without "Then" prefix)
+ "Holmes asked, ",
+ "Holmes said, ",
+ "I asked, ",
+ "I said, ",
+ "The Inspector asked, ",
+ "The Inspector said, ",
+ "%s asked, ",
+ "%s said, ",
+ // Then Holmes/I/The Inspector/Person asked/said
+ "Then Holmes asked, ",
+ "Then Holmes said, ",
+ "Then I asked, ",
+ "Then I said, ",
+ "Then the Inspector asked, ",
+ "Then the Inspector said, ",
+ "Then %s asked, ",
+ "Then %s said, "
+};
+
+static const char *const fixedJournalTextDE[] = {
+ // Holmes asked/said...
+ "Holmes fragte mich, ",
+ "Holmes fragte Inspektor Lestrade, ",
+ "Holmes fragte %s, ",
+ "Holmes sagte mir, ",
+ "Holmes sagte Inspektor Lestrade, ",
+ "Holmes sagte %s, ",
+ // I asked/said...
+ "Ich antwortete, ",
+ "Die Antwort lautete, ",
+ // Holmes/I/The Inspector/Person asked/said (without "Then" prefix)
+ "Holmes fragte, ", // original: "fragte Holmes"
+ "Holmes sagte, ", // original: "sagte Holmes"
+ "Ich fragte, ", // original: "fragte Ich"
+ "Ich sagte, ", // original: "sagte Ich"
+ "Der Inspektor fragte, ",
+ "Der Inspektor sagte, ",
+ "%s fragte, ",
+ "%s sagte, ",
+ // Then Holmes/I/The Inspector/Person asked/said
+ "Dann fragte Holmes, ",
+ "Dann sagte Holmes, ",
+ "Dann fragte ich, ", // original: "Dann sagte Ich"
+ "Dann sagte ich, ", // original: "Dann sagte Ich"
+ "Dann fragte der Inspektor, ",
+ "Dann sagte der Inspektor, ",
+ "Dann fragte %s, ",
+ "Dann sagte %s, "
+};
+
+// Only used for Sherlock Holmes 2, so special characters should use the SH2 charset
+// small a w/ accent grave: 0x85 / octal 205
+// small e w/ accent acute: 0x82 / octal 202
+// small e w/ accent grave: 0x8A / octal 212
+// small e w/ circonflexe: 0x88 / octal 210
+// small cedilla: 0x87 / octal 207
+static const char *const fixedJournalTextFR[] = {
+ // Holmes asked/said...
+ "Holmes me demanda, ", // original: "Holmes m'a demand\202, "
+ "Holmes demanda \205 l'inspecteur, ", // original: "Holmes a demand\202 \205 l'inspecteur, "
+ "Holmes demanda \205 %s, ", // original: "Holmes a demand\202 \205 %s, "
+ "Holmes me dit, ", // original: "Holmes m'a dit, "
+ "Holmes dit \205 l'inspecteur, ", // original: "Holmes a dit \205 l'inspecteur, "
+ "Holmes dit \205 %s, ", // original: "Holmes a dit \205 %s, "
+ // I asked/said...
+ "Je r\202pondis, ", // original: "J'ai r\202pondu, ",
+ "La r\202ponse fut, ",
+ // Holmes/I/The Inspector/Person asked/said (without "Then" prefix)
+ "Holmes demanda, ", // original: "Holmes a demand\202, "
+ "Holmes dit, ",
+ "Je demandai, ", // original: "J'ai demand\202, "
+ "Je dis, ", // original: "J'ai dit, "
+ "L'inspecteur demanda, ", // original: ""L'inspecteur a demand\202, "
+ "L'inspecteur dit, ",
+ "%s demanda, ", // original: "%s a demand\202, "
+ "%s dit, ",
+ // Then Holmes/I/The Inspector/Person asked/said
+ "Alors Holmes demanda, ", // original: it seems "puis"/"then" was not used/removed. They instead added a space character, so sentences looked weird
+ "Alors Holmes dit, ",
+ "Alors je demandai, ",
+ "Alors je dis, ",
+ "Alors l'inspecteur demanda, ",
+ "Alors l'inspecteur dit, ",
+ "Alors %s demanda, ",
+ "Alors %s dit, "
+};
+
+// Sherlock Holmes 1+2:
+// small e w/ accent bottom to top : 0x82 / octal 202
+// big E w/ accent bottom to top : 0x90 / octal 220
+// small a w/ accent bottom to top : 0xA0 / octal 240
+// small i w/ accent bottom to top : 0xA1 / octal 241
+// small o w/ accent bottom to top : 0xA2 / octal 242
+// small u w/ accent bottom to top : 0xA3 / octal 243
+// small n w/ wavy line : 0xA4 / octal 244
+// big N w/ wavy line : 0xA5 / octal 245
+// small a w/ under line : 0xA6 / octal 246
+// small o w/ under line : 0xA7 / octal 247
+// inverted question mark : 0xA8 / octal 250
+static const char *const fixedJournalTextES[] = {
+ // Holmes asked/said...
+ "Holmes me pregunt\242, ", // original: "Holmes me pidi\242, ",
+ "Holmes pregunt\242 al Inspector, ", // original: "el inspector"?
+ "Holmes pregunt\242 %s, ",
+ "Holmes me dijo, ",
+ "Holmes dijo al Inspector, ", // original: "el inspector"?
+ "Holmes dijo a %s, ", // original: "Holmes dijo a %s, "
+ // I asked/said...
+ "Yo content\202, ", // original: "Yo respond\241, ",
+ "La respuesta fue, ",
+ // Holmes/I/The Inspector/Person asked/said (without "Then" prefix)
+ "Holmes pregunt\242, ",
+ "Holmes dijo, ",
+ "Yo pregunt\202, ", // original: "Yo pregunt\242, ",
+ "Yo dije, ",
+ "El Inspector pregunt\242, ",
+ "El Inspector dijo, ",
+ "%s pregunt\242, ",
+ "%s dijo, ",
+ // Then Holmes/I/The Inspector/Person asked/said
+ "Despu\202s Holmes pregunt\242, ", // original: added "Entonces" instead of "Despues"
+ "Despu\202s Holmes dijo, ",
+ "Despu\202s yo pregunt\202, ", // "pregunt\242, "
+ "Despu\202s yo dije, ",
+ "Despu\202s el Inspector pregunt\242, ",
+ "Despu\202s el Inspector dijo, ",
+ "Despu\202s %s pregunt\242, ",
+ "Despu\202s %s dijo, "
+};
+
+FixedText::FixedText(SherlockEngine *vm) {
+ _vm = vm;
+
+ // Figure out which fixed texts to use
+ Common::Language curLanguage = _vm->getLanguage();
+
+ switch (curLanguage) {
+ case Common::EN_ANY:
+ // Used by Sherlock Holmes 1+2
+ _fixedJournalTextArray = fixedJournalTextEN;
+ _fixedObjectPickedUpText = "Picked up %s";
+ break;
+ case Common::DE_DEU:
+ // Used by Sherlock Holmes 1+2
+ _fixedJournalTextArray = fixedJournalTextDE;
+ _fixedObjectPickedUpText = "%s eingesteckt";
+ break;
+ case Common::FR_FRA:
+ // Used by Sherlock Holmes 2
+ _fixedJournalTextArray = fixedJournalTextFR;
+ _fixedObjectPickedUpText = ""; // Not used, because there is no French Sherlock Holmes 1
+ break;
+ case Common::ES_ESP:
+ // Used by Sherlock Holmes 1+2
+ _fixedJournalTextArray = fixedJournalTextES;
+ _fixedObjectPickedUpText = "Cogido/a %s";
+ break;
+ default:
+ // Default to English
+ _fixedJournalTextArray = fixedJournalTextEN;
+ _fixedObjectPickedUpText = "Picked up %s";
+ break;
+ }
+}
+
FixedText *FixedText::init(SherlockEngine *vm) {
if (vm->getGameID() == GType_SerratedScalpel)
return new Scalpel::ScalpelFixedText(vm);
@@ -34,5 +211,12 @@ FixedText *FixedText::init(SherlockEngine *vm) {
return new Tattoo::TattooFixedText(vm);
}
+const char *FixedText::getJournalText(int fixedJournalTextId) {
+ return _fixedJournalTextArray[fixedJournalTextId];
+}
+
+const char *FixedText::getObjectPickedUpText() {
+ return _fixedObjectPickedUpText;
+}
} // End of namespace Sherlock
diff --git a/engines/sherlock/fixed_text.h b/engines/sherlock/fixed_text.h
index 40444f4052..3eae60e1c3 100644
--- a/engines/sherlock/fixed_text.h
+++ b/engines/sherlock/fixed_text.h
@@ -39,13 +39,44 @@ enum FixedTextActionId {
kFixedTextAction_Use
};
+enum FixedJournalTextId {
+ // Holmes asked/said...
+ kFixedJournalText_HolmesAskedMe = 0,
+ kFixedJournalText_HolmesAskedTheInspector,
+ kFixedJournalText_HolmesAskedPerson,
+ kFixedJournalText_HolmesSaidToMe,
+ kFixedJournalText_HolmesSaidToTheInspector,
+ kFixedJournalText_HolmesSaidToPerson,
+ // I asked/said
+ kFixedJournalText_IReplied,
+ kFixedJournalText_TheReplyWas,
+ // Holmes/I/The Inspector/Person asked/said (without "Then" prefix)
+ kFixedJournalText_HolmesAsked,
+ kFixedJournalText_HolmesSaid,
+ kFixedJournalText_IAsked,
+ kFixedJournalText_ISaid,
+ kFixedJournalText_TheInspectorAsked,
+ kFixedJournalText_TheInspectorSaid,
+ kFixedJournalText_PersonAsked,
+ kFixedJournalText_PersonSaid,
+ // Then Holmes/I/The Inspector/Person asked/said
+ kFixedJournalText_ThenHolmesAsked,
+ kFixedJournalText_ThenHolmesSaid,
+ kFixedJournalText_ThenIAsked,
+ kFixedJournalText_ThenISaid,
+ kFixedJournalText_ThenTheInspectorAsked,
+ kFixedJournalText_ThenTheInspectorSaid,
+ kFixedJournalText_ThenPersonAsked,
+ kFixedJournalText_ThenPersonSaid
+};
+
class SherlockEngine;
class FixedText {
protected:
SherlockEngine *_vm;
- FixedText(SherlockEngine *vm) : _vm(vm) {}
+ FixedText(SherlockEngine *vm);
public:
static FixedText *init(SherlockEngine *vm);
virtual ~FixedText() {}
@@ -59,6 +90,20 @@ public:
* Get action message
*/
virtual const Common::String getActionMessage(FixedTextActionId actionId, int messageIndex) = 0;
+
+ /**
+ * Gets journal text
+ */
+ const char *getJournalText(int fixedJournalTextId);
+
+ /**
+ * Gets object "Picked Up" text
+ */
+ const char *getObjectPickedUpText();
+
+private:
+ const char *const *_fixedJournalTextArray;
+ const char *_fixedObjectPickedUpText;
};
} // End of namespace Sherlock
diff --git a/engines/sherlock/fonts.cpp b/engines/sherlock/fonts.cpp
index 482e795b6d..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;
}
@@ -53,6 +53,15 @@ void Fonts::setFont(int fontNum) {
// Discard previous font
delete _font;
+ if (IS_SERRATED_SCALPEL) {
+ // Scalpel
+ if ((_vm->isDemo()) && (!_vm->_interactiveFl)) {
+ // Do not set up any font for the non-interactive demo of scalpel
+ // The non-interactive demo does not contain any font at all
+ return;
+ }
+ }
+
Common::String fontFilename;
if (_vm->getPlatform() != Common::kPlatform3DO) {
@@ -62,6 +71,43 @@ void Fonts::setFont(int fontNum) {
// load font data
_font = new ImageFile(fontFilename);
+
+ if (IS_SERRATED_SCALPEL) {
+ if (_vm->getLanguage() == Common::ES_ESP) {
+ if (_fontNumber == 1) {
+ // Create a new character - inverted exclamation mark (0x88)
+ // Seems this wasn't included originally, but some text has it
+ // This was obviously not done in the original game interpreter
+ ImageFrame &frameExclamationMark = (*_font)[0]; // get actual exclamation mark
+ ImageFrame frameRevExclamationMark;
+
+ frameRevExclamationMark._width = frameExclamationMark._width;
+ frameRevExclamationMark._height = frameExclamationMark._height;
+ frameRevExclamationMark._paletteBase = frameExclamationMark._paletteBase;
+ frameRevExclamationMark._rleEncoded = frameExclamationMark._rleEncoded;
+ frameRevExclamationMark._size = frameExclamationMark._size;
+ frameRevExclamationMark._frame.create(frameExclamationMark._width, frameExclamationMark._height, Graphics::PixelFormat::createFormatCLUT8());
+
+ byte *frameExclMarkPixels = (byte *)frameExclamationMark._frame.getPixels();
+ byte *frameRevExclMarkPixels = (byte *)frameRevExclamationMark._frame.getPixels();
+
+ uint16 revExclMarkY = frameExclamationMark._height - 1;
+ frameRevExclMarkPixels += frameExclamationMark._width * (frameExclamationMark._height - 1);
+ for (uint16 exclMarkY = 0; exclMarkY < frameExclamationMark._height; exclMarkY++) {
+ memcpy(frameRevExclMarkPixels, frameExclMarkPixels, frameExclamationMark._width);
+ revExclMarkY--;
+ frameRevExclMarkPixels -= frameExclamationMark._width;
+ frameExclMarkPixels += frameExclamationMark._width;
+ }
+
+ frameRevExclamationMark._offset.x = frameExclamationMark._offset.x;
+ frameRevExclamationMark._offset.y = frameExclamationMark._offset.y + 1;
+
+ _font->push_back(frameRevExclamationMark);
+ }
+ }
+ }
+
} else {
// 3DO
switch (fontNum) {
@@ -81,10 +127,10 @@ void Fonts::setFont(int fontNum) {
}
_charCount = _font->size();
-
+
// Iterate through the frames to find the widest and tallest font characters
_fontHeight = _widestChar = 0;
- for (uint idx = 0; idx < _charCount; ++idx) {
+ for (uint idx = 0; idx < MIN<uint>(_charCount, 128 - 32); ++idx) {
_fontHeight = MAX((uint16)_fontHeight, (*_font)[idx]._frame.h);
_widestChar = MAX((uint16)_widestChar, (*_font)[idx]._frame.w);
}
@@ -118,6 +164,24 @@ inline byte Fonts::translateChar(byte c) {
return 135; // and this for SH1
default:
if (IS_SERRATED_SCALPEL) {
+ if (_vm->getLanguage() == Common::ES_ESP) {
+ if (_fontNumber == 1) {
+ // Special workarounds for translated game text, which was skipped because of effectively a bug
+ // This was not done in the original interpreter
+ // It seems at least the inverted exclamation mark was skipped by the original interpreter /
+ // wasn't shown at all.
+ // This character is used for example in the alley room, when talking with the inspector after
+ // searching the corpse. "[0xAD]Claro! Mi experiencia profesional revela que esta mujer fue asesinada..."
+ // The same text gets put inside Watson's journal as well and should be on page 10 right after
+ // talking with the inspector. For further study see bug #6931
+ // Inverted question mark was also skipped, but at least that character is inside the font already.
+ if (c == 0xAD) {
+ // inverted exclamation mark
+ return 0x88; // our own font character, created during setFont()
+ }
+ // Inverted question mask is 0x86 (mapped from 0x88)
+ }
+ }
if (c >= 0x80) { // German SH1 version did this, but not German SH2
c--;
}
@@ -131,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;
@@ -147,10 +211,13 @@ void Fonts::writeString(Surface *surface, const Common::String &str,
}
curChar = translateChar(curChar);
- assert(curChar < _charCount);
- ImageFrame &frame = (*_font)[curChar];
- surface->transBlitFrom(frame, Common::Point(charPos.x, charPos.y + _yOffsets[curChar]), false, overrideColor);
- charPos.x += frame._frame.w + 1;
+ if (curChar < _charCount) {
+ ImageFrame &frame = (*_font)[curChar];
+ 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 3d881eb655..c53e537bb8 100644
--- a/engines/sherlock/image_file.cpp
+++ b/engines/sherlock/image_file.cpp
@@ -172,7 +172,7 @@ void ImageFrame::decompressFrame(const byte *src, bool isRoseTattoo) {
while (frameSize > 0) {
if (*src == _rleMarker) {
byte rleColor = src[1];
- byte rleCount = src[2];
+ byte rleCount = MIN((int)src[2], frameSize);
src += 3;
frameSize -= rleCount;
while (rleCount--)
@@ -182,7 +182,6 @@ void ImageFrame::decompressFrame(const byte *src, bool isRoseTattoo) {
--frameSize;
}
}
- assert(frameSize == 0);
} else {
// Uncompressed frame
Common::copy(src, src + _width * _height, dest);
@@ -303,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;
@@ -381,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);
@@ -684,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)
@@ -714,7 +707,7 @@ void ImageFile3DO::load3DOCelRoomData(Common::SeekableReadStream &stream) {
stream.read(celDataPtr, celDataSize);
streamLeft -= celDataSize;
-
+
// Set up frame
{
ImageFrame imageFrame;
@@ -961,59 +954,57 @@ void ImageFile3DO::loadFont(Common::SeekableReadStream &stream) {
for (curChar = 33; curChar < header_charCount; curChar++) {
// create frame
- {
- ImageFrame imageFrame;
-
- imageFrame._width = widthTablePtr[curChar];
- imageFrame._height = header_fontHeight;
- imageFrame._paletteBase = 0;
- imageFrame._offset.x = 0;
- imageFrame._offset.y = 0;
- imageFrame._rleEncoded = false;
- imageFrame._size = 0;
-
- // Extract pixels
- imageFrame._frame.create(imageFrame._width, imageFrame._height, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
- uint16 *dest = (uint16 *)imageFrame._frame.getPixels();
- Common::fill(dest, dest + imageFrame._width * imageFrame._height, 0);
-
- curCharHeightLeft = header_fontHeight;
- while (curCharHeightLeft) {
- curCharWidthLeft = widthTablePtr[curChar];
- curBitsPtr = curBitsLinePtr;
- curBitsLeft = 8;
- curPosX = 0;
-
- while (curCharWidthLeft) {
- if (!(curPosX & 1)) {
- curBits = *curBitsPtr >> 4;
- } else {
- curBits = *curBitsPtr & 0x0F;
- curBitsPtr++;
- }
- // doing this properly is complicated
- // the 3DO has built-in anti-aliasing
- // this here at least results in somewhat readable text
- // TODO: make it better
- if (curBits) {
- curBitsReversed = (curBits >> 3) | ((curBits & 0x04) >> 1) | ((curBits & 0x02) << 1) | ((curBits & 0x01) << 3);
- curBits = 20 - curBits;
- }
-
- byte curIntensity = curBits;
- *dest = (curIntensity << 11) | (curIntensity << 6) | curIntensity;
- dest++;
-
- curCharWidthLeft--;
- curPosX++;
+ ImageFrame imageFrame;
+
+ imageFrame._width = widthTablePtr[curChar];
+ imageFrame._height = header_fontHeight;
+ imageFrame._paletteBase = 0;
+ imageFrame._offset.x = 0;
+ imageFrame._offset.y = 0;
+ imageFrame._rleEncoded = false;
+ imageFrame._size = 0;
+
+ // Extract pixels
+ imageFrame._frame.create(imageFrame._width, imageFrame._height, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
+ uint16 *dest = (uint16 *)imageFrame._frame.getPixels();
+ Common::fill(dest, dest + imageFrame._width * imageFrame._height, 0);
+
+ curCharHeightLeft = header_fontHeight;
+ while (curCharHeightLeft) {
+ curCharWidthLeft = widthTablePtr[curChar];
+ curBitsPtr = curBitsLinePtr;
+ curBitsLeft = 8;
+ curPosX = 0;
+
+ while (curCharWidthLeft) {
+ if (!(curPosX & 1)) {
+ curBits = *curBitsPtr >> 4;
+ } else {
+ curBits = *curBitsPtr & 0x0F;
+ curBitsPtr++;
}
+ // doing this properly is complicated
+ // the 3DO has built-in anti-aliasing
+ // this here at least results in somewhat readable text
+ // TODO: make it better
+ if (curBits) {
+ curBitsReversed = (curBits >> 3) | ((curBits & 0x04) >> 1) | ((curBits & 0x02) << 1) | ((curBits & 0x01) << 3);
+ curBits = 20 - curBits;
+ }
+
+ byte curIntensity = curBits;
+ *dest = (curIntensity << 11) | (curIntensity << 6) | curIntensity;
+ dest++;
- curCharHeightLeft--;
- curBitsLinePtr += header_bytesPerLine;
+ curCharWidthLeft--;
+ curPosX++;
}
- push_back(imageFrame);
+ curCharHeightLeft--;
+ curBitsLinePtr += header_bytesPerLine;
}
+
+ push_back(imageFrame);
}
// Warning below being used to silence unused variable warnings for now
@@ -1051,10 +1042,12 @@ void StreamingImageFile::close() {
_stream = nullptr;
_frameNumber = -1;
_active = false;
+ _imageFrame._frame.free();
}
bool StreamingImageFile::getNextFrame() {
// Don't proceed if we're already at the end of the stream
+ assert(_stream);
if (_stream->pos() >= _stream->size()) {
_active = false;
return false;
@@ -1081,6 +1074,9 @@ bool StreamingImageFile::getNextFrame() {
_imageFrame._size = frameStream->readUint16LE() - 11;
_imageFrame._rleMarker = frameStream->readByte();
+ // Free the previous frame
+ _imageFrame._frame.free();
+
// Decode the frame
if (_compressed) {
delete frameStream;
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/journal.cpp b/engines/sherlock/journal.cpp
index e442a3c903..8763af31dd 100644
--- a/engines/sherlock/journal.cpp
+++ b/engines/sherlock/journal.cpp
@@ -24,6 +24,7 @@
#include "sherlock/scalpel/scalpel.h"
#include "sherlock/scalpel/scalpel_fixed_text.h"
#include "sherlock/scalpel/scalpel_journal.h"
+#include "sherlock/scalpel/scalpel_talk.h"
#include "sherlock/tattoo/tattoo.h"
#include "sherlock/tattoo/tattoo_fixed_text.h"
#include "sherlock/tattoo/tattoo_journal.h"
@@ -298,6 +299,7 @@ bool Journal::drawJournal(int direction, int howFar) {
}
void Journal::loadJournalFile(bool alreadyLoaded) {
+ FixedText &fixedText = *_vm->_fixedText;
People &people = *_vm->_people;
Screen &screen = *_vm->_screen;
Talk &talk = *_vm->_talk;
@@ -380,20 +382,34 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
// If Holmes has something to say first, then take care of it
if (!replyOnly) {
// Handle the grammar
- journalString += "Holmes ";
+ bool asked = false;
+
if (talk[journalEntry._statementNum]._statement.hasSuffix("?"))
- journalString += "asked ";
- else
- journalString += "said to ";
+ asked = true;
if (talk._talkTo == 1) {
- journalString += "me";
+ if (asked)
+ journalString += fixedText.getJournalText(kFixedJournalText_HolmesAskedMe);
+ else
+ journalString += fixedText.getJournalText(kFixedJournalText_HolmesSaidToTheInspector);
+
} else if ((talk._talkTo == 2 && IS_SERRATED_SCALPEL) || (talk._talkTo == 18 && IS_ROSE_TATTOO)) {
- journalString += "the Inspector";
+ if (asked)
+ journalString += fixedText.getJournalText(kFixedJournalText_HolmesAskedTheInspector);
+ else
+ journalString += fixedText.getJournalText(kFixedJournalText_HolmesSaidToMe);
+
} else {
- journalString += people._characters[talk._talkTo]._name;
+ const char *text = nullptr;
+ if (asked)
+ text = fixedText.getJournalText(kFixedJournalText_HolmesAskedPerson);
+ else
+ text = fixedText.getJournalText(kFixedJournalText_HolmesSaidToPerson);
+
+ journalString += Common::String::format(text, people._characters[talk._talkTo]._name);
}
- journalString += ", \"";
+
+ journalString += "\"";
// Add the statement
journalString += statement._statement;
@@ -423,7 +439,7 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
}
// Is it a control character?
- if (c < opcodes[0]) {
+ if (isPrintable(c)) {
// Nope. Set flag for allowing control codes to insert spaces
ctrlSpace = true;
justChangedSpeaker = false;
@@ -456,38 +472,55 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
journalString += "\"\n";
if (talk._talkTo == 1)
- journalString += "I replied, \"";
+ journalString += fixedText.getJournalText(kFixedJournalText_IReplied);
else
- journalString += "The reply was, \"";
+ journalString += fixedText.getJournalText(kFixedJournalText_TheReplyWas);
} else {
- if (talk._talkTo == 1)
- journalString += "I";
- else if (talk._talkTo == inspectorId)
- journalString += "The Inspector";
- else
- journalString += people._characters[talk._talkTo]._name;
-
const byte *strP = replyP + 1;
byte v;
do {
v = *strP++;
} while (v && (v < opcodes[0]) && (v != '.') && (v != '!') && (v != '?'));
+ bool asked = false;
+
if (v == '?')
- journalString += " asked, \"";
- else
- journalString += " said, \"";
+ asked = true;
+
+ if (talk._talkTo == 1) {
+ if (asked)
+ journalString += fixedText.getJournalText(kFixedJournalText_IAsked);
+ else
+ journalString += fixedText.getJournalText(kFixedJournalText_ISaid);
+
+ } else if (talk._talkTo == inspectorId) {
+ if (asked)
+ journalString += fixedText.getJournalText(kFixedJournalText_TheInspectorAsked);
+ else
+ journalString += fixedText.getJournalText(kFixedJournalText_TheInspectorSaid);
+
+ } else {
+ const char *text = nullptr;
+ if (asked)
+ text = fixedText.getJournalText(kFixedJournalText_PersonAsked);
+ else
+ text = fixedText.getJournalText(kFixedJournalText_PersonSaid);
+
+ journalString += Common::String::format(text, people._characters[talk._talkTo]._name);
+ }
}
+ journalString += "\"";
+
startOfReply = false;
}
// Copy text from the place until either the reply ends, a comment
// {} block is started, or a control character is encountered
journalString += c;
- do {
+ while (*replyP && isPrintable(*replyP) && *replyP != '{' && *replyP != '}') {
journalString += *replyP++;
- } while (*replyP && *replyP < opcodes[0] && *replyP != '{' && *replyP != '}');
+ }
commentJustPrinted = false;
}
@@ -501,11 +534,13 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
justChangedSpeaker = true;
}
+ bool addPrefixThen = false;
+
if (!startOfReply) {
if (!commentFlag && !commentJustPrinted)
journalString += "\"\n";
- journalString += "Then ";
+ addPrefixThen = true; // "Then" should get added to the sentence
commentFlag = false;
} else if (!replyOnly) {
journalString += "\"\n";
@@ -516,14 +551,8 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
if (IS_ROSE_TATTOO)
replyP++;
- if (c == 0)
- journalString += "Holmes";
- else if (c == 1)
- journalString += "I";
- else if (c == inspectorId)
- journalString += "the Inspector";
- else
- journalString += people._characters[c]._name;
+ if (IS_SERRATED_SCALPEL && _vm->getLanguage() == Common::DE_DEU)
+ Scalpel::ScalpelTalk::skipBadText(replyP);
const byte *strP = replyP;
byte v;
@@ -531,10 +560,70 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
v = *strP++;
} while (v && v < opcodes[0] && v != '.' && v != '!' && v != '?');
+ bool asked = false;
+
if (v == '?')
- journalString += " asked, \"";
- else
- journalString += " said, \"";
+ asked = true;
+
+ if (c == 0) {
+ // Holmes
+ if (addPrefixThen) {
+ if (asked)
+ journalString += fixedText.getJournalText(kFixedJournalText_ThenHolmesAsked);
+ else
+ journalString += fixedText.getJournalText(kFixedJournalText_ThenHolmesSaid);
+ } else {
+ if (asked)
+ journalString += fixedText.getJournalText(kFixedJournalText_HolmesAsked);
+ else
+ journalString += fixedText.getJournalText(kFixedJournalText_HolmesSaid);
+ }
+ } else if (c == 1) {
+ // I (Watson)
+ if (addPrefixThen) {
+ if (asked)
+ journalString += fixedText.getJournalText(kFixedJournalText_ThenIAsked);
+ else
+ journalString += fixedText.getJournalText(kFixedJournalText_ThenISaid);
+ } else {
+ if (asked)
+ journalString += fixedText.getJournalText(kFixedJournalText_IAsked);
+ else
+ journalString += fixedText.getJournalText(kFixedJournalText_ISaid);
+ }
+ } else if (c == inspectorId) {
+ // The Inspector
+ if (addPrefixThen) {
+ if (asked)
+ journalString += fixedText.getJournalText(kFixedJournalText_ThenTheInspectorAsked);
+ else
+ journalString += fixedText.getJournalText(kFixedJournalText_ThenTheInspectorSaid);
+ } else {
+ if (asked)
+ journalString += fixedText.getJournalText(kFixedJournalText_TheInspectorAsked);
+ else
+ journalString += fixedText.getJournalText(kFixedJournalText_TheInspectorSaid);
+ }
+ } else {
+ // Person
+ const char *text = nullptr;
+ if (addPrefixThen) {
+ if (asked)
+ text = fixedText.getJournalText(kFixedJournalText_ThenPersonAsked);
+ else
+ text = fixedText.getJournalText(kFixedJournalText_ThenPersonSaid);
+ } else {
+ if (asked)
+ text = fixedText.getJournalText(kFixedJournalText_PersonAsked);
+ else
+ text = fixedText.getJournalText(kFixedJournalText_PersonSaid);
+ }
+
+ journalString += Common::String::format(text, people._characters[c]._name);
+ }
+
+ journalString += "\"";
+
} else {
if (IS_SERRATED_SCALPEL) {
// Control code, so move past it and any parameters
@@ -702,6 +791,24 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
}
}
+bool Journal::isPrintable(byte ch) const {
+ Talk &talk = *_vm->_talk;
+ const byte *opcodes = talk._opcodes;
+
+ // Okay.. there is freaky stuff going among the various different languages
+ // and across the two games as to which characters are printable, and which
+ // are opcodes, and which are not opcodes but shouldn't be printed anyway.
+ // I don't want to end up breaking stuff, so this method acts as a bit of a
+ // kludge to get German accents working in the Journal
+ if (ch < opcodes[0])
+ return true;
+
+ if (_vm->getLanguage() == Common::DE_DEU && ch == 0xe1) // accept German Sharp-S character
+ return true;
+
+ return false;
+}
+
void Journal::record(int converseNum, int statementNum, bool replyOnly) {
int saveIndex = _index;
int saveSub = _sub;
@@ -711,6 +818,15 @@ void Journal::record(int converseNum, int statementNum, bool replyOnly) {
return;
}
+ // Do a bit of validation here
+ assert(converseNum >= 0 && converseNum < (int)_directory.size());
+ const Common::String &dirFilename = _directory[converseNum];
+ Common::String locStr(dirFilename.c_str() + 4, dirFilename.c_str() + 6);
+ int newLocation = atoi(locStr.c_str());
+ assert(newLocation >= 1 && newLocation <= (int)_locations.size());
+ assert(!_locations[newLocation - 1].empty());
+ assert(statementNum >= 0 && statementNum < (int)_vm->_talk->_statements.size());
+
// Record the entry into the list
_journal.push_back(JournalEntry(converseNum, statementNum, replyOnly));
_index = _journal.size() - 1;
@@ -722,7 +838,7 @@ void Journal::record(int converseNum, int statementNum, bool replyOnly) {
_index = saveIndex;
_sub = saveSub;
- // If new lines were added to the ournal, update the total number of lines
+ // If new lines were added to the journal, update the total number of lines
// the journal continues
if (!_lines.empty()) {
_maxPage += _lines.size();
diff --git a/engines/sherlock/journal.h b/engines/sherlock/journal.h
index a8fec104f4..bacd9fa8b5 100644
--- a/engines/sherlock/journal.h
+++ b/engines/sherlock/journal.h
@@ -72,6 +72,11 @@ protected:
* first time, or being reloaded
*/
void loadJournalFile(bool alreadyLoaded);
+
+ /**
+ * Returns true if a given character is printable
+ */
+ bool isPrintable(byte ch) const;
public:
static Journal *init(SherlockEngine *vm);
virtual ~Journal() {}
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 7ab5cd4b4f..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
@@ -222,13 +223,14 @@ Music::Music(SherlockEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
_midiParser = NULL;
_musicType = MT_NULL;
_musicPlaying = false;
- _musicOn = false;
_midiOption = false;
- _musicVolume = 0;
+ _midiMusicData = nullptr;
+ _musicVolume = ConfMan.hasKey("music_volume") ? ConfMan.getInt("music_volume") : 255;
+ _musicOn = false;
if (IS_3DO) {
// 3DO - uses digital samples for music
- _musicOn = true;
+ _musicOn = ConfMan.hasKey("music_mute") ? !ConfMan.getBool("music_mute") : true;
return;
}
@@ -327,7 +329,7 @@ Music::Music(SherlockEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
}
}
- _musicOn = true;
+ _musicOn = ConfMan.hasKey("music_mute") ? !ConfMan.getBool("music_mute") : true;
}
}
@@ -470,8 +472,8 @@ bool Music::playMusic(const Common::String &name) {
}
}
+ _midiMusicData = midiMusicData;
_midiParser->loadMusic(midiMusicData, midiMusicDataSize);
-
} else {
// 3DO: sample based
Audio::AudioStream *musicStream;
@@ -517,6 +519,7 @@ void Music::freeSong() {
_midiParser->unloadMusic();
}
+ _midiMusicData = nullptr;
_musicPlaying = false;
}
@@ -578,6 +581,7 @@ bool Music::waitUntilMSec(uint32 msecTarget, uint32 msecMax, uint32 additionalDe
void Music::setMusicVolume(int volume) {
_musicVolume = volume;
+ _musicOn = volume > 0;
_vm->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume);
}
diff --git a/engines/sherlock/music.h b/engines/sherlock/music.h
index 72a5f48833..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"
@@ -68,6 +65,7 @@ private:
MidiDriver *_midiDriver;
Audio::SoundHandle _digitalMusicHandle;
MusicType _musicType;
+ byte *_midiMusicData;
/**
* Play the specified music resource
diff --git a/engines/sherlock/objects.cpp b/engines/sherlock/objects.cpp
index 093f666a46..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);
@@ -539,7 +539,7 @@ int BaseObject::checkNameForCodes(const Common::String &name, FixedTextActionId
// G: Have object go somewhere
// A: Add onto existing co-ordinates
Common::String sx(name.c_str() + 2, name.c_str() + 5);
- Common::String sy(name.c_str() + 6, name.c_str() + 9);
+ Common::String sy(name.c_str() + 5, name.c_str() + 8);
if (ch == 'G')
_position = Common::Point(atoi(sx.c_str()), atoi(sy.c_str()));
@@ -620,6 +620,7 @@ void Sprite::clear() {
_images = nullptr;
_imageFrame = nullptr;
_walkCount = 0;
+ _oldWalkSequence = 0;
_allow = 0;
_frameNumber = 0;
_position.x = _position.y = 0;
@@ -634,7 +635,10 @@ void Sprite::clear() {
_misc = 0;
_altImages = nullptr;
_altSeq = 0;
- Common::fill(&_stopFrames[0], &_stopFrames[8], (ImageFrame *)nullptr);
+ _centerWalk = 0;
+
+ for (int i = 0; i < 8; i++)
+ _stopFrames[i] = nullptr;
}
void Sprite::setImageFrame() {
@@ -1059,6 +1063,11 @@ void Object::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
for (int idx = 0; idx < 6; ++idx)
_use[idx].load(s, true);
+ // WORKAROUND: Fix German version using hatpin/pin in pillow in Pratt's loft
+ if (_use[1]._target == "Nadel" && _use[1]._verb == "Untersuche"
+ && _use[2]._target == "Nadel" && _use[2]._verb == "Untersuche")
+ _use[1]._target = "Alte Nadel";
+
_quickDraw = s.readByte();
_scaleVal = s.readUint16LE();
_requiredFlag[1] = s.readSint16LE();
@@ -1336,7 +1345,7 @@ void Object::adjustObject() {
frame = 0;
int imgNum = _sequences[frame];
- if (imgNum > _maxFrames)
+ if (imgNum > _maxFrames || imgNum == 0)
imgNum = 1;
_imageFrame = &(*_images)[imgNum - 1];
@@ -1422,8 +1431,19 @@ int Object::pickUpObject(FixedTextActionId fixedTextActionId) {
ui.clearInfo();
Common::String itemName = _description;
- itemName.setChar(tolower(itemName[0]), 0);
- screen.print(Common::Point(0, INFO_LINE + 1), COL_INFO_FOREGROUND, "Picked up %s", itemName.c_str());
+
+ // It's an item, make it lowercase
+ switch (_vm->getLanguage()) {
+ case Common::DE_DEU:
+ // don't do this for German version
+ break;
+ default:
+ // do it for English + Spanish version
+ itemName.setChar(tolower(itemName[0]), 0);
+ break;
+ }
+
+ screen.print(Common::Point(0, INFO_LINE + 1), COL_INFO_FOREGROUND, fixedText.getObjectPickedUpText(), itemName.c_str());
ui._menuCounter = 25;
}
}
diff --git a/engines/sherlock/people.cpp b/engines/sherlock/people.cpp
index b1f4abba47..8057e26204 100644
--- a/engines/sherlock/people.cpp
+++ b/engines/sherlock/people.cpp
@@ -184,8 +184,9 @@ void People::reset() {
Person &p = *_data[idx];
if (IS_SERRATED_SCALPEL) {
- p._type = CHARACTER;
- p._position = Point32(100 * FIXED_INT_MULTIPLIER, 110 * FIXED_INT_MULTIPLIER);
+ p._type = _holmesOn ? CHARACTER : HIDDEN;
+ if (!saves._justLoaded)
+ p._position = Point32(100 * FIXED_INT_MULTIPLIER, 110 * FIXED_INT_MULTIPLIER);
} else if (!talk._scriptMoreFlag && !saves._justLoaded) {
p._type = (idx == 0) ? CHARACTER : INVALID;
p._position = Point32(36 * FIXED_INT_MULTIPLIER, 29 * FIXED_INT_MULTIPLIER);
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 17e60f5365..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"
@@ -102,78 +103,78 @@ static const byte MAP_SEQUENCES[3][MAX_FRAME] = {
struct PeopleData {
const char *portrait;
- const char *name;
+ int fixedTextId;
byte stillSequences[MAX_TALK_SEQUENCES];
byte talkSequences[MAX_TALK_SEQUENCES];
};
const PeopleData PEOPLE_DATA[MAX_PEOPLE] = {
- { "HOLM", "Sherlock Holmes", { 1, 0, 0 }, { 1, 0, 0 } },
- { "WATS", "Dr. Watson", { 6, 0, 0 }, { 5, 5, 6, 7, 8, 7, 8, 6, 0, 0 } },
- { "LEST", "Inspector Lestrade", { 4, 0, 0 }, { 2, 0, 0 } },
- { "CON1", "Constable O'Brien", { 2, 0, 0 }, { 1, 0, 0 } },
- { "CON2", "Constable Lewis", { 2, 0, 0 }, { 1, 0, 0 } },
- { "SHEI", "Sheila Parker", { 2, 0, 0 }, { 2, 3, 0, 0 } },
- { "HENR", "Henry Carruthers", { 3, 0, 0 }, { 3, 0, 0 } },
- { "LESL", "Lesley", { 9, 0, 0 }, { 1, 2, 3, 2, 1, 2, 3, 0, 0 } },
- { "USH1", "An Usher", { 13, 0, 0 }, { 13, 14, 0, 0 } },
- { "USH2", "An Usher", { 2, 0, 0 }, { 2, 0, 0 } },
- { "FRED", "Fredrick Epstein", { 4, 0, 0 }, { 1, 2, 3, 4, 3, 4, 3, 2, 0, 0 } },
- { "WORT", "Mrs. Worthington", { 9, 0, 0 }, { 8, 0, 0 } },
- { "COAC", "The Coach", { 2, 0, 0 }, { 1, 2, 3, 4, 5, 4, 3, 2, 0, 0 } },
- { "PLAY", "A Player", { 8, 0, 0 }, { 7, 8, 0, 0 } },
- { "WBOY", "Tim", { 13, 0, 0 }, { 12, 13, 0, 0 } },
- { "JAME", "James Sanders", { 6, 0, 0 }, { 3, 4, 0, 0 } },
- { "BELL", "Belle", { 1, 0, 0 }, { 4, 5, 0, 0 } },
- { "GIRL", "Cleaning Girl", { 20, 0, 0 }, { 14, 15, 16, 17, 18, 19, 20, 20, 20, 0, 0 } },
- { "EPST", "Fredrick Epstein", { 17, 0, 0 }, { 16, 17, 18, 18, 18, 17, 17, 0, 0 } },
- { "WIGG", "Wiggins", { 3, 0, 0 }, { 2, 3, 0, 0 } },
- { "PAUL", "Paul", { 2, 0, 0 }, { 1, 2, 0, 0 } },
- { "BART", "The Bartender", { 1, 0, 0 }, { 1, 0, 0 } },
- { "DIRT", "A Dirty Drunk", { 1, 0, 0 }, { 1, 0, 0 } },
- { "SHOU", "A Shouting Drunk", { 1, 0, 0 }, { 1, 0, 0 } },
- { "STAG", "A Staggering Drunk", { 1, 0, 0 }, { 1, 0, 0 } },
- { "BOUN", "The Bouncer", { 1, 0, 0 }, { 1, 0, 0 } },
- { "SAND", "James Sanders", { 6, 0, 0 }, { 5, 6, 0, 0 } },
- { "CORO", "The Coroner", { 6, 0, 0 }, { 4, 5, 0, 0 } },
- { "EQUE", "Reginald Snipes", { 1, 0, 0 }, { 1, 0, 0 } },
- { "GEOR", "George Blackwood", { 1, 0, 0 }, { 1, 0, 0 } },
- { "LARS", "Lars", { 7, 0, 0 }, { 5, 6, 0, 0 } },
- { "PARK", "Sheila Parker", { 1, 0, 0 }, { 1, 0, 0 } },
- { "CHEM", "The Chemist", { 8, 0, 0 }, { 8, 9, 0, 0 } },
- { "GREG", "Inspector Gregson", { 6, 0, 0 }, { 5, 6, 0, 0 } },
- { "LAWY", "Jacob Farthington", { 1, 0, 0 }, { 1, 0, 0 } },
- { "MYCR", "Mycroft", { 1, 0, 0 }, { 1, 0, 0 } },
- { "SHER", "Old Sherman", { 7, 0, 0 }, { 7, 8, 0, 0 } },
- { "CHMB", "Richard", { 1, 0, 0 }, { 1, 0, 0 } },
- { "BARM", "The Barman", { 1, 0, 0 }, { 1, 0, 0 } },
- { "DAND", "A Dandy Player", { 1, 0, 0 }, { 1, 0, 0 } },
- { "ROUG", "A Rough-looking Player", { 1, 0, 0 }, { 1, 0, 0 } },
- { "SPEC", "A Spectator", { 1, 0, 0 }, { 1, 0, 0 } },
- { "HUNT", "Robert Hunt", { 1, 0, 0 }, { 1, 0, 0 } },
- { "VIOL", "Violet", { 3, 0, 0 }, { 3, 4, 0, 0 } },
- { "PETT", "Pettigrew", { 1, 0, 0 }, { 1, 0, 0 } },
- { "APPL", "Augie", { 8, 0, 0 }, { 14, 15, 0, 0 } },
- { "ANNA", "Anna Carroway", { 16, 0, 0 }, { 3, 4, 5, 6, 0, 0 } },
- { "GUAR", "A Guard", { 1, 0, 0 }, { 4, 5, 6, 0, 0 } },
- { "ANTO", "Antonio Caruso", { 8, 0, 0 }, { 7, 8, 0, 0 } },
- { "TOBY", "Toby the Dog", { 1, 0, 0 }, { 1, 0, 0 } },
- { "KING", "Simon Kingsley", { 13, 0, 0 }, { 13, 14, 0, 0 } },
- { "ALFR", "Alfred", { 2, 0, 0 }, { 2, 3, 0, 0 } },
- { "LADY", "Lady Brumwell", { 1, 0, 0 }, { 3, 4, 0, 0 } },
- { "ROSA", "Madame Rosa", { 1, 0, 0 }, { 1, 30, 0, 0 } },
- { "LADB", "Lady Brumwell", { 1, 0, 0 }, { 3, 4, 0, 0 } },
- { "MOOR", "Joseph Moorehead", { 1, 0, 0 }, { 1, 0, 0 } },
- { "BEAL", "Mrs. Beale", { 5, 0, 0 }, { 14, 15, 16, 17, 18, 19, 20, 0, 0 } },
- { "LION", "Felix", { 1, 0, 0 }, { 1, 0, 0 } },
- { "HOLL", "Hollingston", { 1, 0, 0 }, { 1, 0, 0 } },
- { "CALL", "Constable Callaghan", { 1, 0, 0 }, { 1, 0, 0 } },
- { "JERE", "Sergeant Duncan", { 2, 0, 0 }, { 1, 1, 2, 2, 0, 0 } },
- { "LORD", "Lord Brumwell", { 1, 0, 0 }, { 9, 10, 0, 0 } },
- { "NIGE", "Nigel Jaimeson", { 1, 0, 0 }, { 1, 2, 0, 138, 3, 4, 0, 138, 0, 0 } },
- { "JONA", "Jonas", { 1, 0, 0 }, { 1, 8, 0, 0 } },
- { "DUGA", "Constable Dugan", { 1, 0, 0 }, { 1, 0, 0 } },
- { "INSP", "Inspector Lestrade", { 4, 0, 0 }, { 2, 0, 0 } }
+ { "HOLM", kFixedText_People_SherlockHolmes, { 1, 0, 0 }, { 1, 0, 0 } },
+ { "WATS", kFixedText_People_DrWatson, { 6, 0, 0 }, { 5, 5, 6, 7, 8, 7, 8, 6, 0, 0 } },
+ { "LEST", kFixedText_People_InspectorLestrade, { 4, 0, 0 }, { 2, 0, 0 } },
+ { "CON1", kFixedText_People_ConstableOBrien, { 2, 0, 0 }, { 1, 0, 0 } },
+ { "CON2", kFixedText_People_ConstableLewis, { 2, 0, 0 }, { 1, 0, 0 } },
+ { "SHEI", kFixedText_People_SheilaParker, { 2, 0, 0 }, { 2, 3, 0, 0 } },
+ { "HENR", kFixedText_People_HenryCarruthers, { 3, 0, 0 }, { 3, 0, 0 } },
+ { "LESL", kFixedText_People_Lesley, { 9, 0, 0 }, { 1, 2, 3, 2, 1, 2, 3, 0, 0 } },
+ { "USH1", kFixedText_People_AnUsher, { 13, 0, 0 }, { 13, 14, 0, 0 } },
+ { "USH2", kFixedText_People_AnUsher, { 2, 0, 0 }, { 2, 0, 0 } },
+ { "FRED", kFixedText_People_FredrickEpstein, { 4, 0, 0 }, { 1, 2, 3, 4, 3, 4, 3, 2, 0, 0 } },
+ { "WORT", kFixedText_People_MrsWorthington, { 9, 0, 0 }, { 8, 0, 0 } },
+ { "COAC", kFixedText_People_TheCoach, { 2, 0, 0 }, { 1, 2, 3, 4, 5, 4, 3, 2, 0, 0 } },
+ { "PLAY", kFixedText_People_APlayer, { 8, 0, 0 }, { 7, 8, 0, 0 } },
+ { "WBOY", kFixedText_People_Tim, { 13, 0, 0 }, { 12, 13, 0, 0 } },
+ { "JAME", kFixedText_People_JamesSanders, { 6, 0, 0 }, { 3, 4, 0, 0 } },
+ { "BELL", kFixedText_People_Belle, { 1, 0, 0 }, { 4, 5, 0, 0 } },
+ { "GIRL", kFixedText_People_CleaningGirl, { 20, 0, 0 }, { 14, 15, 16, 17, 18, 19, 20, 20, 20, 0, 0 } },
+ { "EPST", kFixedText_People_FredrickEpstein, { 17, 0, 0 }, { 16, 17, 18, 18, 18, 17, 17, 0, 0 } },
+ { "WIGG", kFixedText_People_Wiggins, { 3, 0, 0 }, { 2, 3, 0, 0 } },
+ { "PAUL", kFixedText_People_Paul, { 2, 0, 0 }, { 1, 2, 0, 0 } },
+ { "BART", kFixedText_People_TheBartender, { 1, 0, 0 }, { 1, 0, 0 } },
+ { "DIRT", kFixedText_People_ADirtyDrunk, { 1, 0, 0 }, { 1, 0, 0 } },
+ { "SHOU", kFixedText_People_AShoutingDrunk, { 1, 0, 0 }, { 1, 0, 0 } },
+ { "STAG", kFixedText_People_AStaggeringDrunk, { 1, 0, 0 }, { 1, 0, 0 } },
+ { "BOUN", kFixedText_People_TheBouncer, { 1, 0, 0 }, { 1, 0, 0 } },
+ { "SAND", kFixedText_People_JamesSanders, { 6, 0, 0 }, { 5, 6, 0, 0 } },
+ { "CORO", kFixedText_People_TheCoroner, { 6, 0, 0 }, { 4, 5, 0, 0 } },
+ { "EQUE", kFixedText_People_ReginaldSnipes, { 1, 0, 0 }, { 1, 0, 0 } },
+ { "GEOR", kFixedText_People_GeorgeBlackwood, { 1, 0, 0 }, { 1, 0, 0 } },
+ { "LARS", kFixedText_People_Lars, { 7, 0, 0 }, { 5, 6, 0, 0 } },
+ { "PARK", kFixedText_People_SheilaParker, { 1, 0, 0 }, { 1, 0, 0 } },
+ { "CHEM", kFixedText_People_TheChemist, { 8, 0, 0 }, { 8, 9, 0, 0 } },
+ { "GREG", kFixedText_People_InspectorGregson, { 6, 0, 0 }, { 5, 6, 0, 0 } },
+ { "LAWY", kFixedText_People_JacobFarthington, { 1, 0, 0 }, { 1, 0, 0 } },
+ { "MYCR", kFixedText_People_Mycroft, { 1, 0, 0 }, { 1, 0, 0 } },
+ { "SHER", kFixedText_People_OldSherman, { 7, 0, 0 }, { 7, 8, 0, 0 } },
+ { "CHMB", kFixedText_People_Richard, { 1, 0, 0 }, { 1, 0, 0 } },
+ { "BARM", kFixedText_People_TheBarman, { 1, 0, 0 }, { 1, 0, 0 } },
+ { "DAND", kFixedText_People_ADandyPlayer, { 1, 0, 0 }, { 1, 0, 0 } },
+ { "ROUG", kFixedText_People_ARoughlookingPlayer, { 1, 0, 0 }, { 1, 0, 0 } },
+ { "SPEC", kFixedText_People_ASpectator, { 1, 0, 0 }, { 1, 0, 0 } },
+ { "HUNT", kFixedText_People_RobertHunt, { 1, 0, 0 }, { 1, 0, 0 } },
+ { "VIOL", kFixedText_People_Violet, { 3, 0, 0 }, { 3, 4, 0, 0 } },
+ { "PETT", kFixedText_People_Pettigrew, { 1, 0, 0 }, { 1, 0, 0 } },
+ { "APPL", kFixedText_People_Augie, { 8, 0, 0 }, { 14, 15, 0, 0 } },
+ { "ANNA", kFixedText_People_AnnaCarroway, { 16, 0, 0 }, { 3, 4, 5, 6, 0, 0 } },
+ { "GUAR", kFixedText_People_AGuard, { 1, 0, 0 }, { 4, 5, 6, 0, 0 } },
+ { "ANTO", kFixedText_People_AntonioCaruso, { 8, 0, 0 }, { 7, 8, 0, 0 } },
+ { "TOBY", kFixedText_People_TobyTheDog, { 1, 0, 0 }, { 1, 0, 0 } },
+ { "KING", kFixedText_People_SimonKingsley, { 13, 0, 0 }, { 13, 14, 0, 0 } },
+ { "ALFR", kFixedText_People_Alfred, { 2, 0, 0 }, { 2, 3, 0, 0 } },
+ { "LADY", kFixedText_People_LadyBrumwell, { 1, 0, 0 }, { 3, 4, 0, 0 } },
+ { "ROSA", kFixedText_People_MadameRosa, { 1, 0, 0 }, { 1, 30, 0, 0 } },
+ { "LADB", kFixedText_People_LadyBrumwell, { 1, 0, 0 }, { 3, 4, 0, 0 } },
+ { "MOOR", kFixedText_People_JosephMoorehead, { 1, 0, 0 }, { 1, 0, 0 } },
+ { "BEAL", kFixedText_People_MrsBeale, { 5, 0, 0 }, { 14, 15, 16, 17, 18, 19, 20, 0, 0 } },
+ { "LION", kFixedText_People_Felix, { 1, 0, 0 }, { 1, 0, 0 } },
+ { "HOLL", kFixedText_People_Hollingston, { 1, 0, 0 }, { 1, 0, 0 } },
+ { "CALL", kFixedText_People_ConstableCallaghan, { 1, 0, 0 }, { 1, 0, 0 } },
+ { "JERE", kFixedText_People_SergeantDuncan, { 2, 0, 0 }, { 1, 1, 2, 2, 0, 0 } },
+ { "LORD", kFixedText_People_LordBrumwell, { 1, 0, 0 }, { 9, 10, 0, 0 } },
+ { "NIGE", kFixedText_People_NigelJaimeson, { 1, 0, 0 }, { 1, 2, 0, 138, 3, 4, 0, 138, 0, 0 } },
+ { "JONA", kFixedText_People_Jonas, { 1, 0, 0 }, { 1, 8, 0, 0 } },
+ { "DUGA", kFixedText_People_ConstableDugan, { 1, 0, 0 }, { 1, 0, 0 } },
+ { "INSP", kFixedText_People_InspectorLestrade, { 4, 0, 0 }, { 2, 0, 0 } }
};
uint INFO_BLACK;
@@ -295,9 +296,14 @@ void ScalpelEngine::initialize() {
loadInventory();
// Set up list of people
- for (int idx = 0; idx < MAX_PEOPLE; ++idx)
- _people->_characters.push_back(PersonData(PEOPLE_DATA[idx].name, PEOPLE_DATA[idx].portrait,
+ ScalpelFixedText &fixedText = *(ScalpelFixedText *)_fixedText;
+ const char *peopleNamePtr = nullptr;
+
+ for (int idx = 0; idx < MAX_PEOPLE; ++idx) {
+ peopleNamePtr = fixedText.getText(PEOPLE_DATA[idx].fixedTextId);
+ _people->_characters.push_back(PersonData(peopleNamePtr, PEOPLE_DATA[idx].portrait,
PEOPLE_DATA[idx].stillSequences, PEOPLE_DATA[idx].talkSequences));
+ }
_animation->setPrologueNames(&PROLOGUE_NAMES[0], PROLOGUE_NAMES_COUNT);
_animation->setPrologueFrames(&PROLOGUE_FRAMES[0][0], 6, 9);
@@ -366,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;
@@ -381,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();
}
@@ -402,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;
@@ -422,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);
}
@@ -456,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
@@ -532,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);
@@ -636,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);
}
@@ -665,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) {
@@ -701,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);
}
@@ -710,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);
@@ -727,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);
@@ -735,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);
}
}
@@ -746,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);
@@ -756,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);
}
}
@@ -775,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);
@@ -814,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)
@@ -843,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);
@@ -903,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);
@@ -932,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];
@@ -940,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;
}
@@ -993,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();
}
@@ -1151,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));
}
}
@@ -1213,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));
}
}
@@ -1267,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;
@@ -1302,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()) {
@@ -1366,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();
@@ -1408,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 7f5e1efa69..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 {
@@ -42,7 +41,7 @@ bool ScalpelDebugger::cmd3DO_PlayMovie(int argc, const char **argv) {
return true;
}
- // play gets postboned until debugger is closed
+ // play gets postponed until debugger is closed
Common::String filename = argv[1];
_3doPlayMovieFile = filename;
diff --git a/engines/sherlock/scalpel/scalpel_fixed_text.cpp b/engines/sherlock/scalpel/scalpel_fixed_text.cpp
index 63f84d68c6..d76136a1db 100644
--- a/engines/sherlock/scalpel/scalpel_fixed_text.cpp
+++ b/engines/sherlock/scalpel/scalpel_fixed_text.cpp
@@ -28,33 +28,70 @@ namespace Sherlock {
namespace Scalpel {
static const char *const fixedTextEN[] = {
+ // Game hotkeys
+ "LMTPOCIUGJFS",
// SH1: Window buttons
- "Exit",
- "Up",
- "Down",
+ "EExit",
+ "UUp",
+ "DDown",
// SH1: Inventory buttons
- "Exit",
- "Look",
- "Use",
- "Give",
+ "EExit",
+ "LLook",
+ "UUse",
+ "GGive",
// SH1: Journal text
"Watson's Journal",
"Page %d",
// SH1: Journal buttons
- "Exit",
- "Back 10",
- "Up",
- "Down",
- "Ahead 10",
- "Search",
- "First Page",
- "Last Page",
- "Print Text",
+ "EExit",
+ "BBack 10",
+ "UUp",
+ "DDown",
+ "AAhead 10",
+ "SSearch",
+ "FFirst Page",
+ "LLast Page",
+ "PPrint Text",
// SH1: Journal search
- "Exit",
- "Backward",
- "Forward",
+ "EExit",
+ "BBackward",
+ "FForward",
"Text Not Found !",
+ // SH1: Settings
+ "EExit",
+ "MMusic on",
+ "MMusic off",
+ "PPortraits on",
+ "PPortraits off",
+ "JJoystick off",
+ "NNew Font Style",
+ "SSound Effects on",
+ "SSound Effects off",
+ "WWindows Slide",
+ "WWindows Appear",
+ "CCalibrate Joystick",
+ "AAuto Help left",
+ "AAuto Help right",
+ "VVoices on",
+ "VVoices off",
+ "FFade by Pixel",
+ "FFade Directly",
+ "KKey Pad Slow",
+ "KKey Pad Fast",
+ // Load/Save
+ "EExit",
+ "LLoad",
+ "SSave",
+ "UUp",
+ "DDown",
+ "QQuit",
+ // Quit Game
+ "Are you sure you wish to Quit ?",
+ "YYes",
+ "NNo",
+ // SH1: Press key text
+ "PPress any Key for More.",
+ "PPress any Key to Continue.",
// SH1: Initial Inventory
"A message requesting help",
"A number of business cards",
@@ -68,11 +105,75 @@ static const char *const fixedTextEN[] = {
"Tarot Cards",
"An ornate key",
"A pawn ticket",
- // SH2: Verbs
- "Open",
- "Look",
- "Talk",
- "Journal"
+ // SH1: User Interface
+ "No, thank you.",
+ "You can't do that.",
+ "Done...",
+ "Use ",
+ " on %s",
+ "Give ",
+ " to %s",
+ // SH1: People names
+ "Sherlock Holmes",
+ "Dr. Watson",
+ "Inspector Lestrade",
+ "Constable O'Brien",
+ "Constable Lewis",
+ "Sheila Parker",
+ "Henry Carruthers",
+ "Lesley",
+ "An Usher",
+ "Fredrick Epstein",
+ "Mrs. Worthington",
+ "The Coach",
+ "A Player",
+ "Tim",
+ "James Sanders",
+ "Belle",
+ "Cleaning Girl",
+ "Wiggins",
+ "Paul",
+ "The Bartender",
+ "A Dirty Drunk",
+ "A Shouting Drunk",
+ "A Staggering Drunk",
+ "The Bouncer",
+ "The Coroner",
+ "Reginald Snipes",
+ "George Blackwood",
+ "Lars",
+ "The Chemist",
+ "Inspector Gregson",
+ "Jacob Farthington",
+ "Mycroft",
+ "Old Sherman",
+ "Richard",
+ "The Barman",
+ "A Dandy Player",
+ "A Rough-looking Player",
+ "A Spectator",
+ "Robert Hunt",
+ "Violet",
+ "Pettigrew",
+ "Augie",
+ "Anna Carroway",
+ "A Guard",
+ "Antonio Caruso",
+ "Toby the Dog",
+ "Simon Kingsley",
+ "Alfred",
+ "Lady Brumwell",
+ "Madame Rosa",
+ "Joseph Moorehead",
+ "Mrs. Beale",
+ "Felix",
+ "Hollingston",
+ "Constable Callaghan",
+ "Sergeant Duncan",
+ "Lord Brumwell",
+ "Nigel Jaimeson",
+ "Jonas",
+ "Constable Dugan"
};
// sharp-s : 0xE1 / octal 341
@@ -80,33 +181,70 @@ static const char *const fixedTextEN[] = {
// small o-umlaut: 0x94 / octal 224
// small u-umlaut: 0x81 / octal 201
static const char *const fixedTextDE[] = {
+ // Game hotkeys
+ "SBRNOCTEGADU", // original: did not support hotkeys for actions
// SH1: Window buttons
- "Zur\201ck",
- "Hoch",
- "Runter",
+ "ZZur\201ck",
+ "HHoch",
+ "RRunter",
// SH1: Inventory buttons
- "Zur\201ck",
- "Schau",
- "Benutze",
- "Gib",
+ "ZZur\201ck",
+ "SSchau",
+ "BBenutze",
+ "GGib",
// SH1: Journal text
"Watsons Tagebuch",
"Seite %d",
// SH1: Journal buttons
- "Zur\201ck",
- "10 hoch",
- "Hoch",
- "Runter",
- "10 runter",
- "Suche",
- "Erste Seite",
- "Letzte Seite",
- "Drucke Text",
+ "ZZur\201ck", // original: "Zur\201ck"
+ "o10 hoch",
+ "HHoch",
+ "RRunter",
+ "u10 runter", // original: "10 runter"
+ "SSuche",
+ "EErste Seite",
+ "LLetzte Seite",
+ "DDrucke Text",
// SH1: Journal search
- "Zur\201ck",
- "R\201ckw\204rts", // original: "Backward"
- "Vorw\204rts", // original: "Forward"
+ "ZZur\201ck",
+ "RR\201ckw\204rts", // original: "Backward"
+ "VVorw\204rts", // original: "Forward"
"Text nicht gefunden!",
+ // SH1: Settings
+ "ZZur\201ck", // original interpreter: "Exit"
+ "MMusik an",
+ "MMusik aus",
+ "PPortr\204ts an", // original interpreter: "Portraits"
+ "PPortr\204ts aus",
+ "JJoystick aus",
+ "NNeue Schrift",
+ "GGer\204uscheffekte on", // original interpreter: "Effekte"
+ "GGer\204uscheffekte off",
+ "FFenster gleitend",
+ "FFenster direkt",
+ "JJustiere Joystick",
+ "HHilfe links",
+ "HHilfe rechts",
+ "SSprache an",
+ "SSprache aus",
+ "cSchnitt",
+ "BBlende",
+ "CCursor langsam",
+ "CCursor schnell",
+ // Load/Save
+ "ZZur\201ck",
+ "LLaden",
+ "SSichern",
+ "HHoch",
+ "RRunter",
+ "EEnde",
+ // Quit Game
+ "Das Spiel verlassen ?",
+ "JJa",
+ "NNein",
+ // SH1: Press key text
+ "MMehr auf Tastendruck...",
+ "BBeliebige Taste dr\201cken.",
// SH1: Initial Inventory
"Ein Hilferuf von Lestrade",
"Holmes' Visitenkarten",
@@ -117,47 +255,149 @@ static const char *const fixedTextDE[] = {
"Eine offene Taschenuhr",
"Ein Zettel mit Zahlen drauf",
"Ein mehrfach gefalteter Briefbogen",
- "Ein Tarock-Kartenspiel", // [sic]
+ "Ein Tarot-Kartenspiel", // original interpreter: "Ein Tarock-Kartenspiel" [sic]
"Ein verzierter Schl\201ssel",
"Ein Pfandschein",
- // SH2: Verbs
- "\231ffne",
- "Schau",
- "Rede",
- "Tagebuch"
+ // SH1: User Interface
+ "Nein, vielen Dank.",
+ "Nein, das geht wirklich nicht.", // original: "Nein, das geht wirklich nicht"
+ "Fertig...",
+ "Benutze ",
+ " mit %s",
+ "Gib ", // original: "Gebe "
+ " an %s", // original: " zu %s"
+ // SH1: People names
+ "Sherlock Holmes",
+ "Dr. Watson",
+ "Inspektor Lestrade",
+ "Konstabler O'Brien",
+ "Konstabler Lewis",
+ "Sheila Parker",
+ "Henry Carruthers",
+ "Lesley",
+ "Platzanweiser",
+ "Fredrick Epstein",
+ "Mrs. Worthington",
+ "Der Trainer",
+ "Ein Spieler",
+ "Tim",
+ "James Sanders",
+ "Belle",
+ "Putzm\204dchen",
+ "Wiggins",
+ "Paul",
+ "Gastwirt",
+ "Schmutziger Betrunkener",
+ "Lallender Betrunkener",
+ "Torkelnder Betrunkener",
+ "The Bouncer",
+ "Der Leichenbeschauer",
+ "Reginald Snipes",
+ "George Blackwood",
+ "Lars",
+ "Apotheker",
+ "Inspektor Gregson",
+ "Jacob Farthington",
+ "Mycroft",
+ "Old Sherman",
+ "Richard",
+ "Barkeeper",
+ "Jock Mahoney",
+ "Nobby Charleton",
+ "Zuschauer",
+ "Robert Hunt",
+ "Violet",
+ "Pettigrew",
+ "Augie",
+ "Anna Carroway",
+ "Wache",
+ "Antonio Caruso",
+ "Toby the Dog",
+ "Simon Kingsley",
+ "Alfred",
+ "Lady Brumwell",
+ "Madame Rosa",
+ "Joseph Moorehead",
+ "Mrs. Beale",
+ "Felix",
+ "Hollingston",
+ "Konstabler Callaghan",
+ "Sergeant Duncan",
+ "Lord Brumwell",
+ "Nigel Jaimeson",
+ "Jonas",
+ "Konstabler Dugan"
};
// up-side down exclamation mark - 0xAD / octal 255
// up-side down question mark - 0xA8 / octal 250
// n with a wave on top - 0xA4 / octal 244
+// more characters see engines/sherlock/fixed_text.cpp
static const char *const fixedTextES[] = {
+ // Game hotkeys
+ "VMHTACIUDNFO",
// SH1: Window buttons
- "Exit",
- "Subir",
- "Bajar",
+ "aSalir", // original interpreter: "Exit"
+ "SSubir",
+ "BBajar",
// SH1: Inventory buttons
- "Exit",
- "Mirar",
- "Usar",
- "Dar",
+ "SSalir", // original interpreter: "Exit"
+ "MMirar",
+ "UUsar",
+ "DDar",
// SH1: Journal text
"Diario de Watson",
"Pagina %d",
// SH1: Journal buttons
- "Exit",
- "Retroceder",
- "Subir",
- "baJar",
- "Adelante",
- "Buscar",
- "1a pagina",
- "Ult pagina",
- "Imprimir",
+ "aSalir", // original interpreter: "Exit"
+ "RRetroceder",
+ "SSubir",
+ "JbaJar",
+ "AAdelante",
+ "BBuscar",
+ "11a pagina",
+ "UUlt pagina",
+ "IImprimir",
// SH1: Journal search
- "Exit",
- "Retroceder",
- "Avanzar",
+ "SSalir", // original interpreter: "Exit"
+ "RRetroceder",
+ "AAvanzar",
"Texto no encontrado!",
+ // SH1: Settings
+ "aSalir", // original interpreter: "Exit"
+ "MMusica si",
+ "MMusica no",
+ "RRetratos si",
+ "RRetratos no",
+ "JJoystick no",
+ "NNuevo fuente",
+ "Sefectos Sonido si",
+ "Sefectos Sonido no",
+ "Tven Tanas desliz.",
+ "Tven Tanas aparecen",
+ "CCalibrar Joystick",
+ "yAyuda lzq", // TODO: check this
+ "yAyuda Dcha",
+ "VVoces si",
+ "VVoces no",
+ "FFundido a pixel",
+ "FFundido directo",
+ "eTeclado lento",
+ "eTeclado rapido",
+ // Load/Save
+ "aSalir", // original interpreter: "Exit"
+ "CCargar",
+ "GGrabar",
+ "SSubir",
+ "BBajar",
+ "AAcabar",
+ // Quit Game
+ "\250Seguro que quieres Acabar?",
+ "SSi",
+ "NNo",
+ // SH1: Press key text
+ "TTecla para ver mas",
+ "TTecla para continuar",
// SH1: Initial Inventory
"Un mensaje solicitando ayuda",
"Unas cuantas tarjetas de visita",
@@ -171,6 +411,75 @@ static const char *const fixedTextES[] = {
"Unas cartas de Tarot",
"Una llave muy vistosa",
"Una papeleta de empe\244o",
+ // SH1: User Interface
+ "No, gracias.",
+ "No puedes hacerlo.", // original: "No puedes hacerlo"
+ "Hecho...",
+ "Usar ",
+ " sobre %s",
+ "Dar ",
+ " a %s",
+ // SH1: People names
+ "Sherlock Holmes",
+ "Dr. Watson",
+ "El inspector Lestrade",
+ "El agente O'Brien",
+ "El agente Lewis",
+ "Sheila Parker",
+ "Henry Carruthers",
+ "Lesley",
+ "Un ujier",
+ "Fredrick Epstein",
+ "Mrs. Worthington",
+ "El entrenador",
+ "El jugador",
+ "Tim",
+ "James Sanders",
+ "Belle",
+ "La chica de la limpieza",
+ "Wiggins",
+ "Paul",
+ "El barman",
+ "Un sucio borracho",
+ "Un borracho griton",
+ "Un tambaleante borracho",
+ "El gorila",
+ "El forense",
+ "Reginald Snipes",
+ "George Blackwood",
+ "Lars",
+ "El quimico",
+ "El inspector Gregson",
+ "Jacob Farthington",
+ "Mycroft",
+ "Old Sherman",
+ "Richard",
+ "El barman",
+ "Un jugador dandy",
+ "Un duro jugador",
+ "Un espectador",
+ "Robert Hunt",
+ "Violeta",
+ "Pettigrew",
+ "Augie",
+ "Anna Carroway",
+ "Un guarda",
+ "Antonio Caruso",
+ "El perro Toby",
+ "Simon Kingsley",
+ "Alfred",
+ "Lady Brumwell",
+ "Madame Rosa",
+ "Joseph Moorehead",
+ "Mrs. Beale",
+ "Felix",
+ "Hollingston",
+ "El agente Callaghan",
+ "El sargento Duncan",
+ "Lord Brumwell",
+ "Nigel Jaimeson",
+ "Jonas",
+ "El agente Dugan"
};
// =========================================
@@ -233,7 +542,7 @@ static const char *const fixedTextDE_ActionMove[] = {
"L\204\341t sich nicht bewegen",
"Festged\201belt in der Erde...",
"Oha, VIEL zu schwer",
- "Der andere Kiste ist im Weg" // [sic]
+ "Die andere Kiste ist im Weg" // original: "Der andere Kiste ist im Weg"
};
static const char *const fixedTextES_ActionMove[] = {
@@ -332,8 +641,6 @@ static const FixedTextActionEntry fixedTextES_Actions[] = {
// =========================================
-// TODO:
-// It seems there was a French version of Sherlock Holmes 2
static const FixedTextLanguageEntry fixedTextLanguages[] = {
{ Common::DE_DEU, fixedTextDE, fixedTextDE_Actions },
{ Common::ES_ESP, fixedTextES, fixedTextES_Actions },
diff --git a/engines/sherlock/scalpel/scalpel_fixed_text.h b/engines/sherlock/scalpel/scalpel_fixed_text.h
index eae86b8f27..d9b3bbed79 100644
--- a/engines/sherlock/scalpel/scalpel_fixed_text.h
+++ b/engines/sherlock/scalpel/scalpel_fixed_text.h
@@ -30,8 +30,10 @@ namespace Sherlock {
namespace Scalpel {
enum FixedTextId {
+ // Game hotkeys
+ kFixedText_Game_Hotkeys = 0,
// Window buttons
- kFixedText_Window_Exit = 0,
+ kFixedText_Window_Exit,
kFixedText_Window_Up,
kFixedText_Window_Down,
// Inventory buttons
@@ -57,6 +59,41 @@ enum FixedTextId {
kFixedText_JournalSearch_Backward,
kFixedText_JournalSearch_Forward,
kFixedText_JournalSearch_NotFound,
+ // Settings
+ kFixedText_Settings_Exit,
+ kFixedText_Settings_MusicOn,
+ kFixedText_Settings_MusicOff,
+ kFixedText_Settings_PortraitsOn,
+ kFixedText_Settings_PortraitsOff,
+ kFixedText_Settings_JoystickOff,
+ kFixedText_Settings_NewFontStyle,
+ kFixedText_Settings_SoundEffectsOn,
+ kFixedText_Settings_SoundEffectsOff,
+ kFixedText_Settings_WindowsSlide,
+ kFixedText_Settings_WindowsAppear,
+ kFixedText_Settings_CalibrateJoystick,
+ kFixedText_Settings_AutoHelpLeft,
+ kFixedText_Settings_AutoHelpRight,
+ kFixedText_Settings_VoicesOn,
+ kFixedText_Settings_VoicesOff,
+ kFixedText_Settings_FadeByPixel,
+ kFixedText_Settings_FadeDirectly,
+ kFixedText_Settings_KeyPadSlow,
+ kFixedText_Settings_KeyPadFast,
+ // Load/Save
+ kFixedText_LoadSave_Exit,
+ kFixedText_LoadSave_Load,
+ kFixedText_LoadSave_Save,
+ kFixedText_LoadSave_Up,
+ kFixedText_LoadSave_Down,
+ kFixedText_LoadSave_Quit,
+ // Quit Game
+ kFixedText_QuitGame_Question,
+ kFixedText_QuitGame_Yes,
+ kFixedText_QuitGame_No,
+ // Press key text
+ kFixedText_PressKey_ForMore,
+ kFixedText_PressKey_ToContinue,
// Initial inventory
kFixedText_InitInventory_Message,
kFixedText_InitInventory_HolmesCard,
@@ -69,7 +106,76 @@ enum FixedTextId {
kFixedText_InitInventory_Letter,
kFixedText_InitInventory_Tarot,
kFixedText_InitInventory_OrnateKey,
- kFixedText_InitInventory_PawnTicket
+ kFixedText_InitInventory_PawnTicket,
+ // SH1: User Interface
+ kFixedText_UserInterface_NoThankYou,
+ kFixedText_UserInterface_YouCantDoThat,
+ kFixedText_UserInterface_Done,
+ kFixedText_UserInterface_Use,
+ kFixedText_UserInterface_UseOn,
+ kFixedText_UserInterface_Give,
+ kFixedText_UserInterface_GiveTo,
+ // People names
+ kFixedText_People_SherlockHolmes,
+ kFixedText_People_DrWatson,
+ kFixedText_People_InspectorLestrade,
+ kFixedText_People_ConstableOBrien,
+ kFixedText_People_ConstableLewis,
+ kFixedText_People_SheilaParker,
+ kFixedText_People_HenryCarruthers,
+ kFixedText_People_Lesley,
+ kFixedText_People_AnUsher,
+ kFixedText_People_FredrickEpstein,
+ kFixedText_People_MrsWorthington,
+ kFixedText_People_TheCoach,
+ kFixedText_People_APlayer,
+ kFixedText_People_Tim,
+ kFixedText_People_JamesSanders,
+ kFixedText_People_Belle,
+ kFixedText_People_CleaningGirl,
+ kFixedText_People_Wiggins,
+ kFixedText_People_Paul,
+ kFixedText_People_TheBartender,
+ kFixedText_People_ADirtyDrunk,
+ kFixedText_People_AShoutingDrunk,
+ kFixedText_People_AStaggeringDrunk,
+ kFixedText_People_TheBouncer,
+ kFixedText_People_TheCoroner,
+ kFixedText_People_ReginaldSnipes,
+ kFixedText_People_GeorgeBlackwood,
+ kFixedText_People_Lars,
+ kFixedText_People_TheChemist,
+ kFixedText_People_InspectorGregson,
+ kFixedText_People_JacobFarthington,
+ kFixedText_People_Mycroft,
+ kFixedText_People_OldSherman,
+ kFixedText_People_Richard,
+ kFixedText_People_TheBarman,
+ kFixedText_People_ADandyPlayer,
+ kFixedText_People_ARoughlookingPlayer,
+ kFixedText_People_ASpectator,
+ kFixedText_People_RobertHunt,
+ kFixedText_People_Violet,
+ kFixedText_People_Pettigrew,
+ kFixedText_People_Augie,
+ kFixedText_People_AnnaCarroway,
+ kFixedText_People_AGuard,
+ kFixedText_People_AntonioCaruso,
+ kFixedText_People_TobyTheDog,
+ kFixedText_People_SimonKingsley,
+ kFixedText_People_Alfred,
+ kFixedText_People_LadyBrumwell,
+ kFixedText_People_MadameRosa,
+ kFixedText_People_JosephMoorehead,
+ kFixedText_People_MrsBeale,
+ kFixedText_People_Felix,
+ kFixedText_People_Hollingston,
+ kFixedText_People_ConstableCallaghan,
+ kFixedText_People_SergeantDuncan,
+ kFixedText_People_LordBrumwell,
+ kFixedText_People_NigelJaimeson,
+ kFixedText_People_Jonas,
+ kFixedText_People_ConstableDugan
};
struct FixedTextActionEntry {
diff --git a/engines/sherlock/scalpel/scalpel_inventory.cpp b/engines/sherlock/scalpel/scalpel_inventory.cpp
index e19a43238c..07659b41f2 100644
--- a/engines/sherlock/scalpel/scalpel_inventory.cpp
+++ b/engines/sherlock/scalpel/scalpel_inventory.cpp
@@ -32,13 +32,39 @@ namespace Scalpel {
ScalpelInventory::ScalpelInventory(SherlockEngine *vm) : Inventory(vm) {
_invShapes.resize(6);
+
+ _fixedTextExit = FIXED(Inventory_Exit);
+ _fixedTextLook = FIXED(Inventory_Look);
+ _fixedTextUse = FIXED(Inventory_Use);
+ _fixedTextGive = FIXED(Inventory_Give);
+
+ _hotkeyExit = toupper(_fixedTextExit[0]);
+ _hotkeyLook = toupper(_fixedTextLook[0]);
+ _hotkeyUse = toupper(_fixedTextUse[0]);
+ _hotkeyGive = toupper(_fixedTextGive[0]);
+
+ _hotkeysIndexed[0] = _hotkeyExit;
+ _hotkeysIndexed[1] = _hotkeyLook;
+ _hotkeysIndexed[2] = _hotkeyUse;
+ _hotkeysIndexed[3] = _hotkeyGive;
+ _hotkeysIndexed[4] = '-';
+ _hotkeysIndexed[5] = '+';
+ _hotkeysIndexed[6] = ',';
+ _hotkeysIndexed[7] = '.';
}
ScalpelInventory::~ScalpelInventory() {
}
+int ScalpelInventory::identifyUserButton(int key) {
+ for (uint16 hotkeyNr = 0; hotkeyNr < sizeof(_hotkeysIndexed); hotkeyNr++) {
+ if (key == _hotkeysIndexed[hotkeyNr])
+ return hotkeyNr;
+ }
+ return -1;
+}
+
void ScalpelInventory::drawInventory(InvNewMode mode) {
- FixedText &fixedText = *_vm->_fixedText;
ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
UserInterface &ui = *_vm->_ui;
InvNewMode tempMode = mode;
@@ -46,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,
@@ -61,34 +87,30 @@ void ScalpelInventory::drawInventory(InvNewMode mode) {
INV_BACKGROUND);
// Draw the buttons
- Common::String fixedText_Exit = fixedText.getText(kFixedText_Inventory_Exit);
- Common::String fixedText_Look = fixedText.getText(kFixedText_Inventory_Look);
- Common::String fixedText_Use = fixedText.getText(kFixedText_Inventory_Use);
- Common::String fixedText_Give = fixedText.getText(kFixedText_Inventory_Give);
-
screen.makeButton(Common::Rect(INVENTORY_POINTS[0][0], CONTROLS_Y1, INVENTORY_POINTS[0][1],
- CONTROLS_Y1 + 10), INVENTORY_POINTS[0][2] - screen.stringWidth(fixedText_Exit) / 2, fixedText_Exit);
+ CONTROLS_Y1 + 10), INVENTORY_POINTS[0][2], _fixedTextExit);
screen.makeButton(Common::Rect(INVENTORY_POINTS[1][0], CONTROLS_Y1, INVENTORY_POINTS[1][1],
- CONTROLS_Y1 + 10), INVENTORY_POINTS[1][2] - screen.stringWidth(fixedText_Look) / 2, fixedText_Look);
+ CONTROLS_Y1 + 10), INVENTORY_POINTS[1][2], _fixedTextLook);
screen.makeButton(Common::Rect(INVENTORY_POINTS[2][0], CONTROLS_Y1, INVENTORY_POINTS[2][1],
- CONTROLS_Y1 + 10), INVENTORY_POINTS[2][2] - screen.stringWidth(fixedText_Use) / 2, fixedText_Use);
+ CONTROLS_Y1 + 10), INVENTORY_POINTS[2][2], _fixedTextUse);
screen.makeButton(Common::Rect(INVENTORY_POINTS[3][0], CONTROLS_Y1, INVENTORY_POINTS[3][1],
- CONTROLS_Y1 + 10), INVENTORY_POINTS[3][2] - screen.stringWidth(fixedText_Give) / 2, fixedText_Give);
+ CONTROLS_Y1 + 10), INVENTORY_POINTS[3][2], _fixedTextGive);
screen.makeButton(Common::Rect(INVENTORY_POINTS[4][0], CONTROLS_Y1, INVENTORY_POINTS[4][1],
- CONTROLS_Y1 + 10), INVENTORY_POINTS[4][2], "^^"); // 2 arrows pointing to the left
+ CONTROLS_Y1 + 10), INVENTORY_POINTS[4][2] + 8, "^^", false); // 2 arrows pointing to the left
screen.makeButton(Common::Rect(INVENTORY_POINTS[5][0], CONTROLS_Y1, INVENTORY_POINTS[5][1],
- CONTROLS_Y1 + 10), INVENTORY_POINTS[5][2], "^"); // 1 arrow pointing to the left
+ CONTROLS_Y1 + 10), INVENTORY_POINTS[5][2] + 4, "^", false); // 1 arrow pointing to the left
screen.makeButton(Common::Rect(INVENTORY_POINTS[6][0], CONTROLS_Y1, INVENTORY_POINTS[6][1],
- CONTROLS_Y1 + 10), INVENTORY_POINTS[6][2], "_"); // 1 arrow pointing to the right
+ CONTROLS_Y1 + 10), INVENTORY_POINTS[6][2] + 4, "_", false); // 1 arrow pointing to the right
screen.makeButton(Common::Rect(INVENTORY_POINTS[7][0], CONTROLS_Y1, INVENTORY_POINTS[7][1],
- CONTROLS_Y1 + 10), INVENTORY_POINTS[7][2], "__"); // 2 arrows pointing to the right
+ CONTROLS_Y1 + 10), INVENTORY_POINTS[7][2] + 8, "__", false); // 2 arrows pointing to the right
if (tempMode == INVENTORY_DONT_DISPLAY)
mode = LOOK_INVENTORY_MODE;
_invMode = (InvMode)((int)mode);
if (mode != PLAIN_INVENTORY) {
- ui._oldKey = INVENTORY_COMMANDS[(int)mode];
+ assert((uint)mode < sizeof(_hotkeysIndexed));
+ ui._oldKey = _hotkeysIndexed[mode];
} else {
ui._oldKey = -1;
}
@@ -106,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);
@@ -114,28 +136,22 @@ void ScalpelInventory::drawInventory(InvNewMode mode) {
}
void ScalpelInventory::invCommands(bool slamIt) {
- FixedText &fixedText = *_vm->_fixedText;
ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
UserInterface &ui = *_vm->_ui;
- Common::String fixedText_Exit = fixedText.getText(kFixedText_Inventory_Exit);
- Common::String fixedText_Look = fixedText.getText(kFixedText_Inventory_Look);
- Common::String fixedText_Use = fixedText.getText(kFixedText_Inventory_Use);
- Common::String fixedText_Give = fixedText.getText(kFixedText_Inventory_Give);
-
if (slamIt) {
screen.buttonPrint(Common::Point(INVENTORY_POINTS[0][2], CONTROLS_Y1),
_invMode == INVMODE_EXIT ? COMMAND_HIGHLIGHTED :COMMAND_FOREGROUND,
- true, fixedText_Exit);
+ true, _fixedTextExit);
screen.buttonPrint(Common::Point(INVENTORY_POINTS[1][2], CONTROLS_Y1),
_invMode == INVMODE_LOOK ? COMMAND_HIGHLIGHTED :COMMAND_FOREGROUND,
- true, fixedText_Look);
+ true, _fixedTextLook);
screen.buttonPrint(Common::Point(INVENTORY_POINTS[2][2], CONTROLS_Y1),
_invMode == INVMODE_USE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
- true, fixedText_Use);
+ true, _fixedTextUse);
screen.buttonPrint(Common::Point(INVENTORY_POINTS[3][2], CONTROLS_Y1),
_invMode == INVMODE_GIVE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
- true, fixedText_Give);
+ true, _fixedTextGive);
screen.print(Common::Point(INVENTORY_POINTS[4][2], CONTROLS_Y1 + 1),
_invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND,
"^^"); // 2 arrows pointing to the left
@@ -153,16 +169,16 @@ void ScalpelInventory::invCommands(bool slamIt) {
} else {
screen.buttonPrint(Common::Point(INVENTORY_POINTS[0][2], CONTROLS_Y1),
_invMode == INVMODE_EXIT ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
- false, fixedText_Exit);
+ false, _fixedTextExit);
screen.buttonPrint(Common::Point(INVENTORY_POINTS[1][2], CONTROLS_Y1),
_invMode == INVMODE_LOOK ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
- false, fixedText_Look);
+ false, _fixedTextLook);
screen.buttonPrint(Common::Point(INVENTORY_POINTS[2][2], CONTROLS_Y1),
_invMode == INVMODE_USE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
- false, fixedText_Use);
+ false, _fixedTextUse);
screen.buttonPrint(Common::Point(INVENTORY_POINTS[3][2], CONTROLS_Y1),
_invMode == INVMODE_GIVE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
- false, fixedText_Give);
+ false, _fixedTextGive);
screen.gPrint(Common::Point(INVENTORY_POINTS[4][2], CONTROLS_Y1),
_invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND,
"^^"); // 2 arrows pointing to the left
@@ -180,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);
}
@@ -201,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();
}
}
@@ -248,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)));
}
@@ -262,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_inventory.h b/engines/sherlock/scalpel/scalpel_inventory.h
index afafb0b94a..49d055593a 100644
--- a/engines/sherlock/scalpel/scalpel_inventory.h
+++ b/engines/sherlock/scalpel/scalpel_inventory.h
@@ -34,6 +34,18 @@ public:
ScalpelInventory(SherlockEngine *vm);
~ScalpelInventory();
+ Common::String _fixedTextExit;
+ Common::String _fixedTextLook;
+ Common::String _fixedTextUse;
+ Common::String _fixedTextGive;
+
+ byte _hotkeyExit;
+ byte _hotkeyLook;
+ byte _hotkeyUse;
+ byte _hotkeyGive;
+
+ byte _hotkeysIndexed[8];
+
/**
* Put the game into inventory mode and open the interface window.
*/
@@ -65,6 +77,11 @@ public:
* and then calls loadGraphics to load the associated graphics
*/
virtual void loadInv();
+
+ /**
+ * Identifies a button number according to the key, that the user pressed
+ */
+ int identifyUserButton(int key);
};
} // End of namespace Scalpel
diff --git a/engines/sherlock/scalpel/scalpel_journal.cpp b/engines/sherlock/scalpel/scalpel_journal.cpp
index 787d899aee..151d986d81 100644
--- a/engines/sherlock/scalpel/scalpel_journal.cpp
+++ b/engines/sherlock/scalpel/scalpel_journal.cpp
@@ -64,6 +64,36 @@ ScalpelJournal::ScalpelJournal(SherlockEngine *vm) : Journal(vm) {
// Load the journal directory and location names
loadLocations();
}
+
+ _fixedTextWatsonsJournal = FIXED(Journal_WatsonsJournal);
+ _fixedTextExit = FIXED(Journal_Exit);
+ _fixedTextBack10 = FIXED(Journal_Back10);
+ _fixedTextUp = FIXED(Journal_Up);
+ _fixedTextDown = FIXED(Journal_Down);
+ _fixedTextAhead10 = FIXED(Journal_Ahead10);
+ _fixedTextSearch = FIXED(Journal_Search);
+ _fixedTextFirstPage = FIXED(Journal_FirstPage);
+ _fixedTextLastPage = FIXED(Journal_LastPage);
+ _fixedTextPrintText = FIXED(Journal_PrintText);
+
+ _hotkeyExit = toupper(_fixedTextExit[0]);
+ _hotkeyBack10 = toupper(_fixedTextBack10[0]);
+ _hotkeyUp = toupper(_fixedTextUp[0]);
+ _hotkeyDown = toupper(_fixedTextDown[0]);
+ _hotkeyAhead10 = toupper(_fixedTextAhead10[0]);
+ _hotkeySearch = toupper(_fixedTextSearch[0]);
+ _hotkeyFirstPage = toupper(_fixedTextFirstPage[0]);
+ _hotkeyLastPage = toupper(_fixedTextLastPage[0]);
+ _hotkeyPrintText = toupper(_fixedTextPrintText[0]);
+
+ _fixedTextSearchExit = FIXED(JournalSearch_Exit);
+ _fixedTextSearchBackward = FIXED(JournalSearch_Backward);
+ _fixedTextSearchForward = FIXED(JournalSearch_Forward);
+ _fixedTextSearchNotFound = FIXED(JournalSearch_NotFound);
+
+ _hotkeySearchExit = toupper(_fixedTextSearchExit[0]);
+ _hotkeySearchBackward = toupper(_fixedTextSearchBackward[0]);
+ _hotkeySearchForward = toupper(_fixedTextSearchForward[0]);
}
void ScalpelJournal::loadLocations() {
@@ -104,6 +134,25 @@ void ScalpelJournal::loadLocations() {
while ((c = loc->readByte()) != 0)
line += c;
+ // WORKAROUND: Special fixes for faulty translations
+ // Was obviously not done in the original interpreter
+ if (_vm->getLanguage() == Common::ES_ESP) {
+ // Spanish version
+ // We fix all sorts of typos
+ // see bug #6931
+ if (line == "En el cajellon destras del teatro Regency") {
+ line = "En el callejon detras del teatro Regency";
+ } else if (line == "En el apartamente de Simon Kingsley") {
+ line = "En el apartamento de Simon Kingsley";
+ } else if (line == "Bajo la muelle de Savoy Pier") {
+ line = "Bajo el muelle de Savoy Pier";
+ } else if (line == "En le viejo Sherman") {
+ line = "En el viejo Sherman";
+ } else if (line == "En la entrada de la cada de Anna Carroway") {
+ line = "En la entrada de la casa de Anna Carroway";
+ }
+ }
+
_locations.push_back(line);
}
@@ -111,7 +160,6 @@ void ScalpelJournal::loadLocations() {
}
void ScalpelJournal::drawFrame() {
- FixedText &fixedText = *_vm->_fixedText;
Resources &res = *_vm->_res;
ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
byte palette[PALETTE_SIZE];
@@ -126,54 +174,43 @@ void ScalpelJournal::drawFrame() {
for (int idx = 0; idx < PALETTE_SIZE; ++idx)
palette[idx] = VGA_COLOR_TRANS(palette[idx]);
- Common::String fixedText_WatsonsJournal = fixedText.getText(kFixedText_Journal_WatsonsJournal);
- Common::String fixedText_Exit = fixedText.getText(kFixedText_Journal_Exit);
- Common::String fixedText_Back10 = fixedText.getText(kFixedText_Journal_Back10);
- Common::String fixedText_Up = fixedText.getText(kFixedText_Journal_Up);
- Common::String fixedText_Down = fixedText.getText(kFixedText_Journal_Down);
- Common::String fixedText_Ahead10 = fixedText.getText(kFixedText_Journal_Ahead10);
- Common::String fixedText_Search = fixedText.getText(kFixedText_Journal_Search);
- Common::String fixedText_FirstPage = fixedText.getText(kFixedText_Journal_FirstPage);
- Common::String fixedText_LastPage = fixedText.getText(kFixedText_Journal_LastPage);
- Common::String fixedText_PrintText = fixedText.getText(kFixedText_Journal_PrintText);
-
// Set the palette and print the title
screen.setPalette(palette);
- screen.gPrint(Common::Point(111, 18), BUTTON_BOTTOM, "%s", fixedText_WatsonsJournal.c_str());
- screen.gPrint(Common::Point(110, 17), INV_FOREGROUND, "%s", fixedText_WatsonsJournal.c_str());
+ screen.gPrint(Common::Point(111, 18), BUTTON_BOTTOM, "%s", _fixedTextWatsonsJournal.c_str());
+ screen.gPrint(Common::Point(110, 17), INV_FOREGROUND, "%s", _fixedTextWatsonsJournal.c_str());
// Draw the buttons
screen.makeButton(Common::Rect(JOURNAL_POINTS[0][0], JOURNAL_BUTTONS_Y,
JOURNAL_POINTS[0][1], JOURNAL_BUTTONS_Y + 10),
- JOURNAL_POINTS[0][2] - screen.stringWidth(fixedText_Exit) / 2, fixedText_Exit);
+ JOURNAL_POINTS[0][2], _fixedTextExit);
screen.makeButton(Common::Rect(JOURNAL_POINTS[1][0], JOURNAL_BUTTONS_Y,
JOURNAL_POINTS[1][1], JOURNAL_BUTTONS_Y + 10),
- JOURNAL_POINTS[1][2] - screen.stringWidth(fixedText_Back10) / 2, fixedText_Back10);
+ JOURNAL_POINTS[1][2], _fixedTextBack10);
screen.makeButton(Common::Rect(JOURNAL_POINTS[2][0], JOURNAL_BUTTONS_Y,
JOURNAL_POINTS[2][1], JOURNAL_BUTTONS_Y + 10),
- JOURNAL_POINTS[2][2] - screen.stringWidth(fixedText_Up) / 2, fixedText_Up);
+ JOURNAL_POINTS[2][2], _fixedTextUp);
screen.makeButton(Common::Rect(JOURNAL_POINTS[3][0], JOURNAL_BUTTONS_Y,
JOURNAL_POINTS[3][1], JOURNAL_BUTTONS_Y + 10),
- JOURNAL_POINTS[3][2] - screen.stringWidth(fixedText_Down) / 2, fixedText_Down);
+ JOURNAL_POINTS[3][2], _fixedTextDown);
screen.makeButton(Common::Rect(JOURNAL_POINTS[4][0], JOURNAL_BUTTONS_Y,
JOURNAL_POINTS[4][1], JOURNAL_BUTTONS_Y + 10),
- JOURNAL_POINTS[4][2] - screen.stringWidth(fixedText_Ahead10) / 2, fixedText_Ahead10);
+ JOURNAL_POINTS[4][2], _fixedTextAhead10);
screen.makeButton(Common::Rect(JOURNAL_POINTS[5][0], JOURNAL_BUTTONS_Y + 11,
JOURNAL_POINTS[5][1], JOURNAL_BUTTONS_Y + 21),
- JOURNAL_POINTS[5][2] - screen.stringWidth(fixedText_Search) / 2, fixedText_Search);
+ JOURNAL_POINTS[5][2], _fixedTextSearch);
screen.makeButton(Common::Rect(JOURNAL_POINTS[6][0], JOURNAL_BUTTONS_Y + 11,
JOURNAL_POINTS[6][1], JOURNAL_BUTTONS_Y + 21),
- JOURNAL_POINTS[6][2] - screen.stringWidth(fixedText_FirstPage) / 2, fixedText_FirstPage);
+ JOURNAL_POINTS[6][2], _fixedTextFirstPage);
screen.makeButton(Common::Rect(JOURNAL_POINTS[7][0], JOURNAL_BUTTONS_Y + 11,
JOURNAL_POINTS[7][1], JOURNAL_BUTTONS_Y + 21),
- JOURNAL_POINTS[7][2] - screen.stringWidth(fixedText_LastPage) / 2, fixedText_LastPage);
+ JOURNAL_POINTS[7][2], _fixedTextLastPage);
// WORKAROUND: Draw Print Text button as disabled, since we don't support it in ScummVM
screen.makeButton(Common::Rect(JOURNAL_POINTS[8][0], JOURNAL_BUTTONS_Y + 11,
JOURNAL_POINTS[8][1], JOURNAL_BUTTONS_Y + 21),
- JOURNAL_POINTS[8][2] - screen.stringWidth(fixedText_PrintText) / 2, fixedText_PrintText);
+ JOURNAL_POINTS[8][2], _fixedTextPrintText);
screen.buttonPrint(Common::Point(JOURNAL_POINTS[8][2], JOURNAL_BUTTONS_Y + 11),
- COMMAND_NULL, false, fixedText_PrintText);
+ COMMAND_NULL, false, _fixedTextPrintText);
}
void ScalpelJournal::drawInterface() {
@@ -194,34 +231,24 @@ void ScalpelJournal::drawInterface() {
}
void ScalpelJournal::doArrows() {
- FixedText &fixedText = *_vm->_fixedText;
ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
byte color;
- Common::String fixedText_Back10 = fixedText.getText(kFixedText_Journal_Back10);
- Common::String fixedText_Up = fixedText.getText(kFixedText_Journal_Up);
- Common::String fixedText_Down = fixedText.getText(kFixedText_Journal_Down);
- Common::String fixedText_Ahead10 = fixedText.getText(kFixedText_Journal_Ahead10);
- Common::String fixedText_Search = fixedText.getText(kFixedText_Journal_Search);
- Common::String fixedText_FirstPage = fixedText.getText(kFixedText_Journal_FirstPage);
- Common::String fixedText_LastPage = fixedText.getText(kFixedText_Journal_LastPage);
- Common::String fixedText_PrintText = fixedText.getText(kFixedText_Journal_PrintText);
-
color = (_page > 1) ? COMMAND_FOREGROUND : COMMAND_NULL;
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[1][2], JOURNAL_BUTTONS_Y), color, false, fixedText_Back10);
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[2][2], JOURNAL_BUTTONS_Y), color, false, fixedText_Up);
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[1][2], JOURNAL_BUTTONS_Y), color, false, _fixedTextBack10);
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[2][2], JOURNAL_BUTTONS_Y), color, false, _fixedTextUp);
color = _down ? COMMAND_FOREGROUND : COMMAND_NULL;
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[3][2], JOURNAL_BUTTONS_Y), color, false, fixedText_Down);
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[4][2], JOURNAL_BUTTONS_Y), color, false, fixedText_Ahead10);
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[7][2], JOURNAL_BUTTONS_Y + 11), color, false, fixedText_LastPage);
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[3][2], JOURNAL_BUTTONS_Y), color, false, _fixedTextDown);
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[4][2], JOURNAL_BUTTONS_Y), color, false, _fixedTextAhead10);
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[7][2], JOURNAL_BUTTONS_Y + 11), color, false, _fixedTextLastPage);
color = _journal.size() > 0 ? COMMAND_FOREGROUND : COMMAND_NULL;
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[5][2], JOURNAL_BUTTONS_Y + 11), color, false, fixedText_Search);
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[8][2], JOURNAL_BUTTONS_Y + 11), COMMAND_NULL, false, fixedText_PrintText);
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[5][2], JOURNAL_BUTTONS_Y + 11), color, false, _fixedTextSearch);
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[8][2], JOURNAL_BUTTONS_Y + 11), COMMAND_NULL, false, _fixedTextPrintText);
color = _page > 1 ? COMMAND_FOREGROUND : COMMAND_NULL;
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[6][2], JOURNAL_BUTTONS_Y + 11), color, false, fixedText_FirstPage);
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[6][2], JOURNAL_BUTTONS_Y + 11), color, false, _fixedTextFirstPage);
}
JournalButton ScalpelJournal::getHighlightedButton(const Common::Point &pt) {
@@ -266,7 +293,6 @@ JournalButton ScalpelJournal::getHighlightedButton(const Common::Point &pt) {
bool ScalpelJournal::handleEvents(int key) {
Events &events = *_vm->_events;
- FixedText &fixedText = *_vm->_fixedText;
ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
bool doneFlag = false;
@@ -275,46 +301,36 @@ bool ScalpelJournal::handleEvents(int key) {
byte color;
if (events._pressed || events._released) {
- Common::String fixedText_Exit = fixedText.getText(kFixedText_Journal_Exit);
- Common::String fixedText_Back10 = fixedText.getText(kFixedText_Journal_Back10);
- Common::String fixedText_Up = fixedText.getText(kFixedText_Journal_Up);
- Common::String fixedText_Down = fixedText.getText(kFixedText_Journal_Down);
- Common::String fixedText_Ahead10 = fixedText.getText(kFixedText_Journal_Ahead10);
- Common::String fixedText_Search = fixedText.getText(kFixedText_Journal_Search);
- Common::String fixedText_FirstPage = fixedText.getText(kFixedText_Journal_FirstPage);
- Common::String fixedText_LastPage = fixedText.getText(kFixedText_Journal_LastPage);
- Common::String fixedText_PrintText = fixedText.getText(kFixedText_Journal_PrintText);
-
// Exit button
color = (btn == BTN_EXIT) ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND;
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[0][2], JOURNAL_BUTTONS_Y), color, true, fixedText_Exit);
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[0][2], JOURNAL_BUTTONS_Y), color, true, _fixedTextExit);
// Back 10 button
if (btn == BTN_BACK10) {
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[1][2], JOURNAL_BUTTONS_Y), COMMAND_HIGHLIGHTED, true, fixedText_Back10);
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[1][2], JOURNAL_BUTTONS_Y), COMMAND_HIGHLIGHTED, true, _fixedTextBack10);
} else if (_page > 1) {
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[1][2], JOURNAL_BUTTONS_Y), COMMAND_FOREGROUND, true, fixedText_Back10);
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[1][2], JOURNAL_BUTTONS_Y), COMMAND_FOREGROUND, true, _fixedTextBack10);
}
// Up button
if (btn == BTN_UP) {
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[2][2], JOURNAL_BUTTONS_Y), COMMAND_HIGHLIGHTED, true, fixedText_Up);
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[2][2], JOURNAL_BUTTONS_Y), COMMAND_HIGHLIGHTED, true, _fixedTextUp);
} else if (_up) {
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[2][2], JOURNAL_BUTTONS_Y), COMMAND_FOREGROUND, true, fixedText_Up);
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[2][2], JOURNAL_BUTTONS_Y), COMMAND_FOREGROUND, true, _fixedTextUp);
}
// Down button
if (btn == BTN_DOWN) {
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[3][2], JOURNAL_BUTTONS_Y), COMMAND_HIGHLIGHTED, true, fixedText_Down);
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[3][2], JOURNAL_BUTTONS_Y), COMMAND_HIGHLIGHTED, true, _fixedTextDown);
} else if (_down) {
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[3][2], JOURNAL_BUTTONS_Y), COMMAND_FOREGROUND, true, fixedText_Down);
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[3][2], JOURNAL_BUTTONS_Y), COMMAND_FOREGROUND, true, _fixedTextDown);
}
// Ahead 10 button
if (btn == BTN_AHEAD110) {
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[4][2], JOURNAL_BUTTONS_Y), COMMAND_HIGHLIGHTED, true, fixedText_Ahead10);
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[4][2], JOURNAL_BUTTONS_Y), COMMAND_HIGHLIGHTED, true, _fixedTextAhead10);
} else if (_down) {
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[4][2], JOURNAL_BUTTONS_Y), COMMAND_FOREGROUND, true, fixedText_Ahead10);
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[4][2], JOURNAL_BUTTONS_Y), COMMAND_FOREGROUND, true, _fixedTextAhead10);
}
// Search button
@@ -325,7 +341,7 @@ bool ScalpelJournal::handleEvents(int key) {
} else {
color = COMMAND_FOREGROUND;
}
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[5][2], JOURNAL_BUTTONS_Y + 11), color, true, fixedText_Search);
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[5][2], JOURNAL_BUTTONS_Y + 11), color, true, _fixedTextSearch);
// First Page button
if (btn == BTN_FIRST_PAGE) {
@@ -335,7 +351,7 @@ bool ScalpelJournal::handleEvents(int key) {
} else {
color = COMMAND_NULL;
}
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[6][2], JOURNAL_BUTTONS_Y + 11), color, true, fixedText_FirstPage);
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[6][2], JOURNAL_BUTTONS_Y + 11), color, true, _fixedTextFirstPage);
// Last Page button
if (btn == BTN_LAST_PAGE) {
@@ -345,17 +361,17 @@ bool ScalpelJournal::handleEvents(int key) {
} else {
color = COMMAND_NULL;
}
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[7][2], JOURNAL_BUTTONS_Y + 11), color, true, fixedText_LastPage);
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[7][2], JOURNAL_BUTTONS_Y + 11), color, true, _fixedTextLastPage);
// Print Text button
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[8][2], JOURNAL_BUTTONS_Y + 11), COMMAND_NULL, true, fixedText_PrintText);
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[8][2], JOURNAL_BUTTONS_Y + 11), COMMAND_NULL, true, _fixedTextPrintText);
}
if (btn == BTN_EXIT && events._released) {
// Exit button pressed
doneFlag = true;
- } else if (((btn == BTN_BACK10 && events._released) || key == 'B') && (_page > 1)) {
+ } else if (((btn == BTN_BACK10 && events._released) || key == _hotkeyBack10) && (_page > 1)) {
// Scrolll up 10 pages
if (_page < 11)
drawJournal(1, (_page - 1) * LINES_PER_PAGE);
@@ -365,19 +381,19 @@ bool ScalpelJournal::handleEvents(int key) {
doArrows();
screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
- } else if (((btn == BTN_UP && events._released) || key == 'U') && _up) {
+ } else if (((btn == BTN_UP && events._released) || key == _hotkeyUp) && _up) {
// Scroll up
drawJournal(1, LINES_PER_PAGE);
doArrows();
screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
- } else if (((btn == BTN_DOWN && events._released) || key == 'D') && _down) {
+ } else if (((btn == BTN_DOWN && events._released) || key == _hotkeyDown) && _down) {
// Scroll down
drawJournal(2, LINES_PER_PAGE);
doArrows();
screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
- } else if (((btn == BTN_AHEAD110 && events._released) || key == 'A') && _down) {
+ } else if (((btn == BTN_AHEAD110 && events._released) || key == _hotkeyAhead10) && _down) {
// Scroll down 10 pages
if ((_page + 10) > _maxPage)
drawJournal(2, (_maxPage - _page) * LINES_PER_PAGE);
@@ -387,8 +403,8 @@ bool ScalpelJournal::handleEvents(int key) {
doArrows();
screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
- } else if (((btn == BTN_SEARCH && events._released) || key == 'S') && !_journal.empty()) {
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[5][2], JOURNAL_BUTTONS_Y + 11), COMMAND_FOREGROUND, true, "Search");
+ } else if (((btn == BTN_SEARCH && events._released) || key == _hotkeySearch) && !_journal.empty()) {
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[5][2], JOURNAL_BUTTONS_Y + 11), COMMAND_FOREGROUND, true, _fixedTextSearch);
bool notFound = false;
do {
@@ -418,7 +434,7 @@ bool ScalpelJournal::handleEvents(int key) {
} while (!doneFlag);
doneFlag = false;
- } else if (((btn == BTN_FIRST_PAGE && events._released) || key == 'F') && _up) {
+ } else if (((btn == BTN_FIRST_PAGE && events._released) || key == _hotkeyFirstPage) && _up) {
// First page
_index = _sub = 0;
_up = _down = false;
@@ -429,7 +445,7 @@ bool ScalpelJournal::handleEvents(int key) {
doArrows();
screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
- } else if (((btn == BTN_LAST_PAGE && events._released) || key == 'L') && _down) {
+ } else if (((btn == BTN_LAST_PAGE && events._released) || key == _hotkeyLastPage) && _down) {
// Last page
if ((_page + 10) > _maxPage)
drawJournal(2, (_maxPage - _page) * LINES_PER_PAGE);
@@ -449,7 +465,6 @@ int ScalpelJournal::getSearchString(bool printError) {
enum Button { BTN_NONE, BTN_EXIT, BTN_BACKWARD, BTN_FORWARD };
Events &events = *_vm->_events;
- FixedText &fixedText = *_vm->_fixedText;
ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
Talk &talk = *_vm->_talk;
int xp;
@@ -459,37 +474,20 @@ int ScalpelJournal::getSearchString(bool printError) {
int done = 0;
byte color;
- Common::String fixedText_Exit = fixedText.getText(kFixedText_JournalSearch_Exit);
- Common::String fixedText_Backward = fixedText.getText(kFixedText_JournalSearch_Backward);
- Common::String fixedText_Forward = fixedText.getText(kFixedText_JournalSearch_Forward);
- Common::String fixedText_NotFound = fixedText.getText(kFixedText_JournalSearch_NotFound);
-
// Draw search panel
screen.makePanel(Common::Rect(6, 171, 313, 199));
screen.makeButton(Common::Rect(SEARCH_POINTS[0][0], yp, SEARCH_POINTS[0][1], yp + 10),
- SEARCH_POINTS[0][2] - screen.stringWidth(fixedText_Exit) / 2, fixedText_Exit);
+ SEARCH_POINTS[0][2], _fixedTextSearchExit);
screen.makeButton(Common::Rect(SEARCH_POINTS[1][0], yp, SEARCH_POINTS[1][1], yp + 10),
- SEARCH_POINTS[1][2] - screen.stringWidth(fixedText_Backward) / 2, fixedText_Backward);
+ SEARCH_POINTS[1][2], _fixedTextSearchBackward);
screen.makeButton(Common::Rect(SEARCH_POINTS[2][0], yp, SEARCH_POINTS[2][1], yp + 10),
- SEARCH_POINTS[2][2] - screen.stringWidth(fixedText_Forward) / 2, fixedText_Forward);
-
- screen.gPrint(Common::Point(SEARCH_POINTS[0][2] - screen.stringWidth(fixedText_Exit) / 2, yp),
- COMMAND_HIGHLIGHTED, "%c", fixedText_Exit[0]);
- screen.gPrint(Common::Point(SEARCH_POINTS[1][2] - screen.stringWidth(fixedText_Backward) / 2, yp),
- COMMAND_HIGHLIGHTED, "%c", fixedText_Backward[0]);
- screen.gPrint(Common::Point(SEARCH_POINTS[2][2] - screen.stringWidth(fixedText_Forward) / 2, yp),
- COMMAND_HIGHLIGHTED, "%c", fixedText_Forward[0]);
+ SEARCH_POINTS[2][2], _fixedTextSearchForward);
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(fixedText_NotFound)) / 2, 185),
- INV_FOREGROUND, "%s", fixedText_NotFound.c_str());
+ screen.gPrint(Common::Point((SHERLOCK_SCREEN_WIDTH - screen.stringWidth(_fixedTextSearchNotFound)) / 2, 185),
+ INV_FOREGROUND, "%s", _fixedTextSearchNotFound.c_str());
} else if (!_find.empty()) {
// There's already a search term, display it already
screen.gPrint(Common::Point(15, 185), TALK_FOREGROUND, "%s", _find.c_str());
@@ -544,7 +542,7 @@ int ScalpelJournal::getSearchString(bool printError) {
} else {
color = COMMAND_FOREGROUND;
}
- screen.print(Common::Point(SEARCH_POINTS[0][2] - screen.stringWidth(fixedText_Exit) / 2, 175), color, "%s", fixedText_Exit.c_str());
+ screen.buttonPrint(Common::Point(SEARCH_POINTS[0][0], SEARCH_POINTS[0][2]), color, false, _fixedTextSearchExit);
if (pt.x > SEARCH_POINTS[1][0] && pt.x < SEARCH_POINTS[1][1] && pt.y > 174 && pt.y < 183) {
found = BTN_BACKWARD;
@@ -552,7 +550,7 @@ int ScalpelJournal::getSearchString(bool printError) {
} else {
color = COMMAND_FOREGROUND;
}
- screen.print(Common::Point(SEARCH_POINTS[1][2] - screen.stringWidth(fixedText_Backward) / 2, 175), color, "%s", fixedText_Backward.c_str());
+ screen.buttonPrint(Common::Point(SEARCH_POINTS[1][0], SEARCH_POINTS[1][2]), color, false, _fixedTextSearchBackward);
if (pt.x > SEARCH_POINTS[2][0] && pt.x < SEARCH_POINTS[2][1] && pt.y > 174 && pt.y < 183) {
found = BTN_FORWARD;
@@ -560,7 +558,7 @@ int ScalpelJournal::getSearchString(bool printError) {
} else {
color = COMMAND_FOREGROUND;
}
- screen.print(Common::Point(SEARCH_POINTS[2][2] - screen.stringWidth(fixedText_Forward) / 2, 175), color, "%s", fixedText_Forward.c_str());
+ screen.buttonPrint(Common::Point(SEARCH_POINTS[2][0], SEARCH_POINTS[2][2]), color, false, _fixedTextSearchForward);
}
events.wait(2);
diff --git a/engines/sherlock/scalpel/scalpel_journal.h b/engines/sherlock/scalpel/scalpel_journal.h
index c8e9c01739..50f1917fca 100644
--- a/engines/sherlock/scalpel/scalpel_journal.h
+++ b/engines/sherlock/scalpel/scalpel_journal.h
@@ -41,6 +41,37 @@ enum JournalButton {
};
class ScalpelJournal: public Journal {
+public:
+ Common::String _fixedTextWatsonsJournal;
+ Common::String _fixedTextExit;
+ Common::String _fixedTextBack10;
+ Common::String _fixedTextUp;
+ Common::String _fixedTextDown;
+ Common::String _fixedTextAhead10;
+ Common::String _fixedTextSearch;
+ Common::String _fixedTextFirstPage;
+ Common::String _fixedTextLastPage;
+ Common::String _fixedTextPrintText;
+
+ byte _hotkeyExit;
+ byte _hotkeyBack10;
+ byte _hotkeyUp;
+ byte _hotkeyDown;
+ byte _hotkeyAhead10;
+ byte _hotkeySearch;
+ byte _hotkeyFirstPage;
+ byte _hotkeyLastPage;
+ byte _hotkeyPrintText;
+
+ Common::String _fixedTextSearchExit;
+ Common::String _fixedTextSearchBackward;
+ Common::String _fixedTextSearchForward;
+ Common::String _fixedTextSearchNotFound;
+
+ byte _hotkeySearchExit;
+ byte _hotkeySearchBackward;
+ byte _hotkeySearchForward;
+
private:
/**
* Load the list of journal locations
diff --git a/engines/sherlock/scalpel/scalpel_map.cpp b/engines/sherlock/scalpel/scalpel_map.cpp
index 369822ba02..ba14b5b300 100644
--- a/engines/sherlock/scalpel/scalpel_map.cpp
+++ b/engines/sherlock/scalpel/scalpel_map.cpp
@@ -100,6 +100,21 @@ void ScalpelMap::loadData() {
while ((c = txtStream->readByte()) != '\0')
line += c;
+ // WORKAROUND: Special fixes for faulty translations
+ // Was obviously not done in the original interpreter
+ if (_vm->getLanguage() == Common::ES_ESP) {
+ // Spanish version
+ if (line == " Alley") {
+ // The "Alley" location was not translated, we do this now
+ // see bug #6931
+ line = " Callejon";
+ } else if (line == " Alamacen") {
+ // "Warehouse" location has a typo, we fix it
+ // see bug #6931
+ line = " Almacen";
+ }
+ }
+
_locationNames.push_back(line);
}
@@ -152,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;
@@ -223,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();
@@ -344,7 +359,6 @@ void ScalpelMap::freeSprites() {
delete _mapCursors;
delete _shapes;
delete _iconShapes;
- _iconSave.free();
}
void ScalpelMap::showPlaces() {
@@ -361,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));
}
}
@@ -373,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) {
@@ -394,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) {
@@ -436,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);
@@ -538,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;
@@ -550,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_saveload.cpp b/engines/sherlock/scalpel/scalpel_saveload.cpp
index 01ba149813..90eab5930c 100644
--- a/engines/sherlock/scalpel/scalpel_saveload.cpp
+++ b/engines/sherlock/scalpel/scalpel_saveload.cpp
@@ -20,6 +20,7 @@
*
*/
+#include "sherlock/scalpel/scalpel_fixed_text.h"
#include "sherlock/scalpel/scalpel_saveload.h"
#include "sherlock/scalpel/scalpel_screen.h"
#include "sherlock/scalpel/scalpel.h"
@@ -39,7 +40,44 @@ const int ENV_POINTS[6][3] = {
/*----------------------------------------------------------------*/
-ScalpelSaveManager::ScalpelSaveManager(SherlockEngine *vm, const Common::String &target) : SaveManager(vm, target) {
+ScalpelSaveManager::ScalpelSaveManager(SherlockEngine *vm, const Common::String &target) :
+ SaveManager(vm, target), _envMode(SAVEMODE_NONE) {
+
+ _fixedTextExit = FIXED(LoadSave_Exit);
+ _fixedTextLoad = FIXED(LoadSave_Load);
+ _fixedTextSave = FIXED(LoadSave_Save);
+ _fixedTextUp = FIXED(LoadSave_Up);
+ _fixedTextDown = FIXED(LoadSave_Down);
+ _fixedTextQuit = FIXED(LoadSave_Quit);
+
+ _hotkeyExit = toupper(_fixedTextExit[0]);
+ _hotkeyLoad = toupper(_fixedTextLoad[0]);
+ _hotkeySave = toupper(_fixedTextSave[0]);
+ _hotkeyUp = toupper(_fixedTextUp[0]);
+ _hotkeyDown = toupper(_fixedTextDown[0]);
+ _hotkeyQuit = toupper(_fixedTextQuit[0]);
+
+ _hotkeysIndexed[0] = _hotkeyExit;
+ _hotkeysIndexed[1] = _hotkeyLoad;
+ _hotkeysIndexed[2] = _hotkeySave;
+ _hotkeysIndexed[3] = _hotkeyUp;
+ _hotkeysIndexed[4] = _hotkeyDown;
+ _hotkeysIndexed[5] = _hotkeyQuit;
+
+ _fixedTextQuitGameQuestion = FIXED(QuitGame_Question);
+ _fixedTextQuitGameYes = FIXED(QuitGame_Yes);
+ _fixedTextQuitGameNo = FIXED(QuitGame_No);
+
+ _hotkeyQuitGameYes = toupper(_fixedTextQuitGameYes[0]);
+ _hotkeyQuitGameNo = toupper(_fixedTextQuitGameNo[0]);
+}
+
+int ScalpelSaveManager::identifyUserButton(int key) {
+ for (uint16 hotkeyNr = 0; hotkeyNr < sizeof(_hotkeysIndexed); hotkeyNr++) {
+ if (key == _hotkeysIndexed[hotkeyNr])
+ return hotkeyNr;
+ }
+ return -1;
}
void ScalpelSaveManager::drawInterface() {
@@ -56,23 +94,23 @@ void ScalpelSaveManager::drawInterface() {
screen._backBuffer1.fillRect(Common::Rect(2, CONTROLS_Y + 10, SHERLOCK_SCREEN_WIDTH - 2, SHERLOCK_SCREEN_HEIGHT - 2), INV_BACKGROUND);
screen.makeButton(Common::Rect(ENV_POINTS[0][0], CONTROLS_Y, ENV_POINTS[0][1], CONTROLS_Y + 10),
- ENV_POINTS[0][2] - screen.stringWidth("Exit") / 2, "Exit");
+ ENV_POINTS[0][2], _fixedTextExit);
screen.makeButton(Common::Rect(ENV_POINTS[1][0], CONTROLS_Y, ENV_POINTS[1][1], CONTROLS_Y + 10),
- ENV_POINTS[1][2] - screen.stringWidth("Load") / 2, "Load");
+ ENV_POINTS[1][2], _fixedTextLoad);
screen.makeButton(Common::Rect(ENV_POINTS[2][0], CONTROLS_Y, ENV_POINTS[2][1], CONTROLS_Y + 10),
- ENV_POINTS[2][2] - screen.stringWidth("Save") / 2, "Save");
+ ENV_POINTS[2][2], _fixedTextSave);
screen.makeButton(Common::Rect(ENV_POINTS[3][0], CONTROLS_Y, ENV_POINTS[3][1], CONTROLS_Y + 10),
- ENV_POINTS[3][2] - screen.stringWidth("Up") / 2, "Up");
+ ENV_POINTS[3][2], _fixedTextUp);
screen.makeButton(Common::Rect(ENV_POINTS[4][0], CONTROLS_Y, ENV_POINTS[4][1], CONTROLS_Y + 10),
- ENV_POINTS[4][2] - screen.stringWidth("Down") / 2, "Down");
+ ENV_POINTS[4][2], _fixedTextDown);
screen.makeButton(Common::Rect(ENV_POINTS[5][0], CONTROLS_Y, ENV_POINTS[5][1], CONTROLS_Y + 10),
- ENV_POINTS[5][2] - screen.stringWidth("Quit") / 2, "Quit");
+ ENV_POINTS[5][2], _fixedTextQuit);
if (!_savegameIndex)
- screen.buttonPrint(Common::Point(ENV_POINTS[3][2], CONTROLS_Y), COMMAND_NULL, 0, "Up");
+ screen.buttonPrint(Common::Point(ENV_POINTS[3][2], CONTROLS_Y), COMMAND_NULL, 0, _fixedTextUp);
if (_savegameIndex == MAX_SAVEGAME_SLOTS - ONSCREEN_FILES_COUNT)
- screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), COMMAND_NULL, 0, "Down");
+ screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), COMMAND_NULL, 0, _fixedTextDown);
for (int idx = _savegameIndex; idx < _savegameIndex + ONSCREEN_FILES_COUNT; ++idx) {
screen.gPrint(Common::Point(6, CONTROLS_Y + 11 + (idx - _savegameIndex) * 10),
@@ -106,31 +144,31 @@ void ScalpelSaveManager::highlightButtons(int btnIndex) {
ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
byte color = (btnIndex == 0) ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND;
- screen.buttonPrint(Common::Point(ENV_POINTS[0][2], CONTROLS_Y), color, 1, "Exit");
+ screen.buttonPrint(Common::Point(ENV_POINTS[0][2], CONTROLS_Y), color, 1, _fixedTextExit);
if ((btnIndex == 1) || ((_envMode == SAVEMODE_LOAD) && (btnIndex != 2)))
- screen.buttonPrint(Common::Point(ENV_POINTS[1][2], CONTROLS_Y), COMMAND_HIGHLIGHTED, true, "Load");
+ screen.buttonPrint(Common::Point(ENV_POINTS[1][2], CONTROLS_Y), COMMAND_HIGHLIGHTED, true, _fixedTextLoad);
else
- screen.buttonPrint(Common::Point(ENV_POINTS[1][2], CONTROLS_Y), COMMAND_FOREGROUND, true, "Load");
+ screen.buttonPrint(Common::Point(ENV_POINTS[1][2], CONTROLS_Y), COMMAND_FOREGROUND, true, _fixedTextLoad);
if ((btnIndex == 2) || ((_envMode == SAVEMODE_SAVE) && (btnIndex != 1)))
- screen.buttonPrint(Common::Point(ENV_POINTS[2][2], CONTROLS_Y), COMMAND_HIGHLIGHTED, true, "Save");
+ screen.buttonPrint(Common::Point(ENV_POINTS[2][2], CONTROLS_Y), COMMAND_HIGHLIGHTED, true, _fixedTextSave);
else
- screen.buttonPrint(Common::Point(ENV_POINTS[2][2], CONTROLS_Y), COMMAND_FOREGROUND, true, "Save");
+ screen.buttonPrint(Common::Point(ENV_POINTS[2][2], CONTROLS_Y), COMMAND_FOREGROUND, true, _fixedTextSave);
if (btnIndex == 3 && _savegameIndex)
- screen.buttonPrint(Common::Point(ENV_POINTS[3][2], CONTROLS_Y), COMMAND_HIGHLIGHTED, true, "Up");
+ screen.buttonPrint(Common::Point(ENV_POINTS[3][2], CONTROLS_Y), COMMAND_HIGHLIGHTED, true, _fixedTextUp);
else
if (_savegameIndex)
- screen.buttonPrint(Common::Point(ENV_POINTS[3][2], CONTROLS_Y), COMMAND_FOREGROUND, true, "Up");
+ screen.buttonPrint(Common::Point(ENV_POINTS[3][2], CONTROLS_Y), COMMAND_FOREGROUND, true, _fixedTextUp);
if ((btnIndex == 4) && (_savegameIndex < MAX_SAVEGAME_SLOTS - 5))
- screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), COMMAND_HIGHLIGHTED, true, "Down");
+ screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), COMMAND_HIGHLIGHTED, true, _fixedTextDown);
else if (_savegameIndex < (MAX_SAVEGAME_SLOTS - 5))
- screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), COMMAND_FOREGROUND, true, "Down");
+ screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), COMMAND_FOREGROUND, true, _fixedTextDown);
color = (btnIndex == 5) ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND;
- screen.buttonPrint(Common::Point(ENV_POINTS[5][2], CONTROLS_Y), color, 1, "Quit");
+ screen.buttonPrint(Common::Point(ENV_POINTS[5][2], CONTROLS_Y), color, 1, _fixedTextQuit);
}
bool ScalpelSaveManager::checkGameOnScreen(int slot) {
@@ -153,10 +191,10 @@ bool ScalpelSaveManager::checkGameOnScreen(int slot) {
screen.slamRect(Common::Rect(3, CONTROLS_Y + 11, 318, SHERLOCK_SCREEN_HEIGHT));
byte color = !_savegameIndex ? COMMAND_NULL : COMMAND_FOREGROUND;
- screen.buttonPrint(Common::Point(ENV_POINTS[3][2], CONTROLS_Y), color, 1, "Up");
+ screen.buttonPrint(Common::Point(ENV_POINTS[3][2], CONTROLS_Y), color, 1, _fixedTextUp);
color = (_savegameIndex == (MAX_SAVEGAME_SLOTS - 5)) ? COMMAND_NULL : COMMAND_FOREGROUND;
- screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), color, 1, "Down");
+ screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), color, 1, _fixedTextDown);
return true;
}
@@ -172,12 +210,12 @@ bool ScalpelSaveManager::promptForDescription(int slot) {
int xp, yp;
bool flag = false;
- screen.buttonPrint(Common::Point(ENV_POINTS[0][2], CONTROLS_Y), COMMAND_NULL, true, "Exit");
- screen.buttonPrint(Common::Point(ENV_POINTS[1][2], CONTROLS_Y), COMMAND_NULL, true, "Load");
- screen.buttonPrint(Common::Point(ENV_POINTS[2][2], CONTROLS_Y), COMMAND_NULL, true, "Save");
- screen.buttonPrint(Common::Point(ENV_POINTS[3][2], CONTROLS_Y), COMMAND_NULL, true, "Up");
- screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), COMMAND_NULL, true, "Down");
- screen.buttonPrint(Common::Point(ENV_POINTS[5][2], CONTROLS_Y), COMMAND_NULL, true, "Quit");
+ screen.buttonPrint(Common::Point(ENV_POINTS[0][2], CONTROLS_Y), COMMAND_NULL, true, _fixedTextExit);
+ screen.buttonPrint(Common::Point(ENV_POINTS[1][2], CONTROLS_Y), COMMAND_NULL, true, _fixedTextLoad);
+ screen.buttonPrint(Common::Point(ENV_POINTS[2][2], CONTROLS_Y), COMMAND_NULL, true, _fixedTextSave);
+ screen.buttonPrint(Common::Point(ENV_POINTS[3][2], CONTROLS_Y), COMMAND_NULL, true, _fixedTextUp);
+ screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), COMMAND_NULL, true, _fixedTextDown);
+ screen.buttonPrint(Common::Point(ENV_POINTS[5][2], CONTROLS_Y), COMMAND_NULL, true, _fixedTextQuit);
Common::String saveName = _savegames[slot];
if (isSlotEmpty(slot)) {
diff --git a/engines/sherlock/scalpel/scalpel_saveload.h b/engines/sherlock/scalpel/scalpel_saveload.h
index 6b035cace3..81e3d834aa 100644
--- a/engines/sherlock/scalpel/scalpel_saveload.h
+++ b/engines/sherlock/scalpel/scalpel_saveload.h
@@ -34,6 +34,30 @@ extern const int ENV_POINTS[6][3];
class ScalpelSaveManager: public SaveManager {
public:
SaveMode _envMode;
+
+ Common::String _fixedTextExit;
+ Common::String _fixedTextLoad;
+ Common::String _fixedTextSave;
+ Common::String _fixedTextUp;
+ Common::String _fixedTextDown;
+ Common::String _fixedTextQuit;
+
+ byte _hotkeyExit;
+ byte _hotkeyLoad;
+ byte _hotkeySave;
+ byte _hotkeyUp;
+ byte _hotkeyDown;
+ byte _hotkeyQuit;
+
+ byte _hotkeysIndexed[6];
+
+ Common::String _fixedTextQuitGameQuestion;
+ Common::String _fixedTextQuitGameYes;
+ Common::String _fixedTextQuitGameNo;
+
+ byte _hotkeyQuitGameYes;
+ byte _hotkeyQuitGameNo;
+
public:
ScalpelSaveManager(SherlockEngine *vm, const Common::String &target);
virtual ~ScalpelSaveManager() {}
@@ -62,6 +86,11 @@ public:
* Prompts the user to enter a description in a given slot
*/
bool promptForDescription(int slot);
+
+ /**
+ * Identifies a button number according to the key, that the user pressed
+ */
+ int identifyUserButton(int key);
};
} // End of namespace Scalpel
diff --git a/engines/sherlock/scalpel/scalpel_scene.cpp b/engines/sherlock/scalpel/scalpel_scene.cpp
index b2c7339363..11fb807c3b 100644
--- a/engines/sherlock/scalpel/scalpel_scene.cpp
+++ b/engines/sherlock/scalpel/scalpel_scene.cpp
@@ -40,6 +40,11 @@ const int FS_TRANS[8] = {
/*----------------------------------------------------------------*/
+ScalpelScene::~ScalpelScene() {
+ for (uint idx = 0; idx < _canimShapes.size(); ++idx)
+ delete _canimShapes[idx];
+}
+
bool ScalpelScene::loadScene(const Common::String &filename) {
ScalpelMap &map = *(ScalpelMap *)_vm->_map;
bool result = Scene::loadScene(filename);
@@ -66,27 +71,27 @@ 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,
- _canimShapes[idx]._position, _canimShapes[idx]._flags & OBJ_FLIPPED);
+ if (_canimShapes[idx]->_type == ACTIVE_BG_SHAPE && _canimShapes[idx]->_misc == BEHIND)
+ 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,
- _canimShapes[idx]._flags & OBJ_FLIPPED);
+ if (_canimShapes[idx]->_type == ACTIVE_BG_SHAPE && _canimShapes[idx]->_misc == NORMAL_BEHIND)
+ screen.getBackBuffer()->SHtransBlitFrom(*_canimShapes[idx]->_imageFrame, _canimShapes[idx]->_position,
+ _canimShapes[idx]->_flags & OBJ_FLIPPED);
}
// Draw any active characters
@@ -98,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);
}
}
@@ -107,16 +112,16 @@ 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);
}
// Draw all static and active canimations that are NORMAL and are in front of the player
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,
- _canimShapes[idx]._flags & OBJ_FLIPPED);
+ if ((_canimShapes[idx]->_type == ACTIVE_BG_SHAPE || _canimShapes[idx]->_type == STATIC_BG_SHAPE) &&
+ _canimShapes[idx]->_misc == NORMAL_FORWARD)
+ screen.getBackBuffer()->SHtransBlitFrom(*_canimShapes[idx]->_imageFrame, _canimShapes[idx]->_position,
+ _canimShapes[idx]->_flags & OBJ_FLIPPED);
}
// Draw all static and active shapes that are FORWARD
@@ -127,16 +132,16 @@ 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);
}
// Draw all static and active canimations that are forward
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,
- _canimShapes[idx]._flags & OBJ_FLIPPED);
+ if ((_canimShapes[idx]->_type == ACTIVE_BG_SHAPE || _canimShapes[idx]->_type == STATIC_BG_SHAPE) &&
+ _canimShapes[idx]->_misc == FORWARD)
+ screen.getBackBuffer()->SHtransBlitFrom(*_canimShapes[idx]->_imageFrame, _canimShapes[idx]->_position,
+ _canimShapes[idx]->_flags & OBJ_FLIPPED);
}
screen.resetDisplayBounds();
@@ -152,7 +157,7 @@ void ScalpelScene::checkBgShapes() {
// Iterate through the canim list
for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
- Object &obj = _canimShapes[idx];
+ Object &obj = *_canimShapes[idx];
if (obj._type == STATIC_BG_SHAPE || obj._type == ACTIVE_BG_SHAPE) {
if ((obj._flags & 5) == 1) {
obj._misc = (pt.y < (obj._position.y + obj._imageFrame->_frame.h - 1)) ?
@@ -221,8 +226,8 @@ void ScalpelScene::doBgAnim() {
people._portrait.checkObject();
for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
- if (_canimShapes[idx]._type != INVALID && _canimShapes[idx]._type != REMOVE)
- _canimShapes[idx].checkObject();
+ if (_canimShapes[idx]->_type != INVALID && _canimShapes[idx]->_type != REMOVE)
+ _canimShapes[idx]->checkObject();
}
if (_currentScene == DRAWING_ROOM)
@@ -237,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];
@@ -256,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));
@@ -266,7 +271,7 @@ void ScalpelScene::doBgAnim() {
}
for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
- Object &o = _canimShapes[idx];
+ Object &o = *_canimShapes[idx];
if (o._type == ACTIVE_BG_SHAPE || o._type == HIDE_SHAPE || o._type == REMOVE)
screen.restoreBackground(Common::Rect(o._oldPosition.x, o._oldPosition.y,
o._oldPosition.x + o._oldSize.x, o._oldPosition.y + o._oldSize.y));
@@ -287,8 +292,8 @@ void ScalpelScene::doBgAnim() {
people._portrait.adjustObject();
for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
- if (_canimShapes[idx]._type != INVALID)
- _canimShapes[idx].adjustObject();
+ if (_canimShapes[idx]->_type != INVALID)
+ _canimShapes[idx]->adjustObject();
}
if (people[HOLMES]._type == CHARACTER && people._holmesOn)
@@ -304,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];
+ 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);
}
}
@@ -319,19 +324,19 @@ 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];
+ 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);
}
}
- // Draw the person if not animating
- if (people[HOLMES]._type == CHARACTER && people[HOLMES]._walkLoaded) {
+ // Draw the player if he's active and his walk has been loaded into memory
+ if (people[HOLMES]._type == CHARACTER && people[HOLMES]._walkLoaded && people._holmesOn) {
// If Holmes is too far to the right, move him back so he's on-screen
int xRight = SHERLOCK_SCREEN_WIDTH - 2 - people[HOLMES]._imageFrame->_frame.w;
int tempX = MIN(people[HOLMES]._position.x / FIXED_INT_MULTIPLIER, xRight);
@@ -339,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);
}
@@ -347,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];
+ 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);
}
}
@@ -362,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];
+ 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);
}
}
@@ -382,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
@@ -450,16 +455,18 @@ void ScalpelScene::doBgAnim() {
}
for (int idx = _canimShapes.size() - 1; idx >= 0; --idx) {
- Object &o = _canimShapes[idx];
+ Object &o = *_canimShapes[idx];
if (o._type == INVALID) {
// Anim shape was invalidated by checkEndOfSequence, so at this point we can remove it
+ delete _canimShapes[idx];
_canimShapes.remove_at(idx);
} else if (o._type == REMOVE) {
if (_goToScene == -1)
screen.slamArea(o._position.x, o._position.y, o._delta.x, o._delta.y);
// Shape for an animation is no longer needed, so remove it completely
+ delete _canimShapes[idx];
_canimShapes.remove_at(idx);
} else if (o._type == ACTIVE_BG_SHAPE) {
screen.flushImage(o._imageFrame, o._position,
@@ -496,6 +503,7 @@ int ScalpelScene::startCAnim(int cAnimNum, int playRate) {
int tpDir, walkDir;
int tFrames = 0;
int gotoCode = -1;
+ Object *cObj;
// Validation
if (cAnimNum >= (int)_cAnim.size())
@@ -533,33 +541,33 @@ int ScalpelScene::startCAnim(int cAnimNum, int playRate) {
return 1;
// Add new anim shape entry for displaying the animation
- _canimShapes.push_back(Object());
- Object &cObj = _canimShapes[_canimShapes.size() - 1];
+ cObj = new Object();
+ _canimShapes.push_back(cObj);
// Copy the canimation into the bgShapes type canimation structure so it can be played
- cObj._allow = cAnimNum + 1; // Keep track of the parent structure
- cObj._name = _cAnim[cAnimNum]._name; // Copy name
+ cObj->_allow = cAnimNum + 1; // Keep track of the parent structure
+ cObj->_name = _cAnim[cAnimNum]._name; // Copy name
// Remove any attempt to draw object frame
if (cAnim._type == NO_SHAPE && cAnim._sequences[0] < 100)
cAnim._sequences[0] = 0;
- cObj._sequences = cAnim._sequences;
- cObj._images = nullptr;
- cObj._position = cAnim._position;
- cObj._delta = Common::Point(0, 0);
- cObj._type = cAnim._type;
- cObj._flags = cAnim._flags;
-
- cObj._maxFrames = 0;
- cObj._frameNumber = -1;
- cObj._sequenceNumber = cAnimNum;
- cObj._oldPosition = Common::Point(0, 0);
- cObj._oldSize = Common::Point(0, 0);
- cObj._goto = Common::Point(0, 0);
- cObj._status = 0;
- cObj._misc = 0;
- cObj._imageFrame = nullptr;
+ cObj->_sequences = cAnim._sequences;
+ cObj->_images = nullptr;
+ cObj->_position = cAnim._position;
+ cObj->_delta = Common::Point(0, 0);
+ cObj->_type = cAnim._type;
+ cObj->_flags = cAnim._flags;
+
+ cObj->_maxFrames = 0;
+ cObj->_frameNumber = -1;
+ cObj->_sequenceNumber = cAnimNum;
+ cObj->_oldPosition = Common::Point(0, 0);
+ cObj->_oldSize = Common::Point(0, 0);
+ cObj->_goto = Common::Point(0, 0);
+ cObj->_status = 0;
+ cObj->_misc = 0;
+ cObj->_imageFrame = nullptr;
if (cAnim._name.size() > 0 && cAnim._type != NO_SHAPE) {
if (tpPos.x != -1)
@@ -584,25 +592,25 @@ int ScalpelScene::startCAnim(int cAnimNum, int playRate) {
// Now load the resource as an image
if (!IS_3DO) {
- cObj._images = new ImageFile(fname);
+ cObj->_images = new ImageFile(fname);
} else {
- cObj._images = new ImageFile3DO(fname, kImageFile3DOType_RoomFormat);
+ cObj->_images = new ImageFile3DO(fname, kImageFile3DOType_RoomFormat);
}
- cObj._imageFrame = &(*cObj._images)[0];
- cObj._maxFrames = cObj._images->size();
+ cObj->_imageFrame = &(*cObj->_images)[0];
+ cObj->_maxFrames = cObj->_images->size();
int frames = 0;
if (playRate < 0) {
// Reverse direction
// Count number of frames
- while (frames < MAX_FRAME && cObj._sequences[frames])
+ while (frames < MAX_FRAME && cObj->_sequences[frames])
++frames;
} else {
// Forward direction
BaseObject::_countCAnimFrames = true;
- while (cObj._type == ACTIVE_BG_SHAPE) {
- cObj.checkObject();
+ while (cObj->_type == ACTIVE_BG_SHAPE) {
+ cObj->checkObject();
++frames;
if (frames >= 1000)
@@ -614,10 +622,10 @@ int ScalpelScene::startCAnim(int cAnimNum, int playRate) {
BaseObject::_countCAnimFrames = false;
- cObj._type = cAnim._type;
- cObj._frameNumber = -1;
- cObj._position = cAnim._position;
- cObj._delta = Common::Point(0, 0);
+ cObj->_type = cAnim._type;
+ cObj->_frameNumber = -1;
+ cObj->_position = cAnim._position;
+ cObj->_delta = Common::Point(0, 0);
}
// Return if animation has no frames in it
@@ -631,7 +639,7 @@ int ScalpelScene::startCAnim(int cAnimNum, int playRate) {
if (playRate < 0) {
// Play in reverse
dir = -2;
- cObj._frameNumber = frames - 3;
+ cObj->_frameNumber = frames - 3;
} else {
dir = 0;
}
@@ -648,14 +656,14 @@ int ScalpelScene::startCAnim(int cAnimNum, int playRate) {
// Repeat same frame
int temp = repeat;
while (--temp > 0) {
- cObj._frameNumber--;
+ cObj->_frameNumber--;
doBgAnim();
if (_vm->shouldQuit())
return 0;
}
- cObj._frameNumber += dir;
+ cObj->_frameNumber += dir;
}
people[HOLMES]._type = CHARACTER;
@@ -670,14 +678,18 @@ int ScalpelScene::startCAnim(int cAnimNum, int playRate) {
if (playRate < 0)
// Reverse direction - set to end sequence
- cObj._frameNumber = tFrames - 1;
+ cObj->_frameNumber = tFrames - 1;
- if (cObj._frameNumber <= 26)
- gotoCode = cObj._sequences[cObj._frameNumber + 3];
+ if (cObj->_frameNumber <= 26)
+ gotoCode = cObj->_sequences[cObj->_frameNumber + 3];
- // Unless anim shape has already been freed, set it to REMOVE so doBgAnim can free it
- if (_canimShapes.indexOf(cObj) != -1)
- cObj.checkObject();
+ // Unless anim shape has already been removed, do a final check to allow it to become REMOVEd
+ for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
+ if (_canimShapes[idx] == cObj) {
+ cObj->checkObject();
+ break;
+ }
+ }
if (gotoCode > 0 && !talk._talkToAbort) {
_goToScene = gotoCode;
diff --git a/engines/sherlock/scalpel/scalpel_scene.h b/engines/sherlock/scalpel/scalpel_scene.h
index 8fe3b66b38..8711fea2d0 100644
--- a/engines/sherlock/scalpel/scalpel_scene.h
+++ b/engines/sherlock/scalpel/scalpel_scene.h
@@ -75,6 +75,8 @@ protected:
public:
ScalpelScene(SherlockEngine *vm) : Scene(vm) {}
+ virtual ~ScalpelScene();
+
/**
* Draw all objects and characters.
*/
diff --git a/engines/sherlock/scalpel/scalpel_screen.cpp b/engines/sherlock/scalpel/scalpel_screen.cpp
index 71bcca5dc5..15e8436be6 100644
--- a/engines/sherlock/scalpel/scalpel_screen.cpp
+++ b/engines/sherlock/scalpel/scalpel_screen.cpp
@@ -28,313 +28,102 @@ 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 &str) {
+ 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);
bb.fillRect(Common::Rect(bounds.left + 1, bounds.bottom - 1, bounds.right, bounds.bottom), BUTTON_BOTTOM);
bb.fillRect(Common::Rect(bounds.left + 1, bounds.top + 1, bounds.right - 1, bounds.bottom - 1), BUTTON_MIDDLE);
- gPrint(Common::Point(textX, bounds.top), COMMAND_HIGHLIGHTED, "%c", str[0]);
- gPrint(Common::Point(textX + charWidth(str[0]), bounds.top),
- COMMAND_FOREGROUND, "%s", str.c_str() + 1);
+ buttonPrint(Common::Point(textX, bounds.top), COMMAND_FOREGROUND, false, buttonText, textContainsHotkey);
}
+// ButtonText is supposed to have its hotkey as a prefix. The hotkey will get highlighted.
void ScalpelScreen::buttonPrint(const Common::Point &pt, uint color, bool slamIt,
- const Common::String &str) {
- int xStart = pt.x - stringWidth(str) / 2;
+ const Common::String &buttonText, bool textContainsHotkey) {
+ int xStart = pt.x;
+ int skipTextOffset = textContainsHotkey ? +1 : 0; // skip first char in case text contains hotkey
- if (color == COMMAND_FOREGROUND) {
- // First character needs to be highlighted
- if (slamIt) {
- print(Common::Point(xStart, pt.y + 1), COMMAND_HIGHLIGHTED, "%c", str[0]);
- print(Common::Point(xStart + charWidth(str[0]), pt.y + 1),
- COMMAND_FOREGROUND, "%s", str.c_str() + 1);
- } else {
- gPrint(Common::Point(xStart, pt.y), COMMAND_HIGHLIGHTED, "%c", str[0]);
- gPrint(Common::Point(xStart + charWidth(str[0]), pt.y),
- COMMAND_FOREGROUND, "%s", str.c_str() + 1);
- }
- } else if (slamIt) {
- print(Common::Point(xStart, pt.y + 1), color, "%s", str.c_str());
+ // Center text around given x-coordinate
+ if (textContainsHotkey) {
+ xStart -= (stringWidth(Common::String(buttonText.c_str() + 1)) / 2);
} else {
- gPrint(Common::Point(xStart, pt.y), color, "%s", str.c_str());
- }
-}
-
-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);
-}
-
-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;
- }
+ xStart -= (stringWidth(buttonText) / 2);
}
-}
-
-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;
+ if (color == COMMAND_FOREGROUND) {
+ uint16 prefixOffsetX = 0;
+ byte hotkey = buttonText[0];
+
+ // Hotkey needs to be highlighted
+ if (textContainsHotkey) {
+ Common::String prefixText = Common::String(buttonText.c_str() + 1);
+ uint16 prefixTextLen = prefixText.size();
+ uint16 prefixTextPos = 0;
+
+ // Hotkey was passed additionally, we search for the hotkey inside the button text and
+ // remove it from there. We then draw the whole text as highlighted and afterward
+ // the processed text again as regular text (without the hotkey)
+ while (prefixTextPos < prefixTextLen) {
+ if (prefixText[prefixTextPos] == hotkey) {
+ // Hotkey found, remove remaining text
+ while (prefixTextPos < prefixText.size()) {
+ prefixText.deleteLastChar();
}
-
- pixelsChanged++;
+ break;
}
-
- currentScreenPtr += _vm->_isScreenDoubled ? 2 : 1;
- targetScreenPtr++;
+ prefixTextPos++;
}
- 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;
+ if (prefixTextPos < prefixTextLen) {
+ // only adjust in case hotkey character was actually found
+ prefixOffsetX = stringWidth(prefixText);
}
-
- currentScreenPtr += _vm->_isScreenDoubled ? 2 : 1;
- targetScreenPtr++;
}
- if (_vm->_isScreenDoubled)
- currentScreenPtr += 640;
+ if (slamIt) {
+ print(Common::Point(xStart, pt.y + 1),
+ COMMAND_FOREGROUND, "%s", buttonText.c_str() + skipTextOffset);
+ print(Common::Point(xStart + prefixOffsetX, pt.y + 1), COMMAND_HIGHLIGHTED, "%c", hotkey);
+ } else {
+ gPrint(Common::Point(xStart, pt.y),
+ COMMAND_FOREGROUND, "%s", buttonText.c_str() + skipTextOffset);
+ gPrint(Common::Point(xStart + prefixOffsetX, pt.y), COMMAND_HIGHLIGHTED, "%c", hotkey);
+ }
+ } else if (slamIt) {
+ print(Common::Point(xStart, pt.y + 1), color, "%s", buttonText.c_str() + skipTextOffset);
+ } else {
+ gPrint(Common::Point(xStart, pt.y), color, "%s", buttonText.c_str() + skipTextOffset);
}
-
- // 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 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);
}
-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);
+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);
}
} // End of namespace Scalpel
diff --git a/engines/sherlock/scalpel/scalpel_screen.h b/engines/sherlock/scalpel/scalpel_screen.h
index d6018a44a0..d9be29c8b2 100644
--- a/engines/sherlock/scalpel/scalpel_screen.h
+++ b/engines/sherlock/scalpel/scalpel_screen.h
@@ -38,14 +38,16 @@ public:
/**
* Draws a button for use in the inventory, talk, and examine dialogs.
+ * ButtonText is supposed to have its hotkey as a prefix. The hotkey will get highlighted.
*/
- void makeButton(const Common::Rect &bounds, int textX, const Common::String &str);
+ void makeButton(const Common::Rect &bounds, int textX, const Common::String &buttonText, bool textContainsHotkey = true);
/**
* Prints an interface command with the first letter highlighted to indicate
* what keyboard shortcut is associated with it
+ * ButtonText is supposed to have its hotkey as a prefix. The hotkey will get highlighted.
*/
- void buttonPrint(const Common::Point &pt, uint color, bool slamIt, const Common::String &str);
+ void buttonPrint(const Common::Point &pt, uint color, bool slamIt, const Common::String &buttonText, bool textContainsHotkey = true);
/**
* Draw a panel in the back buffer with a raised area effect around the edges
@@ -59,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 88a718ea4e..ff38c07537 100644
--- a/engines/sherlock/scalpel/scalpel_talk.cpp
+++ b/engines/sherlock/scalpel/scalpel_talk.cpp
@@ -22,6 +22,7 @@
#include "sherlock/scalpel/scalpel_talk.h"
#include "sherlock/scalpel/scalpel_fixed_text.h"
+#include "sherlock/scalpel/scalpel_journal.h"
#include "sherlock/scalpel/scalpel_map.h"
#include "sherlock/scalpel/scalpel_people.h"
#include "sherlock/scalpel/scalpel_scene.h"
@@ -169,6 +170,13 @@ ScalpelTalk::ScalpelTalk(SherlockEngine *vm) : Talk(vm) {
_opcodes = opcodes;
}
+ _fixedTextWindowExit = FIXED(Window_Exit);
+ _fixedTextWindowUp = FIXED(Window_Up);
+ _fixedTextWindowDown = FIXED(Window_Down);
+
+ _hotkeyWindowExit = toupper(_fixedTextWindowExit[0]);
+ _hotkeyWindowUp = toupper(_fixedTextWindowUp[0]);
+ _hotkeyWindowDown = toupper(_fixedTextWindowDown[0]);
}
void ScalpelTalk::talkTo(const Common::String filename) {
@@ -184,23 +192,22 @@ void ScalpelTalk::talkTo(const Common::String filename) {
}
void ScalpelTalk::talkInterface(const byte *&str) {
- FixedText &fixedText = *_vm->_fixedText;
People &people = *_vm->_people;
ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
UserInterface &ui = *_vm->_ui;
+ if (_vm->getLanguage() == Common::DE_DEU)
+ skipBadText(str);
+
// If the window isn't yet open, draw the window before printing starts
if (!ui._windowOpen && _noTextYet) {
_noTextYet = false;
drawInterface();
if (_talkTo != -1) {
- Common::String fixedText_Exit = fixedText.getText(kFixedText_Window_Exit);
- Common::String fixedText_Up = fixedText.getText(kFixedText_Window_Up);
- Common::String fixedText_Down = fixedText.getText(kFixedText_Window_Down);
- screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_NULL, false, fixedText_Exit);
- screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, false, fixedText_Up);
- screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, false, fixedText_Down);
+ screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_NULL, false, _fixedTextWindowExit);
+ screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, false, _fixedTextWindowUp);
+ screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, false, _fixedTextWindowDown);
}
}
@@ -269,7 +276,7 @@ void ScalpelTalk::talkInterface(const byte *&str) {
str += idx;
// If line wrap occurred, then move to after the separating space between the words
- if ((!isOpcode(str[0])) && str[0] != '{')
+ if (str[0] && (!isOpcode(str[0])) && str[0] != '{')
++str;
_yp += 9;
@@ -508,7 +515,6 @@ OpcodeReturn ScalpelTalk::cmdSfxCommand(const byte *&str) {
OpcodeReturn ScalpelTalk::cmdSummonWindow(const byte *&str) {
Events &events = *_vm->_events;
- FixedText &fixedText = *_vm->_fixedText;
ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
drawInterface();
@@ -517,12 +523,9 @@ OpcodeReturn ScalpelTalk::cmdSummonWindow(const byte *&str) {
_noTextYet = false;
if (_speaker != -1) {
- Common::String fixedText_Exit = fixedText.getText(kFixedText_Window_Exit);
- Common::String fixedText_Up = fixedText.getText(kFixedText_Window_Up);
- Common::String fixedText_Down = fixedText.getText(kFixedText_Window_Down);
- screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_NULL, false, fixedText_Exit);
- screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, false, fixedText_Up);
- screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, false, fixedText_Down);
+ screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_NULL, false, _fixedTextWindowExit);
+ screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, false, _fixedTextWindowUp);
+ screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, false, _fixedTextWindowDown);
}
return RET_SUCCESS;
@@ -680,9 +683,8 @@ Common::Point ScalpelTalk::get3doPortraitPosition() const {
}
void ScalpelTalk::drawInterface() {
- FixedText &fixedText = *_vm->_fixedText;
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);
@@ -694,26 +696,25 @@ void ScalpelTalk::drawInterface() {
SHERLOCK_SCREEN_HEIGHT - 2), INV_BACKGROUND);
if (_talkTo != -1) {
- Common::String fixedText_Exit = fixedText.getText(kFixedText_Window_Exit);
- Common::String fixedText_Up = fixedText.getText(kFixedText_Window_Up);
- Common::String fixedText_Down = fixedText.getText(kFixedText_Window_Down);
+ Common::String fixedText_Exit = FIXED(Window_Exit);
+ Common::String fixedText_Up = FIXED(Window_Up);
+ Common::String fixedText_Down = FIXED(Window_Down);
screen.makeButton(Common::Rect(99, CONTROLS_Y, 139, CONTROLS_Y + 10),
- 119 - screen.stringWidth(fixedText_Exit) / 2, fixedText_Exit);
+ 119, fixedText_Exit);
screen.makeButton(Common::Rect(140, CONTROLS_Y, 180, CONTROLS_Y + 10),
- 159 - screen.stringWidth(fixedText_Up) / 2, fixedText_Up);
+ 159, fixedText_Up);
screen.makeButton(Common::Rect(181, CONTROLS_Y, 221, CONTROLS_Y + 10),
- 200 - screen.stringWidth(fixedText_Down) / 2, fixedText_Down);
+ 200, fixedText_Down);
} else {
- int strWidth = screen.stringWidth(Scalpel::PRESS_KEY_TO_CONTINUE);
+ Common::String fixedText_PressKeyToContinue = FIXED(PressKey_ToContinue);
+
screen.makeButton(Common::Rect(46, CONTROLS_Y, 273, CONTROLS_Y + 10),
- 160 - strWidth / 2, Scalpel::PRESS_KEY_TO_CONTINUE);
- screen.gPrint(Common::Point(160 - strWidth / 2, CONTROLS_Y), COMMAND_FOREGROUND, "P");
+ 160, fixedText_PressKeyToContinue);
}
}
bool ScalpelTalk::displayTalk(bool slamIt) {
- FixedText &fixedText = *_vm->_fixedText;
ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
int yp = CONTROLS_Y + 14;
int lineY = -1;
@@ -731,22 +732,20 @@ bool ScalpelTalk::displayTalk(bool slamIt) {
}
// Display the up arrow and enable Up button if the first option is scrolled off-screen
- Common::String fixedText_Up = fixedText.getText(kFixedText_Window_Up);
- Common::String fixedText_Down = fixedText.getText(kFixedText_Window_Down);
if (_moreTalkUp) {
if (slamIt) {
screen.print(Common::Point(5, CONTROLS_Y + 13), INV_FOREGROUND, "~");
- screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_FOREGROUND, true, fixedText_Up);
+ screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_FOREGROUND, true, _fixedTextWindowUp);
} else {
screen.gPrint(Common::Point(5, CONTROLS_Y + 12), INV_FOREGROUND, "~");
- screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_FOREGROUND, false, fixedText_Up);
+ screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_FOREGROUND, false, _fixedTextWindowUp);
}
} else {
if (slamIt) {
- screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, true, fixedText_Up);
+ screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, true, _fixedTextWindowUp);
screen.vgaBar(Common::Rect(5, CONTROLS_Y + 11, 15, CONTROLS_Y + 22), INV_BACKGROUND);
} else {
- screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, false, fixedText_Up);
+ screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, false, _fixedTextWindowUp);
screen._backBuffer1.fillRect(Common::Rect(5, CONTROLS_Y + 11,
15, CONTROLS_Y + 22), INV_BACKGROUND);
}
@@ -781,17 +780,17 @@ bool ScalpelTalk::displayTalk(bool slamIt) {
if (slamIt) {
screen.print(Common::Point(5, 190), INV_FOREGROUND, "|");
- screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_FOREGROUND, true, fixedText_Down);
+ screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_FOREGROUND, true, _fixedTextWindowDown);
} else {
screen.gPrint(Common::Point(5, 189), INV_FOREGROUND, "|");
- screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_FOREGROUND, false, fixedText_Down);
+ screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_FOREGROUND, false, _fixedTextWindowDown);
}
} else {
if (slamIt) {
- screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, true, fixedText_Down);
+ screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, true, _fixedTextWindowDown);
screen.vgaBar(Common::Rect(5, 189, 16, 199), INV_BACKGROUND);
} else {
- screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, false, fixedText_Down);
+ screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, false, _fixedTextWindowDown);
screen._backBuffer1.fillRect(Common::Rect(5, 189, 16, 199), INV_BACKGROUND);
}
}
@@ -888,11 +887,9 @@ int ScalpelTalk::talkLine(int lineNum, int stateNum, byte color, int lineY, bool
}
void ScalpelTalk::showTalk() {
- FixedText &fixedText = *_vm->_fixedText;
People &people = *_vm->_people;
ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
ScalpelUserInterface &ui = *(ScalpelUserInterface *)_vm->_ui;
- Common::String fixedText_Exit = fixedText.getText(kFixedText_Window_Exit);
byte color = ui._endKeyActive ? COMMAND_FOREGROUND : COMMAND_NULL;
clearSequences();
@@ -912,9 +909,9 @@ void ScalpelTalk::showTalk() {
// If the window is already open, simply draw. Otherwise, do it
// to the back buffer and then summon the window
if (ui._windowOpen) {
- screen.buttonPrint(Common::Point(119, CONTROLS_Y), color, true, fixedText_Exit);
+ screen.buttonPrint(Common::Point(119, CONTROLS_Y), color, true, _fixedTextWindowExit);
} else {
- screen.buttonPrint(Common::Point(119, CONTROLS_Y), color, false, fixedText_Exit);
+ screen.buttonPrint(Common::Point(119, CONTROLS_Y), color, false, _fixedTextWindowExit);
if (!ui._slideWindows) {
screen.slamRect(Common::Rect(0, CONTROLS_Y,
@@ -1006,6 +1003,14 @@ void ScalpelTalk::clearSequences() {
_sequenceStack.clear();
}
+void ScalpelTalk::skipBadText(const byte *&msgP) {
+ // WORKAROUND: Skip over bad text in the original game
+ const char *BAD_PHRASE1 = "Change Speaker to Sherlock Holmes ";
+
+ if (!strncmp((const char *)msgP, BAD_PHRASE1, strlen(BAD_PHRASE1)))
+ msgP += strlen(BAD_PHRASE1);
+}
+
} // End of namespace Scalpel
} // End of namespace Sherlock
diff --git a/engines/sherlock/scalpel/scalpel_talk.h b/engines/sherlock/scalpel/scalpel_talk.h
index 4d54273f4a..e542331ce6 100644
--- a/engines/sherlock/scalpel/scalpel_talk.h
+++ b/engines/sherlock/scalpel/scalpel_talk.h
@@ -88,6 +88,14 @@ public:
ScalpelTalk(SherlockEngine *vm);
virtual ~ScalpelTalk() {}
+ Common::String _fixedTextWindowExit;
+ Common::String _fixedTextWindowUp;
+ Common::String _fixedTextWindowDown;
+
+ byte _hotkeyWindowExit;
+ byte _hotkeyWindowUp;
+ byte _hotkeyWindowDown;
+
/**
* Opens the talk file 'talk.tlk' and searches the index for the specified
* conversation. If found, the data for that conversation is loaded
@@ -132,6 +140,11 @@ public:
bool talk3DOMovieTrigger(int subIndex);
/**
+ * Handles skipping over bad text in conversations
+ */
+ static void skipBadText(const byte *&msgP);
+
+ /**
* Push the details of a passed object onto the saved sequences stack
*/
virtual void pushSequenceEntry(Object *obj);
@@ -145,7 +158,7 @@ public:
/**
* Returns true if the script stack is empty
*/
- virtual bool isSequencesEmpty() const { return _scriptStack.empty(); }
+ virtual bool isSequencesEmpty() const { return _sequenceStack.empty(); }
/**
* Clears the stack of pending object sequences associated with speakers in the scene
diff --git a/engines/sherlock/scalpel/scalpel_user_interface.cpp b/engines/sherlock/scalpel/scalpel_user_interface.cpp
index be8f1aaa0c..8dae24ecd4 100644
--- a/engines/sherlock/scalpel/scalpel_user_interface.cpp
+++ b/engines/sherlock/scalpel/scalpel_user_interface.cpp
@@ -64,11 +64,6 @@ const int INVENTORY_POINTS[8][3] = {
{ 285, 315, 294 }
};
-const char COMMANDS[13] = "LMTPOCIUGJFS";
-const char COMMANDS_3DO[13] = "LMTPOCIUGSFF";
-const char INVENTORY_COMMANDS[9] = { "ELUG-+,." };
-const char *const PRESS_KEY_FOR_MORE = "Press any Key for More.";
-const char *const PRESS_KEY_TO_CONTINUE = "Press any Key to Continue.";
const int UI_OFFSET_3DO = 16; // (320 - 288) / 2
/*----------------------------------------------------------------*/
@@ -101,6 +96,43 @@ ScalpelUserInterface::ScalpelUserInterface(SherlockEngine *vm): UserInterface(vm
_cNum = 0;
_find = 0;
_oldUse = 0;
+
+ // Set up hotkeys
+ Common::String gameHotkeys = FIXED(Game_Hotkeys);
+
+ memset(_hotkeysIndexed, 0, sizeof(_hotkeysIndexed));
+ assert(gameHotkeys.size() <= sizeof(_hotkeysIndexed));
+ memcpy(_hotkeysIndexed, gameHotkeys.c_str(), gameHotkeys.size());
+
+ _hotkeyLook = gameHotkeys[0];
+ _hotkeyMove = gameHotkeys[1];
+ _hotkeyTalk = gameHotkeys[2];
+ _hotkeyPickUp = gameHotkeys[3];
+ _hotkeyOpen = gameHotkeys[4];
+ _hotkeyClose = gameHotkeys[5];
+ _hotkeyInventory = gameHotkeys[6];
+ _hotkeyUse = gameHotkeys[7];
+ _hotkeyGive = gameHotkeys[8];
+ _hotkeyJournal = gameHotkeys[9];
+ _hotkeyFiles = gameHotkeys[10];
+ _hotkeySetUp = gameHotkeys[11];
+ _hotkeyLoadGame = 0;
+ _hotkeySaveGame = 0;
+
+ if (IS_3DO) {
+ // 3DO doesn't have a Journal nor a Files button
+ // Instead it has the setup button in place of the journal
+ // and also "Load" and "Save" buttons underneath it.
+ _hotkeyJournal = 0;
+ _hotkeyFiles = 0;
+ _hotkeyLoadGame = 'A'; // "S" already used for SetUp
+ _hotkeySaveGame = 'V'; // ditto
+
+ _hotkeysIndexed[MAINBUTTON_JOURNAL] = 0;
+ _hotkeysIndexed[MAINBUTTON_FILES] = 0;
+ _hotkeysIndexed[MAINBUTTON_LOADGAME] = 'A';
+ _hotkeysIndexed[MAINBUTTON_SAVEGAME] = 'V';
+ }
}
ScalpelUserInterface::~ScalpelUserInterface() {
@@ -116,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() {
@@ -394,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);
}
@@ -410,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);
@@ -437,12 +470,13 @@ void ScalpelUserInterface::pushButton(int num) {
restoreButton(num);
}
-void ScalpelUserInterface::toggleButton(int num) {
+void ScalpelUserInterface::toggleButton(uint16 num) {
Screen &screen = *_vm->_screen;
if (_menuMode != (MenuMode)(num + 1)) {
_menuMode = (MenuMode)(num + 1);
- _oldKey = COMMANDS[num];
+ assert(num < sizeof(_hotkeysIndexed));
+ _oldKey = _hotkeysIndexed[num];
_oldTemp = num;
if (_keyboardInput) {
@@ -456,7 +490,7 @@ void ScalpelUserInterface::toggleButton(int 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 {
@@ -468,7 +502,7 @@ void ScalpelUserInterface::toggleButton(int num) {
void ScalpelUserInterface::clearInfo() {
if (_infoFlag) {
- _vm->_screen->vgaBar(Common::Rect(IS_3DO ? 33 : 16, INFO_LINE,
+ _vm->_screen->vgaBar(Common::Rect(IS_3DO ? 33 : 16, INFO_LINE,
SHERLOCK_SCREEN_WIDTH - (IS_3DO ? 33 : 19), INFO_LINE + 10), INFO_BLACK);
_infoFlag = false;
_oldLook = -1;
@@ -572,74 +606,92 @@ void ScalpelUserInterface::lookScreen(const Common::Point &pt) {
// If inventory is active and an item is selected for a Use or Give action
if ((_menuMode == INV_MODE || _menuMode == USE_MODE || _menuMode == GIVE_MODE) &&
(inv._invMode == INVMODE_USE || inv._invMode == INVMODE_GIVE)) {
- int width1 = 0, width2 = 0;
- int x, width;
+ int width1 = 0, width2 = 0, width3 = 0;
+ int x;
+
if (inv._invMode == INVMODE_USE) {
// Using an object
- x = width = screen.stringWidth("Use ");
+ Common::String useText1 = FIXED(UserInterface_Use);
+ Common::String useText2;
+ Common::String useText3;
- if (temp < 1000 && scene._bgShapes[temp]._aType != PERSON)
- // It's not a person, so make it lowercase
- tempStr.setChar(tolower(tempStr[0]), 0);
+ x = width1 = screen.stringWidth(useText1);
- x += screen.stringWidth(tempStr);
+ if (temp < 1000 && scene._bgShapes[temp]._aType != PERSON) {
+ // It's not a person, so make it lowercase
+ switch (_vm->getLanguage()) {
+ case Common::DE_DEU:
+ case Common::ES_ESP:
+ // don't do this for German + Spanish version
+ break;
+ default:
+ tempStr.setChar(tolower(tempStr[0]), 0);
+ break;
+ }
+ }
// If we're using an inventory object, add in the width
// of the object name and the " on "
if (_selector != -1) {
- width1 = screen.stringWidth(inv[_selector]._name);
- x += width1;
- width2 = screen.stringWidth(" on ");
+ useText2 = inv[_selector]._name;
+ width2 = screen.stringWidth(useText2);
x += width2;
+
+ useText3 = Common::String::format(FIXED(UserInterface_UseOn), tempStr.c_str());
+
+ } else {
+ useText3 = tempStr;
}
+ width3 = screen.stringWidth(useText3);
+ x += width3;
+
// If the line will be too long, keep cutting off characters
// until the string will fit
while (x > 280) {
- x -= screen.charWidth(tempStr.lastChar());
- tempStr.deleteLastChar();
+ x -= screen.charWidth(useText3.lastChar());
+ useText3.deleteLastChar();
}
int xStart = (SHERLOCK_SCREEN_WIDTH - x) / 2;
screen.print(Common::Point(xStart, INFO_LINE + 1),
- INFO_FOREGROUND, "Use ");
+ INFO_FOREGROUND, "%s", useText1.c_str());
if (_selector != -1) {
- screen.print(Common::Point(xStart + width, INFO_LINE + 1),
- TALK_FOREGROUND, "%s", inv[_selector]._name.c_str());
- screen.print(Common::Point(xStart + width + width1, INFO_LINE + 1),
- INFO_FOREGROUND, " on ");
- screen.print(Common::Point(xStart + width + width1 + width2, INFO_LINE + 1),
- INFO_FOREGROUND, "%s", tempStr.c_str());
+ screen.print(Common::Point(xStart + width1, INFO_LINE + 1),
+ TALK_FOREGROUND, "%s", useText2.c_str());
+ screen.print(Common::Point(xStart + width1 + width2, INFO_LINE + 1),
+ INFO_FOREGROUND, "%s", useText3.c_str());
} else {
- screen.print(Common::Point(xStart + width, INFO_LINE + 1),
- INFO_FOREGROUND, "%s", tempStr.c_str());
+ screen.print(Common::Point(xStart + width1, INFO_LINE + 1),
+ INFO_FOREGROUND, "%s", useText3.c_str());
}
} else if (temp >= 0 && temp < 1000 && _selector != -1 &&
scene._bgShapes[temp]._aType == PERSON) {
+ Common::String giveText1 = FIXED(UserInterface_Give);
+ Common::String giveText2 = inv[_selector]._name;
+ Common::String giveText3 = Common::String::format(FIXED(UserInterface_GiveTo), tempStr.c_str());
+
// Giving an object to a person
- width1 = screen.stringWidth(inv[_selector]._name);
- x = width = screen.stringWidth("Give ");
- x += width1;
- width2 = screen.stringWidth(" to ");
+ x = width1 = screen.stringWidth(giveText1);
+ width2 = screen.stringWidth(giveText2);
x += width2;
- x += screen.stringWidth(tempStr);
+ width3 = screen.stringWidth(giveText3);
+ x += width3;
// Ensure string will fit on-screen
while (x > 280) {
- x -= screen.charWidth(tempStr.lastChar());
- tempStr.deleteLastChar();
+ x -= screen.charWidth(giveText3.lastChar());
+ giveText3.deleteLastChar();
}
int xStart = (SHERLOCK_SCREEN_WIDTH - x) / 2;
screen.print(Common::Point(xStart, INFO_LINE + 1),
- INFO_FOREGROUND, "Give ");
- screen.print(Common::Point(xStart + width, INFO_LINE + 1),
- TALK_FOREGROUND, "%s", inv[_selector]._name.c_str());
- screen.print(Common::Point(xStart + width + width1, INFO_LINE + 1),
- INFO_FOREGROUND, " to ");
- screen.print(Common::Point(xStart + width + width1 + width2, INFO_LINE + 1),
- INFO_FOREGROUND, "%s", tempStr.c_str());
+ INFO_FOREGROUND, "%s", giveText1.c_str());
+ screen.print(Common::Point(xStart + width1, INFO_LINE + 1),
+ TALK_FOREGROUND, "%s", giveText2.c_str());
+ screen.print(Common::Point(xStart + width1 + width2, INFO_LINE + 1),
+ INFO_FOREGROUND, "%s", giveText3.c_str());
}
} else {
screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", tempStr.c_str());
@@ -686,7 +738,6 @@ void ScalpelUserInterface::doEnvControl() {
ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
Talk &talk = *_vm->_talk;
Common::Point mousePos = events.mousePos();
- static const char ENV_COMMANDS[7] = "ELSUDQ";
byte color;
@@ -725,15 +776,15 @@ void ScalpelUserInterface::doEnvControl() {
// Escape _key will close the dialog
if (_key == Common::KEYCODE_ESCAPE)
- _key = 'E';
+ _key = saves._hotkeyExit;
+
+ int buttonIndex = saves.identifyUserButton(_key);
- if (_key == 'E' || _key == 'L' || _key == 'S' || _key == 'U' || _key == 'D' || _key == 'Q') {
- const char *chP = strchr(ENV_COMMANDS, _key);
- int btnIndex = !chP ? -1 : chP - ENV_COMMANDS;
- saves.highlightButtons(btnIndex);
+ if ((buttonIndex >= 0) || (_key >= '1' && _key <= '9')) {
+ saves.highlightButtons(buttonIndex);
_keyboardInput = true;
- if (_key == 'E' || _key == 'Q') {
+ if (_key == saves._hotkeyExit || _key == saves._hotkeyQuit) {
saves._envMode = SAVEMODE_NONE;
} else if (_key >= '1' && _key <= '9') {
_keyboardInput = true;
@@ -768,25 +819,25 @@ void ScalpelUserInterface::doEnvControl() {
}
if (events._released || _keyboardInput) {
- if ((found == 0 && events._released) || _key == 'E') {
+ if ((found == 0 && events._released) || _key == saves._hotkeyExit) {
banishWindow();
_windowBounds.top = CONTROLS_Y1;
events._pressed = events._released = _keyboardInput = false;
_keyPress = '\0';
- } else if ((found == 1 && events._released) || _key == 'L') {
+ } else if ((found == 1 && events._released) || _key == saves._hotkeyLoad) {
saves._envMode = SAVEMODE_LOAD;
if (_selector != -1) {
- saves.loadGame(_selector + 1);
+ saves.loadGame(_selector);
}
- } else if ((found == 2 && events._released) || _key == 'S') {
+ } else if ((found == 2 && events._released) || _key == saves._hotkeySave) {
saves._envMode = SAVEMODE_SAVE;
if (_selector != -1) {
if (saves.checkGameOnScreen(_selector))
_oldSelector = _selector;
if (saves.promptForDescription(_selector)) {
- saves.saveGame(_selector + 1, saves._savegames[_selector]);
+ saves.saveGame(_selector, saves._savegames[_selector]);
banishWindow(1);
_windowBounds.top = CONTROLS_Y1;
@@ -807,7 +858,7 @@ void ScalpelUserInterface::doEnvControl() {
}
}
}
- } else if (((found == 3 && events._released) || _key == 'U') && saves._savegameIndex) {
+ } else if (((found == 3 && events._released) || _key == saves._hotkeyUp) && saves._savegameIndex) {
bool moreKeys;
do {
saves._savegameIndex--;
@@ -826,9 +877,9 @@ void ScalpelUserInterface::doEnvControl() {
screen.slamRect(Common::Rect(3, CONTROLS_Y + 11, SHERLOCK_SCREEN_WIDTH - 2, SHERLOCK_SCREEN_HEIGHT));
color = !saves._savegameIndex ? COMMAND_NULL : COMMAND_FOREGROUND;
- screen.buttonPrint(Common::Point(ENV_POINTS[3][2], CONTROLS_Y), color, true, "Up");
+ screen.buttonPrint(Common::Point(ENV_POINTS[3][2], CONTROLS_Y), color, true, saves._fixedTextUp);
color = (saves._savegameIndex == MAX_SAVEGAME_SLOTS - ONSCREEN_FILES_COUNT) ? COMMAND_NULL : COMMAND_FOREGROUND;
- screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), color, true, "Down");
+ screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), color, true, saves._fixedTextDown);
// Check whether there are more pending U keys pressed
moreKeys = false;
@@ -836,10 +887,10 @@ void ScalpelUserInterface::doEnvControl() {
Common::KeyState keyState = events.getKey();
_key = toupper(keyState.keycode);
- moreKeys = _key == 'U';
+ moreKeys = _key == saves._hotkeyUp;
}
} while ((saves._savegameIndex) && moreKeys);
- } else if (((found == 4 && events._released) || _key == 'D') && saves._savegameIndex < (MAX_SAVEGAME_SLOTS - ONSCREEN_FILES_COUNT)) {
+ } else if (((found == 4 && events._released) || _key == saves._hotkeyDown) && saves._savegameIndex < (MAX_SAVEGAME_SLOTS - ONSCREEN_FILES_COUNT)) {
bool moreKeys;
do {
saves._savegameIndex++;
@@ -861,10 +912,10 @@ void ScalpelUserInterface::doEnvControl() {
screen.slamRect(Common::Rect(3, CONTROLS_Y + 11, SHERLOCK_SCREEN_WIDTH - 2, SHERLOCK_SCREEN_HEIGHT));
color = (!saves._savegameIndex) ? COMMAND_NULL : COMMAND_FOREGROUND;
- screen.buttonPrint(Common::Point(ENV_POINTS[3][2], CONTROLS_Y), color, true, "Up");
+ screen.buttonPrint(Common::Point(ENV_POINTS[3][2], CONTROLS_Y), color, true, saves._fixedTextUp);
color = (saves._savegameIndex == MAX_SAVEGAME_SLOTS - ONSCREEN_FILES_COUNT) ? COMMAND_NULL : COMMAND_FOREGROUND;
- screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), color, true, "Down");
+ screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), color, true, saves._fixedTextDown);
// Check whether there are more pending D keys pressed
moreKeys = false;
@@ -872,16 +923,16 @@ void ScalpelUserInterface::doEnvControl() {
Common::KeyState keyState = events.getKey();
_key = toupper(keyState.keycode);
- moreKeys = _key == 'D';
+ moreKeys = _key == saves._hotkeyDown;
}
} while (saves._savegameIndex < (MAX_SAVEGAME_SLOTS - ONSCREEN_FILES_COUNT) && moreKeys);
- } else if ((found == 5 && events._released) || _key == 'Q') {
+ } else if ((found == 5 && events._released) || _key == saves._hotkeyQuit) {
clearWindow();
- screen.print(Common::Point(0, CONTROLS_Y + 20), INV_FOREGROUND, "Are you sure you wish to Quit ?");
+ screen.print(Common::Point(0, CONTROLS_Y + 20), INV_FOREGROUND, "%s", saves._fixedTextQuitGameQuestion.c_str());
screen.vgaBar(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, CONTROLS_Y + 10), BORDER_COLOR);
- screen.makeButton(Common::Rect(112, CONTROLS_Y, 160, CONTROLS_Y + 10), 136 - screen.stringWidth("Yes") / 2, "Yes");
- screen.makeButton(Common::Rect(161, CONTROLS_Y, 209, CONTROLS_Y + 10), 184 - screen.stringWidth("No") / 2, "No");
+ screen.makeButton(Common::Rect(112, CONTROLS_Y, 160, CONTROLS_Y + 10), 136, saves._fixedTextQuitGameYes);
+ screen.makeButton(Common::Rect(161, CONTROLS_Y, 209, CONTROLS_Y + 10), 184, saves._fixedTextQuitGameNo);
screen.slamArea(112, CONTROLS_Y, 97, 10);
do {
@@ -905,7 +956,7 @@ void ScalpelUserInterface::doEnvControl() {
}
if (_key == Common::KEYCODE_ESCAPE)
- _key = 'N';
+ _key = saves._hotkeyQuitGameNo;
if (_key == Common::KEYCODE_RETURN || _key == ' ') {
events._pressed = false;
@@ -920,28 +971,28 @@ void ScalpelUserInterface::doEnvControl() {
color = COMMAND_HIGHLIGHTED;
else
color = COMMAND_FOREGROUND;
- screen.buttonPrint(Common::Point(136, CONTROLS_Y), color, true, "Yes");
+ screen.buttonPrint(Common::Point(136, CONTROLS_Y), color, true, saves._fixedTextQuitGameYes);
if (mousePos.x > 161 && mousePos.x < 208 && mousePos.y > CONTROLS_Y && mousePos.y < (CONTROLS_Y + 9))
color = COMMAND_HIGHLIGHTED;
else
color = COMMAND_FOREGROUND;
- screen.buttonPrint(Common::Point(184, CONTROLS_Y), color, true, "No");
+ screen.buttonPrint(Common::Point(184, CONTROLS_Y), color, true, saves._fixedTextQuitGameNo);
}
if (mousePos.x > 112 && mousePos.x < 159 && mousePos.y > CONTROLS_Y && mousePos.y < (CONTROLS_Y + 9) && events._released)
- _key = 'Y';
+ _key = saves._hotkeyQuitGameYes;
if (mousePos.x > 161 && mousePos.x < 208 && mousePos.y > CONTROLS_Y && mousePos.y < (CONTROLS_Y + 9) && events._released)
- _key = 'N';
- } while (!_vm->shouldQuit() && _key != 'Y' && _key != 'N');
+ _key = saves._hotkeyQuitGameNo;
+ } while (!_vm->shouldQuit() && _key != saves._hotkeyQuitGameYes && _key != saves._hotkeyQuitGameNo);
- if (_key == 'Y') {
+ if (_key == saves._hotkeyQuitGameYes) {
_vm->quitGame();
events.pollEvents();
return;
} else {
- screen.buttonPrint(Common::Point(184, CONTROLS_Y), COMMAND_HIGHLIGHTED, true, "No");
+ screen.buttonPrint(Common::Point(184, CONTROLS_Y), COMMAND_HIGHLIGHTED, true, saves._fixedTextQuitGameNo);
banishWindow(1);
_windowBounds.top = CONTROLS_Y1;
_key = -1;
@@ -950,14 +1001,14 @@ void ScalpelUserInterface::doEnvControl() {
if (_selector != -1) {
// Are we already in Load mode?
if (saves._envMode == SAVEMODE_LOAD) {
- saves.loadGame(_selector + 1);
+ saves.loadGame(_selector);
} else if (saves._envMode == SAVEMODE_SAVE || saves.isSlotEmpty(_selector)) {
// We're already in save mode, or pointing to an empty save slot
if (saves.checkGameOnScreen(_selector))
_oldSelector = _selector;
if (saves.promptForDescription(_selector)) {
- saves.saveGame(_selector + 1, saves._savegames[_selector]);
+ saves.saveGame(_selector, saves._savegames[_selector]);
banishWindow();
_windowBounds.top = CONTROLS_Y1;
_key = _oldKey = -1;
@@ -983,7 +1034,6 @@ void ScalpelUserInterface::doEnvControl() {
void ScalpelUserInterface::doInvControl() {
Events &events = *_vm->_events;
- FixedText &fixedText = *_vm->_fixedText;
ScalpelInventory &inv = *(ScalpelInventory *)_vm->_inventory;
Scene &scene = *_vm->_scene;
ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
@@ -1009,20 +1059,15 @@ void ScalpelUserInterface::doInvControl() {
if (events._pressed || events._released) {
events.clearKeyboard();
- Common::String fixedText_Exit = fixedText.getText(kFixedText_Inventory_Exit);
- Common::String fixedText_Look = fixedText.getText(kFixedText_Inventory_Look);
- Common::String fixedText_Use = fixedText.getText(kFixedText_Inventory_Use);
- Common::String fixedText_Give = fixedText.getText(kFixedText_Inventory_Give);
-
if (found != -1)
// If a slot highlighted, set its color
colors[found] = COMMAND_HIGHLIGHTED;
- screen.buttonPrint(Common::Point(INVENTORY_POINTS[0][2], CONTROLS_Y1), colors[0], true, fixedText_Exit);
+ screen.buttonPrint(Common::Point(INVENTORY_POINTS[0][2], CONTROLS_Y1), colors[0], true, inv._fixedTextExit);
if (found >= 0 && found <= 3) {
- screen.buttonPrint(Common::Point(INVENTORY_POINTS[1][2], CONTROLS_Y1), colors[1], true, fixedText_Look);
- screen.buttonPrint(Common::Point(INVENTORY_POINTS[2][2], CONTROLS_Y1), colors[2], true, fixedText_Use);
- screen.buttonPrint(Common::Point(INVENTORY_POINTS[3][2], CONTROLS_Y1), colors[3], true, fixedText_Give);
+ screen.buttonPrint(Common::Point(INVENTORY_POINTS[1][2], CONTROLS_Y1), colors[1], true, inv._fixedTextLook);
+ screen.buttonPrint(Common::Point(INVENTORY_POINTS[2][2], CONTROLS_Y1), colors[2], true, inv._fixedTextUse);
+ screen.buttonPrint(Common::Point(INVENTORY_POINTS[3][2], CONTROLS_Y1), colors[3], true, inv._fixedTextGive);
inv._invMode = (InvMode)found;
_selector = -1;
}
@@ -1056,19 +1101,19 @@ void ScalpelUserInterface::doInvControl() {
if (_key == Common::KEYCODE_ESCAPE)
// Escape will also 'E'xit out of inventory display
- _key = 'E';
+ _key = inv._hotkeyExit;
- if (_key == 'E' || _key == 'L' || _key == 'U' || _key == 'G'
- || _key == '-' || _key == '+') {
+ int buttonIndex = inv.identifyUserButton(_key);
+
+ if ((buttonIndex >= 0) && (buttonIndex <= 5)) {
InvMode temp = inv._invMode;
- const char *chP = strchr(INVENTORY_COMMANDS, _key);
- inv._invMode = !chP ? INVMODE_INVALID : (InvMode)(chP - INVENTORY_COMMANDS);
+ inv._invMode = (InvMode)buttonIndex;
inv.invCommands(true);
inv._invMode = temp;
_keyboardInput = true;
- if (_key == 'E')
+ if (_key == inv._hotkeyExit)
inv._invMode = INVMODE_EXIT;
_selector = -1;
} else {
@@ -1090,7 +1135,7 @@ void ScalpelUserInterface::doInvControl() {
}
if (events._released || _keyboardInput) {
- if ((found == 0 && events._released) || _key == 'E') {
+ if ((found == 0 && events._released) || _key == inv._hotkeyExit) {
inv.freeInv();
_infoFlag = true;
clearInfo();
@@ -1098,11 +1143,11 @@ void ScalpelUserInterface::doInvControl() {
_key = -1;
events.clearEvents();
events.setCursor(ARROW);
- } else if ((found == 1 && events._released) || (_key == 'L')) {
+ } else if ((found == 1 && events._released) || (_key == inv._hotkeyLook)) {
inv._invMode = INVMODE_LOOK;
- } else if ((found == 2 && events._released) || (_key == 'U')) {
+ } else if ((found == 2 && events._released) || (_key == inv._hotkeyUse)) {
inv._invMode = INVMODE_USE;
- } else if ((found == 3 && events._released) || (_key == 'G')) {
+ } else if ((found == 3 && events._released) || (_key == inv._hotkeyGive)) {
inv._invMode = INVMODE_GIVE;
} else if (((found == 4 && events._released) || _key == ',') && inv._invIndex) {
if (inv._invIndex >= 6)
@@ -1228,11 +1273,11 @@ 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;
- _key = _oldKey = COMMANDS[LOOK_MODE - 1];
+ _key = _oldKey = _hotkeyLook;
_temp = _oldTemp = 0;
_menuMode = LOOK_MODE;
events.clearEvents();
@@ -1252,17 +1297,17 @@ 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 = COMMANDS[LOOK_MODE - 1];
+ _key = _oldKey = _hotkeyLook;
_temp = _oldTemp = 0;
events.clearEvents();
_invLookFlag = false;
@@ -1278,39 +1323,83 @@ void ScalpelUserInterface::doMainControl() {
ScalpelInventory &inv = *(ScalpelInventory *)_vm->_inventory;
ScalpelSaveManager &saves = *(ScalpelSaveManager *)_vm->_saves;
Common::Point pt = events.mousePos();
- const char *commands = IS_3DO ? COMMANDS_3DO : COMMANDS;
+ int pressedButtonId = -1; // button id according to enum MAINBUTTON_*
if ((events._pressed || events._released) && pt.y > CONTROLS_Y) {
events.clearKeyboard();
_key = -1;
+ _temp = 12; // no button currently selected
// Check whether the mouse is in any of the command areas
- for (_temp = 0; (_temp < 12) && (_key == -1); ++_temp) {
- Common::Rect r(MENU_POINTS[_temp][0], MENU_POINTS[_temp][1],
- MENU_POINTS[_temp][2], MENU_POINTS[_temp][3]);
- if (IS_3DO && _temp >= 0 && _temp <= 2) {
+ for (uint16 buttonNr = 0; buttonNr < 12; buttonNr++) {
+ Common::Rect r(MENU_POINTS[buttonNr][0], MENU_POINTS[buttonNr][1],
+ MENU_POINTS[buttonNr][2], MENU_POINTS[buttonNr][3]);
+ if (IS_3DO && buttonNr <= 2) {
r.left += UI_OFFSET_3DO - 1;
r.right += UI_OFFSET_3DO - 1;
}
- if (r.contains(pt))
- _key = commands[_temp];
+ if (r.contains(pt)) {
+ _temp = buttonNr;
+ pressedButtonId = buttonNr;
+ if (IS_3DO) {
+ // Replace some buttons according to 3DO
+ switch (pressedButtonId) {
+ case MAINBUTTON_JOURNAL:
+ pressedButtonId = MAINBUTTON_SETUP;
+ break;
+ case MAINBUTTON_FILES:
+ pressedButtonId = MAINBUTTON_LOADGAME;
+ break;
+ case MAINBUTTON_SETUP:
+ pressedButtonId = MAINBUTTON_SAVEGAME;
+ break;
+ default:
+ break;
+ }
+ }
+ // Get hotkey, that's assigned to it
+ assert(buttonNr < sizeof(_hotkeysIndexed));
+ _key = _hotkeysIndexed[buttonNr];
+ break;
+ }
}
- --_temp;
} else if (_keyPress) {
// Keyboard control
_keyboardInput = true;
+ _temp = 12; // no button currently selected
+
+ byte key = toupper(_keyPress);
- if (_keyPress >= 'A' && _keyPress <= 'Z') {
- const char *c = strchr(commands, _keyPress);
- _temp = !c ? 12 : c - commands;
+ for (uint16 buttonId = 0; buttonId < sizeof(_hotkeysIndexed); buttonId++) {
+ if (key == _hotkeysIndexed[buttonId]) {
+ pressedButtonId = buttonId;
+ }
+ }
+ if (pressedButtonId >= 0) {
+ _temp = pressedButtonId;
+ _key = key;
+ if (IS_3DO) {
+ // Fix up button number for 3DO
+ switch (pressedButtonId) {
+ case MAINBUTTON_SETUP:
+ _temp = 9;
+ break;
+ case MAINBUTTON_LOADGAME:
+ _temp = 10;
+ break;
+ case MAINBUTTON_SAVEGAME:
+ _temp = 11;
+ break;
+ default:
+ break;
+ }
+ }
} else {
- _temp = 12;
+ _key = -1;
}
- if (_temp == 12)
- _key = -1;
-
if (events._rightPressed) {
+ pressedButtonId = -1;
_temp = 12;
_key = -1;
}
@@ -1340,58 +1429,52 @@ void ScalpelUserInterface::doMainControl() {
}
if (!events._pressed && !_windowOpen) {
- switch (_key) {
- case 'L':
+ switch (pressedButtonId) {
+ case MAINBUTTON_LOOK:
toggleButton(0);
break;
- case 'M':
+ case MAINBUTTON_MOVE:
toggleButton(1);
break;
- case 'T':
+ case MAINBUTTON_TALK:
toggleButton(2);
break;
- case 'P':
+ case MAINBUTTON_PICKUP:
toggleButton(3);
break;
- case 'O':
+ case MAINBUTTON_OPEN:
toggleButton(4);
break;
- case 'C':
+ case MAINBUTTON_CLOSE:
toggleButton(5);
break;
- case 'I':
+ case MAINBUTTON_INVENTORY:
pushButton(6);
_selector = _oldSelector = -1;
_menuMode = INV_MODE;
- inv.drawInventory(PLAIN_INVENTORY);
+ inv.drawInventory(LOOK_INVENTORY_MODE);
break;
- case 'U':
+ case MAINBUTTON_USE:
pushButton(7);
_selector = _oldSelector = -1;
_menuMode = USE_MODE;
inv.drawInventory(USE_INVENTORY_MODE);
break;
- case 'G':
+ case MAINBUTTON_GIVE:
pushButton(8);
_selector = _oldSelector = -1;
_menuMode = GIVE_MODE;
inv.drawInventory(GIVE_INVENTORY_MODE);
break;
- case 'J':
- pushButton(9);
- _menuMode = JOURNAL_MODE;
- journalControl();
+ case MAINBUTTON_JOURNAL:
+ if (!IS_3DO) {
+ pushButton(9);
+ _menuMode = JOURNAL_MODE;
+ journalControl();
+ }
break;
- case 'F':
- if (IS_3DO) {
- if (_temp == 10) {
- pushButton(10);
- vm.showScummVMRestoreDialog();
- } else if (_temp == 11) {
- pushButton(11);
- vm.showScummVMSaveDialog();
- }
- } else {
+ case MAINBUTTON_FILES:
+ if (!IS_3DO) {
pushButton(10);
// Create a thumbnail of the current screen before the files dialog is shown, in case
@@ -1413,7 +1496,19 @@ void ScalpelUserInterface::doMainControl() {
}
}
break;
- case 'S':
+ case MAINBUTTON_LOADGAME:
+ if (IS_3DO) {
+ pushButton(10);
+ vm.showScummVMRestoreDialog();
+ }
+ break;
+ case MAINBUTTON_SAVEGAME:
+ if (IS_3DO) {
+ pushButton(11);
+ vm.showScummVMSaveDialog();
+ }
+ break;
+ case MAINBUTTON_SETUP:
pushButton(IS_3DO ? 9 : 11);
_menuMode = SETUP_MODE;
Settings::show(_vm);
@@ -1500,7 +1595,6 @@ void ScalpelUserInterface::doPickControl() {
void ScalpelUserInterface::doTalkControl() {
Events &events = *_vm->_events;
- FixedText &fixedText = *_vm->_fixedText;
ScalpelJournal &journal = *(ScalpelJournal *)_vm->_journal;
ScalpelPeople &people = *(ScalpelPeople *)_vm->_people;
ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
@@ -1511,28 +1605,24 @@ void ScalpelUserInterface::doTalkControl() {
_key = _oldKey = -1;
_keyboardInput = false;
- Common::String fixedText_Exit = fixedText.getText(kFixedText_Window_Exit);
- Common::String fixedText_Up = fixedText.getText(kFixedText_Window_Up);
- Common::String fixedText_Down = fixedText.getText(kFixedText_Window_Down);
-
if (events._pressed || events._released) {
events.clearKeyboard();
// Handle button printing
if (mousePos.x > 99 && mousePos.x < 138 && mousePos.y > CONTROLS_Y && mousePos.y < (CONTROLS_Y + 10) && !_endKeyActive)
- screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_HIGHLIGHTED, true, fixedText_Exit);
+ screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_HIGHLIGHTED, true, talk._fixedTextWindowExit);
else if (_endKeyActive)
- screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_FOREGROUND, true, fixedText_Exit);
+ screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_FOREGROUND, true, talk._fixedTextWindowExit);
if (mousePos.x > 140 && mousePos.x < 170 && mousePos.y > CONTROLS_Y && mousePos.y < (CONTROLS_Y + 10) && talk._moreTalkUp)
- screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_HIGHLIGHTED, true, fixedText_Up);
+ screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_HIGHLIGHTED, true, talk._fixedTextWindowUp);
else if (talk._moreTalkUp)
- screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_FOREGROUND, true, fixedText_Up);
+ screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_FOREGROUND, true, talk._fixedTextWindowUp);
if (mousePos.x > 181&& mousePos.x < 220 && mousePos.y > CONTROLS_Y && mousePos.y < (CONTROLS_Y + 10) && talk._moreTalkDown)
- screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_HIGHLIGHTED, true, fixedText_Down);
+ screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_HIGHLIGHTED, true, talk._fixedTextWindowDown);
else if (talk._moreTalkDown)
- screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_FOREGROUND, true, fixedText_Down);
+ screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_FOREGROUND, true, talk._fixedTextWindowDown);
bool found = false;
for (_selector = talk._talkIndex; _selector < (int)talk._statements.size() && !found; ++_selector) {
@@ -1548,7 +1638,7 @@ void ScalpelUserInterface::doTalkControl() {
if (_keyPress) {
_key = toupper(_keyPress);
if (_key == Common::KEYCODE_ESCAPE)
- _key = 'E';
+ _key = talk._hotkeyWindowExit;
// Check for number press indicating reply line
if (_key >= '1' && _key <= ('1' + (int)talk._statements.size() - 1)) {
@@ -1561,7 +1651,7 @@ void ScalpelUserInterface::doTalkControl() {
break;
}
}
- } else if (_key == 'E' || _key == 'U' || _key == 'D') {
+ } else if (_key == talk._hotkeyWindowExit || _key == talk._hotkeyWindowUp || _key == talk._hotkeyWindowDown) {
_keyboardInput = true;
} else {
_selector = -1;
@@ -1589,7 +1679,7 @@ void ScalpelUserInterface::doTalkControl() {
if (events._released || _keyboardInput) {
if (((Common::Rect(99, CONTROLS_Y, 138, CONTROLS_Y + 10).contains(mousePos) && events._released)
- || _key == 'E') && _endKeyActive) {
+ || _key == talk._hotkeyWindowExit) && _endKeyActive) {
talk.freeTalkVars();
talk.pullSequence();
@@ -1597,7 +1687,7 @@ void ScalpelUserInterface::doTalkControl() {
banishWindow();
_windowBounds.top = CONTROLS_Y1;
} else if (((Common::Rect(140, CONTROLS_Y, 179, CONTROLS_Y + 10).contains(mousePos) && events._released)
- || _key == 'U') && talk._moreTalkUp) {
+ || _key == talk._hotkeyWindowUp) && talk._moreTalkUp) {
while (talk._statements[--talk._talkIndex]._talkMap == -1)
;
screen._backBuffer1.fillRect(Common::Rect(5, CONTROLS_Y + 11, SHERLOCK_SCREEN_WIDTH - 2,
@@ -1606,7 +1696,7 @@ void ScalpelUserInterface::doTalkControl() {
screen.slamRect(Common::Rect(5, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH - 5, SHERLOCK_SCREEN_HEIGHT - 2));
} else if (((Common::Rect(181, CONTROLS_Y, 220, CONTROLS_Y + 10).contains(mousePos) && events._released)
- || _key == 'D') && talk._moreTalkDown) {
+ || _key == talk._hotkeyWindowDown) && talk._moreTalkDown) {
do {
++talk._talkIndex;
} while (talk._talkIndex < (int)talk._statements.size() && talk._statements[talk._talkIndex]._talkMap == -1);
@@ -1617,9 +1707,9 @@ void ScalpelUserInterface::doTalkControl() {
screen.slamRect(Common::Rect(5, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH - 5, SHERLOCK_SCREEN_HEIGHT - 2));
} else if (_selector != -1) {
- screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_NULL, true, fixedText_Exit);
- screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, true, fixedText_Up);
- screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, true, fixedText_Down);
+ screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_NULL, true, talk._fixedTextWindowExit);
+ screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, true, talk._fixedTextWindowUp);
+ screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, true, talk._fixedTextWindowDown);
// If the reply is new, add it to the journal
if (!talk._talkHistory[talk._converseNum][_selector]) {
@@ -1713,9 +1803,9 @@ void ScalpelUserInterface::doTalkControl() {
!talk._statements[select]._statement.hasPrefix("^")) {
// Not a reply first file, so display the new selections
if (_endKeyActive)
- screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_FOREGROUND, true, fixedText_Exit);
+ screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_FOREGROUND, true, talk._fixedTextWindowExit);
else
- screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_NULL, true, fixedText_Exit);
+ screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_NULL, true, talk._fixedTextWindowExit);
talk.displayTalk(true);
events.setCursor(ARROW);
@@ -1776,7 +1866,7 @@ void ScalpelUserInterface::journalControl() {
if (keyState.keycode == Common::KEYCODE_x && (keyState.flags & Common::KBD_ALT)) {
_vm->quitGame();
return;
- } else if (keyState.keycode == Common::KEYCODE_e || keyState.keycode == Common::KEYCODE_ESCAPE) {
+ } else if (toupper(keyState.ascii) == journal._hotkeyExit || keyState.keycode == Common::KEYCODE_ESCAPE) {
doneFlag = true;
} else {
_key = toupper(keyState.keycode);
@@ -1798,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);
}
@@ -1832,19 +1922,19 @@ 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);
_windowBounds.top = CONTROLS_Y1;
- _key = _oldKey = COMMANDS[LOOK_MODE - 1];
+ _key = _oldKey = _hotkeyLook;
_temp = _oldTemp = 0;
_menuMode = LOOK_MODE;
events.clearEvents();
- screen._backBuffer2.blitFrom(tempSurface, pt);
+ screen._backBuffer2.SHblitFrom(tempSurface, pt);
} else {
events.setCursor(ARROW);
banishWindow(true);
@@ -1866,7 +1956,7 @@ void ScalpelUserInterface::printObjectDesc(const Common::String &str, bool first
banishWindow(1);
_windowBounds.top = CONTROLS_Y1;
- _key = _oldKey = COMMANDS[INV_MODE - 1];
+ _key = _oldKey = _hotkeyInventory;
_temp = _oldTemp = 0;
events.clearEvents();
@@ -1878,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;
@@ -1938,20 +2028,16 @@ void ScalpelUserInterface::printObjectDesc(const Common::String &str, bool first
// Handle display depending on whether all the message was shown
if (!endOfStr) {
+ Common::String fixedText_PressKeyForMore = FIXED(PressKey_ForMore);
+
screen.makeButton(Common::Rect(46, CONTROLS_Y, 272, CONTROLS_Y + 10),
- (SHERLOCK_SCREEN_WIDTH - screen.stringWidth(PRESS_KEY_FOR_MORE)) / 2,
- PRESS_KEY_FOR_MORE);
- screen.gPrint(Common::Point((SHERLOCK_SCREEN_WIDTH -
- screen.stringWidth(PRESS_KEY_FOR_MORE)) / 2, CONTROLS_Y),
- COMMAND_FOREGROUND, "P");
+ SHERLOCK_SCREEN_WIDTH / 2, fixedText_PressKeyForMore);
_descStr = msgP;
} else {
+ Common::String fixedText_PressKeyToContinue = FIXED(PressKey_ToContinue);
+
screen.makeButton(Common::Rect(46, CONTROLS_Y, 272, CONTROLS_Y + 10),
- (SHERLOCK_SCREEN_WIDTH - screen.stringWidth(PRESS_KEY_TO_CONTINUE)) / 2,
- PRESS_KEY_TO_CONTINUE);
- screen.gPrint(Common::Point((SHERLOCK_SCREEN_WIDTH -
- screen.stringWidth(PRESS_KEY_TO_CONTINUE)) / 2, CONTROLS_Y),
- COMMAND_FOREGROUND, "P");
+ SHERLOCK_SCREEN_WIDTH / 2, fixedText_PressKeyToContinue);
_descStr = "";
}
@@ -1986,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));
@@ -1996,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;
}
@@ -2021,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
@@ -2048,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));
@@ -2058,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,
@@ -2085,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));
}
@@ -2167,7 +2253,7 @@ void ScalpelUserInterface::checkUseAction(const UseType *use, const Common::Stri
if (scene._goToScene != 1 && !printed && !talk._talkToAbort) {
_infoFlag = true;
clearInfo();
- screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "Done...");
+ screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", FIXED(UserInterface_Done));
_menuCounter = 25;
}
}
@@ -2177,9 +2263,9 @@ void ScalpelUserInterface::checkUseAction(const UseType *use, const Common::Stri
clearInfo();
if (giveMode) {
- screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "No, thank you.");
+ screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", FIXED(UserInterface_NoThankYou));
} else if (fixedTextActionId == kFixedTextAction_Invalid) {
- screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "You can't do that.");
+ screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", FIXED(UserInterface_YouCantDoThat));
} else {
Common::String errorMessage = fixedText.getActionMessage(fixedTextActionId, 0);
screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", errorMessage.c_str());
diff --git a/engines/sherlock/scalpel/scalpel_user_interface.h b/engines/sherlock/scalpel/scalpel_user_interface.h
index d88e607c2a..cc3aafff65 100644
--- a/engines/sherlock/scalpel/scalpel_user_interface.h
+++ b/engines/sherlock/scalpel/scalpel_user_interface.h
@@ -33,26 +33,38 @@ class Talk;
namespace Scalpel {
-extern const char COMMANDS[13];
-extern const char COMMANDS_3DO[13];
extern const int MENU_POINTS[12][4];
extern const int INVENTORY_POINTS[8][3];
-extern const char INVENTORY_COMMANDS[9];
-extern const char *const PRESS_KEY_FOR_MORE;
-extern const char *const PRESS_KEY_TO_CONTINUE;
+
+enum {
+ MAINBUTTON_LOOK = 0,
+ MAINBUTTON_MOVE,
+ MAINBUTTON_TALK,
+ MAINBUTTON_PICKUP,
+ MAINBUTTON_OPEN,
+ MAINBUTTON_CLOSE,
+ MAINBUTTON_INVENTORY,
+ MAINBUTTON_USE,
+ MAINBUTTON_GIVE,
+ MAINBUTTON_JOURNAL,
+ MAINBUTTON_FILES,
+ MAINBUTTON_SETUP,
+ MAINBUTTON_LOADGAME,
+ MAINBUTTON_SAVEGAME
+};
class Settings;
class ScalpelUserInterface: public UserInterface {
friend class Settings;
- friend class Talk;
+ friend class Sherlock::Talk;
private:
char _keyPress;
int _lookHelp;
int _help, _oldHelp;
int _key, _oldKey;
- int _temp, _oldTemp;
+ int _temp, _oldTemp; // button number (0-11)
int _oldLook;
bool _keyboardInput;
bool _pause;
@@ -77,7 +89,7 @@ private:
* have already been drawn. This simply takes care of switching the mode around
* accordingly
*/
- void toggleButton(int num);
+ void toggleButton(uint16 num);
/**
* Print the name of an object in the scene
@@ -147,6 +159,24 @@ public:
ImageFile *_controlPanel;
ImageFile *_controls;
int _oldUse;
+
+ byte _hotkeyLook;
+ byte _hotkeyMove;
+ byte _hotkeyTalk;
+ byte _hotkeyPickUp;
+ byte _hotkeyOpen;
+ byte _hotkeyClose;
+ byte _hotkeyInventory;
+ byte _hotkeyUse;
+ byte _hotkeyGive;
+ byte _hotkeyJournal; // not used for 3DO
+ byte _hotkeyFiles; // not used for 3DO
+ byte _hotkeySetUp; // SetUp-button is in the spot of Journal for 3DO
+ byte _hotkeyLoadGame; // 3DO
+ byte _hotkeySaveGame; // 3DO
+
+ byte _hotkeysIndexed[14];
+
public:
ScalpelUserInterface(SherlockEngine *vm);
virtual ~ScalpelUserInterface();
diff --git a/engines/sherlock/scalpel/settings.cpp b/engines/sherlock/scalpel/settings.cpp
index f6769a4b99..e039559982 100644
--- a/engines/sherlock/scalpel/settings.cpp
+++ b/engines/sherlock/scalpel/settings.cpp
@@ -24,6 +24,7 @@
#include "sherlock/scalpel/settings.h"
#include "sherlock/scalpel/scalpel_screen.h"
#include "sherlock/scalpel/scalpel_user_interface.h"
+#include "sherlock/scalpel/scalpel_fixed_text.h"
#include "sherlock/scalpel/scalpel.h"
namespace Sherlock {
@@ -45,18 +46,9 @@ static const int SETUP_POINTS[12][4] = {
{ 219, 187, 316, 268 } // _key Pad Accel. Toggle
};
-static const char *const SETUP_STRS0[2] = { "off", "on" };
-static const char *const SETUP_STRS1[2] = { "Directly", "by Pixel" };
-static const char *const SETUP_STRS2[2] = { "Left", "Right" };
-static const char *const SETUP_STRS3[2] = { "Appear", "Slide" };
-static const char *const SETUP_STRS5[2] = { "Left", "Right" };
-static const char *const SETUP_NAMES[12] = {
- "Exit", "M", "V", "S", "B", "New Font Style", "J", "Calibrate Joystick", "F", "W", "P", "K"
-};
-
/*----------------------------------------------------------------*/
-void Settings::drawInteface(bool flag) {
+void Settings::drawInterface(bool flag) {
People &people = *_vm->_people;
ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
Sound &sound = *_vm->_sound;
@@ -74,55 +66,105 @@ void Settings::drawInteface(bool flag) {
SHERLOCK_SCREEN_HEIGHT - 2), INV_BACKGROUND);
}
+ tempStr = FIXED(Settings_Exit);
+ _hotkeyExit = toupper(tempStr.firstChar());
screen.makeButton(Common::Rect(SETUP_POINTS[0][0], SETUP_POINTS[0][1], SETUP_POINTS[0][2], SETUP_POINTS[0][1] + 10),
- SETUP_POINTS[0][3] - screen.stringWidth("Exit") / 2, "Exit");
+ SETUP_POINTS[0][3], tempStr);
- tempStr = Common::String::format("Music %s", SETUP_STRS0[music._musicOn]);
+ if (music._musicOn) {
+ tempStr = FIXED(Settings_MusicOn);
+ } else {
+ tempStr = FIXED(Settings_MusicOff);
+ }
+ _hotkeyMusic = toupper(tempStr.firstChar());
screen.makeButton(Common::Rect(SETUP_POINTS[1][0], SETUP_POINTS[1][1], SETUP_POINTS[1][2], SETUP_POINTS[1][1] + 10),
- SETUP_POINTS[1][3] - screen.stringWidth(tempStr) / 2, tempStr);
+ SETUP_POINTS[1][3], tempStr);
- tempStr = Common::String::format("Voices %s", SETUP_STRS0[sound._voices]);
- screen.makeButton(Common::Rect(SETUP_POINTS[2][0], SETUP_POINTS[2][1], SETUP_POINTS[2][2], SETUP_POINTS[2][1] + 10),
- SETUP_POINTS[2][3] - screen.stringWidth(tempStr) / 2, tempStr);
-
- tempStr = Common::String::format("Sound Effects %s", SETUP_STRS0[sound._digitized]);
- screen.makeButton(Common::Rect(SETUP_POINTS[3][0], SETUP_POINTS[3][1], SETUP_POINTS[3][2], SETUP_POINTS[3][1] + 10),
- SETUP_POINTS[3][3] - screen.stringWidth(tempStr) / 2, tempStr);
-
- tempStr = Common::String::format("Auto Help %s", SETUP_STRS5[ui._helpStyle]);
- screen.makeButton(Common::Rect(SETUP_POINTS[4][0], SETUP_POINTS[4][1], SETUP_POINTS[4][2], SETUP_POINTS[4][1] + 10),
- SETUP_POINTS[4][3] - screen.stringWidth(tempStr) / 2, tempStr);
- screen.makeButton(Common::Rect(SETUP_POINTS[5][0], SETUP_POINTS[5][1], SETUP_POINTS[5][2], SETUP_POINTS[5][1] + 10),
- SETUP_POINTS[5][3] - screen.stringWidth("New Font Style") / 2, "New Font Style");
+ if (people._portraitsOn) {
+ tempStr = FIXED(Settings_PortraitsOn);
+ } else {
+ tempStr = FIXED(Settings_PortraitsOff);
+ }
+ _hotkeyPortraits = toupper(tempStr.firstChar());
+ screen.makeButton(Common::Rect(SETUP_POINTS[10][0], SETUP_POINTS[10][1], SETUP_POINTS[10][2], SETUP_POINTS[10][1] + 10),
+ SETUP_POINTS[10][3], tempStr);
// WORKAROUND: We don't support the joystick in ScummVM, so draw the next two buttons as disabled
- tempStr = "Joystick Off";
+ tempStr = FIXED(Settings_JoystickOff);
screen.makeButton(Common::Rect(SETUP_POINTS[6][0], SETUP_POINTS[6][1], SETUP_POINTS[6][2], SETUP_POINTS[6][1] + 10),
- SETUP_POINTS[6][3] - screen.stringWidth(tempStr) / 2, tempStr);
+ SETUP_POINTS[6][3], tempStr);
screen.buttonPrint(Common::Point(SETUP_POINTS[6][3], SETUP_POINTS[6][1]), COMMAND_NULL, false, tempStr);
- tempStr = "Calibrate Joystick";
+ tempStr = FIXED(Settings_NewFontStyle);
+ _hotkeyNewFontStyle = toupper(tempStr.firstChar());
+ screen.makeButton(Common::Rect(SETUP_POINTS[5][0], SETUP_POINTS[5][1], SETUP_POINTS[5][2], SETUP_POINTS[5][1] + 10),
+ SETUP_POINTS[5][3], tempStr);
+
+ if (sound._digitized) {
+ tempStr = FIXED(Settings_SoundEffectsOn);
+ } else {
+ tempStr = FIXED(Settings_SoundEffectsOff);
+ }
+ _hotkeySoundEffects = toupper(tempStr.firstChar());
+ screen.makeButton(Common::Rect(SETUP_POINTS[3][0], SETUP_POINTS[3][1], SETUP_POINTS[3][2], SETUP_POINTS[3][1] + 10),
+ SETUP_POINTS[3][3], tempStr);
+
+ if (ui._slideWindows) {
+ tempStr = FIXED(Settings_WindowsSlide);
+ } else {
+ tempStr = FIXED(Settings_WindowsAppear);
+ }
+ _hotkeyWindows = toupper(tempStr.firstChar());
+ screen.makeButton(Common::Rect(SETUP_POINTS[9][0], SETUP_POINTS[9][1], SETUP_POINTS[9][2], SETUP_POINTS[9][1] + 10),
+ SETUP_POINTS[9][3], tempStr);
+
+ tempStr = FIXED(Settings_CalibrateJoystick);
screen.makeButton(Common::Rect(SETUP_POINTS[7][0], SETUP_POINTS[7][1], SETUP_POINTS[7][2], SETUP_POINTS[7][1] + 10),
- SETUP_POINTS[7][3] - screen.stringWidth(tempStr) / 2, tempStr);
+ SETUP_POINTS[7][3], tempStr);
screen.buttonPrint(Common::Point(SETUP_POINTS[7][3], SETUP_POINTS[7][1]), COMMAND_NULL, false, tempStr);
- tempStr = Common::String::format("Fade %s", screen._fadeStyle ? "by Pixel" : "Directly");
- screen.makeButton(Common::Rect(SETUP_POINTS[8][0], SETUP_POINTS[8][1], SETUP_POINTS[8][2], SETUP_POINTS[8][1] + 10),
- SETUP_POINTS[8][3] - screen.stringWidth(tempStr) / 2, tempStr);
+ if (ui._helpStyle) {
+ tempStr = FIXED(Settings_AutoHelpRight);
+ } else {
+ tempStr = FIXED(Settings_AutoHelpLeft);
+ }
+ _hotkeyAutoHelp = toupper(tempStr.firstChar());
+ screen.makeButton(Common::Rect(SETUP_POINTS[4][0], SETUP_POINTS[4][1], SETUP_POINTS[4][2], SETUP_POINTS[4][1] + 10),
+ SETUP_POINTS[4][3], tempStr);
- tempStr = Common::String::format("Windows %s", ui._slideWindows ? "Slide" : "Appear");
- screen.makeButton(Common::Rect(SETUP_POINTS[9][0], SETUP_POINTS[9][1], SETUP_POINTS[9][2], SETUP_POINTS[9][1] + 10),
- SETUP_POINTS[9][3] - screen.stringWidth(tempStr) / 2, tempStr);
+ if (sound._voices) {
+ tempStr = FIXED(Settings_VoicesOn);
+ } else {
+ tempStr = FIXED(Settings_VoicesOff);
+ }
+ _hotkeyVoices = toupper(tempStr.firstChar());
+ screen.makeButton(Common::Rect(SETUP_POINTS[2][0], SETUP_POINTS[2][1], SETUP_POINTS[2][2], SETUP_POINTS[2][1] + 10),
+ SETUP_POINTS[2][3], tempStr);
- tempStr = Common::String::format("Portraits %s", SETUP_STRS0[people._portraitsOn]);
- screen.makeButton(Common::Rect(SETUP_POINTS[10][0], SETUP_POINTS[10][1], SETUP_POINTS[10][2], SETUP_POINTS[10][1] + 10),
- SETUP_POINTS[10][3] - screen.stringWidth(tempStr) / 2, tempStr);
+ if (screen._fadeStyle) {
+ tempStr = FIXED(Settings_FadeByPixel);
+ } else {
+ tempStr = FIXED(Settings_FadeDirectly);
+ }
+ _hotkeyFade = toupper(tempStr.firstChar());
+ screen.makeButton(Common::Rect(SETUP_POINTS[8][0], SETUP_POINTS[8][1], SETUP_POINTS[8][2], SETUP_POINTS[8][1] + 10),
+ SETUP_POINTS[8][3], tempStr);
- tempStr = "Key Pad Slow";
+ tempStr = FIXED(Settings_KeyPadSlow);
screen.makeButton(Common::Rect(SETUP_POINTS[11][0], SETUP_POINTS[11][1], SETUP_POINTS[11][2], SETUP_POINTS[11][1] + 10),
- SETUP_POINTS[11][3] - screen.stringWidth(tempStr) / 2, tempStr);
+ SETUP_POINTS[11][3], tempStr);
screen.buttonPrint(Common::Point(SETUP_POINTS[11][3], SETUP_POINTS[11][1]), COMMAND_NULL, false, tempStr);
+ _hotkeysIndexed[0] = _hotkeyExit;
+ _hotkeysIndexed[1] = _hotkeyMusic;
+ _hotkeysIndexed[2] = _hotkeyVoices;
+ _hotkeysIndexed[3] = _hotkeySoundEffects;
+ _hotkeysIndexed[4] = _hotkeyAutoHelp;
+ _hotkeysIndexed[5] = _hotkeyNewFontStyle;
+ _hotkeysIndexed[8] = _hotkeyFade;
+ _hotkeysIndexed[9] = _hotkeyWindows;
+ _hotkeysIndexed[10] = _hotkeyPortraits;
+
// Show the window immediately, or slide it on-screen
if (!flag) {
if (!ui._slideWindows) {
@@ -151,7 +193,7 @@ int Settings::drawButtons(const Common::Point &pt, int _key) {
for (int idx = 0; idx < 12; ++idx) {
if ((pt.x > SETUP_POINTS[idx][0] && pt.x < SETUP_POINTS[idx][2] && pt.y > SETUP_POINTS[idx][1]
&& pt.y < (SETUP_POINTS[idx][1] + 10) && (events._pressed || events._released))
- || (_key == SETUP_NAMES[idx][0])) {
+ || (_key == toupper(_hotkeysIndexed[idx]))) {
found = idx;
color = COMMAND_HIGHLIGHTED;
} else {
@@ -160,50 +202,74 @@ int Settings::drawButtons(const Common::Point &pt, int _key) {
// Print the button text
switch (idx) {
+ case 0:
+ tempStr = FIXED(Settings_Exit);
+ break;
case 1:
- tempStr = Common::String::format("Music %s", SETUP_STRS0[music._musicOn]);
- screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
+ if (music._musicOn) {
+ tempStr = FIXED(Settings_MusicOn);
+ } else {
+ tempStr = FIXED(Settings_MusicOff);
+ }
break;
case 2:
- tempStr = Common::String::format("Voices %s", SETUP_STRS0[sound._voices]);
- screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
+ if (sound._voices) {
+ tempStr = FIXED(Settings_VoicesOn);
+ } else {
+ tempStr = FIXED(Settings_VoicesOff);
+ }
break;
case 3:
- tempStr = Common::String::format("Sound Effects %s", SETUP_STRS0[sound._digitized]);
- screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
+ if (sound._digitized) {
+ tempStr = FIXED(Settings_SoundEffectsOn);
+ } else {
+ tempStr = FIXED(Settings_SoundEffectsOff);
+ }
break;
case 4:
- tempStr = Common::String::format("Auto Help %s", SETUP_STRS2[ui._helpStyle]);
- screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
+ if (ui._helpStyle) {
+ tempStr = FIXED(Settings_AutoHelpRight);
+ } else {
+ tempStr = FIXED(Settings_AutoHelpLeft);
+ }
break;
- case 6:
- tempStr = "Joystick Off";
- screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), COMMAND_NULL, true, tempStr);
+ case 5:
+ tempStr = FIXED(Settings_NewFontStyle);
break;
+ case 6:
+ // Joystick Off - disabled in ScummVM
+ continue;
case 7:
- tempStr = "Calibrate Joystick";
- screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), COMMAND_NULL, true, tempStr);
- break;
+ // Calibrate Joystick - disabled in ScummVM
+ continue;
case 8:
- tempStr = Common::String::format("Fade %s", SETUP_STRS1[screen._fadeStyle]);
- screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
+ if (screen._fadeStyle) {
+ tempStr = FIXED(Settings_FadeByPixel);
+ } else {
+ tempStr = FIXED(Settings_FadeDirectly);
+ }
break;
case 9:
- tempStr = Common::String::format("Windows %s", SETUP_STRS3[ui._slideWindows]);
- screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
+ if (ui._slideWindows) {
+ tempStr = FIXED(Settings_WindowsSlide);
+ } else {
+ tempStr = FIXED(Settings_WindowsAppear);
+ }
break;
case 10:
- tempStr = Common::String::format("Portraits %s", SETUP_STRS0[people._portraitsOn]);
- screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
+ if (people._portraitsOn) {
+ tempStr = FIXED(Settings_PortraitsOn);
+ } else {
+ tempStr = FIXED(Settings_PortraitsOff);
+ }
break;
case 11:
- tempStr = "Key Pad Slow";
- screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), COMMAND_NULL, true, tempStr);
- break;
+ // Key Pad Slow - disabled in ScummVM
+ continue;
default:
- screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, SETUP_NAMES[idx]);
- break;
+ continue;
}
+ screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
}
return found;
@@ -222,7 +288,7 @@ void Settings::show(SherlockEngine *vm) {
assert(vm->getGameID() == GType_SerratedScalpel);
Settings settings(vm);
- settings.drawInteface(false);
+ settings.drawInterface(false);
do {
if (ui._menuCounter)
@@ -244,7 +310,7 @@ void Settings::show(SherlockEngine *vm) {
if (events.kbHit()) {
Common::KeyState keyState = events.getKey();
- ui._key = toupper(keyState.keycode);
+ ui._key = toupper(keyState.ascii);
if (ui._key == Common::KEYCODE_RETURN || ui._key == Common::KEYCODE_SPACE) {
events._pressed = false;
@@ -258,11 +324,11 @@ void Settings::show(SherlockEngine *vm) {
found = settings.drawButtons(pt, ui._key);
}
- if ((found == 0 && events._released) || (ui._key == 'E' || ui._key == Common::KEYCODE_ESCAPE))
+ if ((found == 0 && events._released) || (ui._key == settings._hotkeyExit || ui._key == Common::KEYCODE_ESCAPE))
// Exit
break;
- if ((found == 1 && events._released) || ui._key == 'M') {
+ if ((found == 1 && events._released) || ui._key == settings._hotkeyMusic) {
// Toggle music
music._musicOn = !music._musicOn;
if (!music._musicOn)
@@ -271,30 +337,30 @@ void Settings::show(SherlockEngine *vm) {
music.startSong();
updateConfig = true;
- settings.drawInteface(true);
+ settings.drawInterface(true);
}
- if ((found == 2 && events._released) || ui._key == 'V') {
+ if ((found == 2 && events._released) || ui._key == settings._hotkeyVoices) {
sound._voices = !sound._voices;
updateConfig = true;
- settings.drawInteface(true);
+ settings.drawInterface(true);
}
- if ((found == 3 && events._released) || ui._key == 'S') {
+ if ((found == 3 && events._released) || ui._key == settings._hotkeySoundEffects) {
// Toggle sound effects
sound._digitized = !sound._digitized;
updateConfig = true;
- settings.drawInteface(true);
+ settings.drawInterface(true);
}
- if ((found == 4 && events._released) || ui._key == 'A') {
+ if ((found == 4 && events._released) || ui._key == settings._hotkeyAutoHelp) {
// Help button style
ui._helpStyle = !ui._helpStyle;
updateConfig = true;
- settings.drawInteface(true);
+ settings.drawInterface(true);
}
- if ((found == 5 && events._released) || ui._key == 'N') {
+ if ((found == 5 && events._released) || ui._key == settings._hotkeyNewFontStyle) {
// New font style
int fontNum = screen.fontNumber() + 1;
if (fontNum == 3)
@@ -302,28 +368,28 @@ void Settings::show(SherlockEngine *vm) {
screen.setFont(fontNum);
updateConfig = true;
- settings.drawInteface(true);
+ settings.drawInterface(true);
}
- if ((found == 8 && events._released) || ui._key == 'F') {
+ if ((found == 8 && events._released) || ui._key == settings._hotkeyFade) {
// Toggle fade style
screen._fadeStyle = !screen._fadeStyle;
updateConfig = true;
- settings.drawInteface(true);
+ settings.drawInterface(true);
}
- if ((found == 9 && events._released) || ui._key == 'W') {
+ if ((found == 9 && events._released) || ui._key == settings._hotkeyWindows) {
// Window style
ui._slideWindows = !ui._slideWindows;
updateConfig = true;
- settings.drawInteface(true);
+ settings.drawInterface(true);
}
- if ((found == 10 && events._released) || ui._key == 'P') {
+ if ((found == 10 && events._released) || ui._key == settings._hotkeyPortraits) {
// Toggle portraits being shown
people._portraitsOn = !people._portraitsOn;
updateConfig = true;
- settings.drawInteface(true);
+ settings.drawInterface(true);
}
} while (!vm->shouldQuit());
diff --git a/engines/sherlock/scalpel/settings.h b/engines/sherlock/scalpel/settings.h
index ff2e647a62..9144e9d420 100644
--- a/engines/sherlock/scalpel/settings.h
+++ b/engines/sherlock/scalpel/settings.h
@@ -35,12 +35,36 @@ class Settings {
private:
SherlockEngine *_vm;
- Settings(SherlockEngine *vm) : _vm(vm) {}
+ Settings(SherlockEngine *vm) : _vm(vm) {
+ _hotkeyExit = 0;
+ _hotkeyMusic = 0;
+ _hotkeyPortraits = 0;
+ _hotkeyNewFontStyle = 0;
+ _hotkeySoundEffects = 0;
+ _hotkeyWindows = 0;
+ _hotkeyAutoHelp = 0;
+ _hotkeyVoices = 0;
+ _hotkeyFade = 0;
+
+ memset(_hotkeysIndexed, 0, sizeof(_hotkeysIndexed));
+ }
+
+ byte _hotkeyExit;
+ byte _hotkeyMusic;
+ byte _hotkeyPortraits;
+ byte _hotkeyNewFontStyle;
+ byte _hotkeySoundEffects;
+ byte _hotkeyWindows;
+ byte _hotkeyAutoHelp;
+ byte _hotkeyVoices;
+ byte _hotkeyFade;
+
+ byte _hotkeysIndexed[12];
/**
* Draws the interface for the settings window
*/
- void drawInteface(bool flag);
+ void drawInterface(bool flag);
/**
* Draws the buttons for the settings dialog
diff --git a/engines/sherlock/scalpel/tsage/logo.cpp b/engines/sherlock/scalpel/tsage/logo.cpp
index 014470dcc8..a885057f35 100644
--- a/engines/sherlock/scalpel/tsage/logo.cpp
+++ b/engines/sherlock/scalpel/tsage/logo.cpp
@@ -163,6 +163,7 @@ Object::Object() {
_angle = _changeCtr = 0;
_walkStartFrame = 0;
_majorDiff = _minorDiff = 0;
+ _updateStartFrame = 0;
}
void Object::setVisage(int visage, int strip) {
@@ -216,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() {
@@ -245,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));
}
}
@@ -651,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 ea12fafd7b..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"
@@ -216,7 +217,6 @@ Scene::Scene(SherlockEngine *vm): _vm(vm) {
_currentScene = -1;
_goToScene = -1;
- _loadingSavedGame = false;
_walkedInScene = false;
_version = 0;
_compressed = false;
@@ -274,6 +274,8 @@ void Scene::selectScene() {
}
void Scene::freeScene() {
+ SaveManager &saves = *_vm->_saves;
+
if (_currentScene == -1)
return;
@@ -284,10 +286,8 @@ void Scene::freeScene() {
_vm->_music->freeSong();
_vm->_sound->freeLoadedSounds();
- if (!_loadingSavedGame)
+ if (!saves._justLoaded)
saveSceneStatus();
- else
- _loadingSavedGame = false;
_sequenceBuffer.clear();
_descText.clear();
@@ -357,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);
}
@@ -563,34 +563,37 @@ bool Scene::loadScene(const Common::String &filename) {
// Read in the walk data
size = rrmStream->readUint16LE();
- Common::SeekableReadStream *walkStream = !_compressed ? rrmStream :
+ Common::SeekableReadStream *walkStream = !_compressed ? rrmStream->readStream(size) :
res.decompress(*rrmStream, size);
- int startPos = walkStream->pos();
- while ((walkStream->pos() - startPos) < size) {
- _walkPoints.push_back(WalkArray());
- _walkPoints[_walkPoints.size() - 1]._fileOffset = walkStream->pos() - startPos;
- _walkPoints[_walkPoints.size() - 1].load(*walkStream, IS_ROSE_TATTOO);
- }
-
- if (_compressed)
- delete walkStream;
-
// Translate the file offsets of the walk directory to indexes in the loaded walk data
for (uint idx1 = 0; idx1 < _zones.size(); ++idx1) {
for (uint idx2 = 0; idx2 < _zones.size(); ++idx2) {
- int fileOffset = _walkDirectory[idx1][idx2];
- if (fileOffset == -1)
+ int dataOffset = _walkDirectory[idx1][idx2];
+ if (dataOffset == -1)
continue;
+ // Check to see if we've already loaded the walk set for the given data offset
uint dataIndex = 0;
- while (dataIndex < _walkPoints.size() && _walkPoints[dataIndex]._fileOffset != fileOffset)
+ while (dataIndex < _walkPoints.size() && _walkPoints[dataIndex]._fileOffset != dataOffset)
++dataIndex;
- assert(dataIndex < _walkPoints.size());
+
+ if (dataIndex == _walkPoints.size()) {
+ // Walk data for that offset hasn't been loaded yet, so load it now
+ _walkPoints.push_back(WalkArray());
+
+ walkStream->seek(dataOffset);
+ _walkPoints[_walkPoints.size() - 1]._fileOffset = dataOffset;
+ _walkPoints[_walkPoints.size() - 1].load(*walkStream, IS_ROSE_TATTOO);
+ dataIndex = _walkPoints.size() - 1;
+ }
+
_walkDirectory[idx1][idx2] = dataIndex;
}
}
+ delete walkStream;
+
if (IS_ROSE_TATTOO) {
// Read in the entrance
_entrance.load(*rrmStream);
@@ -647,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;
@@ -893,28 +896,38 @@ bool Scene::loadScene(const Common::String &filename) {
// === WALK DATA === Read in the walk data
roomStream->seek(header3DO_walkData_offset);
- int startPos = roomStream->pos();
- while ((roomStream->pos() - startPos) < (int)header3DO_walkData_size) {
- _walkPoints.push_back(WalkArray());
- _walkPoints[_walkPoints.size() - 1]._fileOffset = roomStream->pos() - startPos;
- _walkPoints[_walkPoints.size() - 1].load(*roomStream, false);
- }
+ // Read in the walk data
+ Common::SeekableReadStream *walkStream = !_compressed ? roomStream->readStream(header3DO_walkData_size) :
+ res.decompress(*roomStream, header3DO_walkData_size);
// Translate the file offsets of the walk directory to indexes in the loaded walk data
for (uint idx1 = 0; idx1 < _zones.size(); ++idx1) {
for (uint idx2 = 0; idx2 < _zones.size(); ++idx2) {
- int fileOffset = _walkDirectory[idx1][idx2];
- if (fileOffset == -1)
+ int dataOffset = _walkDirectory[idx1][idx2];
+ if (dataOffset == -1)
continue;
+ // Check to see if we've already loaded the walk set for the given data offset
uint dataIndex = 0;
- while (dataIndex < _walkPoints.size() && _walkPoints[dataIndex]._fileOffset != fileOffset)
+ while (dataIndex < _walkPoints.size() && _walkPoints[dataIndex]._fileOffset != dataOffset)
++dataIndex;
- assert(dataIndex < _walkPoints.size());
+
+ if (dataIndex == _walkPoints.size()) {
+ // Walk data for that offset hasn't been loaded yet, so load it now
+ _walkPoints.push_back(WalkArray());
+
+ walkStream->seek(dataOffset);
+ _walkPoints[_walkPoints.size() - 1]._fileOffset = dataOffset;
+ _walkPoints[_walkPoints.size() - 1].load(*walkStream, IS_ROSE_TATTOO);
+ dataIndex = _walkPoints.size() - 1;
+ }
+
_walkDirectory[idx1][idx2] = dataIndex;
}
}
+ delete walkStream;
+
// === EXITS === Read in the exits
roomStream->seek(header3DO_exits_offset);
@@ -984,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
@@ -1224,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) {
@@ -1377,7 +1390,6 @@ void Scene::synchronize(Serializer &s) {
s.syncAsSint16LE(_currentScene);
} else {
s.syncAsSint16LE(_goToScene);
- _loadingSavedGame = true;
}
for (int sceneNum = 1; sceneNum < SCENES_COUNT; ++sceneNum) {
diff --git a/engines/sherlock/scene.h b/engines/sherlock/scene.h
index f75dfb40cd..f7aa39fd41 100644
--- a/engines/sherlock/scene.h
+++ b/engines/sherlock/scene.h
@@ -145,8 +145,6 @@ public:
class Scene {
private:
- bool _loadingSavedGame;
-
/**
* Loads sounds for the scene
*/
@@ -229,7 +227,7 @@ public:
Common::Array<Exit> _exits;
SceneEntry _entrance;
Common::Array<SceneSound> _sounds;
- ObjectArray _canimShapes;
+ Common::Array<Object *> _canimShapes;
Common::Array<ScaleZone> _scaleZones;
Common::StringArray _objSoundList;
bool _restoreFlag;
diff --git a/engines/sherlock/screen.cpp b/engines/sherlock/screen.cpp
index 208487d0ca..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)
- _backBuffer1.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.cpp b/engines/sherlock/sherlock.cpp
index d09fd0b270..e068ac481a 100644
--- a/engines/sherlock/sherlock.cpp
+++ b/engines/sherlock/sherlock.cpp
@@ -239,6 +239,9 @@ void SherlockEngine::saveConfig() {
ConfMan.setBool("mute", !_sound->_digitized);
ConfMan.setBool("music_mute", !_music->_musicOn);
ConfMan.setBool("speech_mute", !_sound->_speechOn);
+ ConfMan.setInt("music_volume", _music->_musicVolume);
+ ConfMan.setInt("sfx_volume", _sound->_soundVolume);
+ ConfMan.setInt("speech_volume", _sound->_soundVolume);
ConfMan.setInt("font", _screen->fontNumber());
ConfMan.setBool("fade_style", _screen->_fadeStyle);
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.cpp b/engines/sherlock/sound.cpp
index 66b5b5bf5c..e5b1099123 100644
--- a/engines/sherlock/sound.cpp
+++ b/engines/sherlock/sound.cpp
@@ -58,10 +58,9 @@ Sound::Sound(SherlockEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
_soundPlaying = false;
_speechPlaying = false;
_curPriority = 0;
- _soundVolume = 255;
-
- _soundOn = true;
- _speechOn = true;
+ _soundVolume = ConfMan.hasKey("sfx_volume") ? ConfMan.getInt("sfx_volume") : 255;
+ _soundOn = ConfMan.hasKey("mute") ? !ConfMan.getBool("mute") : true;
+ _speechOn = ConfMan.hasKey("speech_mute") ? !ConfMan.getBool("speech_mute") : true;
if (IS_3DO) {
// 3DO: we don't need to prepare anything for sound
@@ -90,7 +89,7 @@ Sound::Sound(SherlockEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
void Sound::syncSoundSettings() {
_digitized = !ConfMan.getBool("mute");
_speechOn = !ConfMan.getBool("mute") && !ConfMan.getBool("speech_mute");
- _voices = _speechOn ? 1 : 0;
+ _voices = _digitized ? 1 : 0;
}
void Sound::loadSound(const Common::String &name, int priority) {
@@ -121,27 +120,13 @@ byte Sound::decodeSample(byte sample, byte &reference, int16 &scale) {
}
bool Sound::playSound(const Common::String &name, WaitType waitType, int priority, const char *libraryFilename) {
- stopSound();
+ // Scalpel has only a single sound handle, so it must be stopped before starting a new sound
+ if (IS_SERRATED_SCALPEL)
+ stopSound();
- Common::String filename = name;
- if (!filename.contains('.')) {
- if (!IS_3DO) {
- if (IS_SERRATED_SCALPEL) {
- filename += ".SND";
- } else {
- filename += ".WAV";
- }
- } else {
- // 3DO uses .aiff extension
- filename += ".AIFF";
- if (!filename.contains('/')) {
- // if no directory was given, use the room sounds directory
- filename = "rooms/sounds/" + filename;
- }
- }
- }
+ Common::String filename = formFilename(name);
- Audio::SoundHandle soundHandle = (IS_SERRATED_SCALPEL) ? _scalpelEffectsHandle : getFreeSoundHandle();
+ Audio::SoundHandle &soundHandle = (IS_SERRATED_SCALPEL) ? _scalpelEffectsHandle : getFreeSoundHandle();
if (!playSoundResource(filename, libraryFilename, Audio::Mixer::kSFXSoundType, soundHandle))
error("Could not find sound resource - %s", filename.c_str());
@@ -168,6 +153,29 @@ bool Sound::playSound(const Common::String &name, WaitType waitType, int priorit
return retval;
}
+Common::String Sound::formFilename(const Common::String &name) {
+ Common::String filename = name;
+
+ if (!filename.contains('.')) {
+ if (!IS_3DO) {
+ if (IS_SERRATED_SCALPEL) {
+ filename += ".SND";
+ } else {
+ filename += ".WAV";
+ }
+ } else {
+ // 3DO uses .aiff extension
+ filename += ".AIFF";
+ if (!filename.contains('/')) {
+ // if no directory was given, use the room sounds directory
+ filename = "rooms/sounds/" + filename;
+ }
+ }
+ }
+
+ return filename;
+}
+
void Sound::playAiff(const Common::String &name, int volume, bool loop) {
Common::File *file = new Common::File();
if (!file->open(name)) {
@@ -222,7 +230,7 @@ void Sound::freeDigiSound() {
_soundPlaying = false;
}
-Audio::SoundHandle Sound::getFreeSoundHandle() {
+Audio::SoundHandle &Sound::getFreeSoundHandle() {
for (int i = 0; i < MAX_MIXER_CHANNELS; i++) {
if (!_mixer->isSoundHandleActive(_tattooEffectsHandle[i]))
return _tattooEffectsHandle[i];
@@ -232,35 +240,41 @@ Audio::SoundHandle Sound::getFreeSoundHandle() {
}
void Sound::setVolume(int volume) {
- warning("TODO: setVolume - %d", volume);
+ _soundVolume = volume;
+ _vm->_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volume);
+ _vm->_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volume);
+ _vm->_mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, volume);
}
void Sound::playSpeech(const Common::String &name) {
Resources &res = *_vm->_res;
Scene &scene = *_vm->_scene;
- stopSpeech();
-
- // TODO: Technically Scalpel has an sfx command which I've set to call this method because it sets the
- // _voice variable as if it were speech. Need to do a play-through of Scalpel and see if it's ever called.
- // If so, will need to enhance this method to handle the Serrated Scalpel voice resources
- assert(IS_ROSE_TATTOO);
- // Figure out which speech library to use
- Common::String libraryName = Common::String::format("speech%02d.lib", scene._currentScene);
- if ((!scumm_strnicmp(name.c_str(), "SLVE12S", 7)) || (!scumm_strnicmp(name.c_str(), "WATS12X", 7))
- || (!scumm_strnicmp(name.c_str(), "HOLM12X", 7)))
- libraryName = "SPEECH12.LIB";
+ // Stop any previously playing speech
+ stopSpeech();
- // If the speech library file doesn't even exist, then we can't play anything
- Common::File f;
- if (!f.exists(libraryName))
- return;
+ if (IS_SERRATED_SCALPEL) {
+ Common::String filename = formFilename(name);
+ if (playSoundResource(filename, Common::String(), Audio::Mixer::kSFXSoundType, _speechHandle))
+ _speechPlaying = true;
+ } else {
+ // Figure out which speech library to use
+ Common::String libraryName = Common::String::format("speech%02d.lib", scene._currentScene);
+ if ((!scumm_strnicmp(name.c_str(), "SLVE12S", 7)) || (!scumm_strnicmp(name.c_str(), "WATS12X", 7))
+ || (!scumm_strnicmp(name.c_str(), "HOLM12X", 7)))
+ libraryName = "SPEECH12.LIB";
+
+ // If the speech library file doesn't even exist, then we can't play anything
+ Common::File f;
+ if (!f.exists(libraryName))
+ return;
- // Ensure the given library is in the cache
- res.addToCache(libraryName);
+ // Ensure the given library is in the cache
+ res.addToCache(libraryName);
- if (playSoundResource(name, libraryName, Audio::Mixer::kSpeechSoundType, _speechHandle))
- _speechPlaying = true;
+ if (playSoundResource(name, libraryName, Audio::Mixer::kSpeechSoundType, _speechHandle))
+ _speechPlaying = true;
+ }
}
void Sound::stopSpeech() {
diff --git a/engines/sherlock/sound.h b/engines/sherlock/sound.h
index 44969b8923..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 {
@@ -61,6 +58,11 @@ private:
*/
bool playSoundResource(const Common::String &name, const Common::String &libFilename,
Audio::Mixer::SoundType soundType, Audio::SoundHandle &handle);
+
+ /**
+ * Form a filename from a passed sound resource name
+ */
+ Common::String formFilename(const Common::String &name);
public:
bool _digitized;
int _voices;
@@ -116,8 +118,14 @@ public:
void freeDigiSound();
- Audio::SoundHandle getFreeSoundHandle();
+ /**
+ * Return a sound handle to use
+ */
+ Audio::SoundHandle &getFreeSoundHandle();
+ /**
+ * Set the volume
+ */
void setVolume(int volume);
/**
diff --git a/engines/sherlock/surface.cpp b/engines/sherlock/surface.cpp
index d7d5cd95e8..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, src.h - drawRect.bottom,
- src.w - drawRect.left, src.h - drawRect.top);
-
- 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 950905084b..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])
@@ -401,7 +409,7 @@ void Talk::talkTo(const Common::String filename) {
_talkHistory[_converseNum][select] = true;
}
- ui._key = ui._oldKey = Scalpel::COMMANDS[TALK_MODE - 1];
+ ui._key = ui._oldKey = 'T'; // FIXME: I'm not sure what to do here, I need ScalpelUI->_hotkeyTalk
ui._temp = ui._oldTemp = 0;
ui._menuMode = TALK_MODE;
_talkToFlag = 2;
@@ -575,6 +583,7 @@ void Talk::loadTalkFile(const Common::String &filename) {
_converseNum = res.resourceIndex();
talkStream->skip(2); // Skip talk file version num
+ _statements.clear();
_statements.resize(talkStream->readByte());
for (uint idx = 0; idx < _statements.size(); ++idx)
_statements[idx].load(*talkStream, IS_ROSE_TATTOO);
@@ -597,7 +606,7 @@ void Talk::stripVoiceCommands() {
// rest of the name following it
statement._reply = Common::String(statement._reply.c_str(),
statement._reply.c_str() + idx) + " " +
- Common::String(statement._reply.c_str() + 9);
+ Common::String(statement._reply.c_str() + idx + 9);
}
}
@@ -751,6 +760,22 @@ void Talk::doScript(const Common::String &script) {
while (*str++ != '}')
;
} else if (isOpcode(c)) {
+ // the original interpreter checked for c being >= 0x80
+ // and if that is the case, it tried to process it as opcode, BUT ALSO ALWAYS skipped over it
+ // This was done inside the Spanish + German interpreters of Serrated Scalpel, not the original
+ // English interpreter (reverse engineered from the binaries).
+ //
+ // This resulted in special characters not getting shown in case they occurred at the start
+ // of sentences like for example the inverted exclamation mark and the inverted question mark.
+ // For further study see fonts.cpp
+ //
+ // We create an inverted exclamation mark for the Spanish version and we show it.
+ //
+ // Us not skipping over those characters may result in an assert() happening inside fonts.cpp
+ // in case more invalid characters exist.
+ // More information see bug #6931
+ //
+
// Handle control code
switch ((this->*_opcodeTable[c - _opcodes[0]])(str)) {
case RET_EXIT:
@@ -830,7 +855,7 @@ int Talk::waitForMore(int delay) {
playingSpeech = sound.isSpeechPlaying();
do {
- if (IS_SERRATED_SCALPEL && sound._speechOn && !sound.isSpeechPlaying())
+ if (IS_SERRATED_SCALPEL && playingSpeech && !sound.isSpeechPlaying())
people._portrait._frameNumber = -1;
scene.doBgAnim();
@@ -874,7 +899,7 @@ int Talk::waitForMore(int delay) {
} while (!_vm->shouldQuit() && key2 == 254 && (delay || (playingSpeech && sound.isSpeechPlaying()))
&& !events._released && !events._rightReleased);
- // If voices was set 2 to indicate a voice file was place, then reset it back to 1
+ // If voices was set 2 to indicate a Scalpel voice file was playing, then reset it back to 1
if (sound._voices == 2)
sound._voices = 1;
@@ -977,6 +1002,10 @@ OpcodeReturn Talk::cmdAdjustObjectSequence(const byte *&str) {
_seqCount = str[1];
str += (str[0] & 127) + 2;
+ // WORKAROUND: Original German Scalpel crash when moving box at Tobacconists
+ if (_vm->getLanguage() == Common::DE_DEU && _scriptName == "Alfr30Z")
+ _seqCount = 16;
+
// Copy in the new sequence
for (int idx = 0; idx < _seqCount; ++idx, ++str)
scene._bgShapes[objId]._sequences[idx] = str[0] - 1;
@@ -1023,6 +1052,7 @@ OpcodeReturn Talk::cmdEndTextWindow(const byte *&str) {
OpcodeReturn Talk::cmdHolmesOff(const byte *&str) {
People &people = *_vm->_people;
people[HOLMES]._type = REMOVE;
+ people._holmesOn = false;
return RET_SUCCESS;
}
@@ -1030,6 +1060,7 @@ OpcodeReturn Talk::cmdHolmesOff(const byte *&str) {
OpcodeReturn Talk::cmdHolmesOn(const byte *&str) {
People &people = *_vm->_people;
people[HOLMES]._type = CHARACTER;
+ people._holmesOn = true;
return RET_SUCCESS;
}
@@ -1177,7 +1208,7 @@ void Talk::talkWait(const byte *&str) {
_endStr = true;
// If a key was pressed to finish the window, see if further voice files should be skipped
- if (_wait >= 0 && _wait < 254) {
+ if (IS_SERRATED_SCALPEL && _wait >= 0 && _wait < 254) {
if (str[0] == _opcodes[OP_SFX_COMMAND])
str += 9;
}
diff --git a/engines/sherlock/talk.h b/engines/sherlock/talk.h
index f354c28c1b..2c0da24d69 100644
--- a/engines/sherlock/talk.h
+++ b/engines/sherlock/talk.h
@@ -215,10 +215,10 @@ protected:
OpcodeReturn cmdWalkToCAnimation(const byte *&str);
protected:
/**
- * Checks, if a character is an opcode
+ * Checks if a character is an opcode
*/
bool isOpcode(byte checkCharacter);
-
+
/**
* Form a table of the display indexes for statements
*/
diff --git a/engines/sherlock/tattoo/tattoo.cpp b/engines/sherlock/tattoo/tattoo.cpp
index bfb35565bc..3131df7649 100644
--- a/engines/sherlock/tattoo/tattoo.cpp
+++ b/engines/sherlock/tattoo/tattoo.cpp
@@ -65,10 +65,15 @@ void TattooEngine::initialize() {
_res->addToCache("walk.lib");
// Set up list of people
+ TattooFixedText &fixedText = *(TattooFixedText *)_fixedText;
+ const char *peopleNamePtr = nullptr;
+
for (int idx = 0; idx < TATTOO_MAX_PEOPLE; ++idx) {
+ peopleNamePtr = fixedText.getText(PEOPLE_DATA[idx].fixedTextId);
+
_people->_characters.push_back(PersonData(
- getLanguage() == Common::FR_FRA ? FRENCH_NAMES[idx] : ENGLISH_NAMES[idx],
- PORTRAITS[idx], nullptr, nullptr));
+ peopleNamePtr,
+ PEOPLE_DATA[idx].portrait, nullptr, nullptr));
}
// Load the inventory
diff --git a/engines/sherlock/tattoo/tattoo_darts.cpp b/engines/sherlock/tattoo/tattoo_darts.cpp
index 6d6c74dcf6..cbc3ea1fe8 100644
--- a/engines/sherlock/tattoo/tattoo_darts.cpp
+++ b/engines/sherlock/tattoo/tattoo_darts.cpp
@@ -30,7 +30,8 @@ namespace Tattoo {
enum {
DART_COLOR_FORE = 5,
- PLAYER_COLOR = 11
+ PLAYER_COLOR = 11,
+ DART_BAR_FORE = 208
};
static const int STATUS_INFO_X = 430;
@@ -69,6 +70,7 @@ Darts::Darts(SherlockEngine *vm) : _vm(vm) {
_handX = 0;
_compPlay = 1;
_escapePressed = false;
+ _spacing = 0;
}
void Darts::playDarts(GameType gameType) {
@@ -81,7 +83,9 @@ void Darts::playDarts(GameType gameType) {
int numHits = 0;
bool gameOver = false;
bool done = false;
- const char *const NUM_HITS_STR[3] = { "a", FIXED(Double), FIXED(Triple) };
+
+ // Set the game mode
+ _gameType = gameType;
screen.setFont(7);
_spacing = screen.fontHeight() + 2;
@@ -89,6 +93,7 @@ void Darts::playDarts(GameType gameType) {
// Load dart graphics and initialize values
loadDarts();
initDarts();
+ events.hideCursor();
while (!done && !_vm->shouldQuit()) {
int roundStart, score;
@@ -158,51 +163,84 @@ 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, "%s # %d", FIXED(Dart), idx + 1);
+ screen.print(Common::Point(_dartInfo.left, _dartInfo.top), 0, FIXED(DartsCurrentDart), idx + 1);
if (_gameType == GAME_301) {
- if (_vm->getLanguage() == Common::FR_FRA)
- screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0,
- "%s %s: %d", FIXED(Scored), FIXED(Points), lastDart);
- else
- screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0,
- "%s %d %s", FIXED(Scored), lastDart, FIXED(Points));
+ // "Scored x points"
+ Common::String scoredPoints;
+
+ // original treated 1 point and multiple points the same. Wrote "Scored 1 points"
+ if (lastDart == 1) {
+ scoredPoints = Common::String::format(FIXED(DartsScoredPoint), lastDart);
+ } else {
+ scoredPoints = Common::String::format(FIXED(DartsScoredPoints), lastDart);
+ }
+
+ screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0, "%s", scoredPoints.c_str());
} else {
- if (lastDart != 25)
- screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0,
- "%s %s %d", FIXED(Hit), NUM_HITS_STR[numHits - 1], lastDart);
- else
- screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0,
- "%s %s %s", FIXED(Hit), NUM_HITS_STR[numHits - 1], FIXED(Bullseye));
+ Common::String hitText;
+
+ if (lastDart != 25) {
+ // Regular hit
+ switch (numHits) {
+ case 1: // "Hit a X"
+ hitText = Common::String::format(FIXED(DartsHitSingle), lastDart);
+ break;
+ case 2: // "Hit double X"
+ hitText = Common::String::format(FIXED(DartsHitDouble), lastDart);
+ break;
+ case 3: // "Hit triple X"
+ hitText = Common::String::format(FIXED(DartsHitTriple), lastDart);
+ break;
+ default:
+ break;
+ }
+ } else {
+ // Bullseye
+ switch (numHits) {
+ case 1:
+ hitText = Common::String(FIXED(DartsHitSingleBullseye));
+ break;
+ case 2:
+ hitText = Common::String(FIXED(DartsHitDoubleBullseye));
+ break;
+ case 3:
+ hitText = Common::String(FIXED(DartsHitTripleBullseye));
+ break;
+ default:
+ break;
+ }
+ }
+ screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0, "%s", hitText.c_str());
}
if (score != 0 && playerNum == 0 && !gameOver)
screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 3), 0,
- "%s", FIXED(PressAKey));
+ "%s", FIXED(DartsPressKey));
if (gameOver) {
screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 3),
- 0, "%s", FIXED(GameOver));
+ 0, "%s", FIXED(DartsGameOver));
if (playerNum == 0) {
screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 4), 0,
- "%s %s", FIXED(Holmes), FIXED(Wins));
+ FIXED(DartsWins), FIXED(DartsPlayerHolmes));
_vm->setFlagsDirect(531);
} else {
screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 4), 0,
- "%s %s!", _opponent.c_str(), FIXED(Wins));
+ FIXED(DartsWins), _opponent.c_str());
_vm->setFlagsDirect(530);
}
screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 5), 0,
- "%s", FIXED(PressAKey));
+ "%s", FIXED(DartsPressKey));
done = true;
idx = 10;
} else if (_gameType == GAME_301 && score < 0) {
screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 2), 0,
- "%s!", FIXED(Busted));
+ "%s!", FIXED(DartsBusted));
// End turn
idx = 10;
@@ -221,13 +259,19 @@ void Darts::playDarts(GameType gameType) {
done = true;
break;
}
+ // Wait for keypress
+ do {
+ events.pollEventsAndWait();
+ events.setButtonState();
+ } while (!_vm->shouldQuit() && !events.kbHit() && !events._pressed);
} else {
- events.wait(20);
+ events.wait(40);
}
- screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_dartInfo.left, _dartInfo.top - 1),
+ // Clears the status part of the board
+ 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;
@@ -235,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);
}
}
@@ -300,7 +344,7 @@ void Darts::initDarts() {
}
}
- _opponent = FIXED(Jock);
+ _opponent = FIXED(DartsPlayerJock);
}
void Darts::loadDarts() {
@@ -324,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() {
@@ -343,7 +387,7 @@ void Darts::showNames(int playerNum) {
byte color;
color = playerNum == 0 ? PLAYER_COLOR : DART_COLOR_FORE;
- screen.print(Common::Point(STATUS_INFO_X, STATUS_INFO_Y), 0, "%s", FIXED(Holmes));
+ screen.print(Common::Point(STATUS_INFO_X, STATUS_INFO_Y), 0, "%s", FIXED(DartsPlayerHolmes));
screen._backBuffer1.fillRect(Common::Rect(STATUS_INFO_X, STATUS_INFO_Y + _spacing + 1,
STATUS_INFO_X + 50, STATUS_INFO_Y + _spacing + 3), color);
screen.fillRect(Common::Rect(STATUS_INFO_X, STATUS_INFO_Y + _spacing + 1,
@@ -356,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(Bull) };
+ 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);
@@ -371,10 +415,15 @@ void Darts::showStatus(int playerNum) {
screen.print(Common::Point(STATUS2_INFO_X + 30, STATUS_INFO_Y + _spacing + 4), 0, "%d", _score2);
int temp = (_gameType == GAME_CRICKET) ? STATUS_INFO_Y + 10 * _spacing + 5 : STATUS_INFO_Y + 55;
- screen.print(Common::Point(STATUS_INFO_X, temp), 0, "%s: %d", FIXED(Round), _roundNum);
+
+ // "Round: x"
+ Common::String dartsRoundStatus = Common::String::format(FIXED(DartsCurrentRound), _roundNum);
+ screen.print(Common::Point(STATUS_INFO_X, temp), 0, "%s", dartsRoundStatus.c_str());
if (_gameType == GAME_301) {
- screen.print(Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 75), 0, "%s: %d", FIXED(TurnTotal), _roundScore);
+ // "Turn Total: x"
+ Common::String dartsTotalPoints = Common::String::format(FIXED(DartsCurrentTotalPoints), _roundScore);
+ 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) {
@@ -399,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));
}
@@ -409,13 +458,13 @@ 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);
}
bool Darts::dartHit() {
Events &events = *_vm->_events;
- events.pollEventsAndWait();
+ events.pollEvents();
events.setButtonState();
// Keyboard check
@@ -440,10 +489,7 @@ int Darts::doPowerBar(const Common::Point &pt, byte color, int goToPower, int or
events.clearEvents();
events.delay(100);
- while (!_vm->shouldQuit()) {
- if (idx >= DART_BAR_SIZE)
- break;
-
+ while (!_vm->shouldQuit() && idx < DART_BAR_SIZE) {
if ((goToPower - 1) == idx)
break;
else if (goToPower == 0) {
@@ -452,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))
@@ -491,18 +537,15 @@ int Darts::drawHand(int goToPower, int computer) {
Common::Point pt(DARTBOARD_LEFT - HAND_OFFSET[hand], SHERLOCK_SCREEN_HEIGHT - _handSize.y);
int x = 0;
- while (!_vm->shouldQuit()) {
- if (x >= DARTBOARD_WIDTH)
- break;
-
- if ((goToPower - 1) == x)
+ while (!_vm->shouldQuit() && x < DARTBOARD_WIDTH) {
+ if (computer && x >= (goToPower - 1))
break;
else if (goToPower == 0) {
if (dartHit())
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));
@@ -560,7 +603,6 @@ void Darts::drawDartThrow(const Common::Point &dartPos, int computer) {
Events &events = *_vm->_events;
Screen &screen = *_vm->_screen;
int cx, cy;
- int drawX = 0, drawY = 0, oldDrawX = 0, oldDrawY = 0;
int xSize = 0, ySize = 0, oldxSize = 0, oldySize = 0;
int handOCx = 0, handOCy = 0;
int ocx = 0, ocy = 0;
@@ -568,6 +610,7 @@ void Darts::drawDartThrow(const Common::Point &dartPos, int computer) {
int delta = 9;
int dartNum;
int hddy;
+ Common::Point drawPos, oldDrawPos;
// Draw the animation of the hand throwing the dart first
// See which hand animation to use
@@ -589,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));
@@ -607,37 +650,37 @@ void Darts::drawDartThrow(const Common::Point &dartPos, int computer) {
xSize = (*_dartGraphics)[dartNum]._width;
ySize = (*_dartGraphics)[dartNum]._height;
- ocx = drawX = cx - (*_dartGraphics)[dartNum]._width / 2;
- ocy = drawY = cy - (*_dartGraphics)[dartNum]._height;
+ ocx = drawPos.x = cx - (*_dartGraphics)[dartNum]._width / 2;
+ ocy = drawPos.y = cy - (*_dartGraphics)[dartNum]._height;
// Draw dart
- screen._backBuffer1.transBlitFrom((*_dartGraphics)[dartNum], dartPos);
+ screen._backBuffer1.SHtransBlitFrom((*_dartGraphics)[dartNum], drawPos);
- if (drawX < 0) {
- xSize += drawX;
+ if (drawPos.x < 0) {
+ xSize += drawPos.x;
if (xSize < 0)
xSize = 1;
- drawX = 0;
+ drawPos.x = 0;
}
- if (drawY < 0) {
- ySize += drawY;
+ if (drawPos.y < 0) {
+ ySize += drawPos.y;
if (ySize < 0)
ySize = 1;
- drawY = 0;
+ drawPos.y = 0;
}
// Flush the drawn dart to the screen
- screen.slamArea(drawX, drawY, xSize, ySize);
- if (oldDrawX != -1)
+ screen.slamArea(drawPos.x, drawPos.y, xSize, ySize);
+ if (oldDrawPos.x != -1)
// Flush the erased dart area
- screen.slamArea(oldDrawX, oldDrawY, oldxSize, oldySize);
+ screen.slamArea(oldDrawPos.x, oldDrawPos.y, oldxSize, oldySize);
- screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(drawX, drawY),
- Common::Rect(drawX, drawY, drawX + xSize, drawY + ySize));
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(drawPos.x, drawPos.y),
+ Common::Rect(drawPos.x, drawPos.y, drawPos.x + xSize, drawPos.y + ySize));
- oldDrawX = drawX;
- oldDrawY = drawY;
+ oldDrawPos.x = drawPos.x;
+ oldDrawPos.y = drawPos.y;
oldxSize = xSize;
oldySize = ySize;
@@ -651,15 +694,15 @@ void Darts::drawDartThrow(const Common::Point &dartPos, int computer) {
screen.slamArea(handOCx, handOCy, handOldxSize, handOldySize);
// Erase the old dart
- if (oldDrawX != -1)
- screen.slamArea(oldDrawX, oldDrawY, oldxSize, oldySize);
+ if (oldDrawPos.x != -1)
+ screen.slamArea(oldDrawPos.x, oldDrawPos.y, oldxSize, oldySize);
- screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(drawX, drawY),
- Common::Rect(drawX, drawY, drawX + xSize, drawY + ySize));
+ 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;
cy = dartPos.y + 2;
- oldDrawX = oldDrawY = -1;
+ oldDrawPos.x = oldDrawPos.y = -1;
for (int idx = 5; idx <= 23; ++idx) {
dartNum = idx - 4;
@@ -677,38 +720,37 @@ void Darts::drawDartThrow(const Common::Point &dartPos, int computer) {
xSize = (*_dartGraphics)[dartNum]._width;
ySize = (*_dartGraphics)[dartNum]._height;
- ocx = drawX = cx - (*_dartGraphics)[dartNum]._width / 2;
- ocy = drawY = cy - (*_dartGraphics)[dartNum]._height;
+ ocx = drawPos.x = cx - (*_dartGraphics)[dartNum]._width / 2;
+ ocy = drawPos.y = cy - (*_dartGraphics)[dartNum]._height;
- screen._backBuffer1.transBlitFrom((*_dartGraphics)[dartNum], Common::Point(drawX, drawY));
+ screen._backBuffer1.SHtransBlitFrom((*_dartGraphics)[dartNum], Common::Point(drawPos.x, drawPos.y));
- if (drawX < 0) {
- xSize += drawX;
+ if (drawPos.x < 0) {
+ xSize += drawPos.x;
if (xSize < 0)
xSize = 1;
- drawX = 0;
+ drawPos.x = 0;
}
- if (drawY < 0) {
- ySize += drawY;
+ if (drawPos.y < 0) {
+ ySize += drawPos.y;
if (ySize < 0)
ySize = 1;
- drawY = 0;
+ drawPos.y = 0;
}
// flush the dart
- screen.slamArea(drawX, drawY, xSize, ySize);
- if (oldDrawX != -1)
- screen.slamArea(oldDrawX, oldDrawY, oldxSize, oldySize);
+ screen.slamArea(drawPos.x, drawPos.y, xSize, ySize);
+ if (oldDrawPos.x != -1)
+ screen.slamArea(oldDrawPos.x, oldDrawPos.y, oldxSize, oldySize);
if (idx != 23)
- screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(drawX, drawY),
- Common::Rect(drawX, drawY, drawX + xSize, drawY + ySize)); // erase dart
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2, drawPos,
+ Common::Rect(drawPos.x, drawPos.y, drawPos.x + xSize, drawPos.y + ySize)); // erase dart
events.wait(1);
- oldDrawX = drawX;
- oldDrawY = drawY;
+ oldDrawPos = drawPos;
oldxSize = xSize;
oldySize = ySize;
}
@@ -720,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);
}
@@ -891,19 +933,22 @@ int Darts::throwDart(int dartNum, int computer) {
events.clearEvents();
erasePowerBars();
- screen.print(Common::Point(_dartInfo.left, _dartInfo.top), 0, "%s # %d", FIXED(Dart), dartNum);
+
+ // "Dart # x"
+ Common::String currentDart = Common::String::format(FIXED(DartsCurrentDart), dartNum);
+ screen.print(Common::Point(_dartInfo.left, _dartInfo.top), 0, "%s", currentDart.c_str());
drawDartsLeft(dartNum, computer);
if (!computer) {
- screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0, "%s", FIXED(HitAKey));
- screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 2), 0, "%s", FIXED(ToStart));
+ screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0, "%s", FIXED(DartsStartPressKey1));
+ screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 2), 0, "%s", FIXED(DartsStartPressKey2));
}
if (!computer) {
// Wait for a hit
while (!dartHit() && !_vm->shouldQuit())
- ;
+ events.wait(1);
if (_escapePressed)
return 0;
} else {
@@ -911,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) {
@@ -927,7 +972,7 @@ int Darts::throwDart(int dartNum, int computer) {
if (_escapePressed)
return 0;
- height = doPowerBar(Common::Point(DART_BAR_VX, DART_HEIGHT_Y), DART_COLOR_FORE, targetPos.y, 1);
+ height = doPowerBar(Common::Point(DART_BAR_VX, DART_HEIGHT_Y), DART_BAR_FORE, targetPos.y, 1);
if (_escapePressed)
return 0;
@@ -935,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));
@@ -979,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.cpp b/engines/sherlock/tattoo/tattoo_fixed_text.cpp
index c9345e44d1..e41cb1f5eb 100644
--- a/engines/sherlock/tattoo/tattoo_fixed_text.cpp
+++ b/engines/sherlock/tattoo/tattoo_fixed_text.cpp
@@ -27,23 +27,22 @@ namespace Sherlock {
namespace Tattoo {
-static const char *const FIXED_TEXT_ENGLISH[] = {
+static const char *const fixedTextEN[] = {
"Money",
- "Card",
- "Tobacco",
- "Timetable",
- "Summons",
- "Foolscap",
- "Damp Paper",
- "Bull's Eye",
-
"Money",
"Card",
+ "Card",
+ "Tobacco",
"Tobacco",
"Timetable",
+ "Timetable",
+ "Summons",
"Summons",
"Foolscap",
"Foolscap",
+ "Damp Paper",
+ "Foolscap",
+ "Bull's Eye",
"Bull's Eye Lantern",
"Open",
@@ -60,32 +59,34 @@ static const char *const FIXED_TEXT_ENGLISH[] = {
"Picked up",
"Page %d",
- "Close Journal",
+ "Close Journal",
"Search Journal",
"Save Journal",
"Abort Search",
"Search Backwards",
"Search Forwards",
"Text Not Found !",
-
+ // Darts
"Holmes",
"Jock",
"Bull",
- "Round",
- "Turn Total",
- "Dart",
- "to start",
+ "Round: %d",
+ "Turn Total: %d",
+ "Dart # %d",
"Hit a key",
+ "To start",
"Press a key",
- "bullseye",
- "GAME OVER",
- "BUSTED",
- "Wins",
- "Scored",
- "points",
- "Hit",
- "Double",
- "Triple",
+ "GAME OVER!",
+ "BUSTED!",
+ "%s Wins",
+ "Scored %d point", // original: treated 1 point and multiple points the same ("Scored 1 points")
+ "Scored %d points",
+ "Hit a %d",
+ "Hit double %d",
+ "Hit triple %d",
+ "Hit a bullseye",
+ "Hit double bullseye",
+ "Hit triple bullseye",
"Apply",
"Water",
@@ -106,67 +107,173 @@ static const char *const FIXED_TEXT_ENGLISH[] = {
"Yes",
"No",
"Enter Password",
- "Going East"
+ "Going East", // correct password, was not and should not to be translated
+ "Watson's Journal",
+ "Journal saved as journal.txt",
+ // SH2: People names
+ "Sherlock Holmes",
+ "Dr. Watson",
+ "Mrs. Hudson",
+ "Stanley Forbes",
+ "Mycroft Holmes",
+ "Wiggins",
+ "Police Constable Burns",
+ "Augustus Trimble",
+ "Police Constable Daley",
+ "Matron",
+ "Sister Grace",
+ "Preston McCabe",
+ "Bob Colleran",
+ "Jonas Rigby",
+ "Police Constable Roach",
+ "James Dewar",
+ "Sergeant Jeremy Duncan",
+ "Inspector Gregson",
+ "Inspector Lestrade",
+ "Jesse Needhem",
+ "Arthur Fleming",
+ "Mr. Thomas Pratt",
+ "Mathilda (Tillie) Mason",
+ "Adrian Russell",
+ "Eldridge Whitney",
+ "Hepplethwaite",
+ "Horace Silverbridge",
+ "Old Sherman",
+ "Maxwell Verner",
+ "Millicent Redding",
+ "Virgil Silverbridge",
+ "George O'Keeffe",
+ "Lord Denys Lawton",
+ "Jenkins",
+ "Jock Mahoney",
+ "Bartender",
+ "Lady Cordelia Lockridge",
+ "Pettigrew",
+ "Sir Avery Fanshawe",
+ "Hodgkins",
+ "Wilbur \"Birdy\" Heywood",
+ "Jacob Farthington",
+ "Philip Bledsoe",
+ "Sidney Fowler",
+ "Professor Theodore Totman",
+ "Rose Hinchem",
+ "Tallboy",
+ "Ethlebert \"Stitch\" Rumsey",
+ "Charles Freedman",
+ "Nigel Hemmings",
+ "Fairfax Carter",
+ "Wilhelm II",
+ "Wachthund",
+ "Jonathan Wilson",
+ "David Lloyd-Jones",
+ "Edward Hargrove",
+ "Misteray",
+ "The Lascar",
+ "Parrot",
+ "Vincent Scarrett",
+ "Alexandra",
+ "Queen Victoria",
+ "John Brown",
+ "A Patient",
+ "A Patient",
+ "Patron",
+ "Queen Victoria",
+ "Patient in white",
+ "Lush",
+ "Drunk",
+ "Prostitute",
+ "Mudlark",
+ "Grinder",
+ "Bouncer",
+ "Agnes Ratchet",
+ "Aloysius Ratchet",
+ "Real Estate Agent",
+ "Candy Clerk",
+ "Beadle",
+ "Prussian",
+ "Mrs. Rowbottom",
+ "Miss Lloyd-Jones",
+ "Tavern patron",
+ "User",
+ "Toby",
+ "Stationer",
+ "Law Clerk",
+ "Ministry Clerk",
+ "Bather",
+ "Maid",
+ "Lady Fanshawe",
+ "Sidney Ratchet",
+ "Boy",
+ "Patron",
+ "Constable Brit",
+ "Wagon Driver"
};
-static const char *const FIXED_TEXT_GERMAN[] = {
+// sharp-s : 0xE1 / octal 341
+// small a-umlaut: 0x84 / octal 204
+// small o-umlaut: 0x94 / octal 224
+// small u-umlaut: 0x81 / octal 201
+// large O-umlaut: 0x99 / octal 231
+static const char *const fixedTextDE[] = {
"Geld",
- "S. Holmes",
- "Tabak",
- "Plan",
- "Aufforderg.",
- "Blatt pap.",
- "Dunstig pap",
- "Handlampe",
-
"Geld",
"S. Holmes",
+ "S. Holmes",
"Tabak",
+ "Tabak",
+ "Plan",
"Plan",
"Aufforderg.",
+ "Aufforderg.",
+ "Blatt pap.",
"Pergament",
"Dunstig pap",
+ "Dunstig pap",
+ "Handlampe",
"Handlampe",
- "ffne",
+ "\231ffne",
"Schau",
"Rede",
"Benutze",
- "Journal",
- "Inventory",
- "Options",
- "Losen",
+ "Tagebuch",
+ "Tasche",
+ "Optionen",
+ "L\224sen",
"mit",
"Keine Wirkung...",
- "Diese Person weic im Augenblick nichts zu berichten.",
+ "Diese Person wei\341 im Augenblick nichts zu berichten.",
+ "Picked up", // <-- ??
"Seite %d",
- "Schliecen",
- "Lessen",
- "In Datei sichern",
+ "Schlie\341en",
+ "Durchsuchen", // original: "Lessen"
+ "In Datei sichern", // original: "Speichern"
"Suche abbrechen",
- "Rbckwarts suchen ",
- "Vorwarts suchen ",
+ "R\201ckw\204rts suchen ",
+ "Vorw\204rts suchen ",
"Text nicht gefunden",
-
+ // Darts
"Holmes",
"Jock",
"Bull",
- "Runde",
- "Gesamt",
- "Pfeil",
+ "Runde: %d",
+ "Gesamt: %d",
+ "Pfeil # %d",
+ "Taste dr\201cken",
"zum Starten",
- "Taste dracken",
- "Taste dracken",
- "Bullseye",
- "SPIEL BEENDET",
- "VERLOREN",
- "Gewinnt",
- "Erzielte",
- "Punkte",
- "Treffer",
- "Doppel",
- "Dreifach",
+ "Taste dr\201cken",
+ "SPIEL BEENDET!",
+ "VERLOREN!",
+ "%s gewinnt!", // "Holmes Gewinnt!", "%s Gewinnt!", original: "%s Gewinnt!"
+ "Erzielte %d Punkt", // original: treated 1 point and multiple points the same ("Scored 1 points")
+ "Erzielte %d Punkte",
+ "%d getroffen", // original: "Treffer %s %d"
+ "Doppel %d getroffen", // original: see above
+ "Dreifach %d getroffen", // original: see above
+ "Bullseye getroffen",
+ "Doppel Bullseye getroffen",
+ "Dreifach Bullseye getroffen",
"Benutze",
"Wasser",
@@ -177,7 +284,7 @@ static const char *const FIXED_TEXT_GERMAN[] = {
"Soundeffekte",
"Voices",
"Textfenster",
- "Transparente Menbs",
+ "Transparente Men\201s",
"Schriftart andern",
"Aus",
"An",
@@ -186,19 +293,508 @@ static const char *const FIXED_TEXT_GERMAN[] = {
"Sind Sie sicher ?",
"Ja",
"Nein",
- "Pacwort eingeben",
- "Going East"
+ "Pa\341wort eingeben",
+ "Going East", // correct password, was not and should not to be translated
+ "Watsons Tagebuch",
+ "Journal gespeichert als journal.txt",
+ // SH2: People names
+ "Sherlock Holmes", // note: People names were not translated in the German interpreter
+ "Dr. Watson",
+ "Mrs. Hudson",
+ "Stanley Forbes",
+ "Mycroft Holmes",
+ "Wiggins",
+ "Police Constable Burns",
+ "Augustus Trimble",
+ "Police Constable Daley",
+ "Matron",
+ "Sister Grace",
+ "Preston McCabe",
+ "Bob Colleran",
+ "Jonas Rigby",
+ "Police Constable Roach",
+ "James Dewar",
+ "Sergeant Jeremy Duncan",
+ "Inspector Gregson",
+ "Inspector Lestrade",
+ "Jesse Needhem",
+ "Arthur Fleming",
+ "Mr. Thomas Pratt",
+ "Mathilda (Tillie) Mason",
+ "Adrian Russell",
+ "Eldridge Whitney",
+ "Hepplethwaite",
+ "Horace Silverbridge",
+ "Old Sherman",
+ "Maxwell Verner",
+ "Millicent Redding",
+ "Virgil Silverbridge",
+ "George O'Keeffe",
+ "Lord Denys Lawton",
+ "Jenkins",
+ "Jock Mahoney",
+ "Bartender",
+ "Lady Cordelia Lockridge",
+ "Pettigrew",
+ "Sir Avery Fanshawe",
+ "Hodgkins",
+ "Wilbur \"Birdy\" Heywood",
+ "Jacob Farthington",
+ "Philip Bledsoe",
+ "Sidney Fowler",
+ "Professor Theodore Totman",
+ "Rose Hinchem",
+ "Tallboy",
+ "Ethlebert \"Stitch\" Rumsey",
+ "Charles Freedman",
+ "Nigel Hemmings",
+ "Fairfax Carter",
+ "Wilhelm II",
+ "Wachthund",
+ "Jonathan Wilson",
+ "David Lloyd-Jones",
+ "Edward Hargrove",
+ "Misteray",
+ "The Lascar",
+ "Parrot",
+ "Vincent Scarrett",
+ "Alexandra",
+ "Queen Victoria",
+ "John Brown",
+ "A Patient",
+ "A Patient",
+ "Patron",
+ "Queen Victoria",
+ "Patient in white",
+ "Lush",
+ "Drunk",
+ "Prostitute",
+ "Mudlark",
+ "Grinder",
+ "Bouncer",
+ "Agnes Ratchet",
+ "Aloysius Ratchet",
+ "Real Estate Agent",
+ "Candy Clerk",
+ "Beadle",
+ "Prussian",
+ "Mrs. Rowbottom",
+ "Miss Lloyd-Jones",
+ "Tavern patron",
+ "User",
+ "Toby",
+ "Stationer",
+ "Law Clerk",
+ "Ministry Clerk",
+ "Bather",
+ "Maid",
+ "Lady Fanshawe",
+ "Sidney Ratchet",
+ "Boy",
+ "Patron",
+ "Constable Brit",
+ "Wagon Driver"
+};
+
+// small a w/ accent grave: 0x85 / octal 205
+// small e w/ accent acute: 0x82 / octal 202
+// small e w/ accent grave: 0x8A / octal 212
+// small e w/ circonflexe: 0x88 / octal 210
+// small cedilla: 0x87 / octal 207
+static const char *const fixedTextFR[] = {
+ "Argent",
+ "Argent",
+ "S. Holmes",
+ "S. Holmes",
+ "Tabac",
+ "Tabac",
+ "Horaire",
+ "Horaire",
+ "Convocation",
+ "Convocation",
+ "Feuille",
+ "Feuille",
+ "F. humide",
+ "Feuille",
+ "Lanterne",
+ "Lanterne",
+
+ "Ouvrir",
+ "Regarder",
+ "Parler",
+ "Utiliser",
+ "Journal", // <--
+ "Inventaire",
+ "Options",
+ "R\202soudre",
+ "avec",
+ "Sans effet...",
+ "Cette personne n'a rien \205 ajouter pour le moment.",
+ "Picked up", // <-- ??
+
+ "Page %d",
+ "Fermer",
+ "Rechercher",
+ "Sauvegarder",
+ "Annuler ",
+ "Chercher avant",
+ "Chercher apr\212s",
+ "Texte introuvable !",
+ // Darts
+ "Holmes",
+ "Jock",
+ "Bull",
+ "Tour: %d",
+ "Total: %d",
+ "Fl\202chette # %d",
+ "Appuyez sur C",
+ "pour commencer",
+ "Appuyez sur C",
+ "FIN DE LA PARTIE!", // original: "Fin de la partie!"
+ "FIASCO!",
+ "%s a gagn\202!", // "Holmes Gagnant!", "%s Gagnant!"
+ "Rapporte %d point", // original: treated 1 point and multiple points the same ("Scored 1 points")
+ "Rapporte %d points", // original: Total des points: %d",
+ "Touche un %d", // original: ???
+ "Touche double %d",
+ "Touche triple %d",
+ "Touche le Bullseye",
+ "Touche double Bullseye",
+ "Touche triple Bullseye",
+
+ "Mouillez",
+ "Puis",
+ "Chauffez",
+ "Charger",
+ "Sauvegarder",
+ "Musique",
+ "Sons",
+ "Voix",
+ "Fen\210tres de texte", // 0x88
+ "Menu Transparent",
+ "Changer la fonte",
+ "Aus", // ???
+ "An", // ???
+ "Quitter",
+ "Voulez-vous quitter?",
+ "Sind Sie sicher ?", // ???
+ "Oui",
+ "Non",
+ "Entrez le mot de passe",
+ "Going East", // correct password, was not and should not to be translated
+ "Journal de Watson",
+ "Journal enregistree comme journal.txt",
+ // SH2: People names
+ "Sherlock Holmes",
+ "Dr. Watson",
+ "Mme. Hudson",
+ "Stanley Forbes",
+ "Mycroft Holmes",
+ "Wiggins",
+ "Sergent Burns",
+ "Augustus Trimble",
+ "Sergent Daley",
+ "Infirmi\212re chef",
+ "Mme. Grace",
+ "Preston McCabe",
+ "Bob Colleran",
+ "Jonas Rigby",
+ "Sergent Roach",
+ "James Dewar",
+ "Sergent Jeremy Duncan",
+ "Inspecteur Gregson",
+ "Inspecteur Lestrade",
+ "Jesse Needhem",
+ "Arthur Fleming",
+ "M. Thomas Pratt",
+ "Mathilda (Tillie) Mason",
+ "Adrian Russell",
+ "Eldridge Whitney",
+ "Hepplethwaite",
+ "Horace Silverbridge",
+ "Sherman",
+ "Maxwell Verner",
+ "Millicent Redding",
+ "Virgil Silverbridge",
+ "George O'Keeffe",
+ "Lord Denys Lawton",
+ "Jenkins",
+ "Jock Mahoney",
+ "Serveur",
+ "Lady Cordelia Lockridge",
+ "Pettigrew",
+ "Sir Avery Fanshawe",
+ "Hodgkins",
+ "Wilbur \"Birdy\" Heywood",
+ "Jacob Farthington",
+ "Philip Bledsoe",
+ "Sidney Fowler",
+ "Professeur Theodore Totman",
+ "Rose Hinchem",
+ "Tallboy",
+ "Ethlebert \"Stitch\" Rumsey",
+ "Charles Freedman",
+ "Nigel Hemmings",
+ "Fairfax Carter",
+ "Wilhelm II",
+ "Wachthund",
+ "Jonathan Wilson",
+ "David Lloyd-Jones",
+ "Edward Hargrove",
+ "Misteray",
+ "Le Lascar",
+ "Oiseau",
+ "Vincent Scarrett",
+ "Alexandra",
+ "Queen Victoria",
+ "John Brown",
+ "Patient",
+ "Patient",
+ "Client",
+ "Queen Victoria",
+ "Patient en blanc",
+ "Ivrogne",
+ "Ivrogne",
+ "Belle femme",
+ "Mudlark",
+ "Broyeur",
+ "Videur",
+ "Agnes Ratchet",
+ "Aloysius Ratchet",
+ "Immobilier",
+ "Gar\207on",
+ "Beadle",
+ "Prussian",
+ "Mme. Rowbottom",
+ "Mme Lloyd-Jones",
+ "Tavern Client",
+ "User",
+ "Toby",
+ "Papeterie",
+ "Law Clerc",
+ "Ministry Employ\202",
+ "Clint du thermes",
+ "Bonne",
+ "Lady Fanshawe",
+ "Sidney Ratchet",
+ "Gar\207on",
+ "Client",
+ "Sergent Brit",
+ "Wagon Driver"
+};
+
+// small a w/ accent bottom to top : 0xA0 / octal 240
+// small i w/ accent bottom to top : 0xA1 / octal 241
+// small o w/ accent bottom to top : 0xA2 / octal 242
+// small u w/ accent bottom to top : 0xA3 / octal 243
+// small n w/ wavy line : 0xA4 / octal 244
+// inverted question mark : 0xA8 / octal 250
+static const char *const fixedTextES[] = {
+ "Dinero",
+ "Dinero",
+ "Tarjeta",
+ "Tarjeta",
+ "Tabaco",
+ "Tabaco",
+ "Horarios",
+ "Horarios",
+ "Mensaje",
+ "Mensaje",
+ "Papel",
+ "Papel",
+ "Papel",
+ "Papel",
+ "Linterna",
+ "Linterna",
+
+ "Abrir",
+ "Mirar",
+ "Hablar",
+ "Usar",
+ "Diario",
+ "Inventario",
+ "Opciones",
+ "Resolver",
+ "con",
+ "Sin Efecto...",
+ "Esta persona no tiene nada que decir en este momento",
+ "Picked up", // <-- ??
+
+ "P\240gina %d",
+ "Cerrar Diario",
+ "Buscar en Diario",
+ "Salvar en Archivo",
+ "Detener B\243squeda",
+ "Buscar Hacia Atr\240s",
+ "Buscar Hacia Delante",
+ "Texto No Encontrado !",
+
+ "Holmes", //
+ "Jock",
+ "Bull",
+ "Vuelta: %d",
+ "Total del Turno: %d",
+ "Dardo # %d",
+ "Pulsa una tecla",
+ "para empezar",
+ "Pulsa una tecla",
+ "FIN DE LA PARTIDA!",
+ "ROTO!",
+ "%s gana!", // "Holmes Gana!", "%s Gana!", original: "%s Gana!"
+ "Puntuado %d punto", // original: treated 1 point and multiple points the same ("Scored 1 points")
+ "Puntuado %d puntos",
+ "Golpe un %d",
+ "Gople doble %d",
+ "Gople triple %d",
+ "Golpe un ojo de buey",
+ "Gople doble ojo de buey",
+ "Gople triple ojo de buey",
+
+ "aplicar",
+ "Agua",
+ "Calentar",
+ "Cargar Partida",
+ "Salvar Partida",
+ "M\243sica",
+ "Efectos de Sonido",
+ "Voces",
+ "Ventanas de Texto",
+ "Men\243s Transparentes",
+ "Cambiar Tipo de Letra",
+ "Off", // ???
+ "On", // ???
+ "Salir",
+ "quieres salir?",
+ "\250Est\240s seguro de que",
+ "Si",
+ "Non",
+ "Introducir Palabra Clave",
+ "Vas al Este", // correct password, was translated in Spanish version (???)
+ "Diario de Watson",
+ "Diario guarda como journal.txt",
+ // SH2: People names
+ "Sherlock Holmes",
+ "Dr. Watson",
+ "Sta. Hudson",
+ "Stanley Forbes",
+ "Mycroft Holmes",
+ "Wiggins",
+ "Agente de Polic\241a Burns",
+ "Augustus Trimble",
+ "Agente de Polic\241a Daley",
+ "Enfermera",
+ "Hermana Grace",
+ "Preston McCabe",
+ "Bob Colleran",
+ "Jonas Rigby",
+ "Agente de Polic\241a Roach",
+ "James Dewar",
+ "Sargento Jeremy Duncan",
+ "Inspector Gregson",
+ "Inspector Lestrade",
+ "Jesse Needhem",
+ "Arthur Fleming",
+ "Sr. Thomas Pratt",
+ "Mathilda (Tillie) Mason",
+ "Adrian Russell",
+ "Eldridge Whitney",
+ "Hepplethwaite",
+ "Horace Silverbridge",
+ "Old Sherman",
+ "Maxwell Verner",
+ "Millicent Redding",
+ "Virgil Silverbridge",
+ "George O'Keeffe",
+ "Lord Denys Lawton",
+ "Jenkins",
+ "Jock Mahoney",
+ "Camarero",
+ "Lady Cordelia Lockridge",
+ "Pettigrew",
+ "Sir Avery Fanshawe",
+ "Hodgkins",
+ "Wilbur \"Birdy\" Heywood",
+ "Jacob Farthington",
+ "Philip Bledsoe",
+ "Sidney Fowler",
+ "Profesor Theodore Totman",
+ "Rose Hinchem",
+ "Tallboy",
+ "Ethlebert \"Stitch\" Rumsey",
+ "Charles Freedman",
+ "Nigel Hemmings",
+ "Fairfax Carter",
+ "Guillermo II",
+ "Wachthund",
+ "Jonathan Wilson",
+ "David Lloyd-Jones",
+ "Edward Hargrove",
+ "Misteray",
+ "The Lascar",
+ "Loro",
+ "Vincent Scarrett",
+ "Alexandra",
+ "Reina Victoria",
+ "John Brown",
+ "Un Paciente",
+ "Un Paciente",
+ "Cliente",
+ "Reina Victoria",
+ "Paciente de blanco",
+ "Exuberante",
+ "Borracho",
+ "Prostituta",
+ "Mudlark",
+ "Grinder",
+ "Mat\242n", // sic? means block in Spanish and not bouncer?!
+ "Agnes Ratchet",
+ "Aloysius Ratchet",
+ "Agente de Bienes Ra\241ces",
+ "Candy Clerk",
+ "Beadle",
+ "Prusiano",
+ "Sta. Rowbottom",
+ "Sra. Lloyd-Jones",
+ "Parroquiano",
+ "Usuario",
+ "Toby",
+ "Papelero",
+ "Secretario de Justicia",
+ "Secreatrio del Ministerio",
+ "Ba\244ista",
+ "Criada",
+ "Lady Fanshawe",
+ "Sidney Ratchet",
+ "Chico",
+ "Patron", // ??? not found??
+ "Agente Brit",
+ "Cochero"
+};
+
+static const FixedTextLanguageEntry fixedTextLanguages[] = {
+ { Common::DE_DEU, fixedTextDE },
+ { Common::ES_ESP, fixedTextES },
+ { Common::EN_ANY, fixedTextEN },
+ { Common::FR_FRA, fixedTextFR },
+ { Common::UNK_LANG, fixedTextEN }
};
TattooFixedText::TattooFixedText(SherlockEngine *vm) : FixedText(vm) {
- if (vm->getLanguage() == Common::DE_DEU)
- _fixedText = FIXED_TEXT_GERMAN;
- else
- _fixedText = FIXED_TEXT_ENGLISH;
+ // Figure out which fixed texts to use
+ Common::Language curLanguage = _vm->getLanguage();
+
+ const FixedTextLanguageEntry *curLanguageEntry = fixedTextLanguages;
+
+ while (curLanguageEntry->language != Common::UNK_LANG) {
+ if (curLanguageEntry->language == curLanguage)
+ break; // found current language
+ curLanguageEntry++;
+ }
+ _curLanguageEntry = curLanguageEntry;
}
const char *TattooFixedText::getText(int fixedTextId) {
- return _fixedText[fixedTextId];
+ return _curLanguageEntry->fixedTextArray[fixedTextId];
}
const Common::String TattooFixedText::getActionMessage(FixedTextActionId actionId, int messageIndex) {
diff --git a/engines/sherlock/tattoo/tattoo_fixed_text.h b/engines/sherlock/tattoo/tattoo_fixed_text.h
index 3f43678ca2..eb636cdada 100644
--- a/engines/sherlock/tattoo/tattoo_fixed_text.h
+++ b/engines/sherlock/tattoo/tattoo_fixed_text.h
@@ -31,20 +31,20 @@ namespace Tattoo {
enum FixedTextId {
kFixedText_Inv1,
- kFixedText_Inv2,
- kFixedText_Inv3,
- kFixedText_Inv4,
- kFixedText_Inv5,
- kFixedText_Inv6,
- kFixedText_Inv7,
- kFixedText_Inv8,
kFixedText_InvDesc1,
+ kFixedText_Inv2,
kFixedText_InvDesc2,
+ kFixedText_Inv3,
kFixedText_InvDesc3,
+ kFixedText_Inv4,
kFixedText_InvDesc4,
+ kFixedText_Inv5,
kFixedText_InvDesc5,
+ kFixedText_Inv6,
kFixedText_InvDesc6,
+ kFixedText_Inv7,
kFixedText_InvDesc7,
+ kFixedText_Inv8,
kFixedText_InvDesc8,
kFixedText_Open,
kFixedText_Look,
@@ -68,24 +68,26 @@ enum FixedTextId {
kFixedText_SearchForwards,
kFixedText_TextNotFound,
- kFixedText_Holmes,
- kFixedText_Jock,
- kFixedText_Bull,
- kFixedText_Round,
- kFixedText_TurnTotal,
- kFixedText_Dart,
- kFixedText_ToStart,
- kFixedText_HitAKey,
- kFixedText_PressAKey,
- kFixedText_Bullseye,
- kFixedText_GameOver,
- kFixedText_Busted,
- kFixedText_Wins,
- kFixedText_Scored,
- kFixedText_Points,
- kFixedText_Hit,
- kFixedText_Double,
- kFixedText_Triple,
+ kFixedText_DartsPlayerHolmes,
+ kFixedText_DartsPlayerJock,
+ kFixedText_DartsBull,
+ kFixedText_DartsCurrentRound,
+ kFixedText_DartsCurrentTotalPoints,
+ kFixedText_DartsCurrentDart,
+ kFixedText_DartsStartPressKey1,
+ kFixedText_DartsStartPressKey2,
+ kFixedText_DartsPressKey,
+ kFixedText_DartsGameOver,
+ kFixedText_DartsBusted,
+ kFixedText_DartsWins,
+ kFixedText_DartsScoredPoint,
+ kFixedText_DartsScoredPoints,
+ kFixedText_DartsHitSingle,
+ kFixedText_DartsHitDouble,
+ kFixedText_DartsHitTriple,
+ kFixedText_DartsHitSingleBullseye,
+ kFixedText_DartsHitDoubleBullseye,
+ kFixedText_DartsHitTripleBullseye,
kFixedText_Apply,
kFixedText_Water,
@@ -106,12 +108,116 @@ enum FixedTextId {
kFixedText_Yes,
kFixedText_No,
kFixedText_EnterPassword,
- kFixedText_CorrectPassword
+ kFixedText_CorrectPassword,
+ kFixedText_WatsonsJournal,
+ kFixedText_JournalSaved,
+ // SH2: People names
+ kFixedText_People_SherlockHolmes,
+ kFixedText_People_DrWatson,
+ kFixedText_People_MrsHudson,
+ kFixedText_People_StanleyForbes,
+ kFixedText_People_MycroftHolmes,
+ kFixedText_People_Wiggins,
+ kFixedText_People_PoliceConstableBurns,
+ kFixedText_People_AugustusTrimble,
+ kFixedText_People_PoliceConstableDaley,
+ kFixedText_People_Matron,
+ kFixedText_People_SisterGrace,
+ kFixedText_People_PrestonMcCabe,
+ kFixedText_People_BobColleran,
+ kFixedText_People_JonasRigby,
+ kFixedText_People_PoliceConstableRoach,
+ kFixedText_People_JamesDewar,
+ kFixedText_People_SergeantJeremyDuncan,
+ kFixedText_People_InspectorGregson,
+ kFixedText_People_InspectorLestrade,
+ kFixedText_People_JesseNeedhem,
+ kFixedText_People_ArthurFleming,
+ kFixedText_People_MrThomasPratt,
+ kFixedText_People_MathildaTillieMason,
+ kFixedText_People_AdrianRussell,
+ kFixedText_People_EldridgeWhitney,
+ kFixedText_People_Hepplethwaite,
+ kFixedText_People_HoraceSilverbridge,
+ kFixedText_People_OldSherman,
+ kFixedText_People_MaxwellVerner,
+ kFixedText_People_MillicentRedding,
+ kFixedText_People_VirgilSilverbridge,
+ kFixedText_People_GeorgeOKeeffe,
+ kFixedText_People_LordDenysLawton,
+ kFixedText_People_Jenkins,
+ kFixedText_People_JockMahoney,
+ kFixedText_People_Bartender,
+ kFixedText_People_LadyCordeliaLockridge,
+ kFixedText_People_Pettigrew,
+ kFixedText_People_SirAveryFanshawe,
+ kFixedText_People_Hodgkins,
+ kFixedText_People_WilburBirdyHeywood,
+ kFixedText_People_JacobFarthington,
+ kFixedText_People_PhilipBledsoe,
+ kFixedText_People_SidneyFowler,
+ kFixedText_People_ProfessorTheodoreTotman,
+ kFixedText_People_RoseHinchem,
+ kFixedText_People_Tallboy,
+ kFixedText_People_EthlebertStitchRumsey,
+ kFixedText_People_CharlesFreedman,
+ kFixedText_People_NigelHemmings,
+ kFixedText_People_FairfaxCarter,
+ kFixedText_People_WilhelmII,
+ kFixedText_People_Wachthund,
+ kFixedText_People_JonathanWilson,
+ kFixedText_People_DavidLloydJones,
+ kFixedText_People_EdwardHargrove,
+ kFixedText_People_Misteray,
+ kFixedText_People_TheLascar,
+ kFixedText_People_Parrot,
+ kFixedText_People_VincentScarrett,
+ kFixedText_People_Alexandra,
+ kFixedText_People_QueenVictoria,
+ kFixedText_People_JohnBrown,
+ kFixedText_People_APatient1,
+ kFixedText_People_APatient2,
+ kFixedText_People_Patron,
+ kFixedText_People_QueenVictoria2,
+ kFixedText_People_PatientInWhite,
+ kFixedText_People_Lush,
+ kFixedText_People_Drunk,
+ kFixedText_People_Prostitute,
+ kFixedText_People_Mudlark,
+ kFixedText_People_Grinder,
+ kFixedText_People_Bouncer,
+ kFixedText_People_AgnesRatchet,
+ kFixedText_People_AloysiusRatchet,
+ kFixedText_People_RealEstateAgent,
+ kFixedText_People_CandyClerk,
+ kFixedText_People_Beadle,
+ kFixedText_People_Prussian,
+ kFixedText_People_MrsRowbottom,
+ kFixedText_People_MissLloydJones,
+ kFixedText_People_TavernPatron,
+ kFixedText_People_User,
+ kFixedText_People_Toby,
+ kFixedText_People_Stationer,
+ kFixedText_People_LawClerk,
+ kFixedText_People_MinistryClerk,
+ kFixedText_People_Bather,
+ kFixedText_People_Maid,
+ kFixedText_People_LadyFanshawe,
+ kFixedText_People_SidneyRatchet,
+ kFixedText_People_Boy,
+ kFixedText_People_Patron2,
+ kFixedText_People_ConstableBrit,
+ kFixedText_People_WagonDriver
+};
+
+struct FixedTextLanguageEntry {
+ Common::Language language;
+ const char *const *fixedTextArray;
};
class TattooFixedText: public FixedText {
private:
- const char *const *_fixedText;
+ const FixedTextLanguageEntry *_curLanguageEntry;
public:
TattooFixedText(SherlockEngine *vm);
virtual ~TattooFixedText() {}
@@ -127,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 e836cca620..4d4f37f8d5 100644
--- a/engines/sherlock/tattoo/tattoo_journal.cpp
+++ b/engines/sherlock/tattoo/tattoo_journal.cpp
@@ -20,6 +20,7 @@
*
*/
+#include "common/savefile.h"
#include "sherlock/tattoo/tattoo_journal.h"
#include "sherlock/tattoo/tattoo_fixed_text.h"
#include "sherlock/tattoo/tattoo_scene.h"
@@ -49,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);
@@ -64,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()) {
@@ -86,12 +87,12 @@ void TattooJournal::show() {
handleKeyboardEvents();
highlightJournalControls(true);
-
+
handleButtons();
if (_wait)
events.wait(2);
-
+
} while (!_vm->shouldQuit() && !_exitJournal);
// Clear events
@@ -130,7 +131,7 @@ void TattooJournal::handleKeyboardEvents() {
events.warpMouse(Common::Point(r.left + r.width() / 3 - 10, r.top + screen.fontHeight() + 2));
} else {
if (_selector == JH_CLOSE)
- _selector = JH_PRINT;
+ _selector = JH_SAVE;
else
--_selector;
@@ -232,7 +233,7 @@ void TattooJournal::handleKeyboardEvents() {
if (_selector == JH_NONE) {
events.warpMouse(Common::Point(r.left + r.width() / 3 - 10, r.top + screen.fontHeight() + 2));
} else {
- if (_selector == JH_PRINT)
+ if (_selector == JH_SAVE)
_selector = JH_NONE;
else
++_selector;
@@ -274,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:
@@ -354,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;
@@ -378,8 +379,13 @@ void TattooJournal::handleButtons() {
break;
}
- case JH_PRINT:
- // Print Journal - not implemented in ScummVM
+ case JH_SAVE:
+ // Save journal to file
+ disableControls();
+ saveJournal();
+ drawFrame();
+ drawJournal(0, 0);
+ screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
break;
default:
@@ -455,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);
}
@@ -480,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);
@@ -507,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);
@@ -517,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;
}
}
@@ -533,7 +539,7 @@ void TattooJournal::drawControls(int mode) {
_oldSelector = 100;
switch (mode) {
- case 0:
+ case 0:
highlightJournalControls(false);
break;
case 1:
@@ -542,7 +548,7 @@ void TattooJournal::drawControls(int mode) {
default:
break;
}
-
+
_oldSelector = savedSelector;
}
@@ -552,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;
@@ -570,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))
@@ -592,7 +598,7 @@ void TattooJournal::highlightJournalControls(bool slamIt) {
}
// See if the Search was selected, but is not available
- if (_journal.empty() && (_selector == JH_SEARCH || _selector == JH_PRINT))
+ if (_journal.empty() && (_selector == JH_SEARCH || _selector == JH_SAVE))
_selector = JH_NONE;
if (_selector == JH_PAGE_LEFT && _oldSelector == JH_PAGE_RIGHT)
@@ -618,8 +624,11 @@ void TattooJournal::highlightJournalControls(bool slamIt) {
color, "%s", FIXED(SearchJournal));
xp += r.width() / 3;
- color = INFO_BOTTOM;
- screen.gPrint(Common::Point(xp - screen.stringWidth(FIXED(SaveJournal)) / 2, r.top + 5),
+ if (!_journal.empty())
+ 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),
color, "%s", FIXED(SaveJournal));
// Draw the horizontal scrollbar
@@ -692,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;
@@ -707,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);
@@ -737,7 +746,7 @@ void TattooJournal::disableControls() {
// Print the Journal commands
int xp = r.left + r.width() / 6;
- for (int idx = 0; idx < 2; ++idx) {
+ for (int idx = 0; idx < 3; ++idx) {
screen.gPrint(Common::Point(xp - screen.stringWidth(JOURNAL_COMMANDS[idx]) / 2, r.top + 5),
INFO_BOTTOM, "%s", JOURNAL_COMMANDS[idx]);
@@ -767,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
@@ -801,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()) {
@@ -837,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());
}
@@ -880,11 +889,11 @@ int TattooJournal::getFindName(bool printError) {
} else {
if (keyState.keycode & Common::KBD_SHIFT) {
if (_selector == JH_CLOSE)
- _selector = JH_PRINT;
+ _selector = JH_SAVE;
else
--_selector;
} else {
- if (_selector == JH_PRINT)
+ if (_selector == JH_SAVE)
_selector = JH_CLOSE;
else
++_selector;
@@ -903,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());
@@ -949,6 +958,173 @@ void TattooJournal::record(int converseNum, int statementNum, bool replyOnly) {
Journal::record(converseNum, statementNum, replyOnly);
}
+void TattooJournal::saveJournal() {
+ Talk &talk = *_vm->_talk;
+ Common::OutSaveFile *file = g_system->getSavefileManager()->openForSaving("journal.txt", false);
+ int tempIndex = _index;
+
+ _index = 0;
+ talk._converseNum = -1;
+
+ file->writeString(" ");
+ file->writeString(FIXED(WatsonsJournal));
+ file->writeString("\n\n");
+
+ // Loop through saving each page of the journal
+ do {
+ // Print a single talk file
+ Common::String text;
+ int line = 0;
+
+ // Copy all of the talk files entries into one big string
+ do {
+ if (_lines[line].hasPrefix("@")) {
+ text += Common::String(_lines[line].c_str() + 1);
+ if ((line + 1) < (int)_lines.size() && _lines[line + 1].hasPrefix("@"))
+ text += "\n";
+ else
+ text += " ";
+ } else {
+ text += _lines[line];
+ text += " ";
+
+ // Check for embedded location names embedded in comment fields,
+ // 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";
+ }
+
+ ++line;
+ } while (line < (int)_lines.size());
+
+ // Now write out the text in 80 column lines
+ 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
+ const char *cr = strchr(text.c_str(), '\n');
+ file->writeString(Common::String(text.c_str(), cr));
+ text = Common::String(cr + 1);
+ } else {
+ // Move backwards to find a word break
+ while (*msgP != ' ')
+ --msgP;
+
+ // Write out the figured out line
+ file->writeString(Common::String(text.c_str(), msgP));
+
+ // Remove the line that was written out
+ while (*msgP == ' ')
+ ++msgP;
+ text = Common::String(msgP);
+ }
+ } else {
+ // The remainder of the string is under 80 characters.
+ // Check to see if has any line ends
+ if (text.contains("\n")) {
+ // Write out the line up to the carraige return
+ const char *cr = strchr(text.c_str(), '\n');
+ file->writeString(Common::String(text.c_str(), cr));
+ text = Common::String(cr + 1);
+ } else {
+ // Write out the final line
+ file->writeString(text);
+ text = "";
+ }
+ }
+
+ file->writeString("\n");
+ } while (!text.empty());
+
+ // Move to next talk file
+ do {
+ ++_index;
+
+ if (_index < (int)_journal.size())
+ loadJournalFile(false);
+ } while (_index < (int)_journal.size() && _lines.empty());
+
+ // Don't immediately exit if there are no loaded lines for
+ // the next page, since it's probably a stealth file and
+ // can simply be skipped
+ file->writeString("\n");
+ } while (_index < (int)_journal.size());
+
+ file->finalize();
+ delete file;
+
+ // Free up any talk file in memory
+ talk.freeTalkVars();
+
+ // Show the message for the journal having been saved
+ showSavedDialog();
+
+ // Reset the previous settings of the journal
+ _index = tempIndex;
+}
+
+void TattooJournal::showSavedDialog() {
+ TattooEngine &vm = *(TattooEngine *)_vm;
+ Events &events = *vm._events;
+ Screen &screen = *vm._screen;
+ TattooUserInterface &ui = *(TattooUserInterface *)vm._ui;
+ ImageFile &images = *ui._interfaceImages;
+ disableControls();
+
+ Common::String msg = FIXED(JournalSaved);
+ Common::Rect inner(0, 0, screen.stringWidth(msg), screen.fontHeight());
+ inner.moveTo((SHERLOCK_SCREEN_WIDTH - inner.width()) / 2,
+ (SHERLOCK_SCREEN_HEIGHT / 2) - (screen.fontHeight() / 2));
+
+ Common::Rect r = inner;
+ r.grow(10);
+
+ if (vm._transparentMenus)
+ ui.makeBGArea(r);
+ else
+ screen._backBuffer1.fillRect(r, 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));
+
+ // Draw the top of the info box
+ screen._backBuffer1.hLine(r.left + images[0]._width, r.top, r.right - images[0]._height, INFO_TOP);
+ screen._backBuffer1.hLine(r.left + images[0]._width, r.top + 1, r.right - images[0]._height, INFO_MIDDLE);
+ screen._backBuffer1.hLine(r.left + images[0]._width, r.top + 2, r.right - images[0]._height, INFO_BOTTOM);
+
+ // Draw the bottom of the info box
+ screen._backBuffer1.hLine(r.left + images[0]._width, r.bottom - 3, r.right - images[0]._height, INFO_TOP);
+ screen._backBuffer1.hLine(r.left + images[0]._width, r.bottom - 2, r.right - images[0]._height, INFO_MIDDLE);
+ screen._backBuffer1.hLine(r.left + images[0]._width, r.bottom - 1, r.right - images[0]._height, INFO_BOTTOM);
+
+ // Draw the left side of the info box
+ screen._backBuffer1.vLine(r.left, r.top + images[0]._height, r.bottom - images[2]._height, INFO_TOP);
+ screen._backBuffer1.vLine(r.left + 1, r.top + images[0]._height, r.bottom - images[2]._height, INFO_MIDDLE);
+ screen._backBuffer1.vLine(r.left + 2, r.top + images[0]._height, r.bottom - images[2]._height, INFO_BOTTOM);
+
+ // Draw the right side of the info box
+ screen._backBuffer1.vLine(r.right - 3, r.top + images[0]._height, r.bottom - images[2]._height, INFO_TOP);
+ screen._backBuffer1.vLine(r.right - 2, r.top + images[0]._height, r.bottom - images[2]._height, INFO_MIDDLE);
+ screen._backBuffer1.vLine(r.right - 1, r.top + images[0]._height, r.bottom - images[2]._height, INFO_BOTTOM);
+
+ // Draw the text
+ screen._backBuffer1.writeString(msg, Common::Point(inner.left, inner.top), INFO_TOP);
+ screen.slamRect(r);
+
+ // Five second pause
+ events.delay(5000, true);
+}
+
} // End of namespace Tattoo
} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/tattoo_journal.h b/engines/sherlock/tattoo/tattoo_journal.h
index 96c1c6cab4..9f0fa1fc9b 100644
--- a/engines/sherlock/tattoo/tattoo_journal.h
+++ b/engines/sherlock/tattoo/tattoo_journal.h
@@ -31,7 +31,7 @@ namespace Sherlock {
namespace Tattoo {
enum JournalHighlight {
- JH_NONE = -1, JH_CLOSE = 0, JH_SEARCH = 1, JH_PRINT = 2,
+ JH_NONE = -1, JH_CLOSE = 0, JH_SEARCH = 1, JH_SAVE = 2,
JH_SCROLL_LEFT = 3, JH_PAGE_LEFT = 4, JH_PAGE_RIGHT = 5, JH_SCROLL_RIGHT = 6, JH_THUMBNAIL = 7
};
@@ -86,6 +86,16 @@ private:
* Get in a name to search through the journal for
*/
int getFindName(bool printError);
+
+ /**
+ * Save the journal to file
+ */
+ void saveJournal();
+
+ /**
+ * Show a message that the journal has been saved to file
+ */
+ void showSavedDialog();
public:
TattooJournal(SherlockEngine *vm);
virtual ~TattooJournal() {}
diff --git a/engines/sherlock/tattoo/tattoo_map.cpp b/engines/sherlock/tattoo/tattoo_map.cpp
index 8438734996..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,18 +357,17 @@ 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) {
Events &events = *_vm->_events;
Screen &screen = *_vm->_screen;
- // Reset scroll position
- screen._currentScroll = Common::Point(0, 0);
+ // Hide the cursor
events.hideCursor();
// Get the closeup images
@@ -404,10 +405,11 @@ void TattooMap::showCloseUp(int closeUpNum) {
for (int step = 0; step < CLOSEUP_STEPS; ++step) {
Common::Point picSize(pic[0].sDrawXSize(scaleVal), pic[0].sDrawYSize(scaleVal));
- Common::Point pt(closeUp.x / 100 - picSize.x / 2, closeUp.y / 100 - picSize.y / 2);
+ Common::Point pt(screen._currentScroll.x + closeUp.x / 100 - picSize.x / 2,
+ 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);
@@ -420,12 +422,13 @@ void TattooMap::showCloseUp(int closeUpNum) {
}
// Handle final drawing of closeup
- Common::Rect r(SHERLOCK_SCREEN_WIDTH / 2 - pic[0]._width / 2, SHERLOCK_SCREEN_HEIGHT / 2 - pic[0]._height / 2,
- SHERLOCK_SCREEN_WIDTH / 2 - pic[0]._width / 2 + pic[0]._width,
- SHERLOCK_SCREEN_HEIGHT / 2 - pic[0]._height / 2 + pic[0]._height);
+ Common::Rect r(screen._currentScroll.x + SHERLOCK_SCREEN_WIDTH / 2 - pic[0]._width / 2,
+ screen._currentScroll.y + SHERLOCK_SCREEN_HEIGHT / 2 - pic[0]._height / 2,
+ screen._currentScroll.x + SHERLOCK_SCREEN_WIDTH / 2 - pic[0]._width / 2 + pic[0]._width,
+ 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 46d91cead8..65cc283b66 100644
--- a/engines/sherlock/tattoo/tattoo_people.cpp
+++ b/engines/sherlock/tattoo/tattoo_people.cpp
@@ -121,12 +121,13 @@ TattooPerson::TattooPerson() : Person() {
_lookHolmes = false;
}
-void TattooPerson::freeAltGraphics() {
- if (_altImages != nullptr) {
- delete _altImages;
- _altImages = nullptr;
- }
+TattooPerson::~TattooPerson() {
+ delete _altImages;
+}
+void TattooPerson::freeAltGraphics() {
+ delete _altImages;
+ _altImages = nullptr;
_altSeq = 0;
}
@@ -1041,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)
@@ -1167,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
@@ -1353,6 +1354,7 @@ void TattooPeople::setTalkSequence(int speaker, int sequenceNum) {
int TattooPeople::findSpeaker(int speaker) {
+ speaker &= 0x7f;
int result = People::findSpeaker(speaker);
const char *portrait = _characters[speaker]._portrait;
@@ -1476,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 722c4a9aaa..c844d86e19 100644
--- a/engines/sherlock/tattoo/tattoo_people.h
+++ b/engines/sherlock/tattoo/tattoo_people.h
@@ -128,7 +128,7 @@ public:
bool _lookHolmes;
public:
TattooPerson();
- virtual ~TattooPerson() {}
+ virtual ~TattooPerson();
/**
* Clear the NPC related data
@@ -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_resources.cpp b/engines/sherlock/tattoo/tattoo_resources.cpp
index 3be41e2650..4b73356d58 100644
--- a/engines/sherlock/tattoo/tattoo_resources.cpp
+++ b/engines/sherlock/tattoo/tattoo_resources.cpp
@@ -21,309 +21,111 @@
*/
#include "sherlock/tattoo/tattoo_resources.h"
+#include "sherlock/tattoo/tattoo_fixed_text.h"
namespace Sherlock {
namespace Tattoo {
-const char PORTRAITS[TATTOO_MAX_PEOPLE][5] = {
- { "HOLM" }, // Sherlock Holmes
- { "WATS" }, // Dr. Watson
- { "HUDS" }, // Mrs. Hudson
- { "FORB" }, // Stanley Forbes
- { "MYCR" }, // Mycroft Holmes
- { "WIGG" }, // Wiggins
- { "BURN" }, // Police Constable Burns
- { "TRIM" }, // Augustus Trimble
- { "DALE" }, // Police Constable Daley
- { "MATR" }, // Matron
- { "GRAC" }, // Sister Grace
- { "MCCA" }, // Preston McCabe
- { "COLL" }, // Bob Colleran
- { "JONA" }, // Jonas Rigby
- { "ROAC" }, // Police Constable Roach
- { "DEWA" }, // James Dewar
- { "JERE" }, // Sergeant Jeremy Duncan
- { "GREG" }, // Inspector Gregson
- { "LEST" }, // Inspector Lestrade
- { "NEED" }, // Jesse Needhem
- { "FLEM" }, // Arthur Fleming
- { "PRAT" }, // Mr. Thomas Pratt
- { "TILL" }, // Mathilda (Tillie) Mason
- { "RUSS" }, // Adrian Russell
- { "WHIT" }, // Eldridge Whitney
- { "HEPP" }, // Hepplethwaite
- { "HORA" }, // Horace Silverbridge
- { "SHER" }, // Old Sherman
- { "VERN" }, // Maxwell Verner
- { "REDD" }, // Millicent Redding
- { "VIRG" }, // Virgil Silverbridge
- { "GEOR" }, // George O'Keeffe
- { "LAWT" }, // Lord Denys Lawton
- { "JENK" }, // Jenkins
- { "JOCK" }, // Jock Mahoney
- { "BART" }, // Bartender
- { "LADY" }, // Lady Cordelia Lockridge
- { "PETT" }, // Pettigrew
- { "FANS" }, // Sir Avery Fanshawe
- { "HODG" }, // Hodgkins
- { "WILB" }, // Wilbur "Birdy" Heywood
- { "JACO" }, // Jacob Farthington
- { "BLED" }, // Philip Bledsoe
- { "FOWL" }, // Sidney Fowler
- { "PROF" }, // Professor Theodore Totman
- { "ROSE" }, // Rose Hinchem
- { "TALL" }, // Tallboy
- { "STIT" }, // Ethlebert "Stitch" Rumsey
- { "FREE" }, // Charles Freedman
- { "HEMM" }, // Nigel Hemmings
- { "CART" }, // Fairfax Carter
- { "WILH" }, // Wilhelm II
- { "WACH" }, // Wachthund
- { "WILS" }, // Jonathan Wilson
- { "DAVE" }, // David Lloyd-Jones
- { "HARG" }, // Edward Hargrove
- { "MORI" }, // Professor James Moriarty
- { "LASC" }, // The Lascar
- { "PARR" }, // Parrot
- { "SCAR" }, // Vincent Scarrett
- { "ALEX" }, // Alexandra
- { "QUEE" }, // Queen Victoria
- { "JOHN" }, // John Brown
- { "PAT1" }, // Patient #1
- { "PAT2" }, // Patient #2
- { "PATR" }, // Patron
- { "QUEN" }, // Queen Victoria
- { "WITE" }, // Patient in White
- { "LUSH" }, // Lush
- { "DRNK" }, // Drunk
- { "PROS" }, // Prostitute
- { "MUDL" }, // Mudlark
- { "GRIN" }, // Grinder
- { "BOUN" }, // Bouncer
- { "RATC" }, // Agnes Ratchet
- { "ALOY" }, // Aloysius Ratchet
- { "REAL" }, // Real Estate Agent
- { "CAND" }, // Candy Clerk
- { "BEAD" }, // Beadle
- { "PRUS" }, // Prussian
- { "ROWB" }, // Mrs. Rowbottom
- { "MSLJ" }, // Miss Lloyd-Jones
- { "TPAT" }, // Tavern patron
- { "USER" }, // User
- { "TOBY" }, // Toby
- { "STAT" }, // Stationer
- { "CLRK" }, // Law Clerk
- { "CLER" }, // Ministry Clerk
- { "BATH" }, // Bather
- { "MAID" }, // Maid
- { "LADF" }, // Lady Fanshawe
- { "SIDN" }, // Sidney Ratchet
- { "BOYO" }, // Boy
- { "PTR2" }, // Second Patron
- { "BRIT" }, // Constable Brit
- { "DROV" } // Wagon Driver
+const PeopleData PEOPLE_DATA[TATTOO_MAX_PEOPLE] = {
+ { "HOLM", kFixedText_People_SherlockHolmes },
+ { "WATS", kFixedText_People_DrWatson },
+ { "HUDS", kFixedText_People_MrsHudson },
+ { "FORB", kFixedText_People_StanleyForbes },
+ { "MYCR", kFixedText_People_MycroftHolmes },
+ { "WIGG", kFixedText_People_Wiggins },
+ { "BURN", kFixedText_People_PoliceConstableBurns },
+ { "TRIM", kFixedText_People_AugustusTrimble },
+ { "DALE", kFixedText_People_PoliceConstableDaley },
+ { "MATR", kFixedText_People_Matron },
+ { "GRAC", kFixedText_People_SisterGrace },
+ { "MCCA", kFixedText_People_PrestonMcCabe },
+ { "COLL", kFixedText_People_BobColleran },
+ { "JONA", kFixedText_People_JonasRigby },
+ { "ROAC", kFixedText_People_PoliceConstableRoach },
+ { "DEWA", kFixedText_People_JamesDewar },
+ { "JERE", kFixedText_People_SergeantJeremyDuncan },
+ { "GREG", kFixedText_People_InspectorGregson },
+ { "LEST", kFixedText_People_InspectorLestrade },
+ { "NEED", kFixedText_People_JesseNeedhem },
+ { "FLEM", kFixedText_People_ArthurFleming },
+ { "PRAT", kFixedText_People_MrThomasPratt },
+ { "TILL", kFixedText_People_MathildaTillieMason },
+ { "RUSS", kFixedText_People_AdrianRussell },
+ { "WHIT", kFixedText_People_EldridgeWhitney },
+ { "HEPP", kFixedText_People_Hepplethwaite },
+ { "HORA", kFixedText_People_HoraceSilverbridge },
+ { "SHER", kFixedText_People_OldSherman },
+ { "VERN", kFixedText_People_MaxwellVerner },
+ { "REDD", kFixedText_People_MillicentRedding },
+ { "VIRG", kFixedText_People_VirgilSilverbridge },
+ { "GEOR", kFixedText_People_GeorgeOKeeffe },
+ { "LAWT", kFixedText_People_LordDenysLawton },
+ { "JENK", kFixedText_People_Jenkins },
+ { "JOCK", kFixedText_People_JockMahoney },
+ { "BART", kFixedText_People_Bartender },
+ { "LADY", kFixedText_People_LadyCordeliaLockridge },
+ { "PETT", kFixedText_People_Pettigrew },
+ { "FANS", kFixedText_People_SirAveryFanshawe },
+ { "HODG", kFixedText_People_Hodgkins },
+ { "WILB", kFixedText_People_WilburBirdyHeywood },
+ { "JACO", kFixedText_People_JacobFarthington },
+ { "BLED", kFixedText_People_PhilipBledsoe },
+ { "FOWL", kFixedText_People_SidneyFowler },
+ { "PROF", kFixedText_People_ProfessorTheodoreTotman },
+ { "ROSE", kFixedText_People_RoseHinchem },
+ { "TALL", kFixedText_People_Tallboy },
+ { "STIT", kFixedText_People_EthlebertStitchRumsey },
+ { "FREE", kFixedText_People_CharlesFreedman },
+ { "HEMM", kFixedText_People_NigelHemmings },
+ { "CART", kFixedText_People_FairfaxCarter },
+ { "WILH", kFixedText_People_WilhelmII },
+ { "WACH", kFixedText_People_Wachthund },
+ { "WILS", kFixedText_People_JonathanWilson },
+ { "DAVE", kFixedText_People_DavidLloydJones },
+ { "HARG", kFixedText_People_EdwardHargrove },
+ { "MORI", kFixedText_People_Misteray },
+ { "LASC", kFixedText_People_TheLascar },
+ { "PARR", kFixedText_People_Parrot },
+ { "SCAR", kFixedText_People_VincentScarrett },
+ { "ALEX", kFixedText_People_Alexandra },
+ { "QUEE", kFixedText_People_QueenVictoria },
+ { "JOHN", kFixedText_People_JohnBrown },
+ { "PAT1", kFixedText_People_APatient1 },
+ { "PAT2", kFixedText_People_APatient2 },
+ { "PATR", kFixedText_People_Patron },
+ { "QUEN", kFixedText_People_QueenVictoria },
+ { "WITE", kFixedText_People_PatientInWhite },
+ { "LUSH", kFixedText_People_Lush },
+ { "DRNK", kFixedText_People_Drunk },
+ { "PROS", kFixedText_People_Prostitute },
+ { "MUDL", kFixedText_People_Mudlark },
+ { "GRIN", kFixedText_People_Grinder },
+ { "BOUN", kFixedText_People_Bouncer },
+ { "RATC", kFixedText_People_AgnesRatchet },
+ { "ALOY", kFixedText_People_AloysiusRatchet },
+ { "REAL", kFixedText_People_RealEstateAgent },
+ { "CAND", kFixedText_People_CandyClerk },
+ { "BEAD", kFixedText_People_Beadle },
+ { "PRUS", kFixedText_People_Prussian },
+ { "ROWB", kFixedText_People_MrsRowbottom },
+ { "MSLJ", kFixedText_People_MissLloydJones },
+ { "TPAT", kFixedText_People_TavernPatron },
+ { "USER", kFixedText_People_User },
+ { "TOBY", kFixedText_People_Toby },
+ { "STAT", kFixedText_People_Stationer },
+ { "CLRK", kFixedText_People_LawClerk },
+ { "CLER", kFixedText_People_MinistryClerk },
+ { "BATH", kFixedText_People_Bather },
+ { "MAID", kFixedText_People_Maid },
+ { "LADF", kFixedText_People_LadyFanshawe },
+ { "SIDN", kFixedText_People_SidneyRatchet },
+ { "BOYO", kFixedText_People_Boy },
+ { "PTR2", kFixedText_People_Patron2 },
+ { "BRIT", kFixedText_People_ConstableBrit },
+ { "DROV", kFixedText_People_WagonDriver }
};
-const char *const FRENCH_NAMES[TATTOO_MAX_PEOPLE] = {
- "Sherlock Holmes",
- "Dr. Watson",
- "Mme. Hudson",
- "Stanley Forbes",
- "Mycroft Holmes",
- "Wiggins",
- "Sergent Burns",
- "Augustus Trimble",
- "Sergent Daley",
- "Infirmi?re chef",
- "Mme. Grace",
- "Preston McCabe",
- "Bob Colleran",
- "Jonas Rigby",
- "Sergent Roach",
- "James Dewar",
- "Sergent Jeremy Duncan",
- "Inspecteur Gregson",
- "Inspecteur Lestrade",
- "Jesse Needhem",
- "Arthur Fleming",
- "M. Thomas Pratt",
- "Mathilda (Tillie) Mason",
- "Adrian Russell",
- "Eldridge Whitney",
- "Hepplethwaite",
- "Horace Silverbridge",
- "Sherman",
- "Maxwell Verner",
- "Millicent Redding",
- "Virgil Silverbridge",
- "George O'Keeffe",
- "Lord Denys Lawton",
- "Jenkins",
- "Jock Mahoney",
- "Serveur",
- "Lady Cordelia Lockridge",
- "Pettigrew",
- "Sir Avery Fanshawe",
- "Hodgkins",
- "Wilbur \"Birdy\" Heywood",
- "Jacob Farthington",
- "Philip Bledsoe",
- "Sidney Fowler",
- "Professeur Theodore Totman",
- "Rose Hinchem",
- "Tallboy",
- "Ethlebert \"Stitch\" Rumsey",
- "Charles Freedman",
- "Nigel Hemmings",
- "Fairfax Carter",
- "Wilhelm II",
- "Wachthund",
- "Jonathan Wilson",
- "David Lloyd-Jones",
- "Edward Hargrove",
- "Misteray",
- "Le Lascar",
- "Oiseau",
- "Vincent Scarrett",
- "Alexandra",
- "Queen Victoria",
- "John Brown",
- "Patient",
- "Patient",
- "Client",
- "Queen Victoria",
- "Patient en blanc",
- "Ivrogne",
- "Ivrogne",
- "Belle femme",
- "Mudlark",
- "Broyeur",
- "Videur",
- "Agnes Ratchet",
- "Aloysius Ratchet",
- "Immobilier",
- "Gar?on",
- "Beadle",
- "Prussian",
- "Mme. Rowbottom",
- "Mme Lloyd-Jones",
- "Tavern Client",
- "User",
- "Toby",
- "Papeterie",
- "Law Clerc",
- "Ministry Employ?",
- "Clint du thermes",
- "Bonne",
- "Lady Fanshawe",
- "Sidney Ratchet",
- "Gar?on",
- "Client",
- "Sergent Brit",
- "Wagon Driver"
-};
-
-const char *const ENGLISH_NAMES[TATTOO_MAX_PEOPLE] = {
- "Sherlock Holmes",
- "Dr. Watson",
- "Mrs. Hudson",
- "Stanley Forbes",
- "Mycroft Holmes",
- "Wiggins",
- "Police Constable Burns",
- "Augustus Trimble",
- "Police Constable Daley",
- "Matron",
- "Sister Grace",
- "Preston McCabe",
- "Bob Colleran",
- "Jonas Rigby",
- "Police Constable Roach",
- "James Dewar",
- "Sergeant Jeremy Duncan",
- "Inspector Gregson",
- "Inspector Lestrade",
- "Jesse Needhem",
- "Arthur Fleming",
- "Mr. Thomas Pratt",
- "Mathilda (Tillie) Mason",
- "Adrian Russell",
- "Eldridge Whitney",
- "Hepplethwaite",
- "Horace Silverbridge",
- "Old Sherman",
- "Maxwell Verner",
- "Millicent Redding",
- "Virgil Silverbridge",
- "George O'Keeffe",
- "Lord Denys Lawton",
- "Jenkins",
- "Jock Mahoney",
- "Bartender",
- "Lady Cordelia Lockridge",
- "Pettigrew",
- "Sir Avery Fanshawe",
- "Hodgkins",
- "Wilbur \"Birdy\" Heywood",
- "Jacob Farthington",
- "Philip Bledsoe",
- "Sidney Fowler",
- "Professor Theodore Totman",
- "Rose Hinchem",
- "Tallboy",
- "Ethlebert \"Stitch\" Rumsey",
- "Charles Freedman",
- "Nigel Hemmings",
- "Fairfax Carter",
- "Wilhelm II",
- "Wachthund",
- "Jonathan Wilson",
- "David Lloyd-Jones",
- "Edward Hargrove",
- "Misteray",
- "The Lascar",
- "Parrot",
- "Vincent Scarrett",
- "Alexandra",
- "Queen Victoria",
- "John Brown",
- "A Patient",
- "A Patient",
- "Patron",
- "Queen Victoria",
- "Patient in white",
- "Lush",
- "Drunk",
- "Prostitute",
- "Mudlark",
- "Grinder",
- "Bouncer",
- "Agnes Ratchet",
- "Aloysius Ratchet",
- "Real Estate Agent",
- "Candy Clerk",
- "Beadle",
- "Prussian",
- "Mrs. Rowbottom",
- "Miss Lloyd-Jones",
- "Tavern patron",
- "User",
- "Toby",
- "Stationer",
- "Law Clerk",
- "Ministry Clerk",
- "Bather",
- "Maid",
- "Lady Fanshawe",
- "Sidney Ratchet",
- "Boy",
- "Patron",
- "Constable Brit",
- "Wagon Driver"
-};
-
-
} // End of namespace Tattoo
} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/tattoo_resources.h b/engines/sherlock/tattoo/tattoo_resources.h
index b706d90f2d..85a78734b9 100644
--- a/engines/sherlock/tattoo/tattoo_resources.h
+++ b/engines/sherlock/tattoo/tattoo_resources.h
@@ -31,9 +31,12 @@ namespace Tattoo {
#define TATTOO_MAX_PEOPLE 96
-extern const char PORTRAITS[TATTOO_MAX_PEOPLE][5];
-extern const char *const FRENCH_NAMES[TATTOO_MAX_PEOPLE];
-extern const char *const ENGLISH_NAMES[TATTOO_MAX_PEOPLE];
+struct PeopleData {
+ const char *portrait;
+ int fixedTextId;
+};
+
+extern const PeopleData PEOPLE_DATA[TATTOO_MAX_PEOPLE];
} // End of namespace Tattoo
diff --git a/engines/sherlock/tattoo/tattoo_scene.cpp b/engines/sherlock/tattoo/tattoo_scene.cpp
index ca536f3e64..00015cb189 100644
--- a/engines/sherlock/tattoo/tattoo_scene.cpp
+++ b/engines/sherlock/tattoo/tattoo_scene.cpp
@@ -90,20 +90,25 @@ bool TattooScene::loadScene(const Common::String &filename) {
}
}
+ // Handle loading music for the scene
+ if (talk._scriptMoreFlag != 1 && talk._scriptMoreFlag != 3)
+ music._nextSongName = Common::String::format("res%02d", _currentScene);
+
// Set the NPC paths for the scene
setNPCPath(WATSON);
- // Handle loading music for the scene
- if (music._musicOn) {
- if (talk._scriptMoreFlag != 1 && talk._scriptMoreFlag != 3)
- music._nextSongName = Common::String::format("res%02d", _currentScene);
-
- // If it's a new song, then start it up
- if (music._currentSongName.compareToIgnoreCase(music._nextSongName)) {
- if (music.loadSong(music._nextSongName)) {
- if (music._musicOn)
- music.startSong();
- }
+ // If it's a new song, then start it up
+ if (music._currentSongName.compareToIgnoreCase(music._nextSongName)) {
+ // WORKAROUND: Stop playing music after Diogenes fire scene in the intro,
+ // since it overlaps slightly into the next scene
+ if (talk._scriptName == "prol80p" && _currentScene == 80) {
+ music.stopMusic();
+ events.wait(5);
+ }
+
+ if (music.loadSong(music._nextSongName)) {
+ if (music._musicOn)
+ music.startSong();
}
}
@@ -136,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();
@@ -189,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
@@ -207,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) {
@@ -237,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);
}
}
@@ -250,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) {
@@ -655,8 +660,6 @@ int TattooScene::startCAnim(int cAnimNum, int playRate) {
if (ui._windowOpen)
ui.banishWindow();
- //_activeCAnim._filesize = cAnim._size;
-
// Open up the room resource file and get the data for the animation
Common::SeekableReadStream *stream = res.load(_roomFilename);
stream->seek(44 + cAnimNum * 4);
@@ -692,6 +695,7 @@ int TattooScene::startCAnim(int cAnimNum, int playRate) {
_goToScene = STARTING_GAME_SCENE;
talk._talkToAbort = true;
_activeCAnim.close();
+ break;
}
}
}
@@ -718,6 +722,7 @@ int TattooScene::startCAnim(int cAnimNum, int playRate) {
// Flag the Canimation to be cleared
_activeCAnim._zPlacement = REMOVE;
_activeCAnim._removeBounds = _activeCAnim._oldBounds;
+ _vm->_ui->_bgFound = -1;
// Free up the animation
_activeCAnim.close();
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/sherlock/tattoo/tattoo_screen.h b/engines/sherlock/tattoo/tattoo_screen.h
new file mode 100644
index 0000000000..b55e9bb0dd
--- /dev/null
+++ b/engines/sherlock/tattoo/tattoo_screen.h
@@ -0,0 +1,44 @@
+/* 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_TATTOO_SCREEN_H
+#define SHERLOCK_TATTOO_SCREEN_H
+
+#include "sherlock/screen.h"
+
+namespace Sherlock {
+
+class SherlockEngine;
+
+namespace Tattoo {
+
+class TattooScreen : public Screen {
+public:
+ TattooScreen(SherlockEngine *vm);
+ virtual ~TattooScreen() {}
+};
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/tattoo/tattoo_talk.cpp b/engines/sherlock/tattoo/tattoo_talk.cpp
index a4ceca042b..e6b9a9627e 100644
--- a/engines/sherlock/tattoo/tattoo_talk.cpp
+++ b/engines/sherlock/tattoo/tattoo_talk.cpp
@@ -341,6 +341,10 @@ OpcodeReturn TattooTalk::cmdNextSong(const byte *&str) {
music._nextSongName += str[idx];
str += 7;
+ // WORKAROUND: Original game set wrong music name at the end of the introduction sequence
+ if (_scriptName == "prol80p" && music._nextSongName == "default")
+ music._nextSongName = "01cue90";
+
return RET_SUCCESS;
}
@@ -791,7 +795,10 @@ OpcodeReturn TattooTalk::cmdTalkInterruptsDisable(const byte *&str) { error("Dum
// Dummy opcode
OpcodeReturn TattooTalk::cmdTalkInterruptsEnable(const byte *&str) { error("Dummy opcode cmdTalkInterruptsEnable called"); }
-OpcodeReturn TattooTalk::cmdTurnSoundsOff(const byte *&str) { error("TODO: script opcode (cmdTurnSoundsOff)"); }
+OpcodeReturn TattooTalk::cmdTurnSoundsOff(const byte *&str) {
+ _vm->_sound->stopSound();
+ return RET_SUCCESS;
+}
OpcodeReturn TattooTalk::cmdWalkHolmesAndNPCToCAnimation(const byte *&str) {
int npcNum = *++str;
diff --git a/engines/sherlock/tattoo/tattoo_user_interface.cpp b/engines/sherlock/tattoo/tattoo_user_interface.cpp
index 139497a8a4..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);
}
@@ -215,9 +215,10 @@ void TattooUserInterface::doJournal() {
TattooJournal &journal = *(TattooJournal *)_vm->_journal;
TattooScene &scene = *(TattooScene *)_vm->_scene;
Screen &screen = *_vm->_screen;
- byte lookupTable[PALETTE_COUNT];
+ byte lookupTable[PALETTE_COUNT], lookupTable1[PALETTE_COUNT];
Common::copy(&_lookupTable[0], &_lookupTable[PALETTE_COUNT], &lookupTable[0]);
+ Common::copy(&_lookupTable1[0], &_lookupTable1[PALETTE_COUNT], &lookupTable1[0]);
_menuMode = JOURNAL_MODE;
journal.show();
@@ -229,9 +230,10 @@ void TattooUserInterface::doJournal() {
screen.clear();
screen.setPalette(screen._cMap);
Common::copy(&lookupTable[0], &lookupTable[PALETTE_COUNT], &_lookupTable[0]);
+ 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);
}
@@ -275,7 +277,7 @@ void TattooUserInterface::handleInput() {
scene._goToScene = STARTING_GAME_SCENE;
} else if (_menuMode == STD_MODE) {
if (_keyState.keycode == Common::KEYCODE_s && vm._allowFastMode) {
- vm._fastMode = !vm._fastMode;
+ events.toggleSpeed();
} else if (_keyState.keycode == Common::KEYCODE_l && _bgFound != -1) {
// Beging used for testing that Look dialogs work
@@ -373,6 +375,7 @@ void TattooUserInterface::doStandardControl() {
TattooEngine &vm = *(TattooEngine *)_vm;
Events &events = *_vm->_events;
People &people = *_vm->_people;
+ SaveManager &saves = *_vm->_saves;
TattooScene &scene = *(TattooScene *)_vm->_scene;
Talk &talk = *_vm->_talk;
Common::Point mousePos = events.mousePos();
@@ -470,6 +473,7 @@ void TattooUserInterface::doStandardControl() {
if (events._rightReleased) {
// Show the verbs menu for the highlighted object
_tooltipWidget.banishWindow();
+ saves.createThumbnail();
_verbsWidget.load(!noDesc);
_verbsWidget.summonWindow();
@@ -723,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) {
@@ -753,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;
@@ -775,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));
}
@@ -789,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;
@@ -866,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
@@ -889,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/tattoo_user_interface.h b/engines/sherlock/tattoo/tattoo_user_interface.h
index c92ff21dd1..d89da4a6da 100644
--- a/engines/sherlock/tattoo/tattoo_user_interface.h
+++ b/engines/sherlock/tattoo/tattoo_user_interface.h
@@ -185,6 +185,9 @@ public:
*/
void doBgAnimEraseBackground();
+ /**
+ * Draws overlays onto the scene. Basically, the smoke effects some scenes have
+ */
void drawMaskArea(bool mode);
/**
diff --git a/engines/sherlock/tattoo/widget_base.cpp b/engines/sherlock/tattoo/widget_base.cpp
index 9e10cee0d1..a35f4e5d74 100644
--- a/engines/sherlock/tattoo/widget_base.cpp
+++ b/engines/sherlock/tattoo/widget_base.cpp
@@ -33,6 +33,7 @@ namespace Tattoo {
WidgetBase::WidgetBase(SherlockEngine *vm) : _vm(vm) {
_scroll = false;
_dialogTimer = 0;
+ _outsideMenu = false;
}
void WidgetBase::summonWindow() {
@@ -87,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
@@ -110,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
@@ -182,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) {
@@ -191,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 b8e297709f..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)) {
@@ -185,14 +185,12 @@ void WidgetCredits::blitCredits() {
screen.slamRect(r);
}
-
- _creditLines[idx]._position.y -= _creditSpeed;
}
}
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)) {
@@ -200,7 +198,10 @@ void WidgetCredits::eraseCredits() {
r.moveTo(_creditLines[idx]._position.x, _creditLines[idx]._position.y - 1 + _creditSpeed);
screen.restoreBackground(r);
+ screen.slamRect(r);
}
+
+ _creditLines[idx]._position.y -= _creditSpeed;
}
if (_creditLines[_creditLines.size() - 1]._position.y < -_creditSpeed) {
diff --git a/engines/sherlock/tattoo/widget_files.cpp b/engines/sherlock/tattoo/widget_files.cpp
index 0f5e6793c4..7666e81480 100644
--- a/engines/sherlock/tattoo/widget_files.cpp
+++ b/engines/sherlock/tattoo/widget_files.cpp
@@ -107,55 +107,53 @@ 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;
int yp = _surface.fontHeight() + 14;
for (int idx = _savegameIndex; idx < (_savegameIndex + FILES_LINES_COUNT); ++idx) {
- if (OP_NAMES || idx == _selector || idx == _oldSelector) {
- if (idx == _selector && mode != RENDER_ALL)
- color = COMMAND_HIGHLIGHTED;
- else
- color = INFO_TOP;
+ if (idx == _selector && mode != RENDER_ALL)
+ color = COMMAND_HIGHLIGHTED;
+ else
+ color = INFO_TOP;
- if (mode == RENDER_NAMES_AND_SCROLLBAR)
- _surface.fillRect(Common::Rect(4, yp, _surface.w() - BUTTON_SIZE - 9, yp + _surface.fontHeight()), TRANSPARENCY);
+ if (mode == RENDER_NAMES_AND_SCROLLBAR)
+ _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);
- _surface.writeString(_savegames[idx], Common::Point(xp, yp), color);
- }
+ Common::String numStr = Common::String::format("%d.", idx + 1);
+ _surface.writeString(numStr, Common::Point(_surface.widestChar(), yp), color);
+ _surface.writeString(_savegames[idx], Common::Point(xp, yp), color);
yp += _surface.fontHeight() + 1;
}
@@ -326,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)
@@ -388,8 +386,8 @@ bool WidgetFiles::getFilename() {
done = -1;
}
- if ((keyState.ascii >= ' ') && ((keyState.ascii <= 168) || (keyState.ascii == 225)) && (index < 50)) {
- if (pt.x + _surface.charWidth(keyState.ascii) < _surface.w() - BUTTON_SIZE - 20) {
+ if ((keyState.ascii >= ' ') && (keyState.ascii <= 'z') && (index < 50)) {
+ 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_files.h b/engines/sherlock/tattoo/widget_files.h
index 94a029d18d..87106f8edb 100644
--- a/engines/sherlock/tattoo/widget_files.h
+++ b/engines/sherlock/tattoo/widget_files.h
@@ -67,7 +67,6 @@ private:
virtual Common::Rect getScrollBarBounds() const;
public:
WidgetFiles(SherlockEngine *vm, const Common::String &target);
- virtual ~WidgetFiles() {}
/**
* Prompt the user whether to quit
diff --git a/engines/sherlock/tattoo/widget_foolscap.cpp b/engines/sherlock/tattoo/widget_foolscap.cpp
index 8246e9a371..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)) {
@@ -184,8 +184,7 @@ void WidgetFoolscap::handleKeyboardEvents() {
TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
Common::KeyState keyState = ui._keyState;
- if (((toupper(keyState.ascii) >= 'A') && (toupper(keyState.ascii) <= 'Z')) ||
- ((keyState.ascii >= 128) && ((keyState.ascii <= 168) || (keyState.ascii == 225)))) {
+ if ((toupper(keyState.ascii) >= 'A') && (toupper(keyState.ascii) <= 'Z')) {
// Visible key pressed, set it and set the keycode to move the caret to the right
_answers[_lineNum][_charNum] = keyState.ascii;
keyState.keycode = Common::KEYCODE_RIGHT;
@@ -266,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 3555ecdffd..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));
}
}
@@ -641,10 +641,12 @@ void WidgetInventory::handleEvents() {
bool found = false;
if (ui._bgFound != -1) {
if (ui._personFound) {
+ Person &person = people[ui._bgFound - 1000];
+
for (int idx = 0; idx < 2; ++idx) {
- if (!people[ui._bgFound - 1000]._use[idx]._verb.compareToIgnoreCase(_verb) &&
- !people[ui._bgFound - 1000]._use[idx]._target.compareToIgnoreCase(_invTarget)) {
- ui.checkAction(people[ui._bgFound - 1000]._use[idx], ui._bgFound);
+ if (!person._use[idx]._verb.compareToIgnoreCase(_verb) &&
+ !person._use[idx]._target.compareToIgnoreCase(_invTarget)) {
+ ui.checkAction(person._use[idx], ui._bgFound);
found = true;
}
}
diff --git a/engines/sherlock/tattoo/widget_options.cpp b/engines/sherlock/tattoo/widget_options.cpp
index 5dc6fc55b9..81f50f3bc5 100644
--- a/engines/sherlock/tattoo/widget_options.cpp
+++ b/engines/sherlock/tattoo/widget_options.cpp
@@ -130,10 +130,9 @@ void WidgetOptions::handleEvents() {
else if (_digiSliderX > _bounds.width() - _surface.widestChar())
_digiSliderX = _bounds.width() - _surface.widestChar();
- int temp = sound._soundVolume;
- sound._soundVolume = (_digiSliderX - _surface.widestChar()) * 255 / (_bounds.width() - _surface.widestChar() * 2);
- if (sound._soundVolume != temp) {
- sound.setVolume(sound._soundVolume);
+ int newVolume = (_digiSliderX - _surface.widestChar()) * 255 / (_bounds.width() - _surface.widestChar() * 2);
+ if (newVolume != sound._soundVolume) {
+ sound.setVolume(newVolume);
vm.saveConfig();
}
@@ -188,7 +187,7 @@ void WidgetOptions::handleEvents() {
case 5:
// Toggle Voices
- sound._voices = !sound._voices;
+ sound._speechOn = !sound._speechOn;
render(OP_NAMES);
vm.saveConfig();
@@ -258,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)
@@ -282,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;
@@ -303,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);
@@ -316,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;
}
@@ -326,25 +325,25 @@ void WidgetOptions::render(OptionRenderMode mode) {
break;
case 5:
- str = Common::String::format("%s %s", FIXED(Voices), OFF_ON[sound._voices]);
+ str = Common::String::format("%s %s", FIXED(Voices), OFF_ON[sound._speechOn]);
break;
case 6: {
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;
}
@@ -376,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 3dd0e308ff..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);
@@ -159,7 +159,7 @@ void WidgetPassword::handleEvents() {
} else if (keycode == Common::KEYCODE_RETURN || keycode == Common::KEYCODE_ESCAPE) {
close();
return;
- } else if (((ui._keyState.ascii >= ' ' && ui._keyState.ascii < 169) || ui._keyState.ascii == 225)) {
+ } else if ((ui._keyState.ascii >= ' ') && (ui._keyState.ascii <= 'z')) {
if (_cursorPos.x + _surface.charWidth(ui._keyState.ascii) < _bounds.width() - _surface.widestChar() - 3) {
if (_insert)
_password.insertChar(ui._keyState.ascii, _index);
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 86aa067301..a29cd2700f 100644
--- a/engines/sherlock/tattoo/widget_text.cpp
+++ b/engines/sherlock/tattoo/widget_text.cpp
@@ -80,6 +80,7 @@ void WidgetText::centerWindowOnSpeaker(int speaker) {
TattooScene &scene = *(TattooScene *)_vm->_scene;
Common::Point pt;
+ speaker &= 0x7f;
bool flag = _vm->readFlags(FLAG_PLAYER_IS_HOLMES);
if (people[HOLMES]._type == CHARACTER && ((speaker == HOLMES && flag) || (speaker == WATSON && !flag))) {
// Place the window centered above the player
@@ -165,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();
@@ -194,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 4c7bb2dc17..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 &&
@@ -222,8 +222,7 @@ SaveStateList SkyMetaEngine::listSaves(const char *target) const {
// Find all saves
Common::StringArray filenames;
- filenames = saveFileMan->listSavefiles("SKY-VM.???");
- sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
+ filenames = saveFileMan->listSavefiles("SKY-VM.###");
// Slot 0 is the autosave, if it exists.
// TODO: Check for the existence of the autosave -- but this require us
@@ -235,16 +234,16 @@ SaveStateList SkyMetaEngine::listSaves(const char *target) const {
// Extract the extension
Common::String ext = file->c_str() + file->size() - 3;
ext.toUppercase();
- if (Common::isDigit(ext[0]) && Common::isDigit(ext[1]) && Common::isDigit(ext[2])) {
- int slotNum = atoi(ext.c_str());
- Common::InSaveFile *in = saveFileMan->openForLoading(*file);
- if (in) {
- saveList.push_back(SaveStateDescriptor(slotNum+1, savenames[slotNum]));
- delete in;
- }
+ int slotNum = atoi(ext.c_str());
+ Common::InSaveFile *in = saveFileMan->openForLoading(*file);
+ if (in) {
+ saveList.push_back(SaveStateDescriptor(slotNum+1, savenames[slotNum]));
+ delete in;
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
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 8a1f3dfef9..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();
}
@@ -240,8 +240,7 @@ SaveStateList SwordMetaEngine::listSaves(const char *target) const {
SaveStateList saveList;
char saveName[40];
- Common::StringArray filenames = saveFileMan->listSavefiles("sword1.???");
- sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
+ Common::StringArray filenames = saveFileMan->listSavefiles("sword1.###");
int slotNum = 0;
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
@@ -259,6 +258,8 @@ SaveStateList SwordMetaEngine::listSaves(const char *target) const {
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
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/objectman.cpp b/engines/sword1/objectman.cpp
index 07f19154a0..651e47f211 100644
--- a/engines/sword1/objectman.cpp
+++ b/engines/sword1/objectman.cpp
@@ -119,7 +119,7 @@ char *ObjectMan::lockText(uint32 textId, uint8 lang) {
return NULL;
addr += sizeof(Header);
if ((textId & ITM_ID) >= _resMan->readUint32(addr)) {
- // Workaround for missing sentences in some langages in the demo.
+ // Workaround for missing sentences in some languages in the demo.
switch(textId) {
case 8455194:
return const_cast<char *>(_translationId8455194[lang]);
@@ -160,7 +160,7 @@ char *ObjectMan::lockText(uint32 textId, uint8 lang) {
}
uint32 offset = _resMan->readUint32(addr + ((textId & ITM_ID) + 1) * 4);
if (offset == 0) {
- // Workaround bug for missing sentence in some langages in Syria (see bug #1977094).
+ // Workaround bug for missing sentence in some languages in Syria (see bug #1977094).
// We use the hardcoded text in this case.
if (textId == 2950145)
return const_cast<char *>(_translationId2950145[lang]);
@@ -223,7 +223,7 @@ void ObjectMan::saveLiveList(uint16 *dest) {
}
// String displayed when a subtitle sentence is missing in the cluster file.
-// It happens with at least one sentence in Syria in some langages (see bug
+// It happens with at least one sentence in Syria in some languages (see bug
// #1977094).
// Note: an empty string or a null pointer causes a crash.
diff --git a/engines/sword1/objectman.h b/engines/sword1/objectman.h
index fef1a8da3a..79be82c02f 100644
--- a/engines/sword1/objectman.h
+++ b/engines/sword1/objectman.h
@@ -62,7 +62,7 @@ private:
uint16 _liveList[TOTAL_SECTIONS]; //which sections are active
uint8 *_cptData[TOTAL_SECTIONS];
static char _missingSubTitleStr[];
- static const char *const _translationId2950145[7]; //translation for textId 2950145 (missing from cluster file for some langages)
+ static const char *const _translationId2950145[7]; //translation for textId 2950145 (missing from cluster file for some languages)
static const char *const _translationId8455194[7]; //translation for textId 8455194 (missing in the demo)
static const char *const _translationId8455195[7]; //translation for textId 8455195 (missing in the demo)
static const char *const _translationId8455196[7]; //translation for textId 8455196 (missing in the demo)
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/router.cpp b/engines/sword1/router.cpp
index 72c8440e1c..0c2e9569b6 100644
--- a/engines/sword1/router.cpp
+++ b/engines/sword1/router.cpp
@@ -1455,7 +1455,7 @@ int32 Router::newCheck(int32 status, int32 x1, int32 y1, int32 x2, int32 y2) {
* newCheck differs from check in that that 4 route options are
* considered corresponding to actual walked routes.
*
- * Note distance doesnt take account of shrinking ???
+ * Note distance doesn't take account of shrinking ???
*
* Note Bars array must be properly calculated ie min max dx dy co
*********************************************************************/
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/interpreter.cpp b/engines/sword2/interpreter.cpp
index e7fb979d69..a13161625c 100644
--- a/engines/sword2/interpreter.cpp
+++ b/engines/sword2/interpreter.cpp
@@ -449,7 +449,7 @@ int Logic::runScript2(byte *scriptData, byte *objectData, byte *offsetPtr) {
Read16ip(parameter);
stack.push(_vm->_memory->encodePtr(localVars + parameter));
- debug(9, "CP_PUSH_LOCAL_ADDR: &localVars[%d] => %p", parameter / 4, localVars + parameter);
+ debug(9, "CP_PUSH_LOCAL_ADDR: &localVars[%d] => %p", parameter / 4, (void *)(localVars + parameter));
break;
case CP_PUSH_STRING:
// Push the address of a string on to the stack
@@ -467,7 +467,7 @@ int Logic::runScript2(byte *scriptData, byte *objectData, byte *offsetPtr) {
Read32ip(parameter);
ptr = objectData + 4 + ResHeader::size() + ObjectHub::size() + parameter;
stack.push(_vm->_memory->encodePtr(ptr));
- debug(9, "CP_PUSH_DEREFERENCED_STRUCTURE: %d => %p", parameter, ptr);
+ debug(9, "CP_PUSH_DEREFERENCED_STRUCTURE: %d => %p", parameter, (void *)ptr);
break;
case CP_POP_LOCAL_VAR32:
// Pop a value into a local word variable
diff --git a/engines/sword2/memory.cpp b/engines/sword2/memory.cpp
index 391983930d..593bb672b6 100644
--- a/engines/sword2/memory.cpp
+++ b/engines/sword2/memory.cpp
@@ -225,7 +225,7 @@ void MemoryManager::memFree(byte *ptr) {
int16 idx = findExactPointerInIndex(ptr);
if (idx == -1) {
- warning("Freeing non-allocated pointer %p", ptr);
+ warning("Freeing non-allocated pointer %p", (void *)ptr);
return;
}
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/router.cpp b/engines/sword2/router.cpp
index d3f274dd2c..e95fa367a0 100644
--- a/engines/sword2/router.cpp
+++ b/engines/sword2/router.cpp
@@ -1712,7 +1712,7 @@ int32 Router::newCheck(int32 status, int32 x1, int32 y1, int32 x2, int32 y2) {
* newCheck differs from check in that that 4 route options are
* considered corresponding to actual walked routes.
*
- * Note distance doesnt take account of shrinking ???
+ * Note distance doesn't take account of shrinking ???
*
* Note Bars array must be properly calculated ie min max dx dy co
*********************************************************************/
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.cpp b/engines/sword2/sword2.cpp
index 3375dda312..44371bf6cf 100644
--- a/engines/sword2/sword2.cpp
+++ b/engines/sword2/sword2.cpp
@@ -231,10 +231,9 @@ SaveStateList Sword2MetaEngine::listSaves(const char *target) const {
Common::StringArray filenames;
char saveDesc[SAVE_DESCRIPTION_LEN];
Common::String pattern = target;
- pattern += ".???";
+ pattern += ".###";
filenames = saveFileMan->listSavefiles(pattern);
- sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
SaveStateList saveList;
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
@@ -252,6 +251,8 @@ SaveStateList Sword2MetaEngine::listSaves(const char *target) const {
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
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 1729bbeb33..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" no "" "" "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 a9f263b7d4..927060bf18 100644
--- a/engines/sword25/detection_tables.h
+++ b/engines/sword25/detection_tables.h
@@ -29,7 +29,7 @@ static const ADGameDescription gameDescriptions[] = {
AD_ENTRY1s("data.b25c", "f8b6e03ada2d2f6cf27fbc11ad1572e9", 654310588),
Common::EN_ANY,
Common::kPlatformUnknown,
- ADGF_UNSTABLE,
+ ADGF_NO_FLAGS,
GUIO1(GUIO_NOASPECT)
},
{
@@ -38,7 +38,7 @@ static const ADGameDescription gameDescriptions[] = {
AD_ENTRY1s("lang_fr.b25c", "690caf157387e06d2c3d1ca53c43f428", 1006043),
Common::FR_FRA,
Common::kPlatformUnknown,
- ADGF_UNSTABLE,
+ ADGF_NO_FLAGS,
GUIO1(GUIO_NOASPECT)
},
{
@@ -47,7 +47,7 @@ static const ADGameDescription gameDescriptions[] = {
AD_ENTRY1s("data.b25c", "f8b6e03ada2d2f6cf27fbc11ad1572e9", 654310588),
Common::DE_DEU,
Common::kPlatformUnknown,
- ADGF_UNSTABLE,
+ ADGF_NO_FLAGS,
GUIO1(GUIO_NOASPECT)
},
{
@@ -56,7 +56,7 @@ static const ADGameDescription gameDescriptions[] = {
AD_ENTRY1s("lang_hr.b25c", "e881054d1f8ec1e527422fc521c25405", 1273217),
Common::HR_HRV,
Common::kPlatformUnknown,
- ADGF_UNSTABLE,
+ ADGF_NO_FLAGS,
GUIO1(GUIO_NOASPECT)
},
{
@@ -65,7 +65,7 @@ static const ADGameDescription gameDescriptions[] = {
AD_ENTRY1s("lang_it.b25c", "f3325666da0515cc2b42062e953c0889", 996197),
Common::IT_ITA,
Common::kPlatformUnknown,
- ADGF_UNSTABLE,
+ ADGF_NO_FLAGS,
GUIO1(GUIO_NOASPECT)
},
{
@@ -74,7 +74,7 @@ static const ADGameDescription gameDescriptions[] = {
AD_ENTRY1s("lang_pl.b25c", "49dc1a20f95391a808e475c49be2bac0", 1281799),
Common::PL_POL,
Common::kPlatformUnknown,
- ADGF_UNSTABLE,
+ ADGF_NO_FLAGS,
GUIO1(GUIO_NOASPECT)
},
{
@@ -83,7 +83,7 @@ static const ADGameDescription gameDescriptions[] = {
AD_ENTRY1s("lang_pt.b25c", "1df701432f9e13dcefe1adeb890b9c69", 993812),
Common::PT_BRA,
Common::kPlatformUnknown,
- ADGF_UNSTABLE,
+ ADGF_NO_FLAGS,
GUIO1(GUIO_NOASPECT)
},
{
@@ -92,7 +92,7 @@ static const ADGameDescription gameDescriptions[] = {
AD_ENTRY1s("lang_ru.b25c", "deb33dd2f90a71ff60181918a8ce5063", 1235378),
Common::RU_RUS,
Common::kPlatformUnknown,
- ADGF_UNSTABLE,
+ ADGF_NO_FLAGS,
GUIO1(GUIO_NOASPECT)
},
{
@@ -101,7 +101,7 @@ static const ADGameDescription gameDescriptions[] = {
AD_ENTRY1s("lang_es.b25c", "384c19072d83725f351bb9ecb4d3f02b", 987965),
Common::ES_ESP,
Common::kPlatformUnknown,
- ADGF_UNSTABLE,
+ ADGF_NO_FLAGS,
GUIO1(GUIO_NOASPECT)
},
// Hungarian "psylog" version.
@@ -112,7 +112,7 @@ static const ADGameDescription gameDescriptions[] = {
AD_ENTRY1s("lang_hu.b25c", "7de51a3b4926a192549e75b1a7d81667", 1864915),
Common::HU_HUN,
Common::kPlatformUnknown,
- ADGF_UNSTABLE,
+ ADGF_NO_FLAGS,
GUIO1(GUIO_NOASPECT)
},
@@ -126,9 +126,25 @@ static const ADGameDescription gameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY,
Common::kPlatformUnknown,
- GF_EXTRACTED | ADGF_UNSTABLE,
+ GF_EXTRACTED | ADGF_NO_FLAGS,
GUIO1(GUIO_NOASPECT)
},
+
+ // 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::UNK_LANG,
+ Common::kPlatformUnknown,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NOASPECT)
+ },
+
AD_TABLE_END_MARKER
};
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/fmv/movieplayer.h b/engines/sword25/fmv/movieplayer.h
index 95fb05ee60..b59b223b4c 100644
--- a/engines/sword25/fmv/movieplayer.h
+++ b/engines/sword25/fmv/movieplayer.h
@@ -67,7 +67,7 @@ public:
* movie file, it will be unloaded and, if necessary, stopped playing.
* @param Filename The filename of the movie file to be loaded
* @param Z Z indicates the position of the film on the main graphics layer
- * @return Returns false if an error occured while loading, otherwise true.
+ * @return Returns false if an error occurred while loading, otherwise true.
*/
bool loadMovie(const Common::String &filename, uint z);
diff --git a/engines/sword25/gfx/animation.cpp b/engines/sword25/gfx/animation.cpp
index e2662fb2b3..541c44662b 100644
--- a/engines/sword25/gfx/animation.cpp
+++ b/engines/sword25/gfx/animation.cpp
@@ -119,6 +119,10 @@ void Animation::initMembers() {
_animationResourcePtr = 0;
_animationTemplateHandle = 0;
_framesLocked = false;
+
+ _loopPointCallback = 0;
+ _actionCallback = 0;
+ _deleteCallback = 0;
}
Animation::~Animation() {
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/graphicengine.cpp b/engines/sword25/gfx/graphicengine.cpp
index f887c3cd51..fd3b63aeee 100644
--- a/engines/sword25/gfx/graphicengine.cpp
+++ b/engines/sword25/gfx/graphicengine.cpp
@@ -60,13 +60,13 @@ enum {
namespace Sword25 {
-static const uint FRAMETIME_SAMPLE_COUNT = 5; // Anzahl der Framezeiten über die, die Framezeit gemittelt wird
+static const uint FRAMETIME_SAMPLE_COUNT = 5; // Frame duration is averaged over FRAMETIME_SAMPLE_COUNT frames
GraphicEngine::GraphicEngine(Kernel *pKernel) :
_width(0),
_height(0),
_bitDepth(0),
- _lastTimeStamp((uint) -1), // max. BS_INT64 um beim ersten Aufruf von _UpdateLastFrameDuration() einen Reset zu erzwingen
+ _lastTimeStamp((uint) -1), // force reset of _UpdateLastFrameDuration() on first call
_lastFrameDuration(0),
_timerActive(true),
_frameTimeSampleSlot(0),
@@ -87,19 +87,18 @@ GraphicEngine::~GraphicEngine() {
}
bool GraphicEngine::init(int width, int height, int bitDepth, int backbufferCount) {
- // Warnung ausgeben, wenn eine nicht unterstützte Bittiefe gewählt wurde.
+ // Warn when an unsupported bit depth has been selected.
if (bitDepth != BIT_DEPTH) {
warning("Can't use a bit depth of %d (not supported). Falling back to %d.", bitDepth, BIT_DEPTH);
_bitDepth = BIT_DEPTH;
}
- // Warnung ausgeben, wenn nicht genau ein Backbuffer gewählt wurde.
+ // Warn when wrong BackBuffer is specified.
if (backbufferCount != BACKBUFFER_COUNT) {
warning("Can't use %d backbuffers (not supported). Falling back to %d.", backbufferCount, BACKBUFFER_COUNT);
backbufferCount = BACKBUFFER_COUNT;
}
- // Parameter in lokale Variablen kopieren
_width = width;
_height = height;
_bitDepth = bitDepth;
@@ -112,13 +111,13 @@ bool GraphicEngine::init(int width, int height, int bitDepth, int backbufferCoun
_backSurface.create(width, height, format);
- // Standardmäßig ist Vsync an.
+ // By default Vsync is on.
setVsync(true);
- // Layer-Manager initialisieren.
+ // Layer-Manager initialization
_renderObjectManagerPtr.reset(new RenderObjectManager(width, height, backbufferCount + 1));
- // Hauptpanel erstellen
+ // Create the main panel
_mainPanelPtr = _renderObjectManagerPtr->getTreeRoot()->addPanel(width, height, BS_ARGB(0, 0, 0, 0));
if (!_mainPanelPtr.isValid())
return false;
@@ -128,11 +127,10 @@ bool GraphicEngine::init(int width, int height, int bitDepth, int backbufferCoun
}
bool GraphicEngine::startFrame(bool updateAll) {
- // Berechnen, wie viel Zeit seit dem letzten Frame vergangen ist.
- // Dieser Wert kann über GetLastFrameDuration() von Modulen abgefragt werden, die zeitabhängig arbeiten.
+ // Calculate how much time has elapsed since the last frame.
updateLastFrameDuration();
- // Den Layer-Manager auf den nächsten Frame vorbereiten
+ // Prepare the Layer Manager for the next frame
_renderObjectManagerPtr->startFrame();
return true;
@@ -276,7 +274,7 @@ Resource *GraphicEngine::loadResource(const Common::String &filename) {
PackageManager *pPackage = Kernel::getInstance()->getPackage();
assert(pPackage);
- // Datei laden
+ // Loading data
byte *pFileData;
uint fileSize;
pFileData = pPackage->getFile(filename, &fileSize);
@@ -375,10 +373,10 @@ bool GraphicEngine::saveThumbnailScreenshot(const Common::String &filename) {
void GraphicEngine::ARGBColorToLuaColor(lua_State *L, uint color) {
lua_Number components[4] = {
- (lua_Number)((color >> 16) & 0xff), // Rot
- (lua_Number)((color >> 8) & 0xff), // Grün
- (lua_Number)(color & 0xff), // Blau
- (lua_Number)(color >> 24), // Alpha
+ (lua_Number)((color >> 16) & 0xff), // Red
+ (lua_Number)((color >> 8) & 0xff), // Green
+ (lua_Number)(color & 0xff), // Blue
+ (lua_Number)(color >> 24), // Alpha
};
lua_newtable(L);
@@ -395,11 +393,11 @@ uint GraphicEngine::luaColorToARGBColor(lua_State *L, int stackIndex) {
int __startStackDepth = lua_gettop(L);
#endif
- // Sicherstellen, dass wir wirklich eine Tabelle betrachten
+ // Make sure that we really look at a table
luaL_checktype(L, stackIndex, LUA_TTABLE);
- // Größe der Tabelle auslesen
+ // getting table size
uint n = luaL_getn(L, stackIndex);
- // RGB oder RGBA Farben werden unterstützt und sonst keine
+ // only RGB or RGBA colors are supported
if (n != 3 && n != 4)
luaL_argcheck(L, 0, stackIndex, "at least 3 of the 4 color components have to be specified");
diff --git a/engines/sword25/gfx/graphicengine.h b/engines/sword25/gfx/graphicengine.h
index cf4289b8bb..cca87b491c 100644
--- a/engines/sword25/gfx/graphicengine.h
+++ b/engines/sword25/gfx/graphicengine.h
@@ -310,8 +310,6 @@ private:
uint _frameTimeSampleSlot;
private:
- byte *_backBuffer;
-
RenderObjectPtr<Panel> _mainPanelPtr;
Common::ScopedPtr<RenderObjectManager> _renderObjectManagerPtr;
diff --git a/engines/sword25/gfx/image/imgloader.cpp b/engines/sword25/gfx/image/imgloader.cpp
index f299cee9d1..6ec0e7c542 100644
--- a/engines/sword25/gfx/image/imgloader.cpp
+++ b/engines/sword25/gfx/image/imgloader.cpp
@@ -33,11 +33,13 @@
#include "sword25/gfx/image/image.h"
#include "sword25/gfx/image/imgloader.h"
#include "graphics/pixelformat.h"
+#include "graphics/surface.h"
#include "image/png.h"
namespace Sword25 {
-bool ImgLoader::decodePNGImage(const byte *fileDataPtr, uint fileSize, byte *&uncompressedDataPtr, int &width, int &height, int &pitch) {
+bool ImgLoader::decodePNGImage(const byte *fileDataPtr, uint fileSize, Graphics::Surface *dest) {
+ assert(dest);
Common::MemoryReadStream *fileStr = new Common::MemoryReadStream(fileDataPtr, fileSize, DisposeAfterUse::NO);
::Image::PNGDecoder png;
@@ -47,12 +49,9 @@ bool ImgLoader::decodePNGImage(const byte *fileDataPtr, uint fileSize, byte *&un
const Graphics::Surface *sourceSurface = png.getSurface();
Graphics::Surface *pngSurface = sourceSurface->convertTo(Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0), png.getPalette());
- width = pngSurface->w;
- height = pngSurface->h;
- uncompressedDataPtr = new byte[pngSurface->pitch * pngSurface->h];
- memcpy(uncompressedDataPtr, (byte *)pngSurface->getPixels(), pngSurface->pitch * pngSurface->h);
- pngSurface->free();
+ dest->copyFrom(*pngSurface);
+ pngSurface->free();
delete pngSurface;
delete fileStr;
@@ -60,24 +59,22 @@ bool ImgLoader::decodePNGImage(const byte *fileDataPtr, uint fileSize, byte *&un
return true;
}
-bool ImgLoader::decodeThumbnailImage(const byte *pFileData, uint fileSize, byte *&pUncompressedData, int &width, int &height, int &pitch) {
+bool ImgLoader::decodeThumbnailImage(const byte *pFileData, uint fileSize, Graphics::Surface *dest) {
+ assert(dest);
const byte *src = pFileData + 4; // skip header
- width = READ_LE_UINT16(src); src += 2;
- height = READ_LE_UINT16(src); src += 2;
+ uint width = READ_LE_UINT16(src); src += 2;
+ uint height = READ_LE_UINT16(src); src += 2;
src++; // version, ignored for now
- pitch = width * 4;
- uint32 totalSize = pitch * height;
- pUncompressedData = new byte[totalSize];
- uint32 *dst = (uint32 *)pUncompressedData; // treat as uint32, for pixelformat output
- const Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
+ dest->create(width, height, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
+ uint32 *dst = (uint32 *)dest->getBasePtr(0, 0); // treat as uint32, for pixelformat output
byte r, g, b;
- for (uint32 i = 0; i < totalSize / 4; i++) {
+ for (uint32 i = 0; i < width * height; i++) {
r = *src++;
g = *src++;
b = *src++;
- *dst++ = format.RGBToColor(r, g, b);
+ *dst++ = dest->format.RGBToColor(r, g, b);
}
return true;
diff --git a/engines/sword25/gfx/image/imgloader.h b/engines/sword25/gfx/image/imgloader.h
index b932cdc903..d9cf3f4d6d 100644
--- a/engines/sword25/gfx/image/imgloader.h
+++ b/engines/sword25/gfx/image/imgloader.h
@@ -35,6 +35,10 @@
#include "sword25/kernel/common.h"
#include "sword25/gfx/graphicengine.h"
+namespace Graphics {
+struct Surface;
+} // End of namespace Graphics
+
namespace Sword25 {
/**
@@ -52,25 +56,18 @@ public:
* Decode an image.
* @param[in] fileDatePtr pointer to the image data
* @param[in] fileSize size of the image data in bytes
- * @param[out] pUncompressedData if successful, this is set to a pointer containing the decoded image data
- * @param[out] width if successful, this is set to the width of the image
- * @param[out] height if successful, this is set to the height of the image
- * @param[out] pitch if successful, this is set to the number of bytes per scanline in the image
+ * @param[out] dest if successful, surface will contain the image
+ * data (storage is allocated via create).
* @return false in case of an error
*
- * @remark The size of the output data equals pitch * height.
* @remark This function does not free the image buffer passed to it,
* it is the callers responsibility to do so.
*/
static bool decodePNGImage(const byte *pFileData, uint fileSize,
- byte *&pUncompressedData,
- int &width, int &height,
- int &pitch);
+ Graphics::Surface *dest);
static bool decodeThumbnailImage(const byte *pFileData, uint fileSize,
- byte *&pUncompressedData,
- int &width, int &height,
- int &pitch);
+ Graphics::Surface *dest);
};
} // End of namespace Sword25
diff --git a/engines/sword25/gfx/image/renderedimage.cpp b/engines/sword25/gfx/image/renderedimage.cpp
index 8c6369a790..8d90d1fa8b 100644
--- a/engines/sword25/gfx/image/renderedimage.cpp
+++ b/engines/sword25/gfx/image/renderedimage.cpp
@@ -126,19 +126,10 @@ RenderedImage::RenderedImage(const Common::String &filename, bool &result) :
}
// Uncompress the image
- int pitch;
- byte *dst;
- int w, h;
if (isPNG)
- result = ImgLoader::decodePNGImage(pFileData, fileSize, dst, w, h, pitch);
+ result = ImgLoader::decodePNGImage(pFileData, fileSize, &_surface);
else
- result = ImgLoader::decodeThumbnailImage(pFileData, fileSize, dst, w, h, pitch);
-
- _surface.w = w;
- _surface.h = h;
- _surface.pitch = w * 4;
- _surface.setPixels(dst);
- _surface.format = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
+ result = ImgLoader::decodeThumbnailImage(pFileData, fileSize, &_surface);
if (!result) {
error("Could not decode image.");
@@ -187,6 +178,9 @@ RenderedImage::RenderedImage() : _isTransparent(true) {
// -----------------------------------------------------------------------------
RenderedImage::~RenderedImage() {
+ if (_doCleanup) {
+ _surface.free();
+ }
}
// -----------------------------------------------------------------------------
diff --git a/engines/sword25/gfx/image/renderedimage.h b/engines/sword25/gfx/image/renderedimage.h
index 5b65a27355..e4d573f369 100644
--- a/engines/sword25/gfx/image/renderedimage.h
+++ b/engines/sword25/gfx/image/renderedimage.h
@@ -44,6 +44,9 @@
namespace Sword25 {
class RenderedImage : public Image {
+private:
+ RenderedImage(const RenderedImage &) : _doCleanup(false) {}
+ RenderedImage &operator=(const RenderedImage &) { return *this; }
public:
RenderedImage(const Common::String &filename, bool &result);
diff --git a/engines/sword25/gfx/image/swimage.cpp b/engines/sword25/gfx/image/swimage.cpp
index 776f8ce8d3..7a3c95b5f9 100644
--- a/engines/sword25/gfx/image/swimage.cpp
+++ b/engines/sword25/gfx/image/swimage.cpp
@@ -35,10 +35,7 @@
namespace Sword25 {
-SWImage::SWImage(const Common::String &filename, bool &result) :
- _imageDataPtr(0),
- _width(0),
- _height(0) {
+SWImage::SWImage(const Common::String &filename, bool &result) : _image() {
result = false;
PackageManager *pPackage = Kernel::getInstance()->getPackage();
@@ -54,9 +51,7 @@ SWImage::SWImage(const Common::String &filename, bool &result) :
}
// Uncompress the image
- int pitch;
- byte *pUncompressedData;
- if (!ImgLoader::decodePNGImage(pFileData, fileSize, pUncompressedData, _width, _height, pitch)) {
+ if (!ImgLoader::decodePNGImage(pFileData, fileSize, &_image)) {
error("Could not decode image.");
return;
}
@@ -64,14 +59,12 @@ SWImage::SWImage(const Common::String &filename, bool &result) :
// Cleanup FileData
delete[] pFileData;
- _imageDataPtr = (uint *)pUncompressedData;
-
result = true;
return;
}
SWImage::~SWImage() {
- delete[] _imageDataPtr;
+ _image.free();
}
@@ -96,10 +89,10 @@ bool SWImage::setContent(const byte *pixeldata, uint size, uint offset, uint str
}
uint SWImage::getPixel(int x, int y) {
- assert(x >= 0 && x < _width);
- assert(y >= 0 && y < _height);
+ assert(x >= 0 && x < _image.w);
+ assert(y >= 0 && y < _image.h);
- return _imageDataPtr[_width * y + x];
+ return *((const uint32 *)_image.getBasePtr(0, 0));
}
} // End of namespace Sword25
diff --git a/engines/sword25/gfx/image/swimage.h b/engines/sword25/gfx/image/swimage.h
index 60978eb6cc..97c6395278 100644
--- a/engines/sword25/gfx/image/swimage.h
+++ b/engines/sword25/gfx/image/swimage.h
@@ -45,10 +45,10 @@ public:
virtual ~SWImage();
virtual int getWidth() const {
- return _width;
+ return _image.w;
}
virtual int getHeight() const {
- return _height;
+ return _image.h;
}
virtual GraphicEngine::COLOR_FORMATS getColorFormat() const {
return GraphicEngine::CF_ARGB32;
@@ -86,10 +86,7 @@ public:
return false;
}
private:
- uint *_imageDataPtr;
-
- int _width;
- int _height;
+ Graphics::Surface _image;
};
} // End of namespace Sword25
diff --git a/engines/sword25/gfx/image/vectorimage.cpp b/engines/sword25/gfx/image/vectorimage.cpp
index 0e5dfb9c53..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.
@@ -283,7 +284,18 @@ VectorImage::VectorImage(const byte *pFileData, uint fileSize, bool &success, co
case 32:
success = parseDefineShape(3, bs);
return;
+ case 9:
+ // SetBackgroundColor
+ {
+ byte r, g, b;
+ r = bs.getByte();
+ g = bs.getByte();
+ b = bs.getByte();
+ _bgColor = Graphics::ARGBToColor<Graphics::ColorMasks<8888> >(0xff, r, g, b);
+ }
+ break;
default:
+ warning("Ignoring tag: %d, %d bytes", tagType, tagLength);
// Ignore unknown tags
bs.skipBytes(tagLength);
}
@@ -300,8 +312,7 @@ VectorImage::~VectorImage() {
if (_elements[j].getPathInfo(i).getVec())
free(_elements[j].getPathInfo(i).getVec());
- if (_pixelData)
- free(_pixelData);
+ free(_pixelData);
}
diff --git a/engines/sword25/gfx/image/vectorimage.h b/engines/sword25/gfx/image/vectorimage.h
index 057064fc6a..b5c2100681 100644
--- a/engines/sword25/gfx/image/vectorimage.h
+++ b/engines/sword25/gfx/image/vectorimage.h
@@ -228,6 +228,7 @@ private:
byte *_pixelData;
Common::String _fname;
+ uint _bgColor;
};
} // End of namespace Sword25
diff --git a/engines/sword25/gfx/image/vectorimagerenderer.cpp b/engines/sword25/gfx/image/vectorimagerenderer.cpp
index c69cb497c1..be734c7b98 100644
--- a/engines/sword25/gfx/image/vectorimagerenderer.cpp
+++ b/engines/sword25/gfx/image/vectorimagerenderer.cpp
@@ -38,8 +38,7 @@
*
*/
-#include "art.h"
-
+#include "sword25/gfx/image/art.h"
#include "sword25/gfx/image/vectorimage.h"
#include "graphics/colormasks.h"
diff --git a/engines/sword25/gfx/panel.cpp b/engines/sword25/gfx/panel.cpp
index 9699db7f6a..2b71854060 100644
--- a/engines/sword25/gfx/panel.cpp
+++ b/engines/sword25/gfx/panel.cpp
@@ -62,7 +62,7 @@ Panel::Panel(RenderObjectPtr<RenderObject> parentPtr, int width, int height, uin
}
Panel::Panel(InputPersistenceBlock &reader, RenderObjectPtr<RenderObject> parentPtr, uint handle) :
- RenderObject(parentPtr, RenderObject::TYPE_PANEL, handle) {
+ RenderObject(parentPtr, RenderObject::TYPE_PANEL, handle), _color(0) {
_initSuccess = unpersist(reader);
}
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/screenshot.cpp b/engines/sword25/gfx/screenshot.cpp
index 4b4f967f29..eeaece97f2 100644
--- a/engines/sword25/gfx/screenshot.cpp
+++ b/engines/sword25/gfx/screenshot.cpp
@@ -40,7 +40,7 @@ namespace Sword25 {
bool Screenshot::saveToFile(Graphics::Surface *data, Common::WriteStream *stream) {
// Convert the RGBA data to RGB
- const byte *pSrc = (const byte *)data->getPixels();
+ const uint32 *pSrc = (const uint32 *)data->getPixels();
// Write our own custom header
stream->writeUint32BE(MKTAG('S','C','R','N')); // SCRN, short for "Screenshot"
@@ -52,11 +52,12 @@ bool Screenshot::saveToFile(Graphics::Surface *data, Common::WriteStream *stream
for (uint x = 0; x < data->w; x++) {
// This is only called by createThumbnail below, which
// provides a fake 'surface' with LE data in it.
- uint32 srcPixel = READ_LE_UINT32(pSrc);
- pSrc += sizeof(uint32);
- stream->writeByte((srcPixel >> 16) & 0xff); // R
- stream->writeByte((srcPixel >> 8) & 0xff); // G
- stream->writeByte(srcPixel & 0xff); // B
+ byte a, r, g, b;
+
+ data->format.colorToARGB(*pSrc++, a, r, g, b);
+ stream->writeByte(r);
+ stream->writeByte(g);
+ stream->writeByte(b);
}
}
@@ -81,30 +82,27 @@ Common::SeekableReadStream *Screenshot::createThumbnail(Graphics::Surface *data)
Graphics::Surface thumbnail;
thumbnail.create(200, 125, g_system->getScreenFormat());
- // Über das Zielbild iterieren und einen Pixel zur Zeit berechnen.
+ // Uber das Zielbild iterieren und einen Pixel zur Zeit berechnen.
uint x, y;
x = y = 0;
- for (byte *pDest = (byte *)thumbnail.getPixels(); pDest < ((byte *)thumbnail.getBasePtr(0, thumbnail.h)); ) {
+ for (uint32 *pDest = (uint32 *)thumbnail.getPixels(); pDest < thumbnail.getBasePtr(0, thumbnail.h); ) {
// Get an average over a 4x4 pixel block in the source image
int alpha, red, green, blue;
alpha = red = green = blue = 0;
for (int j = 0; j < 4; ++j) {
const uint32 *srcP = (const uint32 *)data->getBasePtr(x * 4, y * 4 + j + 50);
for (int i = 0; i < 4; ++i) {
- uint32 pixel = READ_UINT32(srcP + i);
- alpha += (pixel >> 24);
- red += (pixel >> 16) & 0xff;
- green += (pixel >> 8) & 0xff;
- blue += pixel & 0xff;
+ byte a, r, g, b;
+ data->format.colorToARGB(*(srcP + i), a, r, g, b);
+ alpha += a;
+ red += r;
+ green += g;
+ blue += b;
}
}
- // Write target pixel
- *pDest++ = blue / 16;
- *pDest++ = green / 16;
- *pDest++ = red / 16;
- *pDest++ = alpha / 16;
+ *pDest++ = thumbnail.format.ARGBToColor(alpha / 16, red / 16, green / 16, blue / 16);
// Move to next block
++x;
diff --git a/engines/sword25/gfx/staticbitmap.cpp b/engines/sword25/gfx/staticbitmap.cpp
index 1a6c812508..7ab76e625e 100644
--- a/engines/sword25/gfx/staticbitmap.cpp
+++ b/engines/sword25/gfx/staticbitmap.cpp
@@ -124,6 +124,10 @@ uint StaticBitmap::getPixel(int x, int y) const {
assert(pResource->getType() == Resource::TYPE_BITMAP);
BitmapResource *pBitmapResource = static_cast<BitmapResource *>(pResource);
uint result = pBitmapResource->getPixel(x, y);
+ // Convert to LUA-ready format
+ byte a;
+ a = result & 0xff;
+ result = (result >> 8) | (a << 24);
pResource->release();
return result;
}
diff --git a/engines/sword25/gfx/text.cpp b/engines/sword25/gfx/text.cpp
index 904435fcb0..769c9b1162 100644
--- a/engines/sword25/gfx/text.cpp
+++ b/engines/sword25/gfx/text.cpp
@@ -29,10 +29,6 @@
*
*/
-// TODO:
-// Entweder Fontfile absolut abspeichern, oder Verzeichniswechseln verbieten
-// Eine relative Fontfile-Angabe könnte verwandt werden nachdem das Verzeichnis bereits gewechselt wurde und die Datei würde nicht mehr gefunden
-
#include "sword25/kernel/kernel.h"
#include "sword25/kernel/outputpersistenceblock.h"
#include "sword25/kernel/inputpersistenceblock.h"
@@ -81,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();
@@ -99,7 +96,7 @@ void Text::setText(const Common::String &text) {
}
void Text::setColor(uint32 modulationColor) {
- uint32 newModulationColor = (modulationColor & 0xffffff00) | (_modulationColor & 0x000000ff);
+ uint32 newModulationColor = (modulationColor & 0x00ffffff) | (_modulationColor & 0xff000000);
if (newModulationColor != _modulationColor) {
_modulationColor = newModulationColor;
forceRefresh();
@@ -108,7 +105,7 @@ void Text::setColor(uint32 modulationColor) {
void Text::setAlpha(int alpha) {
assert(alpha >= 0 && alpha < 256);
- uint32 newModulationColor = (_modulationColor & 0xffffff00) | alpha;
+ uint32 newModulationColor = (_modulationColor & 0xffffff) | (alpha << 24);
if (newModulationColor != _modulationColor) {
_modulationColor = newModulationColor;
forceRefresh();
@@ -132,12 +129,12 @@ void Text::setAutoWrapThreshold(uint32 autoWrapThreshold) {
}
bool Text::doRender(RectangleList *updateRects) {
- // Font-Resource locken.
+ // lock Font Resource
FontResource *fontPtr = lockFontResource();
if (!fontPtr)
return false;
- // Charactermap-Resource locken.
+ // lock Character map resource
ResourceManager *rmPtr = getResourceManager();
BitmapResource *charMapPtr;
{
@@ -154,18 +151,18 @@ bool Text::doRender(RectangleList *updateRects) {
charMapPtr = static_cast<BitmapResource *>(pResource);
}
- // Framebufferobjekt holen.
+ // Getting frame buffer object
GraphicEngine *gfxPtr = Kernel::getInstance()->getGfx();
assert(gfxPtr);
bool result = true;
Common::Array<Line>::iterator iter = _lines.begin();
for (; iter != _lines.end(); ++iter) {
- // Feststellen, ob überhaupt Buchstaben der aktuellen Zeile vom Update betroffen sind.
+ // Determine whether any letters of the current line are affected by the update.
Common::Rect checkRect = (*iter).bbox;
checkRect.translate(_absoluteX, _absoluteY);
- // Jeden Buchstaben einzeln Rendern.
+ // Render each letter individually.
int curX = _absoluteX + (*iter).bbox.left;
int curY = _absoluteY + (*iter).bbox.top;
for (uint i = 0; i < (*iter).text.size(); ++i) {
@@ -181,24 +178,24 @@ bool Text::doRender(RectangleList *updateRects) {
}
}
- // Charactermap-Resource freigeben.
+ // Free Character map resource
charMapPtr->release();
- // Font-Resource freigeben.
+ // Free Font resource
fontPtr->release();
return result;
}
ResourceManager *Text::getResourceManager() {
- // Pointer auf den Resource-Manager holen.
+ // Getting pointer to resource manager
return Kernel::getInstance()->getResourceManager();
}
FontResource *Text::lockFontResource() {
ResourceManager *rmPtr = getResourceManager();
- // Font-Resource locken.
+ // Lock font resource
FontResource *fontPtr;
{
Resource *resourcePtr = rmPtr->requestResource(_font);
@@ -278,7 +275,7 @@ void Text::updateFormat() {
i = lastSpace;
}
- // Bounding-Box der einzelnen Zeilen relativ zur ersten festlegen (vor allem zentrieren).
+ // Bounding box of each line relative to the first set (center aligned).
_height = 0;
Common::Array<Line>::iterator iter = _lines.begin();
for (; iter != _lines.end(); ++iter) {
@@ -290,7 +287,7 @@ void Text::updateFormat() {
_height += bbox.height();
}
} else {
- // Keine automatische Formatierung, also wird der gesamte Text in nur eine Zeile kopiert.
+ // No auto format, so all the text is copied to a single line.
_lines[0].text = _text;
_lines[0].bbox = Common::Rect(0, 0, _width, _height);
}
@@ -333,11 +330,11 @@ bool Text::unpersist(InputPersistenceBlock &reader) {
result &= RenderObject::unpersist(reader);
- // Farbe und Alpha einlesen.
+ // Read color and alpha
reader.read(_modulationColor);
- // Beim Laden der anderen Member werden die Set-Methoden benutzt statt der tatsächlichen Member.
- // So wird das Layout automatisch aktualisiert und auch alle anderen notwendigen Methoden ausgeführt.
+ // Run all methods on loading relevant members.
+ // So, the layout is automatically updated and all necessary logic is executed.
Common::String font;
reader.readString(font);
diff --git a/engines/sword25/kernel/kernel_script.cpp b/engines/sword25/kernel/kernel_script.cpp
index 1b7c6a6f14..40dcbd5b98 100644
--- a/engines/sword25/kernel/kernel_script.cpp
+++ b/engines/sword25/kernel/kernel_script.cpp
@@ -257,6 +257,7 @@ static int processMessages(lua_State *L) {
// to the closeWanted() opcode; see also the TODO comment in there.
lua_pushbooleancpp(L, !Engine::shouldQuit());
+ g_system->delayMillis(10);
return 1;
}
diff --git a/engines/sword25/math/polygon.cpp b/engines/sword25/math/polygon.cpp
index ccefa1901e..99a0d37ed7 100644
--- a/engines/sword25/math/polygon.cpp
+++ b/engines/sword25/math/polygon.cpp
@@ -110,7 +110,7 @@ bool Polygon::computeIsCW() const {
// Cross product form
// If the cross product of the vertex lying fartherest bottom left is positive,
- // the vertecies arrranged in a clockwise order. Otherwise counter-clockwise
+ // the vertecies arranged in a clockwise order. Otherwise counter-clockwise
if (crossProduct(vertices[v1Index], vertices[v2Index], vertices[v3Index]) >= 0)
return true;
}
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/script/luacallback.cpp b/engines/sword25/script/luacallback.cpp
index 72f7e01612..acfda498c6 100644
--- a/engines/sword25/script/luacallback.cpp
+++ b/engines/sword25/script/luacallback.cpp
@@ -119,7 +119,7 @@ void LuaCallback::invokeCallbackFunctions(lua_State *L, uint objectHandle) {
// Lua_pcall the function and the parameters pop themselves from the stack
if (lua_pcall(L, argumentCount, 0, 0) != 0) {
// An error has occurred
- error("An error occured executing a callback function: %s", lua_tostring(L, -1));
+ error("An error occurred executing a callback function: %s", lua_tostring(L, -1));
// Pop error message from the stack
lua_pop(L, 1);
diff --git a/engines/sword25/script/luascript.cpp b/engines/sword25/script/luascript.cpp
index e93289596b..3aca6676ac 100644
--- a/engines/sword25/script/luascript.cpp
+++ b/engines/sword25/script/luascript.cpp
@@ -214,7 +214,7 @@ bool LuaScriptEngine::executeBuffer(const byte *data, uint size, const Common::S
// Run buffer contents
if (lua_pcall(_state, 0, 0, -2) != 0) {
- error("An error occured while executing \"%s\":\n%s.",
+ error("An error occurred while executing \"%s\":\n%s.",
name.c_str(),
lua_tostring(_state, -1));
lua_pop(_state, 2);
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.cpp b/engines/sword25/sword25.cpp
index 76142c2534..b6f2641714 100644
--- a/engines/sword25/sword25.cpp
+++ b/engines/sword25/sword25.cpp
@@ -95,7 +95,7 @@ Common::Error Sword25Engine::run() {
}
Common::Error Sword25Engine::appStart() {
- // Initialize the graphics mode to ARGB8888
+ // Initialize the graphics mode to RGBA8888
Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
initGraphics(800, 600, true, &format);
if (format != g_system->getScreenFormat())
@@ -120,7 +120,7 @@ Common::Error Sword25Engine::appStart() {
// Pass the command line to the script engine.
ScriptEngine *scriptPtr = Kernel::getInstance()->getScript();
if (!scriptPtr) {
- error("Script intialization failed.");
+ error("Script initialization failed.");
return Common::kUnknownError;
}
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/sword25/util/lua/lbaselib.cpp b/engines/sword25/util/lua/lbaselib.cpp
index 659c61d956..ec044970ad 100644
--- a/engines/sword25/util/lua/lbaselib.cpp
+++ b/engines/sword25/util/lua/lbaselib.cpp
@@ -492,7 +492,7 @@ static int costatus (lua_State *L, lua_State *co) {
else
return CO_SUS; /* initial state */
}
- default: /* some error occured */
+ default: /* some error occurred */
return CO_DEAD;
}
}
diff --git a/engines/sword25/util/lua/ldo.cpp b/engines/sword25/util/lua/ldo.cpp
index a230097f2a..f4139cb9fc 100644
--- a/engines/sword25/util/lua/ldo.cpp
+++ b/engines/sword25/util/lua/ldo.cpp
@@ -111,10 +111,9 @@ static const char* luaErrorDescription[] = {
void luaD_throw (lua_State *L, int errcode) {
if (L->errorJmp) {
L->errorJmp->status = errcode;
- // LUAI_THROW has been replaced with an error message in ScummVM, together
- // with the LUA error code and description
- //LUAI_THROW(L, L->errorJmp);
- error("LUA error occured, error code is %d (%s)", errcode, luaErrorDescription[errcode]);
+ // LUAI_THROW is sometimes used to ignore the error and restore LUA state
+ LUAI_THROW(L, L->errorJmp);
+ error("LUA error occurred, error code is %d (%s)", errcode, luaErrorDescription[errcode]);
}
else {
L->status = cast_byte(errcode);
diff --git a/engines/sword25/util/lua/luaconf.h b/engines/sword25/util/lua/luaconf.h
index fb85983998..53d0f55290 100644
--- a/engines/sword25/util/lua/luaconf.h
+++ b/engines/sword25/util/lua/luaconf.h
@@ -621,7 +621,7 @@ union luai_Cast { double l_d; long l_l; };
#else
/* default handling with long jumps */
-//#define LUAI_THROW(L,c) longjmp((c)->b, 1) // replaced with error() in ScummVM
+#define LUAI_THROW(L,c) longjmp((c)->b, 1)
#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a }
#define luai_jmpbuf jmp_buf
diff --git a/engines/sword25/util/lua/scummvm_file.cpp b/engines/sword25/util/lua/scummvm_file.cpp
index c38aba004f..bdceff0c0c 100644
--- a/engines/sword25/util/lua/scummvm_file.cpp
+++ b/engines/sword25/util/lua/scummvm_file.cpp
@@ -183,7 +183,7 @@ Common::String Sword25FileProxy::getLanguage() {
case Common::FR_FRA:
return "fr";
case Common::HU_HUN:
- return "hr";
+ return "hu";
case Common::IT_ITA:
return "it";
case Common::PL_POL:
@@ -210,7 +210,7 @@ void Sword25FileProxy::setLanguage(const Common::String &lang) {
ConfMan.set("language", Common::getLanguageCode(Common::ES_ESP));
else if (lang == "fr")
ConfMan.set("language", Common::getLanguageCode(Common::FR_FRA));
- else if (lang == "hr")
+ else if (lang == "hu")
ConfMan.set("language", Common::getLanguageCode(Common::HU_HUN));
else if (lang == "it")
ConfMan.set("language", Common::getLanguageCode(Common::IT_ITA));
diff --git a/engines/sword25/util/lua_persistence_util.cpp b/engines/sword25/util/lua_persistence_util.cpp
index 958fb7ac3c..d0192c2e66 100644
--- a/engines/sword25/util/lua_persistence_util.cpp
+++ b/engines/sword25/util/lua_persistence_util.cpp
@@ -280,15 +280,6 @@ void lua_reallocstack(lua_State *L, int newsize) {
correctStack(L, oldstack);
}
-void lua_growstack(lua_State *L, int n) {
- // Double size is enough?
- if (n <= L->stacksize) {
- lua_reallocstack(L, 2 * L->stacksize);
- } else {
- lua_reallocstack(L, L->stacksize + n);
- }
-}
-
void lua_reallocCallInfo(lua_State *lauState, int newsize) {
CallInfo *oldci = lauState->base_ci;
lua_reallocvector(lauState, lauState->base_ci, lauState->size_ci, newsize, CallInfo);
diff --git a/engines/sword25/util/lua_persistence_util.h b/engines/sword25/util/lua_persistence_util.h
index 4d0085e242..e3a2935f2c 100644
--- a/engines/sword25/util/lua_persistence_util.h
+++ b/engines/sword25/util/lua_persistence_util.h
@@ -90,7 +90,6 @@ void unboxUpValue(lua_State *luaState);
size_t appendStackToStack_reverse(lua_State *from, lua_State *to);
void correctStack(lua_State *L, TValue *oldstack);
void lua_reallocstack(lua_State *L, int newsize);
-void lua_growstack(lua_State *L, int n);
void lua_reallocCallInfo(lua_State *lauState, int newsize);
diff --git a/engines/sword25/util/lua_unpersist.cpp b/engines/sword25/util/lua_unpersist.cpp
index ef0ef31041..678ddb52db 100644
--- a/engines/sword25/util/lua_unpersist.cpp
+++ b/engines/sword25/util/lua_unpersist.cpp
@@ -425,7 +425,7 @@ void unpersistThread(UnSerializationInfo *info, int index) {
// First, deserialize the object stack
uint32 stackSize = info->readStream->readUint32LE();
- lua_growstack(info->luaState, (int)stackSize);
+ lua_checkstack(info->luaState, (int)stackSize);
// Make sure that the first stack element (a nil, representing
// the imaginary top-level C function) is written to the very,
diff --git a/engines/teenagent/detection.cpp b/engines/teenagent/detection.cpp
index 7a53faf98a..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 {
@@ -125,10 +125,9 @@ public:
virtual SaveStateList listSaves(const char *target) const {
Common::String pattern = target;
- pattern += ".??";
+ pattern += ".##";
Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles(pattern);
- Common::sort(filenames.begin(), filenames.end());
SaveStateList saveList;
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
@@ -145,6 +144,8 @@ public:
saveList.push_back(SaveStateDescriptor(slot, buf));
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
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.cpp b/engines/testbed/testbed.cpp
index 635fd09bac..885429cafd 100644
--- a/engines/testbed/testbed.cpp
+++ b/engines/testbed/testbed.cpp
@@ -152,6 +152,9 @@ void TestbedEngine::invokeTestsuites(TestbedConfigManager &cfMan) {
Common::Point pt = Testsuite::getDisplayRegionCoordinates();
int numSuitesEnabled = cfMan.getNumSuitesEnabled();
+ if (!numSuitesEnabled)
+ return;
+
for (iter = _testsuiteList.begin(); iter != _testsuiteList.end(); iter++) {
if (shouldQuit()) {
return;
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/testbed/testsuite.cpp b/engines/testbed/testsuite.cpp
index 7729c4911b..853f1288b3 100644
--- a/engines/testbed/testsuite.cpp
+++ b/engines/testbed/testsuite.cpp
@@ -283,6 +283,9 @@ void Testsuite::execute() {
pt.y += getLineSeparation();
int numEnabledTests = getNumTestsEnabled();
+ if (!numEnabledTests)
+ return;
+
for (Common::Array<Test *>::iterator i = _testsToExecute.begin(); i != _testsToExecute.end(); ++i) {
if (!(*i)->enabled) {
logPrintf("Info! Skipping Test: %s, Skipped by configuration.\n", ((*i)->featureName).c_str());
diff --git a/engines/tinsel/anim.cpp b/engines/tinsel/anim.cpp
index 19e180b57e..e241c7cba0 100644
--- a/engines/tinsel/anim.cpp
+++ b/engines/tinsel/anim.cpp
@@ -43,7 +43,7 @@ SCRIPTSTATE DoNextFrame(ANIM *pAnim) {
while (1) { // repeat until a real image
debugC(DEBUG_DETAILED, kTinselDebugAnimations,
- "DoNextFrame %ph index=%d, op=%xh", (byte *)pAnim, pAnim->scriptIndex,
+ "DoNextFrame %ph index=%d, op=%xh", (const void *)pAnim, pAnim->scriptIndex,
FROM_32(pAni[pAnim->scriptIndex].op));
switch ((int32)FROM_32(pAni[pAnim->scriptIndex].op)) {
@@ -217,7 +217,7 @@ void InitStepAnimScript(ANIM *pAnim, OBJECT *pAniObj, SCNHANDLE hNewScript, int
"InitStepAnimScript Object=(%d,%d,%xh) script=%xh aniSpeed=%d rec=%ph",
!pAniObj ? 0 : fracToInt(pAniObj->xPos),
!pAniObj ? 0 : fracToInt(pAniObj->yPos),
- !pAniObj ? 0 : pAniObj->hImg, hNewScript, aniSpeed, (byte *)pAnim);
+ !pAniObj ? 0 : pAniObj->hImg, hNewScript, aniSpeed, (void *)pAnim);
pAnim->aniDelta = 1; // will animate on next call to NextAnimRate
pAnim->pObject = pAniObj; // set object to animate
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 c7a62dacad..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 {
@@ -134,9 +134,8 @@ extern int getList(Common::SaveFileManager *saveFileMan, const Common::String &t
SaveStateList TinselMetaEngine::listSaves(const char *target) const {
Common::String pattern = target;
- pattern = pattern + ".???";
+ pattern = pattern + ".###";
Common::StringArray files = g_system->getSavefileManager()->listSavefiles(pattern);
- sort(files.begin(), files.end()); // Sort (hopefully ensuring we are sorted numerically..)
SaveStateList saveList;
int slotNum = 0;
@@ -160,6 +159,8 @@ SaveStateList TinselMetaEngine::listSaves(const char *target) const {
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
@@ -227,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 {
@@ -264,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;
@@ -274,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/detection_tables.h b/engines/tinsel/detection_tables.h
index a2ea67b3e6..6c1a3a39f4 100644
--- a/engines/tinsel/detection_tables.h
+++ b/engines/tinsel/detection_tables.h
@@ -556,6 +556,27 @@ static const TinselGameDescription gameDescriptions[] = {
TINSEL_V1,
},
+ { // Russian Discworld 1. Fan translation v1.1
+ {
+ "dw",
+ "CD v1.1",
+ {
+ {"dw.scn", 0, "133041bde59d05c1bf084fd6f1bdce4b", 776524},
+ {"english.txt", 0, "317542cf2e50106d9c9421ddcf821e22", 221656},
+ {"english.smp", 0, NULL, -1},
+ {NULL, 0, NULL, 0}
+ },
+ Common::RU_RUS,
+ Common::kPlatformDOS,
+ ADGF_CD,
+ GUIO1(GUIO_NOASPECT)
+ },
+ GID_DW1,
+ 0,
+ GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT,
+ TINSEL_V1,
+ },
+
{ // Polish fan translaction Discworld 1
{
"dw",
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/graphics.cpp b/engines/tinsel/graphics.cpp
index 0282aff3cb..2ff96a9b64 100644
--- a/engines/tinsel/graphics.cpp
+++ b/engines/tinsel/graphics.cpp
@@ -164,7 +164,7 @@ static void t0WrtNonZero(DRAWOBJECT *pObj, uint8 *srcP, uint8 *destP, bool apply
// Horizontal loop
for (int x = 0; x < pObj->width; ) {
- uint32 numBytes = READ_UINT32(srcP);
+ uint32 numBytes = READ_LE_UINT32(srcP);
srcP += sizeof(uint32);
bool repeatFlag = (numBytes & 0x80000000L) != 0;
numBytes &= 0x7fffffff;
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 9b4e2494e0..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"
@@ -381,14 +380,28 @@ MidiMusicPlayer::MidiMusicPlayer(TinselEngine *vm) {
bool milesAudioEnabled = false;
if (vm->getPlatform() == Common::kPlatformDOS) {
- // Enable Miles Audio for DOS only
- milesAudioEnabled = true;
+ // Enable Miles Audio for DOS platform only...
+ switch (vm->getGameID()) {
+ case GID_DW1:
+ if (!vm->getIsADGFDemo()) {
+ // ...for Discworld 1
+ milesAudioEnabled = true;
+ } else {
+ if (vm->isV1CD()) {
+ // ...and for Discworld 1 CD Demo
+ milesAudioEnabled = true;
+ }
+ }
+ break;
+ default:
+ break;
+ }
}
- if ((vm->getGameId() == GID_DW1) && (milesAudioEnabled)) {
+ 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:
@@ -418,9 +431,12 @@ MidiMusicPlayer::MidiMusicPlayer(TinselEngine *vm) {
// Version 2: drivers got installed and fat.opl got copied over by the user
_driver = Audio::MidiDriver_Miles_AdLib_create("MIDPAK.AD", "");
} else {
- // Version 1: sample.ad / sample.opl, have to be copied over by the user for this version
- // That's why we check those last, because then the user gets a proper error message for them
- _driver = Audio::MidiDriver_Miles_AdLib_create("SAMPLE.AD", "SAMPLE.OPL");
+ if ((fileClass.exists("SAMPLE.AD")) || (fileClass.exists("SAMPLE.OPL"))) {
+ // Version 1: sample.ad / sample.opl, have to be copied over by the user for this version
+ _driver = Audio::MidiDriver_Miles_AdLib_create("SAMPLE.AD", "SAMPLE.OPL");
+ } else {
+ error("MILES-ADLIB: timbre file not found (may be called FAT.OPL, MIDPAK.AD, SAMPLE.AD or SAMPLE.OPL, may be in a subdirectory)");
+ }
}
}
break;
@@ -623,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 6dc8e3bb35..44e81494f7 100644
--- a/engines/tinsel/tinsel.cpp
+++ b/engines/tinsel/tinsel.cpp
@@ -528,8 +528,6 @@ void SetNewScene(SCNHANDLE scene, int entrance, int transition) {
* Store a scene as hooked
*/
void SetHookScene(SCNHANDLE scene, int entrance, int transition) {
- assert(g_HookScene.scene == 0); // scene already hooked
-
g_HookScene.scene = scene;
g_HookScene.entry = entrance;
g_HookScene.trans = transition;
@@ -822,9 +820,12 @@ const char *const TinselEngine::_textFiles[][3] = {
TinselEngine::TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc) :
Engine(syst), _gameDescription(gameDesc), _random("tinsel"),
- _sound(0), _midiMusic(0), _pcmMusic(0), _bmv(0) {
+ _console(0), _sound(0), _midiMusic(0), _pcmMusic(0), _bmv(0) {
_vm = this;
+ _gameId = 0;
+ _driver = NULL;
+
_config = new Config(this);
// Register debug flags
@@ -843,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;
@@ -977,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 e8f08bcc61..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 {
@@ -262,11 +262,10 @@ SaveStateList ToltecsMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Toltecs::ToltecsEngine::SaveHeader header;
Common::String pattern = target;
- pattern += ".???";
+ pattern += ".###";
Common::StringArray filenames;
filenames = saveFileMan->listSavefiles(pattern.c_str());
- Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
SaveStateList saveList;
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
@@ -284,6 +283,8 @@ SaveStateList ToltecsMetaEngine::listSaves(const char *target) const {
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
@@ -299,7 +300,7 @@ void ToltecsMetaEngine::removeSaveState(const char *target, int slot) const {
Common::StringArray filenames;
Common::String pattern = target;
- pattern += ".???";
+ pattern += ".###";
filenames = saveFileMan->listSavefiles(pattern.c_str());
Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
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.cpp b/engines/toltecs/toltecs.cpp
index d3b69e7f21..c91f51bade 100644
--- a/engines/toltecs/toltecs.cpp
+++ b/engines/toltecs/toltecs.cpp
@@ -62,9 +62,6 @@ struct GameSettings {
};
ToltecsEngine::ToltecsEngine(OSystem *syst, const ToltecsGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) {
- // Assign default values to the config manager, in case settings are missing
- ConfMan.registerDefault("originalsaveload", "false");
-
_rnd = new Common::RandomSource("toltecs");
}
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/detection.cpp b/engines/tony/detection.cpp
index 9bb768d1ed..ec0b3e186b 100644
--- a/engines/tony/detection.cpp
+++ b/engines/tony/detection.cpp
@@ -115,10 +115,9 @@ SaveStateList TonyMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Common::StringArray filenames;
Common::String saveDesc;
- Common::String pattern = "tony.0??";
+ Common::String pattern = "tony.0##";
filenames = saveFileMan->listSavefiles(pattern);
- sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
SaveStateList saveList;
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
@@ -137,6 +136,8 @@ SaveStateList TonyMetaEngine::listSaves(const char *target) const {
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
diff --git a/engines/tony/detection_tables.h b/engines/tony/detection_tables.h
index 28dcaac752..1bb91a862d 100644
--- a/engines/tony/detection_tables.h
+++ b/engines/tony/detection_tables.h
@@ -24,7 +24,7 @@ namespace Tony {
static const TonyGameDescription gameDescriptions[] = {
{
- // Tony Tough English
+ // Tony Tough English not installed
{
"tony",
0,
@@ -32,8 +32,6 @@ static const TonyGameDescription gameDescriptions[] = {
// TODO: AdvancedDetector seems to have a problem where it thinks data1.cab is unrecognized.
// Is it perhaps because the Agos engine also has detection entries for data1.cab?
{"data1.cab", 0, "ce82907242166bfb594d97bdb68f96d2", 4350},
- /*{"roasted.mpr", 0, "06203dbbc85fdd1e6dc8fc211c1a6207", 135911071},
- {"roasted.mpc", 0, "57c4a3860cf899443c357e0078ea6f49", 366773},*/
AD_LISTEND
},
Common::EN_ANY,
@@ -44,6 +42,24 @@ static const TonyGameDescription gameDescriptions[] = {
},
{
+ // Tony Tough Czech not installed
+ {
+ "tony",
+ 0,
+ {
+ // TODO: AdvancedDetector seems to have a problem where it thinks data1.cab is unrecognized.
+ // Is it perhaps because the Agos engine also has detection entries for data1.cab?
+ {"data1.cab", 0, "c6d5dd8f0c1241a6e3f7861b7f27bf7b", 4350},
+ AD_LISTEND
+ },
+ Common::CZ_CZE,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+ },
+
+ {
// Tony Tough English Demo
{
"tony",
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/loc.cpp b/engines/tony/loc.cpp
index 09a00deed1..be2b20294f 100644
--- a/engines/tony/loc.cpp
+++ b/engines/tony/loc.cpp
@@ -506,15 +506,13 @@ void RMItem::readFromStream(Common::SeekableReadStream &ds, bool bLOX) {
if (!ds.err()) {
for (int i = 0; i < _nSprites && !ds.err(); i++) {
// Download the sprites
- if (bLOX) {
+ if (bLOX)
_sprites[i].LOXGetSizeFromStream(ds, &dimx, &dimy);
- _sprites[i].init(newItemSpriteBuffer(dimx, dimy, true));
- _sprites[i].readFromStream(ds, true);
- } else {
+ else
_sprites[i].getSizeFromStream(ds, &dimx, &dimy);
- _sprites[i].init(newItemSpriteBuffer(dimx, dimy, false));
- _sprites[i].readFromStream(ds, false);
- }
+
+ _sprites[i].init(newItemSpriteBuffer(dimx, dimy, bLOX));
+ _sprites[i].readFromStream(ds, bLOX);
if (_cm == CM_256 && _bPal)
_sprites[i].setPalette(_pal._data);
@@ -523,21 +521,14 @@ void RMItem::readFromStream(Common::SeekableReadStream &ds, bool bLOX) {
if (!ds.err()) {
for (int i = 0; i < _nSfx && !ds.err(); i++) {
- if (bLOX)
- _sfx[i].readFromStream(ds, true);
- else
- _sfx[i].readFromStream(ds, false);
+ _sfx[i].readFromStream(ds, bLOX);
}
}
// Read the pattern from pattern 1
if (!ds.err()) {
- for (int i = 1; i <= _nPatterns && !ds.err(); i++) {
- if (bLOX)
- _patterns[i].readFromStream(ds, true);
- else
- _patterns[i].readFromStream(ds, false);
- }
+ for (int i = 1; i <= _nPatterns && !ds.err(); i++)
+ _patterns[i].readFromStream(ds, bLOX);
}
// Initialize the current pattern
@@ -610,7 +601,7 @@ void RMItem::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
// Offset direction for scrolling
prim->getDst().offset(-_curScroll);
- // We must offset the cordinates of the item inside the primitive
+ // We must offset the coordinates of the item inside the primitive
// It is estimated as nonno + (babbo + figlio)
prim->getDst().offset(calculatePos());
diff --git a/engines/tony/loc.h b/engines/tony/loc.h
index ac65a4a0bd..d065d60445 100644
--- a/engines/tony/loc.h
+++ b/engines/tony/loc.h
@@ -151,7 +151,7 @@ public:
// Reads the position of the pattern
RMPoint pos();
- void readFromStream(Common::ReadStream &ds, bool bLOX = false);
+ void readFromStream(Common::ReadStream &ds, bool bLOX);
private:
void updateCoord();
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 2a4eb826f3..fed51dacf4 100644
--- a/engines/tony/sound.cpp
+++ b/engines/tony/sound.cpp
@@ -28,7 +28,9 @@
#include "audio/audiostream.h"
#include "audio/decoders/adpcm.h"
-#include "audio/decoders/raw.h"
+#include "audio/decoders/flac.h"
+#include "audio/decoders/mp3.h"
+#include "audio/decoders/vorbis.h"
#include "audio/decoders/wave.h"
#include "common/textconsole.h"
#include "tony/game.h"
@@ -49,6 +51,18 @@ static int remapVolume(int volume) {
return (int)((double)Audio::Mixer::kMaxChannelVolume * pow(10.0, dsvol / 2000.0) + 0.5);
}
+// Another obvious rip from gob engine. Hi DrMcCoy!
+Common::String setExtension(const Common::String &str, const Common::String &ext) {
+ if (str.empty())
+ return str;
+
+ const char *dot = strrchr(str.c_str(), '.');
+ if (dot)
+ return Common::String(str.c_str(), dot - str.c_str()) + ext;
+
+ return str + ext;
+}
+
/****************************************************************************\
* FPSOUND Methods
\****************************************************************************/
@@ -147,6 +161,7 @@ FPSfx::FPSfx(bool soundOn) {
_loopStream = 0;
_rewindableStream = 0;
_paused = false;
+ _loop = 0;
g_vm->_activeSfx.push_back(this);
}
@@ -204,12 +219,45 @@ bool FPSfx::loadVoiceFromVDB(Common::File &vdbFP) {
if (!_soundSupported)
return true;
- uint32 size = vdbFP.readUint32LE();
- uint32 rate = vdbFP.readUint32LE();
- _isVoice = true;
-
- _rewindableStream = Audio::makeADPCMStream(vdbFP.readStream(size), DisposeAfterUse::YES, 0, Audio::kADPCMDVI, rate, 1);
+ switch (g_vm->_vdbCodec) {
+ case FPCODEC_ADPCM: {
+ uint32 size = vdbFP.readUint32LE();
+ uint32 rate = vdbFP.readUint32LE();
+ _rewindableStream = Audio::makeADPCMStream(vdbFP.readStream(size), DisposeAfterUse::YES, 0, Audio::kADPCMDVI, rate, 1);
+ }
+ break;
+ case FPCODEC_MP3 : {
+#ifdef USE_MAD
+ uint32 size = vdbFP.readUint32LE();
+ _rewindableStream = Audio::makeMP3Stream(vdbFP.readStream(size), DisposeAfterUse::YES);
+#else
+ return false;
+#endif
+ }
+ break;
+ case FPCODEC_OGG : {
+#ifdef USE_VORBIS
+ uint32 size = vdbFP.readUint32LE();
+ _rewindableStream = Audio::makeVorbisStream(vdbFP.readStream(size), DisposeAfterUse::YES);
+#else
+ return false;
+#endif
+ }
+ break;
+ case FPCODEC_FLAC : {
+#ifdef USE_FLAC
+ uint32 size = vdbFP.readUint32LE();
+ _rewindableStream = Audio::makeFLACStream(vdbFP.readStream(size), DisposeAfterUse::YES);
+#else
+ return false;
+#endif
+ }
+ break;
+ default:
+ return false;
+ }
+ _isVoice = true;
_fileLoaded = true;
setVolume(62);
return true;
@@ -219,39 +267,64 @@ bool FPSfx::loadVoiceFromVDB(Common::File &vdbFP) {
* Opens a file and loads a sound effect.
*
* @param fileName Sfx filename
- * @param codec CODEC used to uncompress the samples
*
* @returns True is everything is OK, False otherwise
*/
-bool FPSfx::loadFile(const char *fileName, uint32 codec) {
+bool FPSfx::loadFile(const char *fileName) {
if (!_soundSupported)
return true;
+ SoundCodecs codec = FPCODEC_UNKNOWN;
+
Common::File file;
- if (!file.open(fileName)) {
+ if (file.open(fileName))
+ codec = FPCODEC_ADPCM;
+ else if (file.open(setExtension(fileName, ".MP3")))
+ codec = FPCODEC_MP3;
+ else if (file.open(setExtension(fileName, ".OGG")))
+ codec = FPCODEC_OGG;
+ else if (file.open(setExtension(fileName, ".FLA")))
+ codec = FPCODEC_FLAC;
+ else {
warning("FPSfx::LoadFile(): Cannot open sfx file!");
return false;
}
- if (file.readUint32BE() != MKTAG('A', 'D', 'P', 0x10)) {
- warning("FPSfx::LoadFile(): Invalid ADP header!");
- return false;
- }
-
- uint32 rate = file.readUint32LE();
- uint32 channels = file.readUint32LE();
+ Common::SeekableReadStream *buffer;
+ switch (codec) {
+ case FPCODEC_ADPCM: {
+ if (file.readUint32BE() != MKTAG('A', 'D', 'P', 0x10)) {
+ warning("FPSfx::LoadFile(): Invalid ADP header!");
+ return false;
+ }
- Common::SeekableReadStream *buffer = file.readStream(file.size() - file.pos());
+ uint32 rate = file.readUint32LE();
+ uint32 channels = file.readUint32LE();
- if (codec == FPCODEC_ADPCM) {
+ buffer = file.readStream(file.size() - file.pos());
_rewindableStream = Audio::makeADPCMStream(buffer, DisposeAfterUse::YES, 0, Audio::kADPCMDVI, rate, channels);
- } else {
- byte flags = Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN;
-
- if (channels == 2)
- flags |= Audio::FLAG_STEREO;
-
- _rewindableStream = Audio::makeRawStream(buffer, rate, flags, DisposeAfterUse::YES);
+ }
+ break;
+ case FPCODEC_MP3:
+#ifdef USE_MAD
+ buffer = file.readStream(file.size());
+ _rewindableStream = Audio::makeMP3Stream(buffer, DisposeAfterUse::YES);
+#endif
+ break;
+ case FPCODEC_OGG:
+#ifdef USE_VORBIS
+ buffer = file.readStream(file.size());
+ _rewindableStream = Audio::makeVorbisStream(buffer, DisposeAfterUse::YES);
+#endif
+ break;
+ case FPCODEC_FLAC:
+ buffer = file.readStream(file.size());
+#ifdef USE_FLAC
+ _rewindableStream = Audio::makeFLACStream(buffer, DisposeAfterUse::YES);
+#endif
+ break;
+ default:
+ return false;
}
_fileLoaded = true;
@@ -469,50 +542,96 @@ void FPStream::release() {
* Opens a file stream
*
* @param fileName Filename to be opened
- * @param codec CODEC to be used to uncompress samples
+ * @param bufSize Buffer size
*
* @returns True is everything is OK, False otherwise
*/
-bool FPStream::loadFile(const Common::String &fileName, uint32 codec, int bufSize) {
+bool FPStream::loadFile(const Common::String &fileName, int bufSize) {
if (!_soundSupported)
return true;
if (_fileLoaded)
unloadFile();
- // Save the codec type
- _codec = codec;
+ SoundCodecs codec = FPCODEC_UNKNOWN;
// Open the file stream for reading
- if (!_file.open(fileName)) {
- // Fallback: try with an extra '0' prefix
- if (!_file.open("0" + fileName))
- return false;
+ if (_file.open(fileName))
+ codec = FPCODEC_ADPCM;
+ else if (_file.open(setExtension(fileName, ".MP3")))
+ codec = FPCODEC_MP3;
+ else if (_file.open(setExtension(fileName, ".OGG")))
+ codec = FPCODEC_OGG;
+ else if (_file.open(setExtension(fileName, ".FLA")))
+ codec = FPCODEC_FLAC;
+ // Fallback: try with an extra '0' prefix
+ else if (_file.open("0" + fileName)) {
+ codec = FPCODEC_ADPCM;
warning("FPStream::loadFile(): Fallback from %s to %s", fileName.c_str(), _file.getName());
- }
+ } else if (_file.open(setExtension("0" + fileName, ".MP3"))) {
+ codec = FPCODEC_MP3;
+ warning("FPStream::loadFile(): Fallback from %s to %s", fileName.c_str(), _file.getName());
+ } else if (_file.open(setExtension("0" + fileName, ".OGG"))) {
+ codec = FPCODEC_OGG;
+ warning("FPStream::loadFile(): Fallback from %s to %s", fileName.c_str(), _file.getName());
+ } else if (_file.open(setExtension("0" + fileName, ".FLA"))) {
+ codec = FPCODEC_FLAC;
+ warning("FPStream::loadFile(): Fallback from %s to %s", fileName.c_str(), _file.getName());
+ } else
+ return false;
// Save the size of the stream
_size = _file.size();
- switch (_codec) {
- case FPCODEC_RAW:
- _rewindableStream = Audio::makeRawStream(&_file, 44100, Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN | Audio::FLAG_STEREO, DisposeAfterUse::NO);
- break;
-
- case FPCODEC_ADPCM:
#ifdef __amigaos4__
- // HACK: AmigaOS 4 has weird performance problems with reading in the audio thread,
- // so we read the whole stream into memory.
+ // HACK: AmigaOS 4 has weird performance problems with reading in the audio thread,
+ // so we read the whole stream into memory.
+ switch (codec) {
+ case FPCODEC_ADPCM:
_rewindableStream = Audio::makeADPCMStream(_file.readStream(_size), DisposeAfterUse::YES, 0, Audio::kADPCMDVI, 44100, 2);
+ break;
+ case FPCODEC_MP3:
+#ifdef USE_MAD
+ _rewindableStream = Audio::makeMP3Stream(&_file, DisposeAfterUse::YES);
+#endif
+ break;
+ case FPCODEC_OGG:
+#ifdef USE_VORBIS
+ _rewindableStream = Audio::makeVorbisStream(&_file, DisposeAfterUse::YES);
+#endif
+ break;
+ case FPCODEC_FLAC:
+#ifdef USE_FLAC
+ _rewindableStream = Audio::makeFLACStream(&_file, DisposeAfterUse::YES);
+#endif
+ break;
+ default:
+ break;
+ }
#else
+ switch (codec) {
+ case FPCODEC_ADPCM:
_rewindableStream = Audio::makeADPCMStream(&_file, DisposeAfterUse::NO, 0, Audio::kADPCMDVI, 44100, 2);
+ break;
+ case FPCODEC_MP3:
+#ifdef USE_MAD
+ _rewindableStream = Audio::makeMP3Stream(&_file, DisposeAfterUse::NO);
+#endif
+ break;
+ case FPCODEC_OGG:
+#ifdef USE_VORBIS
+ _rewindableStream = Audio::makeVorbisStream(&_file, DisposeAfterUse::NO);
+#endif
+ break;
+ case FPCODEC_FLAC:
+#ifdef USE_FLAC
+ _rewindableStream = Audio::makeFLACStream(&_file, DisposeAfterUse::NO);
#endif
break;
-
default:
- _file.close();
- return false;
+ break;
}
+#endif
// All done
_fileLoaded = true;
diff --git a/engines/tony/sound.h b/engines/tony/sound.h
index 446dc68d80..206935f314 100644
--- a/engines/tony/sound.h
+++ b/engines/tony/sound.h
@@ -45,8 +45,11 @@ class FPStream;
class FPSfx;
enum SoundCodecs {
- FPCODEC_RAW,
- FPCODEC_ADPCM
+ FPCODEC_UNKNOWN,
+ FPCODEC_ADPCM,
+ FPCODEC_MP3,
+ FPCODEC_OGG,
+ FPCODEC_FLAC
};
/**
@@ -179,7 +182,7 @@ public:
* @returns True is everything is OK, False otherwise
*/
- bool loadFile(const char *fileName, uint32 codec = FPCODEC_RAW);
+ bool loadFile(const char *fileName);
bool loadWave(Common::SeekableReadStream *stream);
bool loadVoiceFromVDB(Common::File &vdbFP);
@@ -246,7 +249,6 @@ class FPStream {
private:
uint32 _bufferSize; // Buffer size (bytes)
uint32 _size; // Stream size (bytes)
- uint32 _codec; // CODEC used
Common::File _file; // File handle used for the stream
@@ -297,12 +299,11 @@ public:
* Opens a file stream
*
* @param fileName Filename to be opened
- * @param codec CODEC to be used to uncompress samples
*
* @returns True is everything is OK, False otherwise
*/
- bool loadFile(const Common::String &fileName, uint32 codec = FPCODEC_RAW, int sync = 2000);
+ bool loadFile(const Common::String &fileName, int sync);
/**
* Closes a file stream (opened or not).
diff --git a/engines/tony/tony.cpp b/engines/tony/tony.cpp
index 2857bb93f8..c51f449aa1 100644
--- a/engines/tony/tony.cpp
+++ b/engines/tony/tony.cpp
@@ -82,6 +82,9 @@ TonyEngine::TonyEngine(OSystem *syst, const TonyGameDescription *gameDesc) : Eng
_bQuitNow = false;
_bTimeFreezed = false;
_nTimeFreezed = 0;
+ _vdbCodec = FPCODEC_UNKNOWN;
+
+ memset(_funcList, 0, sizeof(_funcList));
}
TonyEngine::~TonyEngine() {
@@ -323,10 +326,10 @@ void TonyEngine::playMusic(int nChannel, const Common::String &fname, int nFX, b
_stream[GLOBALS._nextChannel]->unloadFile();
if (!getIsDemo()) {
- if (!_stream[GLOBALS._nextChannel]->loadFile(fname, FPCODEC_ADPCM, nSync))
+ if (!_stream[GLOBALS._nextChannel]->loadFile(fname, nSync))
error("failed to open music file '%s'", fname.c_str());
} else {
- _stream[GLOBALS._nextChannel]->loadFile(fname, FPCODEC_ADPCM, nSync);
+ _stream[GLOBALS._nextChannel]->loadFile(fname, nSync);
}
_stream[GLOBALS._nextChannel]->setLoop(bLoop);
@@ -335,10 +338,10 @@ void TonyEngine::playMusic(int nChannel, const Common::String &fname, int nFX, b
GLOBALS._flipflop = 1 - GLOBALS._flipflop;
} else {
if (!getIsDemo()) {
- if (!_stream[nChannel]->loadFile(fname, FPCODEC_ADPCM, nSync))
+ if (!_stream[nChannel]->loadFile(fname, nSync))
error("failed to open music file '%s'", fname.c_str());
} else {
- _stream[nChannel]->loadFile(fname, FPCODEC_ADPCM, nSync);
+ _stream[nChannel]->loadFile(fname, nSync);
}
_stream[nChannel]->setLoop(bLoop);
@@ -356,10 +359,10 @@ void TonyEngine::doNextMusic(CORO_PARAM, const void *param) {
CORO_BEGIN_CODE(_ctx);
if (!g_vm->getIsDemo()) {
- if (!streams[GLOBALS._nextChannel]->loadFile(GLOBALS._nextMusic, FPCODEC_ADPCM, GLOBALS._nextSync))
+ if (!streams[GLOBALS._nextChannel]->loadFile(GLOBALS._nextMusic, GLOBALS._nextSync))
error("failed to open next music file '%s'", GLOBALS._nextMusic.c_str());
} else {
- streams[GLOBALS._nextChannel]->loadFile(GLOBALS._nextMusic, FPCODEC_ADPCM, GLOBALS._nextSync);
+ streams[GLOBALS._nextChannel]->loadFile(GLOBALS._nextMusic, GLOBALS._nextSync);
}
streams[GLOBALS._nextChannel]->setLoop(GLOBALS._nextLoop);
@@ -433,7 +436,7 @@ void TonyEngine::preloadSFX(int nChannel, const char *fn) {
_theSound.createSfx(&_sfx[nChannel]);
- _sfx[nChannel]->loadFile(fn, FPCODEC_ADPCM);
+ _sfx[nChannel]->loadFile(fn);
}
FPSfx *TonyEngine::createSFX(Common::SeekableReadStream *stream) {
@@ -453,7 +456,7 @@ void TonyEngine::preloadUtilSFX(int nChannel, const char *fn) {
_theSound.createSfx(&_utilSfx[nChannel]);
- _utilSfx[nChannel]->loadFile(fn, FPCODEC_ADPCM);
+ _utilSfx[nChannel]->loadFile(fn);
_utilSfx[nChannel]->setVolume(63);
}
@@ -573,18 +576,26 @@ void TonyEngine::loadState(CORO_PARAM, int n) {
}
bool TonyEngine::openVoiceDatabase() {
- char id[4];
- uint32 numfiles;
-
// Open the voices database
if (!_vdbFP.open("voices.vdb"))
- return false;
+ if (!_vdbFP.open("voices.mdb"))
+ if (!_vdbFP.open("voices.odb"))
+ if (!_vdbFP.open("voices.fdb"))
+ return false;
_vdbFP.seek(-8, SEEK_END);
- numfiles = _vdbFP.readUint32LE();
- _vdbFP.read(id, 4);
-
- if (id[0] != 'V' || id[1] != 'D' || id[2] != 'B' || id[3] != '1') {
+ uint32 numfiles = _vdbFP.readUint32LE();
+ int32 id = _vdbFP.readUint32BE();
+
+ if (id == MKTAG('V', 'D', 'B', '1'))
+ _vdbCodec = FPCODEC_ADPCM;
+ else if (id == MKTAG('M', 'D', 'B', '1'))
+ _vdbCodec = FPCODEC_MP3;
+ else if (id == MKTAG('O', 'D', 'B', '1'))
+ _vdbCodec = FPCODEC_OGG;
+ else if (id == MKTAG('F', 'D', 'B', '1'))
+ _vdbCodec = FPCODEC_FLAC;
+ else {
_vdbFP.close();
return false;
}
diff --git a/engines/tony/tony.h b/engines/tony/tony.h
index 40a5184c31..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"
@@ -104,6 +104,7 @@ public:
RMResUpdate _resUpdate;
uint32 _hEndOfFrame;
Common::File _vdbFP;
+ SoundCodecs _vdbCodec;
Common::Array<VoiceHeader> _voices;
FPSound _theSound;
Common::List<FPSfx *> _activeSfx;
@@ -241,4 +242,4 @@ extern TonyEngine *g_vm;
} // End of namespace Tony
-#endif /* TONY_H */
+#endif /* TONY_TONY_H */
diff --git a/engines/toon/POTFILES b/engines/toon/POTFILES
new file mode 100644
index 0000000000..5bdfa37e5f
--- /dev/null
+++ b/engines/toon/POTFILES
@@ -0,0 +1 @@
+engines/toon/toon.cpp
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 4f82514213..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;
}
@@ -173,10 +173,9 @@ SaveStateList ToonMetaEngine::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..)
SaveStateList saveList;
for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) {
@@ -208,6 +207,8 @@ SaveStateList ToonMetaEngine::listSaves(const char *target) const {
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
diff --git a/engines/toon/toon.cpp b/engines/toon/toon.cpp
index 9e2905f454..837339402c 100644
--- a/engines/toon/toon.cpp
+++ b/engines/toon/toon.cpp
@@ -27,6 +27,7 @@
#include "common/config-manager.h"
#include "common/savefile.h"
#include "common/memstream.h"
+#include "common/translation.h"
#include "engines/advancedDetector.h"
#include "engines/util.h"
@@ -34,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"
@@ -708,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 {
@@ -797,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);
}
@@ -935,10 +935,12 @@ bool ToonEngine::showOptions() {
_gameState->_inMenu = false;
_firstFrame = true;
_gameState->_currentScrollValue = oldScrollValue;
-
+
restorePalette();
dirtyAllScreen();
+ delete optionPicture;
+
return exitGame;
}
@@ -1296,6 +1298,7 @@ ToonEngine::ToonEngine(OSystem *syst, const ADGameDescription *gameDescription)
_scriptState[i].running = false;
}
_currentScriptRegion = 0;
+ _currentFont = nullptr;
}
ToonEngine::~ToonEngine() {
@@ -3334,7 +3337,7 @@ bool ToonEngine::saveGame(int32 slot, const Common::String &saveGameDesc) {
Common::String savegameDescription;
if (slot == -1) {
- GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Save game:", "Save", true);
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
savegameId = dialog->runModalWithCurrentTarget();
savegameDescription = dialog->getResultString();
delete dialog;
@@ -3426,7 +3429,7 @@ bool ToonEngine::loadGame(int32 slot) {
int16 savegameId;
if (slot == -1) {
- GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Restore game:", "Restore", false);
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false);
savegameId = dialog->runModalWithCurrentTarget();
delete dialog;
} else {
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/opcodes.cpp b/engines/touche/opcodes.cpp
index ee7f3a9b6b..2af942885a 100644
--- a/engines/touche/opcodes.cpp
+++ b/engines/touche/opcodes.cpp
@@ -610,8 +610,13 @@ void ToucheEngine::op_getInventoryItem() {
keyChar = _currentKeyCharNum;
}
assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
- assert(item < sizeof(_keyCharsTable[keyChar].inventoryItems));
- *_script.stackDataPtr = _keyCharsTable[keyChar].inventoryItems[item];
+ if (item == 4) {
+ // item 4 is the 'money' field
+ *_script.stackDataPtr = _keyCharsTable[keyChar].money;
+ } else {
+ assert(item < ARRAYSIZE(_keyCharsTable[keyChar].inventoryItems));
+ *_script.stackDataPtr = _keyCharsTable[keyChar].inventoryItems[item];
+ }
}
void ToucheEngine::op_setInventoryItem() {
@@ -625,8 +630,13 @@ void ToucheEngine::op_setInventoryItem() {
keyChar = _currentKeyCharNum;
}
assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
- assert(item < sizeof(_keyCharsTable[keyChar].inventoryItems));
- _keyCharsTable[keyChar].inventoryItems[item] = *_script.stackDataPtr;
+ if (item == 4) {
+ // item 4 is the 'money' field
+ _keyCharsTable[keyChar].money = *_script.stackDataPtr;
+ } else {
+ assert(item < ARRAYSIZE(_keyCharsTable[keyChar].inventoryItems));
+ _keyCharsTable[keyChar].inventoryItems[item] = *_script.stackDataPtr;
+ }
if (item == 4 && !_hideInventoryTexts) {
drawAmountOfMoneyInInventory();
}
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 20bf723553..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"
@@ -102,7 +101,7 @@ struct KeyChar {
int16 zPosPrev;
int16 prevWalkDataNum;
uint16 textColor;
- int16 inventoryItems[5];
+ int16 inventoryItems[4];
int16 money;
int16 pointsDataNum;
int16 currentWalkBox;
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 388967931d..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 {
@@ -114,10 +114,9 @@ public:
virtual SaveStateList listSaves(const char *target) const {
Common::String pattern = target;
- pattern += ".???";
+ pattern += ".###";
Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles(pattern);
- sort(filenames.begin(), filenames.end());
TsAGE::tSageSavegameHeader header;
SaveStateList saveList;
@@ -141,6 +140,8 @@ public:
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
diff --git a/engines/tsage/detection_tables.h b/engines/tsage/detection_tables.h
index 109ac353e6..f331ecdab5 100644
--- a/engines/tsage/detection_tables.h
+++ b/engines/tsage/detection_tables.h
@@ -165,7 +165,7 @@ static const tSageGameDescription gameDescriptions[] = {
AD_ENTRY1s("r2rw.rlb", "df6c25622387007788ca36d99362c1f0", 47586928),
Common::EN_ANY,
Common::kPlatformDOS,
- ADGF_CD | ADGF_TESTING,
+ ADGF_CD,
GUIO0()
},
GType_Ringworld2,
@@ -179,7 +179,7 @@ static const tSageGameDescription gameDescriptions[] = {
AD_ENTRY1s("r2rw.rlb", "c8e1a82c67c3caf57368eadde13dc15f", 32384464),
Common::EN_ANY,
Common::kPlatformDOS,
- ADGF_CD | ADGF_TESTING,
+ ADGF_CD,
GUIO0()
},
GType_Ringworld2,
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/backends/mixer/sdl13/sdl13-mixer.h b/engines/tsage/screen.h
index ff2bb43084..c5cfee754a 100644
--- a/backends/mixer/sdl13/sdl13-mixer.h
+++ b/engines/tsage/screen.h
@@ -20,48 +20,47 @@
*
*/
-#ifndef BACKENDS_MIXER_SDL13_H
-#define BACKENDS_MIXER_SDL13_H
+#ifndef TSAGE_SCREEN_H
+#define TSAGE_SCREEN_H
-#include "backends/mixer/sdl/sdl-mixer.h"
+#include "common/scummsys.h"
+#include "common/array.h"
+#include "graphics/screen.h"
+#include "tsage/graphics.h"
-/**
- * SDL mixer manager. It wraps the actual implementation
- * of the Audio:Mixer used by the engine, and setups
- * the SDL audio subsystem and the callback for the
- * audio mixer implementation.
- */
-class Sdl13MixerManager : public SdlMixerManager {
-public:
- Sdl13MixerManager();
- virtual ~Sdl13MixerManager();
+namespace TsAGE {
- /**
- * Initialize and setups the mixer
- */
- virtual void init();
+#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 {
/**
- * Pauses the audio system
+ * Override the addDirtyRect from GfxSurface, since for our screen
+ * class we need to reintroduce the standard Graphics::Screen implementation
*/
- virtual void suspendAudio();
-
+ virtual void addDirtyRect(const Common::Rect &r) {
+ Graphics::Screen::addDirtyRect(r);
+ }
+public:
/**
- * Resumes the audio system
+ * Constructor
*/
- virtual int resumeAudio();
-
-protected:
+ Screen();
/**
- * The opened SDL audio device
+ * Destructor
*/
- SDL_AudioDeviceID _device;
+ virtual ~Screen();
/**
- * Starts SDL audio
+ * Update the screen
*/
- virtual void startAudio();
+ virtual void update();
};
-#endif
+} // 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 3d7859e4fd..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 {
@@ -182,6 +182,8 @@ public:
saveList.push_back(SaveStateDescriptor(slot, description));
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
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/sequences.cpp b/engines/tucker/sequences.cpp
index d9f284e443..0151c55eb1 100644
--- a/engines/tucker/sequences.cpp
+++ b/engines/tucker/sequences.cpp
@@ -54,6 +54,7 @@ void TuckerEngine::handleCreditsSequence() {
int counter2 = 0;
int counter1 = 0;
loadCharset2();
+ showCursor(false);
stopSounds();
_locationNum = 74;
_flagsTable[236] = 74;
@@ -159,12 +160,16 @@ void TuckerEngine::handleCreditsSequence() {
redrawScreen(0);
waitForTimer(2);
} while (_fadePaletteCounter > 0);
+ showCursor(true);
}
void TuckerEngine::handleCongratulationsSequence() {
+ // This method is only called right before the program terminates,
+ // so it doesn't bother restoring the palette
_timerCounter2 = 0;
_fadePaletteCounter = 0;
stopSounds();
+ showCursor(false);
loadImage("congrat.pcx", _loadTempBuf, 1);
Graphics::copyRect(_locationBackgroundGfxBuf, 640, _loadTempBuf, 320, 320, 200);
_fullRedraw = true;
@@ -176,11 +181,13 @@ void TuckerEngine::handleCongratulationsSequence() {
}
waitForTimer(3);
}
+ showCursor(true);
}
void TuckerEngine::handleNewPartSequence() {
char filename[40];
+ showCursor(false);
stopSounds();
if (_flagsTable[219] == 1) {
_flagsTable[219] = 0;
@@ -244,7 +251,7 @@ void TuckerEngine::handleNewPartSequence() {
_inputKeys[kInputKeyEscape] = false;
break;
}
- } while (isSpeechSoundPlaying());
+ } while (isSpeechSoundPlaying() && !_quitGame);
stopSpeechSound();
do {
if (_fadePaletteCounter > 0) {
@@ -257,8 +264,9 @@ void TuckerEngine::handleNewPartSequence() {
drawSprite(0);
redrawScreen(0);
waitForTimer(3);
- } while (_fadePaletteCounter > 0);
+ } while (_fadePaletteCounter > 0 && !_quitGame);
_locationNum = currentLocation;
+ showCursor(true);
}
void TuckerEngine::handleMeanwhileSequence() {
@@ -280,8 +288,9 @@ void TuckerEngine::handleMeanwhileSequence() {
strcpy(filename, "loc80.pcx");
}
loadImage(filename, _quadBackgroundGfxBuf + 89600, 1);
+ showCursor(false);
_fadePaletteCounter = 0;
- for (int i = 0; i < 60; ++i) {
+ for (int i = 0; i < 60 && !_quitGame; ++i) {
if (_fadePaletteCounter < 16) {
fadeOutPalette();
++_fadePaletteCounter;
@@ -290,7 +299,10 @@ void TuckerEngine::handleMeanwhileSequence() {
_fullRedraw = true;
redrawScreen(0);
waitForTimer(3);
- ++i;
+ if (_inputKeys[kInputKeyEscape]) {
+ _inputKeys[kInputKeyEscape] = false;
+ break;
+ }
}
do {
if (_fadePaletteCounter > 0) {
@@ -301,9 +313,10 @@ void TuckerEngine::handleMeanwhileSequence() {
_fullRedraw = true;
redrawScreen(0);
waitForTimer(3);
- } while (_fadePaletteCounter > 0);
+ } while (_fadePaletteCounter > 0 && !_quitGame);
memcpy(_currentPalette, backupPalette, 256 * 3);
_fullRedraw = true;
+ showCursor(true);
}
void TuckerEngine::handleMapSequence() {
diff --git a/engines/tucker/staticres.cpp b/engines/tucker/staticres.cpp
index b884851d7e..b9f6a6efee 100644
--- a/engines/tucker/staticres.cpp
+++ b/engines/tucker/staticres.cpp
@@ -329,8 +329,13 @@ static const SoundSequenceData _soundDataSeq19_20[] = {
{ 53, 2, 14, 100, 1 }, { 78, 2, 0, 100, 2 }, { 80, 0, 0, 100, 4 },
};
+// I've been told that there are versions of the game that don't play the
+// "introdub" music (130) for the first scene of the intro. The English "Euro
+// power pack" release does however, and I see no harm in doing it for every
+// version here. The volume is just a guess, though.
+
const SoundSequenceDataList AnimationSequencePlayer::_soundSeqDataList[] = {
- { 0, 0, 14, 10, 58, _soundDataSeq3_4 },
+ { 130, 80, 14, 10, 58, _soundDataSeq3_4 },
{ 0, 0, 14, 5, 60, _soundDataSeq9_10 },
{ 0, 0, 14, 9, 48, _soundDataSeq21_20 },
{ 1, 80, 14, 4, 25, _soundDataSeq13_14 },
@@ -471,6 +476,7 @@ const char *const AnimationSequencePlayer::_audioFileNamesTable[] = {
"rdfx38.wav",
"rdfx8.wav",
"rdfx9.wav",
+ "introdub.raw",
};
} // namespace Tucker
diff --git a/engines/tucker/tucker.cpp b/engines/tucker/tucker.cpp
index de555cd7b6..ad455c5ded 100644
--- a/engines/tucker/tucker.cpp
+++ b/engines/tucker/tucker.cpp
@@ -710,6 +710,10 @@ void TuckerEngine::setCursorType(int type) {
CursorMan.showMouse(_cursorType < 2);
}
+void TuckerEngine::showCursor(bool visible) {
+ CursorMan.showMouse(visible);
+}
+
void TuckerEngine::setupNewLocation() {
debug(2, "setupNewLocation() current %d next %d", _locationNum, _nextLocationNum);
_locationNum = _nextLocationNum;
diff --git a/engines/tucker/tucker.h b/engines/tucker/tucker.h
index a423915a5f..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"
@@ -246,6 +246,15 @@ private:
};
inline int scaleMixerVolume(int volume, int max = 100) {
+ if (volume > max) {
+ // This happens for instance for Bud's line, "Is that the
+ // great mystery invention you had hidden away?" in the intro,
+ // which is played at volume 110 out of 100. This made it very
+ // hard to hear. I'm not sure if this was a bug in the original
+ // game, or if it had the ability to amplify sounds.
+ warning("scaleMixerVolume: Adjusting volume %d to %d", volume, max);
+ volume = max;
+ }
return volume * Audio::Mixer::kMaxChannelVolume / max;
}
@@ -291,6 +300,7 @@ protected:
void updateCursorPos(int x, int y);
void setCursorNum(int num);
void setCursorType(int type);
+ void showCursor(bool visible);
void setupNewLocation();
void copyLocBitmap(const char *filename, int offset, bool isMask);
void updateMouseState();
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 3503eb11ef..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;
@@ -114,10 +114,9 @@ SaveStateList VoyeurMetaEngine::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);
+ Common::String pattern = Common::String::format("%s.0##", target);
filenames = saveFileMan->listSavefiles(pattern);
- sort(filenames.begin(), filenames.end()); // Sort to get the files in numerical order
SaveStateList saveList;
Voyeur::VoyeurSavegameHeader header;
@@ -139,6 +138,8 @@ SaveStateList VoyeurMetaEngine::listSaves(const char *target) const {
}
}
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
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 53eb5ce3c5..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;
@@ -1390,7 +1390,7 @@ int ThreadResource::doInterface() {
Common::Point(pt.x - MANSION_VIEW_X, pt.y - MANSION_VIEW_Y);
regionIndex = -1;
- for (int hotspotIdx = 0; hotspotIdx < (int)hotspots->size(); ++hotspotIdx) {
+ for (uint hotspotIdx = 0; hotspotIdx < hotspots->size(); ++hotspotIdx) {
if ((*hotspots)[hotspotIdx].contains(pt)) {
// Rect check done
for (int arrIndex = 0; arrIndex < 3; ++arrIndex) {
@@ -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));
}
}
@@ -1446,7 +1446,7 @@ int ThreadResource::doInterface() {
_vm->flipPageAndWait();
pt = _vm->_eventsManager->getMousePos();
- if ((_vm->_voy->_RTVNum >= _vm->_voy->_RTVLimit) || ((_vm->_voy->_eventFlags & 0x80) &&
+ if ((_vm->_voy->_RTVNum >= _vm->_voy->_RTVLimit) || ((_vm->_voy->_eventFlags & EVTFLAG_VICTIM_PRESET) &&
_vm->_eventsManager->_rightClick && (pt.x == 0))) {
// Time to transition to the next time period
_vm->_eventsManager->getMouseInfo();
@@ -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 68a30e41f4..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;
@@ -159,7 +160,7 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des
destFlags = destPic->_flags;
byte *cursorData = NULL;
- if (srcFlags & 1) {
+ if (srcFlags & DISPFLAG_1) {
if (_clipPtr) {
int xs = _clipPtr->left - destPic->_bounds.left;
int ys = _clipPtr->top - destPic->_bounds.top;
@@ -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 {
@@ -433,7 +440,7 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des
}
}
} else {
- if (srcFlags & 0x100) {
+ if (srcFlags & DISPFLAG_100) {
// Simple run-length encoded image
srcP = srcImgData;
@@ -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,22 +901,19 @@ 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;
for (uint idx = 0; idx < viewPorts.size(); ++idx) {
- if (viewPorts[idx]->_flags & DISPFLAG_20) {
- if ((viewPorts[idx]->_flags & (DISPFLAG_8 || DISPFLAG_1))
- == (DISPFLAG_8 || DISPFLAG_1)) {
- if (_planeSelect == idx)
- sDisplayPic(viewPorts[idx]->_currentPic);
- flipFlag = true;
- }
+ if ((viewPorts[idx]->_flags & (DISPFLAG_20 | DISPFLAG_8 | DISPFLAG_1)) == (DISPFLAG_20 | DISPFLAG_8 | DISPFLAG_1)) {
+ if (_planeSelect == idx)
+ sDisplayPic(viewPorts[idx]->_currentPic);
+ flipFlag = true;
}
if (flipFlag) {
@@ -910,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
@@ -932,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;
@@ -968,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;
@@ -976,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;
@@ -987,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;
@@ -997,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;
@@ -1010,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;
@@ -1023,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;
@@ -1040,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 c0e5a043cd..483dfc7cbc 100644
--- a/engines/voyeur/sound.cpp
+++ b/engines/voyeur/sound.cpp
@@ -22,13 +22,15 @@
#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"
namespace Voyeur {
- SoundManager::SoundManager(Audio::Mixer *mixer) {
+SoundManager::SoundManager(Audio::Mixer *mixer) {
_mixer = mixer;
_vocOffset = 0;
}
@@ -54,6 +56,7 @@ void SoundManager::setVOCOffset(int offset) {
}
Common::String SoundManager::getVOCFileName(int idx) {
+ assert(idx >= 0);
return Common::String::format("%s.voc", SZ_FILENAMES[idx]);
}
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 dad634c9bb..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"
@@ -33,8 +33,6 @@
namespace Voyeur {
-VoyeurEngine *g_vm;
-
VoyeurEngine::VoyeurEngine(OSystem *syst, const VoyeurGameDescription *gameDesc) : Engine(syst),
_gameDescription(gameDesc), _randomSource("Voyeur"),
_defaultFontInfo(3, 0xff, 0xff, 0, 0, ALIGN_LEFT, 0, Common::Point(), 1, 1,
@@ -42,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;
@@ -67,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;
@@ -90,7 +81,7 @@ VoyeurEngine::~VoyeurEngine() {
delete _bVoy;
delete _voy;
delete _soundManager;
- delete _graphicsManager;
+ delete _screen;
delete _filesManager;
delete _eventsManager;
delete _debugger;
@@ -128,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;
@@ -146,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() {
@@ -215,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
@@ -239,7 +237,7 @@ void VoyeurEngine::showConversionScreen() {
flipPageAndWaitForFade();
- _graphicsManager->screenReset();
+ _screen->screenReset();
}
bool VoyeurEngine::doLock() {
@@ -251,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);
@@ -280,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());
@@ -290,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) {
@@ -358,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;
@@ -375,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);
@@ -395,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
@@ -424,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;
@@ -461,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;
@@ -474,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) {
@@ -501,7 +497,7 @@ void VoyeurEngine::doOpening() {
}
if (textPic) {
- _graphicsManager->sDrawPic(textPic, _graphicsManager->_vPort, textPos);
+ _screen->sDrawPic(textPic, _screen->_vPort, textPos);
}
flipPageAndWait();
@@ -529,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();
@@ -575,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();
@@ -593,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;
}
@@ -610,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;
@@ -635,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;
@@ -663,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);
@@ -671,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();
@@ -682,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();
}
@@ -704,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();
@@ -719,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();
@@ -854,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);
}
@@ -908,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 c7df924f7e..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;
@@ -404,10 +404,9 @@ void VoyeurEngine::doPiracy() {
fi._justifyHeight = 230;
// Loop through the piracy message array to draw each line
- int yp, idx;
- for (idx = 0, yp = 33; idx < 10; ++idx) {
+ 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;
}
@@ -440,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) {
@@ -482,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();
@@ -544,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();
@@ -651,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;
@@ -674,20 +673,20 @@ 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;
_eventsManager->_intPtr._flashTimer = 0;
_voy->_eventFlags &= ~EVTFLAG_TIME_DISABLED;
- // Play suond for the given duration
+ // Play sound for the given duration
_soundManager->setVOCOffset(_voy->_vocSecondsOffset);
_soundManager->startVOCPlay(_audioVideoId + 159);
uint32 secondsDuration = e._computerOff;
@@ -726,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;
@@ -753,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;
@@ -763,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;
@@ -776,7 +775,7 @@ void VoyeurEngine::doGossip() {
decoder2.close();
_bVoy->freeBoltGroup(0x300);
- _graphicsManager->screenReset();
+ _screen->screenReset();
}
void VoyeurEngine::doTapePlaying() {
@@ -784,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();
@@ -933,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;
@@ -956,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;
@@ -968,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();
@@ -983,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;
@@ -1017,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() {
@@ -1078,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) {
@@ -1102,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() {
@@ -1125,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();
@@ -1164,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;
@@ -1181,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);
@@ -1189,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);
@@ -1207,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;
}
@@ -1224,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);
}
@@ -1252,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;
}
@@ -1264,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();
@@ -1281,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);
}
}
}
@@ -1304,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;
@@ -1344,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);
@@ -1395,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/combat.cpp b/engines/wage/combat.cpp
new file mode 100644
index 0000000000..4f2956d7d2
--- /dev/null
+++ b/engines/wage/combat.cpp
@@ -0,0 +1,916 @@
+/* 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 "wage/wage.h"
+#include "wage/entities.h"
+#include "wage/randomhat.h"
+#include "wage/world.h"
+
+namespace Wage {
+
+Obj *WageEngine::getOffer() {
+ if (_offer != NULL) {
+ Chr *owner = _offer->_currentOwner;
+ if (owner == NULL || owner->_playerCharacter || owner->_currentScene != _world->_player->_currentScene) {
+ _offer = NULL;
+ }
+ }
+ return _offer;
+}
+
+Chr *WageEngine::getMonster() {
+ if (_monster != NULL && _monster->_currentScene != _world->_player->_currentScene) {
+ _monster = NULL;
+ }
+ return _monster;
+}
+
+void WageEngine::encounter(Chr *player, Chr *chr) {
+ char buf[512];
+
+ snprintf(buf, 512, "You encounter %s%s.", chr->_nameProperNoun ? "" : getIndefiniteArticle(chr->_name),
+ chr->_name.c_str());
+ appendText(buf);
+
+ if (!chr->_initialComment.empty())
+ appendText(chr->_initialComment.c_str());
+
+ if (chr->_armor[Chr::HEAD_ARMOR] != NULL) {
+ snprintf(buf, 512, "%s%s is wearing %s.", chr->getDefiniteArticle(true), chr->_name.c_str(),
+ getIndefiniteArticle(chr->_armor[Chr::HEAD_ARMOR]->_name));
+ appendText(buf);
+ }
+ if (chr->_armor[Chr::BODY_ARMOR] != NULL) {
+ snprintf(buf, 512, "%s is protected by %s%s.", getGenderSpecificPronoun(chr->_gender, true),
+ prependGenderSpecificPronoun(chr->_gender), chr->_armor[Chr::BODY_ARMOR]->_name.c_str());
+ appendText(buf);
+ }
+ if (chr->_armor[Chr::SHIELD_ARMOR] != NULL) {
+ Obj *obj = chr->_armor[Chr::SHIELD_ARMOR];
+
+ snprintf(buf, 512, "%s carries %s%s.", getGenderSpecificPronoun(chr->_gender, true),
+ obj->_namePlural ? "" : getIndefiniteArticle(obj->_name), obj->_name.c_str());
+ appendText(buf);
+ }
+}
+
+void WageEngine::performCombatAction(Chr *npc, Chr *player) {
+ if (npc->_context._frozen)
+ return;
+
+ RandomHat hat(_rnd);
+
+ bool winning = (npc->_context._statVariables[PHYS_HIT_CUR] > player->_context._statVariables[PHYS_HIT_CUR]);
+ int validMoves = getValidMoveDirections(npc);
+ ObjArray *weapons = npc->getWeapons(false);
+ ObjArray *magics = npc->getMagicalObjects();
+ // TODO: Figure out under what circumstances we need to add +1
+ // for the chance (e.g. only when all values were set to 0?).
+ if (winning) {
+ if (!_world->_weaponMenuDisabled) {
+ if (!weapons->empty())
+ hat.addTokens(kTokWeapons, npc->_winningWeapons + 1);
+ if (!magics->empty())
+ hat.addTokens(kTokMagic, npc->_winningMagic);
+ }
+ if (validMoves != 0)
+ hat.addTokens(kTokRun, npc->_winningRun + 1);
+ if (!npc->_inventory.empty())
+ hat.addTokens(kTokOffer, npc->_winningOffer + 1);
+ } else {
+ if (!_world->_weaponMenuDisabled) {
+ if (!weapons->empty())
+ hat.addTokens(kTokWeapons, npc->_losingWeapons + 1);
+ if (!magics->empty())
+ hat.addTokens(kTokMagic, npc->_losingMagic);
+ }
+ if (validMoves != 0)
+ hat.addTokens(kTokRun, npc->_losingRun + 1);
+ if (!npc->_inventory.empty())
+ hat.addTokens(kTokOffer, npc->_losingOffer + 1);
+ }
+
+ ObjList *objs = &npc->_currentScene->_objs;
+ if (npc->_inventory.size() < npc->_maximumCarriedObjects) {
+ int cnt = 0;
+ for (ObjList::const_iterator it = objs->begin(); it != objs->end(); ++it, ++cnt) {
+ if ((*it)->_type != Obj::IMMOBILE_OBJECT) {
+ // TODO: I'm not sure what the chance should be here.
+ hat.addTokens(cnt, 123);
+ }
+ }
+ }
+
+ int token = hat.drawToken();
+ switch (token) {
+ case kTokWeapons:
+ // TODO: I think the monster should choose the "best" weapon.
+ performAttack(npc, player, weapons->operator[](_rnd->getRandomNumber(weapons->size() - 1)));
+ break;
+ case kTokMagic:
+ // TODO: I think the monster should choose the "best" magic.
+ performMagic(npc, player, magics->operator[](_rnd->getRandomNumber(magics->size() - 1)));
+ break;
+ case kTokRun:
+ performMove(npc, validMoves);
+ break;
+ case kTokOffer:
+ performOffer(npc, player);
+ break;
+ case kTokNone:
+ break;
+ default:
+ {
+ int cnt = 0;
+ for (ObjList::const_iterator it = objs->begin(); it != objs->end(); ++it, ++cnt)
+ if (cnt == token)
+ performTake(npc, *it);
+ break;
+ }
+ }
+
+ delete weapons;
+ delete magics;
+}
+
+static const char *const targets[] = { "head", "chest", "side" };
+
+void WageEngine::performAttack(Chr *attacker, Chr *victim, Obj *weapon) {
+ if (_world->_weaponMenuDisabled)
+ return;
+
+ // TODO: verify that a player not aiming will always target the chest??
+ int targetIndex = -1;
+ char buf[256];
+
+ if (weapon->_type != Obj::MAGICAL_OBJECT) {
+ if (attacker->_playerCharacter) {
+ targetIndex = _aim;
+ } else {
+ targetIndex = _rnd->getRandomNumber(ARRAYSIZE(targets) - 1);
+ _opponentAim = targetIndex + 1;
+ }
+
+ if (!attacker->_playerCharacter) {
+ snprintf(buf, 256, "%s%s %ss %s%s at %s%s's %s.",
+ attacker->getDefiniteArticle(true), attacker->_name.c_str(),
+ weapon->_operativeVerb.c_str(),
+ prependGenderSpecificPronoun(attacker->_gender), weapon->_name.c_str(),
+ victim->getDefiniteArticle(true), victim->_name.c_str(),
+ targets[targetIndex]);
+ appendText(buf);
+ }
+ } else if (!attacker->_playerCharacter) {
+ snprintf(buf, 256, "%s%s %ss %s%s at %s%s.",
+ attacker->getDefiniteArticle(true), attacker->_name.c_str(),
+ weapon->_operativeVerb.c_str(),
+ prependGenderSpecificPronoun(attacker->_gender), weapon->_name.c_str(),
+ victim->getDefiniteArticle(true), victim->_name.c_str());
+ appendText(buf);
+ }
+
+ playSound(weapon->_sound);
+
+ bool usesDecremented = false;
+ int chance = _rnd->getRandomNumber(255);
+ // TODO: what about obj accuracy
+ if (chance < attacker->_physicalAccuracy) {
+ usesDecremented = attackHit(attacker, victim, weapon, targetIndex);
+ } else if (weapon->_type != Obj::MAGICAL_OBJECT) {
+ appendText("A miss!");
+ } else if (attacker->_playerCharacter) {
+ appendText("The spell has no effect.");
+ }
+
+ if (!usesDecremented) {
+ decrementUses(weapon);
+ }
+}
+
+void WageEngine::decrementUses(Obj *obj) {
+ int numberOfUses = obj->_numberOfUses;
+ if (numberOfUses != -1) {
+ numberOfUses--;
+ if (numberOfUses > 0) {
+ obj->_numberOfUses = numberOfUses;
+ } else {
+ if (!obj->_failureMessage.empty()) {
+ appendText(obj->_failureMessage.c_str());
+ }
+ if (obj->_returnToRandomScene) {
+ _world->move(obj, _world->getRandomScene());
+ } else {
+ _world->move(obj, _world->_storageScene);
+ }
+ obj->resetState(obj->_currentOwner, obj->_currentScene);
+ }
+ }
+}
+
+bool WageEngine::attackHit(Chr *attacker, Chr *victim, Obj *weapon, int targetIndex) {
+ bool receivedHitTextPrinted = false;
+ char buf[512];
+
+ if (targetIndex != -1) {
+ Obj *armor = victim->_armor[targetIndex];
+ if (armor != NULL) {
+ // TODO: Absorb some damage.
+ snprintf(buf, 512, "%s%s's %s weakens the impact of %s%s's %s.",
+ victim->getDefiniteArticle(true), victim->_name.c_str(),
+ victim->_armor[targetIndex]->_name.c_str(),
+ attacker->getDefiniteArticle(false), attacker->_name.c_str(),
+ weapon->_name.c_str());
+ appendText(buf);
+ decrementUses(armor);
+ } else {
+ snprintf(buf, 512, "A hit to the %s!", targets[targetIndex]);
+ appendText(buf);
+ }
+ playSound(attacker->_scoresHitSound);
+ appendText(attacker->_scoresHitComment.c_str());
+ playSound(victim->_receivesHitSound);
+ appendText(victim->_receivesHitComment.c_str());
+ receivedHitTextPrinted = true;
+ } else if (weapon->_type == Obj::MAGICAL_OBJECT) {
+ appendText(weapon->_useMessage.c_str());
+ appendText("The spell is effective!");
+ }
+
+ bool causesPhysicalDamage = true;
+ bool causesSpiritualDamage = false;
+ bool freezesOpponent = false;
+ bool usesDecremented = false;
+
+ if (weapon->_type == Obj::THROW_WEAPON) {
+ _world->move(weapon, victim->_currentScene);
+ } else if (weapon->_type == Obj::MAGICAL_OBJECT) {
+ int type = weapon->_attackType;
+ causesPhysicalDamage = (type == Obj::CAUSES_PHYSICAL_DAMAGE || type == Obj::CAUSES_PHYSICAL_AND_SPIRITUAL_DAMAGE);
+ causesSpiritualDamage = (type == Obj::CAUSES_SPIRITUAL_DAMAGE || type == Obj::CAUSES_PHYSICAL_AND_SPIRITUAL_DAMAGE);
+ freezesOpponent = (type == Obj::FREEZES_OPPONENT);
+ }
+
+ if (causesPhysicalDamage) {
+ victim->_context._userVariables[PHYS_HIT_CUR] -= weapon->_damage;
+
+ /* Do it here to get the right order of messages in case of death. */
+ decrementUses(weapon);
+ usesDecremented = true;
+
+ if (victim->_context._userVariables[PHYS_HIT_CUR] < 0) {
+ playSound(victim->_dyingSound);
+ appendText(victim->_dyingWords.c_str());
+ snprintf(buf, 512, "%s%s is dead!", victim->getDefiniteArticle(true), victim->_name.c_str());
+ appendText(buf);
+
+ attacker->_context._kills++;
+ attacker->_context._experience += victim->_context._userVariables[SPIR_HIT_CUR] + victim->_context._userVariables[PHYS_HIT_CUR];
+
+ if (!victim->_playerCharacter && !victim->_inventory.empty()) {
+ Scene *currentScene = victim->_currentScene;
+
+ for (int i = victim->_inventory.size() - 1; i >= 0; i--) {
+ _world->move(victim->_inventory[i], currentScene);
+ }
+ Common::String *s = getGroundItemsList(currentScene);
+ appendText(s->c_str());
+ delete s;
+ }
+ _world->move(victim, _world->_storageScene);
+ } else if (attacker->_playerCharacter && !receivedHitTextPrinted) {
+ double physicalPercent = (double)victim->_context._userVariables[SPIR_HIT_CUR] /
+ victim->_context._userVariables[SPIR_HIT_BAS];
+ snprintf(buf, 512, "%s%s's condition appears to be %s.",
+ victim->getDefiniteArticle(true), victim->_name.c_str(),
+ getPercentMessage(physicalPercent));
+ appendText(buf);
+ }
+ }
+
+ if (causesSpiritualDamage) {
+ /* TODO */
+ warning("TODO: Spiritual damage");
+ }
+
+ if (freezesOpponent) {
+ victim->_context._frozen = true;
+ }
+
+ return usesDecremented;
+}
+
+void WageEngine::performMagic(Chr *attacker, Chr *victim, Obj *magicalObject) {
+ switch (magicalObject->_attackType) {
+ case Obj::HEALS_PHYSICAL_DAMAGE:
+ case Obj::HEALS_SPIRITUAL_DAMAGE:
+ case Obj::HEALS_PHYSICAL_AND_SPIRITUAL_DAMAGE:
+ performHealingMagic(attacker, magicalObject);
+ return;
+ }
+
+ performAttack(attacker, victim, magicalObject);
+}
+
+void WageEngine::performHealingMagic(Chr *chr, Obj *magicalObject) {
+ char buf[512];
+
+ if (!chr->_playerCharacter) {
+ snprintf(buf, 512, "%s%s %ss %s%s.",
+ chr->getDefiniteArticle(true), chr->_name.c_str(),
+ magicalObject->_operativeVerb.c_str(),
+ getIndefiniteArticle(magicalObject->_name), magicalObject->_name.c_str());
+ appendText(buf);
+ }
+
+ uint chance = _rnd->getRandomNumber(255);
+ if (chance < magicalObject->_accuracy) {
+ int type = magicalObject->_attackType;
+
+ if (type == Obj::HEALS_PHYSICAL_DAMAGE || type == Obj::HEALS_PHYSICAL_AND_SPIRITUAL_DAMAGE)
+ chr->_context._statVariables[PHYS_HIT_CUR] += magicalObject->_damage;
+
+ if (type == Obj::HEALS_SPIRITUAL_DAMAGE || type == Obj::HEALS_PHYSICAL_AND_SPIRITUAL_DAMAGE)
+ chr->_context._statVariables[SPIR_HIT_CUR] += magicalObject->_damage;
+
+ playSound(magicalObject->_sound);
+ appendText(magicalObject->_useMessage.c_str());
+
+ // TODO: what if enemy heals himself?
+ if (chr->_playerCharacter) {
+ double physicalPercent = (double)chr->_context._statVariables[PHYS_HIT_CUR] / chr->_context._statVariables[PHYS_HIT_BAS];
+ double spiritualPercent = (double)chr->_context._statVariables[SPIR_HIT_CUR] / chr->_context._statVariables[SPIR_HIT_BAS];
+ snprintf(buf, 256, "Your physical condition is %s.", getPercentMessage(physicalPercent));
+ appendText(buf);
+
+ snprintf(buf, 256, "Your spiritual condition is %s.", getPercentMessage(spiritualPercent));
+ appendText(buf);
+ }
+ }
+
+ decrementUses(magicalObject);
+}
+
+static const int directionsX[] = { 0, 0, 1, -1 };
+static const int directionsY[] = { -1, 1, 0, 0 };
+static const char *const directionsS[] = { "north", "south", "east", "west" };
+
+void WageEngine::performMove(Chr *chr, int validMoves) {
+ // count how many valid moves we have
+ int numValidMoves = 0;
+
+ for (int i = 0; i < 4; i++)
+ if ((validMoves & (1 << i)) != 0)
+ numValidMoves++;
+
+ // Now pick random dir
+ int dirNum = _rnd->getRandomNumber(numValidMoves - 1);
+ int dir = 0;
+
+ // And get it
+ for (int i = 0; i < 4; i++)
+ if ((validMoves & (1 << i)) != 0) {
+ if (dirNum == 0) {
+ dir = i;
+ break;
+ }
+ dirNum--;
+ }
+
+ char buf[256];
+ snprintf(buf, 256, "%s%s runs %s.", chr->getDefiniteArticle(true), chr->_name.c_str(), directionsS[dir]);
+ appendText(buf);
+
+ _running = chr;
+ Scene *currentScene = chr->_currentScene;
+ int destX = currentScene->_worldX + directionsX[dir];
+ int destY = currentScene->_worldY + directionsY[dir];
+
+ _world->move(chr, _world->getSceneAt(destX, destY));
+}
+
+void WageEngine::performOffer(Chr *attacker, Chr *victim) {
+ /* TODO: choose in a smarter way? */
+ Obj *obj = attacker->_inventory[0];
+ char buf[512];
+
+ snprintf(buf, 512, "%s%s offers %s%s.", attacker->getDefiniteArticle(true), attacker->_name.c_str(),
+ obj->_namePlural ? "some " : getIndefiniteArticle(obj->_name), obj->_name.c_str());
+
+ appendText(buf);
+
+ _offer = obj;
+}
+
+void WageEngine::performTake(Chr *npc, Obj *obj) {
+ char buf[512];
+
+ snprintf(buf, 512, "%s%s picks up the %s%s.", npc->getDefiniteArticle(true), npc->_name.c_str(),
+ getIndefiniteArticle(obj->_name), obj->_name.c_str());
+
+ appendText(buf);
+
+ _world->move(obj, npc);
+}
+
+int WageEngine::getValidMoveDirections(Chr *npc) {
+ int directions = 0;
+ Scene *currentScene = npc->_currentScene;
+ for (int dir = 0; dir < 4; dir++) {
+ if (!currentScene->_blocked[dir]) {
+ int destX = currentScene->_worldX + directionsX[dir];
+ int destY = currentScene->_worldY + directionsY[dir];
+
+ Scene *scene = _world->getSceneAt(destX, destY);
+
+ if (scene != NULL && scene->_chrs.empty()) {
+ directions |= (1 << dir);
+ }
+ }
+ }
+
+ return directions;
+}
+
+void WageEngine::regen() {
+ Chr *player = _world->_player;
+ int curHp = player->_context._statVariables[PHYS_HIT_CUR];
+ int maxHp = player->_context._statVariables[PHYS_HIT_BAS];
+ int delta = maxHp - curHp;
+
+ if (delta > 0) {
+ int bonus = (int)(delta / (8 + _rnd->getRandomNumber(2)));
+ player->_context._statVariables[PHYS_HIT_CUR] += bonus;
+ }
+}
+
+void WageEngine::takeObj(Obj *obj) {
+ if (_world->_player->_inventory.size() >= _world->_player->_maximumCarriedObjects) {
+ appendText("Your pack is full, you must drop something.");
+ } else {
+ char buf[256];
+
+ _world->move(obj, _world->_player);
+ int type = _world->_player->wearObjIfPossible(obj);
+ if (type == Chr::HEAD_ARMOR) {
+ snprintf(buf, 256, "You are now wearing the %s.", obj->_name.c_str());
+ appendText(buf);
+ } else if (type == Chr::BODY_ARMOR) {
+ snprintf(buf, 256, "You are now wearing the %s.", obj->_name.c_str());
+ appendText(buf);
+ } else if (type == Chr::SHIELD_ARMOR) {
+ snprintf(buf, 256, "You are now wearing the %s.", obj->_name.c_str());
+ appendText(buf);
+ } else if (type == Chr::MAGIC_ARMOR) {
+ snprintf(buf, 256, "You are now wearing the %s.", obj->_name.c_str());
+ appendText(buf);
+ } else {
+ snprintf(buf, 256, "You now have the %s.", obj->_name.c_str());
+ appendText(buf);
+ }
+ appendText(obj->_clickMessage.c_str());
+ }
+}
+
+bool WageEngine::handleMoveCommand(Directions dir, const char *dirName) {
+ Scene *playerScene = _world->_player->_currentScene;
+ const char *msg = playerScene->_messages[dir].c_str();
+
+ if (!playerScene->_blocked[dir]) {
+ int destX = playerScene->_worldX + directionsX[dir];
+ int destY = playerScene->_worldY + directionsY[dir];
+
+ Scene *scene = _world->getSceneAt(destX, destY);
+
+ if (scene != NULL) {
+ if (strlen(msg) > 0) {
+ appendText(msg);
+ }
+ _world->move(_world->_player, scene);
+ return true;
+ }
+ }
+ if (strlen(msg) > 0) {
+ appendText(msg);
+ } else {
+ Common::String txt("You can't go ");
+ txt += dirName;
+ txt += ".";
+ appendText(txt.c_str());
+ }
+
+ return true;
+}
+
+bool WageEngine::handleLookCommand() {
+ appendText(_world->_player->_currentScene->_text.c_str());
+
+ Common::String *items = getGroundItemsList(_world->_player->_currentScene);
+ if (items != NULL) {
+ appendText(items->c_str());
+
+ delete items;
+ }
+
+ return true;
+}
+
+Common::String *WageEngine::getGroundItemsList(Scene *scene) {
+ ObjArray objs;
+
+ for (ObjList::const_iterator it = scene->_objs.begin(); it != scene->_objs.end(); ++it)
+ if ((*it)->_type != Obj::IMMOBILE_OBJECT)
+ objs.push_back(*it);
+
+ if (!objs.empty()) {
+ Common::String *res = new Common::String("On the ground you see ");
+ appendObjNames(*res, objs);
+ return res;
+ }
+ return NULL;
+}
+
+void WageEngine::appendObjNames(Common::String &str, const ObjArray &objs) {
+ for (uint i = 0; i < objs.size(); i++) {
+ Obj *obj = objs[i];
+
+ if (!obj->_namePlural)
+ str += getIndefiniteArticle(obj->_name);
+ else
+ str += "some ";
+
+ str += obj->_name;
+
+ if (i == objs.size() - 1) {
+ str += ".";
+ } else if (i == objs.size() - 2) {
+ if (objs.size() > 2)
+ str += ",";
+ str += " and ";
+ } else {
+ str += ", ";
+ }
+ }
+}
+
+bool WageEngine::handleInventoryCommand() {
+ Chr *player = _world->_player;
+ ObjArray objs;
+
+ for (ObjArray::const_iterator it = player->_inventory.begin(); it != player->_inventory.end(); ++it)
+ if (!player->isWearing(*it))
+ objs.push_back(*it);
+
+ if (objs.empty()) {
+ appendText("Your pack is empty.");
+ } else {
+ Common::String res("Your pack contains ");
+ appendObjNames(res, objs);
+ appendText(res.c_str());
+ }
+
+ return true;
+}
+
+static const char *const armorMessages[] = {
+ "Head protection:",
+ "Chest protection:",
+ "Shield protection:", // TODO: check message
+ "Magical protection:"
+};
+
+bool WageEngine::handleStatusCommand() {
+ Chr *player = _world->_player;
+ char buf[512];
+
+ snprintf(buf, 512, "Character name: %s%s", player->getDefiniteArticle(false), player->_name.c_str());
+ appendText(buf);
+ snprintf(buf, 512, "Experience: %d", player->_context._experience);
+ appendText(buf);
+
+ int wealth = 0;
+ for (ObjArray::const_iterator it = player->_inventory.begin(); it != player->_inventory.end(); ++it)
+ wealth += (*it)->_value;
+
+ snprintf(buf, 512, "Wealth: %d", wealth);
+ appendText(buf);
+
+ for (int i = 0; i < Chr::NUMBER_OF_ARMOR_TYPES; i++) {
+ if (player->_armor[i] != NULL) {
+ snprintf(buf, 512, "%s %s", armorMessages[i], player->_armor[i]->_name.c_str());
+ appendText(buf);
+ }
+ }
+
+ for (ObjArray::const_iterator it = player->_inventory.begin(); it != player->_inventory.end(); ++it) {
+ int uses = (*it)->_numberOfUses;
+
+ if (uses > 0) {
+ snprintf(buf, 512, "Your %s has %d uses left.", (*it)->_name.c_str(), uses);
+ appendText(buf);
+ }
+ }
+
+ printPlayerCondition(player);
+
+ _commandWasQuick = true;
+
+ return true;
+}
+
+bool WageEngine::handleRestCommand() {
+ if (getMonster() != NULL) {
+ appendText("This is no time to rest!");
+ _commandWasQuick = true;
+ } else {
+ regen();
+ printPlayerCondition(_world->_player);
+ }
+
+ return true;
+}
+
+bool WageEngine::handleAcceptCommand() {
+ Chr *chr = _offer->_currentOwner;
+
+ char buf[512];
+ snprintf(buf, 512, "%s%s lays the %s on the ground and departs peacefully.",
+ chr->getDefiniteArticle(true), chr->_name.c_str(), _offer->_name.c_str());
+ appendText(buf);
+
+ _world->move(_offer, chr->_currentScene);
+ _world->move(chr, _world->_storageScene);
+
+ return true;
+}
+
+bool WageEngine::handleTakeCommand(const char *target) {
+ Common::String t(target);
+ bool handled = false;
+
+ for (ObjList::const_iterator it = _world->_player->_currentScene->_objs.begin(); it != _world->_player->_currentScene->_objs.end(); ++it) {
+ Common::String n((*it)->_name);
+ n.toLowercase();
+
+ if (t.contains(n)) {
+ if ((*it)->_type == Obj::IMMOBILE_OBJECT) {
+ appendText("You can't move it.");
+ } else {
+ takeObj(*it);
+ }
+
+ handled = true;
+ break;
+ }
+ }
+
+ return handled;
+}
+
+bool WageEngine::handleDropCommand(const char *target) {
+ Common::String t(target);
+ bool handled = false;
+
+ t.toLowercase();
+
+ for (ObjArray::const_iterator it = _world->_player->_inventory.begin(); it != _world->_player->_inventory.end(); ++it) {
+ Common::String n((*it)->_name);
+ n.toLowercase();
+
+ if (t.contains(n)) {
+ char buf[256];
+
+ snprintf(buf, 256, "You no longer have the %s.", (*it)->_name.c_str());
+ appendText(buf);
+ _world->move(*it, _world->_player->_currentScene);
+
+ handled = true;
+ break;
+ }
+ }
+
+ return handled;
+}
+
+bool WageEngine::handleAimCommand(const char *t) {
+ bool wasHandled = true;
+ Common::String target(t);
+
+ target.toLowercase();
+
+ if (target.contains("head")) {
+ _aim = Chr::HEAD;
+ } else if (target.contains("chest")) {
+ _aim = Chr::CHEST;
+ } else if (target.contains("side")) {
+ _aim = Chr::SIDE;
+ } else {
+ wasHandled = false;
+ appendText("Please aim for the head, chest, or side.");
+ }
+
+ _commandWasQuick = true;
+
+ return wasHandled;
+}
+
+bool WageEngine::handleWearCommand(const char *t) {
+ Chr *player = _world->_player;
+ char buf[512];
+ Common::String target(t);
+ bool handled = false;
+
+ target.toLowercase();
+
+ for (ObjArray::const_iterator it = _world->_player->_inventory.begin(); it != _world->_player->_inventory.end(); ++it) {
+ Common::String n((*it)->_name);
+
+ if (target.contains(n)) {
+ if ((*it)->_type == Obj::HELMET) {
+ wearObj(*it, Chr::HEAD_ARMOR);
+ } else if ((*it)->_type == Obj::CHEST_ARMOR) {
+ wearObj(*it, Chr::BODY_ARMOR);
+ } else if ((*it)->_type == Obj::SHIELD) {
+ wearObj(*it, Chr::SHIELD_ARMOR);
+ } else if ((*it)->_type == Obj::SPIRITUAL_ARMOR) {
+ wearObj(*it, Chr::MAGIC_ARMOR);
+ } else {
+ appendText("You cannot wear that object.");
+ }
+
+ handled = true;
+ break;
+ }
+ }
+
+ for (ObjList::const_iterator it = player->_currentScene->_objs.begin(); it != player->_currentScene->_objs.end(); ++it) {
+ Common::String n((*it)->_name);
+ n.toLowercase();
+ if (target.contains(n)) {
+ snprintf(buf, 512, "First you must get the %s.", (*it)->_name.c_str());
+ appendText(buf);
+
+ handled = true;
+ break;
+ }
+ }
+
+ return handled;
+}
+
+void WageEngine::wearObj(Obj *o, int pos) {
+ Chr *player = _world->_player;
+ char buf[512];
+
+ if (player->_armor[pos] == o) {
+ snprintf(buf, 512, "You are already wearing the %s.", o->_name.c_str());
+ appendText(buf);
+ } else {
+ if (player->_armor[pos] != NULL) {
+ snprintf(buf, 512, "You are no longer wearing the %s.", player->_armor[pos]->_name.c_str());
+ appendText(buf);
+ }
+
+ player->_armor[pos] = o;
+ snprintf(buf, 512, "You are now wearing the %s.", o->_name.c_str());
+ appendText(buf);
+ }
+}
+
+
+bool WageEngine::handleOfferCommand(const char *target) {
+ Chr *player = _world->_player;
+ Chr *enemy = getMonster();
+
+ if (enemy != NULL) {
+ Common::String t(target);
+ t.toLowercase();
+
+ for (ObjArray::const_iterator it = player->_inventory.begin(); it != player->_inventory.end(); ++it) {
+ Common::String n((*it)->_name);
+ n.toLowercase();
+
+ if (t.contains(n)) {
+ if ((*it)->_value < enemy->_rejectsOffers) {
+ appendText("Your offer is rejected.");
+ } else {
+ appendText("Your offer is accepted.");
+ appendText(enemy->_acceptsOfferComment.c_str());
+ _world->move(*it, enemy);
+ _world->move(enemy, _world->_storageScene);
+ }
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool WageEngine::tryAttack(const Obj *weapon, const Common::String &input) {
+ Common::String w(weapon->_name);
+ w.toLowercase();
+ Common::String i(input);
+ i.toLowercase();
+ Common::String v(weapon->_operativeVerb);
+ v.toLowercase();
+
+ return i.contains(w) && i.contains(v);
+}
+
+bool WageEngine::handleAttack(Obj *weapon) {
+ Chr *player = _world->_player;
+ Chr *enemy = getMonster();
+
+ if (weapon->_type == Obj::MAGICAL_OBJECT) {
+ switch (weapon->_attackType) {
+ case Obj::HEALS_PHYSICAL_AND_SPIRITUAL_DAMAGE:
+ case Obj::HEALS_PHYSICAL_DAMAGE:
+ case Obj::HEALS_SPIRITUAL_DAMAGE:
+ performMagic(player, enemy, weapon);
+ return true;
+ }
+ }
+ if (enemy != NULL)
+ performAttack(player, enemy, weapon);
+ else if (weapon->_type == Obj::MAGICAL_OBJECT)
+ appendText("There is nobody to cast a spell at.");
+ else
+ appendText("There is no one to fight.");
+
+ return true;
+}
+
+const char *WageEngine::getPercentMessage(double percent) {
+ if (percent < 0.40) {
+ return "very bad";
+ } else if (percent < 0.55) {
+ return "bad";
+ } else if (percent < 0.70) {
+ return "average";
+ } else if (percent < 0.85) {
+ return "good";
+ } else if (percent <= 1.00) {
+ return "very good";
+ } else {
+ return "enhanced";
+ }
+}
+
+void WageEngine::printPlayerCondition(Chr *player) {
+ double physicalPercent = (double)player->_context._statVariables[PHYS_HIT_CUR] / player->_context._statVariables[PHYS_HIT_BAS];
+ double spiritualPercent = (double)player->_context._statVariables[SPIR_HIT_CUR] / player->_context._statVariables[SPIR_HIT_BAS];
+ char buf[256];
+
+ snprintf(buf, 256, "Your physical condition is %s.", getPercentMessage(physicalPercent));
+ appendText(buf);
+
+ snprintf(buf, 256, "Your spiritual condition is %s.", getPercentMessage(spiritualPercent));
+ appendText(buf);
+}
+
+} // End of namespace Wage
diff --git a/engines/wage/configure.engine b/engines/wage/configure.engine
new file mode 100644
index 0000000000..6205211158
--- /dev/null
+++ b/engines/wage/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 wage "WAGE" no
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
new file mode 100644
index 0000000000..2bfea9df7d
--- /dev/null
+++ b/engines/wage/design.cpp
@@ -0,0 +1,543 @@
+/* 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/managed_surface.h"
+#include "graphics/primitives.h"
+
+#include "wage/macwindowmanager.h"
+#include "wage/design.h"
+
+namespace Wage {
+
+struct PlotData {
+ Graphics::ManagedSurface *surface;
+ Patterns *patterns;
+ uint fillType;
+ int thickness;
+ Design *design;
+
+ 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);
+void drawPixelPlain(int x, int y, int color, void *data);
+
+Design::Design(Common::SeekableReadStream *data) {
+ _len = data->readUint16BE() - 2;
+ _data = (byte *)malloc(_len);
+ data->read(_data, _len);
+
+ _surface = NULL;
+ _bounds = NULL;
+
+ _boundsCalculationMode = false;
+}
+
+Design::~Design() {
+ free(_data);
+ if (_surface)
+ _surface->free();
+ delete _surface;
+}
+
+void Design::paint(Graphics::ManagedSurface *surface, Patterns &patterns, int x, int y) {
+ bool needRender = false;
+
+ if (_surface == NULL) {
+ _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->clear(kColorGreen);
+
+ needRender = true;
+ }
+
+ _bounds->debugPrint(4, "Using bounds:");
+#if 0
+ 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);
+
+ drawThickLine(x1, y1, x2-borderThickness, y1, borderThickness, kColorBlack, drawPixel, &pd);
+ drawThickLine(x2-borderThickness, y1, x2-borderThickness, y2, borderThickness, kColorBlack, drawPixel, &pd);
+ drawThickLine(x2-borderThickness, y2-borderThickness, x1, y2-borderThickness, borderThickness, kColorBlack, drawPixel, &pd);
+ drawThickLine(x1, y2-borderThickness, x1, y1, borderThickness, kColorBlack, drawPixel, &pd);
+ drawThickLine(x2+10, y2+10, x2+100, y2+100, borderThickness, kColorBlack, drawPixel, &pd);
+
+ g_system->copyRectToScreen(_surface->getPixels(), _surface->pitch, 0, 0, _surface->w, _surface->h);
+
+ while (true) {
+ ((WageEngine *)g_engine)->processEvents();
+ g_system->updateScreen();
+ g_system->delayMillis(50);
+ }
+ 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();
+ byte borderFillType = in.readByte();
+ int type = in.readByte();
+
+ if (in.eos())
+ break;
+
+ debug(8, "fill: %d borderFill: %d border: %d type: %d", fillType, borderFillType, borderThickness, type);
+ switch (type) {
+ case 4:
+ drawRect(_surface, in, patterns, fillType, borderThickness, borderFillType);
+ break;
+ case 8:
+ drawRoundRect(_surface, in, patterns, fillType, borderThickness, borderFillType);
+ break;
+ case 12:
+ drawOval(_surface, in, patterns, fillType, borderThickness, borderFillType);
+ break;
+ case 16:
+ case 20:
+ drawPolygon(_surface, in, patterns, fillType, borderThickness, borderFillType);
+ break;
+ case 24:
+ drawBitmap(_surface, in);
+ break;
+ default:
+ warning("Unknown type => %d", type);
+ break;
+ }
+
+ //g_system->copyRectToScreen(_surface->getPixels(), _surface->pitch, 0, 0, _surface->w, _surface->h);
+ //((WageEngine *)g_engine)->processEvents();
+ //g_system->updateScreen();
+ //g_system->delayMillis(500);
+ }
+}
+
+bool Design::isPointOpaque(int x, int y) {
+ if (_surface == NULL)
+ error("Surface is null");
+
+ byte pixel = ((byte *)_surface->getBasePtr(x, y))[0];
+
+ 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;
+ 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 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::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();
+
+ if (x1 > x2)
+ SWAP(x1, x2);
+ if (y1 > y2)
+ SWAP(y1, y2);
+
+ Common::Rect r(x1, y1, x2, y2);
+ PlotData pd(surface, &patterns, fillType, 1, this);
+
+ if (fillType <= patterns.size())
+ Graphics::drawFilledRect(r, kColorBlack, drawPixel, &pd);
+
+ pd.fillType = borderFillType;
+ pd.thickness = borderThickness;
+
+ if (borderThickness > 0 && borderFillType <= patterns.size()) {
+ Graphics::drawLine(x1, y1, x2, y1, kColorBlack, drawPixel, &pd);
+ Graphics::drawLine(x2, y1, x2, y2, kColorBlack, drawPixel, &pd);
+ Graphics::drawLine(x2, y2, x1, y2, kColorBlack, drawPixel, &pd);
+ Graphics::drawLine(x1, y2, x1, y1, kColorBlack, drawPixel, &pd);
+ }
+}
+
+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();
+ int16 y2 = in.readSint16BE();
+ int16 x2 = in.readSint16BE();
+ int16 arc = in.readSint16BE();
+
+ if (x1 > x2)
+ SWAP(x1, x2);
+ if (y1 > y2)
+ SWAP(y1, y2);
+
+ Common::Rect r(x1, y1, x2, y2);
+ PlotData pd(surface, &patterns, fillType, 1, this);
+
+ if (fillType <= patterns.size())
+ 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);
+}
+
+void Design::drawPolygon(Graphics::ManagedSurface *surface, Common::ReadStream &in,
+ Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType) {
+
+ byte ignored = in.readSint16BE(); // ignored
+
+ if (ignored)
+ warning("Ignored: %d", ignored);
+
+ int numBytes = in.readSint16BE(); // #bytes used by polygon data, including the numBytes
+ int16 by1 = in.readSint16BE();
+ int16 bx1 = in.readSint16BE();
+ int16 by2 = in.readSint16BE();
+ int16 bx2 = in.readSint16BE();
+ Common::Rect bbox(bx1, by1, bx2, by2);
+
+ numBytes -= 8;
+
+ int y1 = in.readSint16BE();
+ int x1 = in.readSint16BE();
+
+ Common::Array<int> xcoords;
+ Common::Array<int> ycoords;
+
+ numBytes -= 6;
+
+ while (numBytes > 0) {
+ int y2 = y1;
+ int x2 = x1;
+ int b = in.readSByte();
+ if (b == -128) {
+ y2 = in.readSint16BE();
+ numBytes -= 3;
+ } else {
+ y2 += b;
+ numBytes -= 1;
+ }
+ b = in.readSByte();
+ if (b == -128) {
+ x2 = in.readSint16BE();
+ numBytes -= 3;
+ } else {
+ x2 += b;
+ numBytes -= 1;
+ }
+ xcoords.push_back(x1);
+ ycoords.push_back(y1);
+ x1 = x2;
+ y1 = y2;
+ }
+ xcoords.push_back(x1);
+ ycoords.push_back(y1);
+
+ int npoints = xcoords.size();
+ int *xpoints = (int *)calloc(npoints, sizeof(int));
+ int *ypoints = (int *)calloc(npoints, sizeof(int));
+ for (int i = 0; i < npoints; i++) {
+ xpoints[i] = xcoords[i];
+ ypoints[i] = ycoords[i];
+ }
+
+ PlotData pd(surface, &patterns, fillType, 1, this);
+
+ if (fillType <= patterns.size()) {
+ Graphics::drawPolygonScan(xpoints, ypoints, npoints, bbox, kColorBlack, drawPixel, &pd);
+ }
+
+ pd.fillType = borderFillType;
+ pd.thickness = borderThickness;
+ if (borderThickness > 0 && borderFillType <= patterns.size()) {
+ for (int i = 1; i < npoints; i++)
+ Graphics::drawLine(xpoints[i-1], ypoints[i-1], xpoints[i], ypoints[i], kColorBlack, drawPixel, &pd);
+ }
+
+ free(xpoints);
+ free(ypoints);
+}
+
+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, this);
+
+ if (fillType <= patterns.size())
+ Graphics::drawEllipse(x1, y1, x2-1, y2-1, kColorBlack, true, drawPixel, &pd);
+
+ pd.fillType = borderFillType;
+ pd.thickness = borderThickness;
+
+ if (borderThickness > 0 && borderFillType <= patterns.size())
+ Graphics::drawEllipse(x1, y1, x2-1, y2-1, kColorBlack, false, drawPixel, &pd);
+}
+
+void Design::drawBitmap(Graphics::ManagedSurface *surface, Common::SeekableReadStream &in) {
+ int numBytes = in.readSint16BE();
+ int y1 = in.readSint16BE();
+ int x1 = in.readSint16BE();
+ int y2 = in.readSint16BE();
+ int x2 = in.readSint16BE();
+ int w = x2 - x1;
+ int h = y2 - y1;
+ Graphics::Surface tmp;
+
+ tmp.create(w, h, Graphics::PixelFormat::createFormatCLUT8());
+
+ numBytes -= 10;
+
+ int x = 0, y = 0;
+ while (numBytes > 0 && y < h) {
+ int n = in.readSByte();
+ int count;
+ int b = 0;
+ int state = 0;
+
+ numBytes--;
+
+ if ((n >= 0) && (n <= 127)) { // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally.
+ count = n + 1;
+ state = 1;
+ } else if ((n >= -127) && (n <= -1)) { // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times.
+ b = in.readByte();
+ numBytes--;
+ count = -n + 1;
+ state = 2;
+ } else { // Else if n is -128, noop.
+ count = 0;
+ }
+
+ for (int i = 0; i < count && y < h; i++) {
+ byte color = 0;
+ if (state == 1) {
+ color = in.readByte();
+ numBytes--;
+ } else if (state == 2)
+ color = b;
+
+ for (int c = 0; c < 8; c++) {
+ 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) {
+ y++;
+ x = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ in.skip(numBytes);
+
+ 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::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::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);
+ Graphics::drawLine(x2, y2, x1, y2, kColorBlack, drawPixel, &pd);
+ Graphics::drawLine(x1, y2, x1, y1, kColorBlack, drawPixel, &pd);
+}
+
+
+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::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::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::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);
+}
+
+} // End of namespace Wage
diff --git a/engines/wage/design.h b/engines/wage/design.h
new file mode 100644
index 0000000000..86225c9224
--- /dev/null
+++ b/engines/wage/design.h
@@ -0,0 +1,105 @@
+/* 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_DESIGN_H
+#define WAGE_DESIGN_H
+
+#include "common/memstream.h"
+#include "common/rect.h"
+
+#include "wage/macwindowmanager.h"
+
+namespace Wage {
+
+class Design {
+public:
+ Design(Common::SeekableReadStream *data);
+ ~Design();
+
+ void setBounds(Common::Rect *bounds) {
+ _bounds = bounds;
+ }
+
+ Common::Rect *getBounds() {
+ return _bounds;
+ }
+
+ void paint(Graphics::ManagedSurface *canvas, Patterns &patterns, int x, int y);
+ bool isPointOpaque(int x, int y);
+ 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::ManagedSurface *_surface;
+ bool _boundsCalculationMode;
+
+private:
+ void render(Patterns &patterns);
+ void drawRect(Graphics::ManagedSurface *surface, Common::ReadStream &in,
+ Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType);
+ void drawRoundRect(Graphics::ManagedSurface *surface, Common::ReadStream &in,
+ Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType);
+ void drawPolygon(Graphics::ManagedSurface *surface, Common::ReadStream &in,
+ Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType);
+ void drawOval(Graphics::ManagedSurface *surface, Common::ReadStream &in,
+ Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType);
+ void drawBitmap(Graphics::ManagedSurface *surface, Common::SeekableReadStream &in);
+};
+
+} // End of namespace Wage
+
+#endif
diff --git a/engines/wage/detection.cpp b/engines/wage/detection.cpp
new file mode 100644
index 0000000000..8b8a6399a8
--- /dev/null
+++ b/engines/wage/detection.cpp
@@ -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.
+ *
+ */
+
+
+#include "base/plugins.h"
+
+#include "engines/advancedDetector.h"
+#include "common/system.h"
+#include "common/savefile.h"
+
+#include "wage/wage.h"
+
+namespace Wage {
+
+const char *WageEngine::getGameFile() const {
+ return _gameDescription->filesDescriptions[0].fileName;
+}
+
+}
+
+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}
+};
+
+#include "wage/detection_tables.h"
+
+class WageMetaEngine : public AdvancedMetaEngine {
+public:
+ WageMetaEngine() : AdvancedMetaEngine(Wage::gameDescriptions, sizeof(ADGameDescription), wageGames) {
+ _md5Bytes = 50000;
+ _singleId = "wage";
+ _guiOptions = GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI);
+ }
+
+ virtual const char *getName() const {
+ return "World Adventure Game Engine";
+ }
+
+ virtual const char *getOriginalCopyright() const {
+ return "World Builder (C) Silicon Beach Software";
+ }
+
+ virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
+ virtual bool hasFeature(MetaEngineFeature f) const;
+ virtual SaveStateList listSaves(const char *target) const;
+ virtual int getMaximumSaveSlot() const;
+ virtual void removeSaveState(const char *target, int slot) const;
+};
+
+bool WageMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsListSaves) ||
+ (f == kSupportsLoadingDuringStartup) ||
+ (f == kSupportsDeleteSave);
+}
+
+bool Wage::WageEngine::hasFeature(EngineFeature f) const {
+ return
+ (f == kSupportsRTL) ||
+ (f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsSavingDuringRuntime);
+}
+
+bool WageMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
+ if (desc) {
+ *engine = new Wage::WageEngine(syst, desc);
+ }
+ return desc != 0;
+}
+
+SaveStateList WageMetaEngine::listSaves(const char *target) const {
+ const uint32 WAGEflag = MKTAG('W','A','G','E');
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::StringArray filenames;
+ char saveDesc[31];
+ Common::String pattern = target;
+ pattern += ".###";
+
+ filenames = saveFileMan->listSavefiles(pattern);
+
+ SaveStateList saveList;
+ 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);
+
+ if (slotNum >= 0 && slotNum <= 999) {
+ Common::InSaveFile *in = saveFileMan->openForLoading(*file);
+ if (in) {
+ uint32 type = in->readUint32BE();
+ if (type == WAGEflag)
+ in->read(saveDesc, 31);
+ saveList.push_back(SaveStateDescriptor(slotNum, saveDesc));
+ delete in;
+ }
+ }
+ }
+
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
+ return saveList;
+}
+
+int WageMetaEngine::getMaximumSaveSlot() const { return 999; }
+
+void WageMetaEngine::removeSaveState(const char *target, int slot) const {
+ g_system->getSavefileManager()->removeSavefile(Common::String::format("%s.%03d", target, slot));
+}
+
+#if PLUGIN_ENABLED_DYNAMIC(WAGE)
+ REGISTER_PLUGIN_DYNAMIC(WAGE, PLUGIN_TYPE_ENGINE, WageMetaEngine);
+#else
+ REGISTER_PLUGIN_STATIC(WAGE, PLUGIN_TYPE_ENGINE, WageMetaEngine);
+#endif
+
+namespace Wage {
+
+bool WageEngine::canLoadGameStateCurrently() {
+ return false;
+}
+
+bool WageEngine::canSaveGameStateCurrently() {
+ return false;
+}
+
+} // End of namespace Wage
diff --git a/engines/wage/detection_tables.h b/engines/wage/detection_tables.h
new file mode 100644
index 0000000000..59d93cc12f
--- /dev/null
+++ b/engines/wage/detection_tables.h
@@ -0,0 +1,180 @@
+/* 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.
+ *
+ */
+
+namespace Wage {
+
+#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,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", "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", "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
+};
+
+} // End of namespace Wage
diff --git a/engines/wage/dialog.cpp b/engines/wage/dialog.cpp
new file mode 100644
index 0000000000..86080c9a6f
--- /dev/null
+++ b/engines/wage/dialog.cpp
@@ -0,0 +1,244 @@
+/* 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/system.h"
+#include "common/events.h"
+
+#include "wage/wage.h"
+#include "wage/macwindowmanager.h"
+#include "wage/design.h"
+#include "wage/gui.h"
+#include "wage/dialog.h"
+
+namespace Wage {
+
+enum {
+ kDialogHeight = 113
+};
+
+Dialog::Dialog(Gui *gui, int width, const char *text, DialogButtonArray *buttons, uint defaultButton) :
+ _gui(gui), _text(text), _buttons(buttons), _defaultButton(defaultButton) {
+ assert(_gui->_engine);
+ assert(_gui->_engine->_world);
+
+ _font = getDialogFont();
+
+ _tempSurface.create(width + 1, kDialogHeight + 1, Graphics::PixelFormat::createFormatCLUT8());
+
+ _bbox.left = (_gui->_screen.w - width) / 2;
+ _bbox.top = (_gui->_screen.h - kDialogHeight) / 2;
+ _bbox.right = (_gui->_screen.w + width) / 2;
+ _bbox.bottom = (_gui->_screen.h + kDialogHeight) / 2;
+
+ _pressedButton = -1;
+
+ _mouseOverPressedButton = false;
+
+ // Adjust button positions
+ for (uint i = 0; i < _buttons->size(); i++)
+ _buttons->operator[](i)->bounds.translate(_bbox.left, _bbox.top);
+
+ _needsRedraw = true;
+}
+
+Dialog::~Dialog() {
+ for (uint i = 0; i < _buttons->size(); i++)
+ delete _buttons->operator[](i);
+}
+
+const Graphics::Font *Dialog::getDialogFont() {
+ return _gui->_wm.getFont("Chicago-12", Graphics::FontManager::kBigGUIFont);
+}
+
+void Dialog::paint() {
+ 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 };
+ drawOutline(_bbox, boxOutline, ARRAYSIZE(boxOutline));
+
+ for (uint i = 0; i < _buttons->size(); i++) {
+ DialogButton *button = _buttons->operator[](i);
+ static int buttonOutline[] = { 0, 0, 0, 0, 1 };
+
+ if (i == _defaultButton) {
+ buttonOutline[0] = buttonOutline[1] = 1;
+ } else {
+ buttonOutline[0] = buttonOutline[1] = 0;
+ }
+
+ int color = kColorBlack;
+
+ if ((int)i == _pressedButton && _mouseOverPressedButton) {
+ 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->_wm.getPatterns(), kPatternSolid);
+
+ color = kColorWhite;
+ }
+ int w = _font->getStringWidth(button->text);
+ int x = button->bounds.left + (button->bounds.width() - w) / 2;
+ int y = button->bounds.top + 6;
+
+ _font->drawString(&_gui->_screen, button->text, x, y, _bbox.width(), color);
+
+ drawOutline(button->bounds, buttonOutline, ARRAYSIZE(buttonOutline));
+ }
+
+ g_system->copyRectToScreen(_gui->_screen.getBasePtr(_bbox.left, _bbox.top), _gui->_screen.pitch,
+ _bbox.left, _bbox.top, _bbox.width() + 1, _bbox.height() + 1);
+
+ _needsRedraw = false;
+}
+
+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->_wm.getPatterns(), kPatternSolid);
+}
+
+int Dialog::run() {
+ bool shouldQuit = false;
+ 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->_wm.pushArrowCursor();
+
+ while (!shouldQuit) {
+ Common::Event event;
+
+ while (_gui->_engine->_eventMan->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_QUIT:
+ _gui->_engine->_shouldQuit = true;
+ shouldQuit = true;
+ break;
+ case Common::EVENT_MOUSEMOVE:
+ mouseMove(event.mouse.x, event.mouse.y);
+ break;
+ case Common::EVENT_LBUTTONDOWN:
+ mouseClick(event.mouse.x, event.mouse.y);
+ break;
+ case Common::EVENT_LBUTTONUP:
+ shouldQuit = mouseRaise(event.mouse.x, event.mouse.y);
+ break;
+ case Common::EVENT_KEYDOWN:
+ switch (event.kbd.keycode) {
+ case Common::KEYCODE_ESCAPE:
+ _pressedButton = -1;
+ shouldQuit = true;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (_needsRedraw)
+ paint();
+
+ g_system->updateScreen();
+ g_system->delayMillis(50);
+ }
+
+ _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->_wm.popCursor();
+
+ return _pressedButton;
+}
+
+int Dialog::matchButton(int x, int y) {
+ for (uint i = 0; i < _buttons->size(); i++)
+ if (_buttons->operator[](i)->bounds.contains(x, y))
+ return i;
+
+ return -1;
+}
+
+void Dialog::mouseMove(int x, int y) {
+ if (_pressedButton != -1) {
+ int match = matchButton(x, y);
+
+ if (_mouseOverPressedButton && match != _pressedButton) {
+ _mouseOverPressedButton = false;
+ _needsRedraw = true;
+ } else if (!_mouseOverPressedButton && match == _pressedButton) {
+ _mouseOverPressedButton = true;
+ _needsRedraw = true;
+ }
+ }
+}
+
+void Dialog::mouseClick(int x, int y) {
+ int match = matchButton(x, y);
+
+ if (match != -1) {
+ _pressedButton = match;
+ _mouseOverPressedButton = true;
+
+ _needsRedraw = true;
+ }
+}
+
+int Dialog::mouseRaise(int x, int y) {
+ bool res = false;
+
+ if (_pressedButton != -1) {
+ if (matchButton(x, y) == _pressedButton)
+ res = true;
+ }
+
+ return res;
+}
+
+} // End of namespace Wage
diff --git a/engines/wage/dialog.h b/engines/wage/dialog.h
new file mode 100644
index 0000000000..ec99fc06b2
--- /dev/null
+++ b/engines/wage/dialog.h
@@ -0,0 +1,101 @@
+/* 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_DIALOG_H
+#define WAGE_DIALOG_H
+
+namespace Wage {
+
+struct DialogButton {
+ Common::String text;
+ Common::Rect bounds;
+
+ DialogButton(const char *t, int x1, int y1, int w, int h) {
+ text = t;
+ bounds.left = x1;
+ bounds.top = y1;
+ bounds.right = x1 + w - 1;
+ bounds.bottom = y1 + h - 1;
+ }
+};
+
+typedef Common::Array<DialogButton *> DialogButtonArray;
+
+class Dialog {
+public:
+ Dialog(Gui *gui, int width, const char *text, DialogButtonArray *buttons, uint defaultButton);
+ ~Dialog();
+
+ int run();
+
+private:
+ Gui *_gui;
+ Graphics::ManagedSurface _tempSurface;
+ Common::Rect _bbox;
+ Common::String _text;
+
+ const Graphics::Font *_font;
+ DialogButtonArray *_buttons;
+ int _pressedButton;
+ uint _defaultButton;
+ bool _mouseOverPressedButton;
+
+ bool _needsRedraw;
+
+private:
+ const Graphics::Font *getDialogFont();
+ void drawOutline(Common::Rect &bounds, int *spec, int speclen);
+ void paint();
+ void mouseMove(int x, int y);
+ void mouseClick(int x, int y);
+ int mouseRaise(int x, int y);
+ int matchButton(int x, int y);
+};
+
+} // End of namespace Wage
+
+#endif
diff --git a/engines/wage/entities.cpp b/engines/wage/entities.cpp
new file mode 100644
index 0000000000..43ac6c8cc7
--- /dev/null
+++ b/engines/wage/entities.cpp
@@ -0,0 +1,531 @@
+/* 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 "wage/wage.h"
+#include "wage/entities.h"
+#include "wage/design.h"
+#include "wage/script.h"
+#include "wage/world.h"
+
+#include "common/memstream.h"
+#include "graphics/managed_surface.h"
+
+namespace Wage {
+
+void Designed::setDesignBounds(Common::Rect *bounds) {
+ _designBounds = bounds;
+ _design->setBounds(bounds);
+}
+
+Designed::~Designed() {
+ delete _design;
+ delete _designBounds;
+}
+
+Context::Context() {
+ _visits = 0;
+ _kills = 0;
+ _experience = 0;
+ _frozen = false;
+
+ for (int i = 0; i < 26 * 9; i++)
+ _userVariables[i] = 0;
+
+ for (int i = 0; i < 18; i++)
+ _statVariables[i] = 0;
+}
+
+Scene::Scene() {
+ _script = NULL;
+ _design = NULL;
+ _textBounds = NULL;
+ _fontSize = 0;
+ _fontType = 0;
+
+ for (int i = 0; i < 4; i++)
+ _blocked[i] = false;
+
+ _soundFrequency = 0;
+ _soundType = 0;
+ _worldX = 0;
+ _worldY = 0;
+
+ _visited = false;
+}
+
+Scene::Scene(Common::String name, Common::SeekableReadStream *data) {
+ debug(9, "Creating scene: %s", name.c_str());
+
+ _name = name;
+ _classType = SCENE;
+ _design = new Design(data);
+
+ _script = NULL;
+ _textBounds = NULL;
+ _fontSize = 0;
+ _fontType = 0;
+
+ setDesignBounds(readRect(data));
+ _worldY = data->readSint16BE();
+ _worldX = data->readSint16BE();
+ _blocked[NORTH] = (data->readByte() != 0);
+ _blocked[SOUTH] = (data->readByte() != 0);
+ _blocked[EAST] = (data->readByte() != 0);
+ _blocked[WEST] = (data->readByte() != 0);
+ _soundFrequency = data->readSint16BE();
+ _soundType = data->readByte();
+ data->readByte(); // unknown
+ _messages[NORTH] = readPascalString(data);
+ _messages[SOUTH] = readPascalString(data);
+ _messages[EAST] = readPascalString(data);
+ _messages[WEST] = readPascalString(data);
+ _soundName = readPascalString(data);
+
+ _visited = false;
+
+ delete data;
+}
+
+Scene::~Scene() {
+ delete _script;
+ delete _textBounds;
+}
+
+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);
+
+ for (ObjList::const_iterator it = _objs.begin(); it != _objs.end(); ++it) {
+ 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);
+ }
+}
+
+// Source: Apple IIGS Technical Note #41, "Font Family Numbers"
+// http://apple2.boldt.ca/?page=til/tn.iigs.041
+static const char *const fontNames[] = {
+ "Chicago", // system font
+ "Geneva", // application font
+ "New York",
+ "Geneva",
+
+ "Monaco",
+ "Venice",
+ "London",
+ "Athens",
+
+ "San Francisco",
+ "Toronto",
+ NULL,
+ "Cairo",
+ "Los Angeles", // 12
+
+ "Zapf Dingbats",
+ "Bookman",
+ "Helvetica Narrow",
+ "Palatino",
+ NULL,
+ "Zapf Chancery",
+ NULL,
+
+ "Times", // 20
+ "Helvetica",
+ "Courier",
+ "Symbol",
+ "Taliesin", // mobile?
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, // 30
+ NULL,
+ NULL,
+ "Avant Garde",
+ "New Century Schoolbook"
+};
+
+const char *Scene::getFontName() {
+ if (_fontType >= 0 && _fontType < ARRAYSIZE(fontNames) && fontNames[_fontType] != NULL) {
+ return fontNames[_fontType];
+ }
+ 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;
+ _value = 0;
+ _attackType = 0;
+ _numberOfUses = 0;
+ _returnToRandomScene = false;
+ _type = 0;
+ _accuracy = 0;
+ _damage = 0;
+}
+
+Obj::Obj(Common::String name, Common::SeekableReadStream *data) {
+ _name = name;
+ _classType = OBJ;
+ _currentOwner = NULL;
+ _currentScene = NULL;
+
+ _index = 0;
+
+ _design = new Design(data);
+
+ setDesignBounds(readRect(data));
+
+ int16 namePlural = data->readSint16BE();
+
+ if (namePlural == 256)
+ _namePlural = true; // TODO: other flags?
+ else if (namePlural == 0)
+ _namePlural = false;
+ else
+ error("Obj <%s> had weird namePlural set (%d)", name.c_str(), namePlural);
+
+ if (data->readSint16BE() != 0)
+ error("Obj <%s> had short set", name.c_str());
+
+ if (data->readByte() != 0)
+ error("Obj <%s> had byte set", name.c_str());
+
+ _accuracy = data->readByte();
+ _value = data->readByte();
+ _type = data->readSByte();
+ _damage = data->readByte();
+ _attackType = data->readSByte();
+ _numberOfUses = data->readSint16BE();
+ int16 returnTo = data->readSint16BE();
+ if (returnTo == 256) // TODO any other possibilities?
+ _returnToRandomScene = true;
+ else if (returnTo == 0)
+ _returnToRandomScene = false;
+ else
+ error("Obj <%s> had weird returnTo set", name.c_str());
+
+ _sceneOrOwner = readPascalString(data);
+ _clickMessage = readPascalString(data);
+ _operativeVerb = readPascalString(data);
+ _failureMessage = readPascalString(data);
+ _useMessage = readPascalString(data);
+ _sound = readPascalString(data);
+
+ delete data;
+}
+
+Obj::~Obj() {
+}
+
+Chr *Obj::removeFromChr() {
+ if (_currentOwner != NULL) {
+ for (int i = (int)_currentOwner->_inventory.size() - 1; i >= 0; i--)
+ if (_currentOwner->_inventory[i] == this)
+ _currentOwner->_inventory.remove_at(i);
+
+ for (int i = 0; i < Chr::NUMBER_OF_ARMOR_TYPES; i++) {
+ if (_currentOwner->_armor[i] == this) {
+ _currentOwner->_armor[i] = NULL;
+ }
+ }
+ }
+
+ return _currentOwner;
+}
+
+Designed *Obj::removeFromCharOrScene() {
+ Designed *from = removeFromChr();
+
+ if (_currentScene != NULL) {
+ _currentScene->_objs.remove(this);
+ from = _currentScene;
+ }
+
+ return from;
+}
+
+void Obj::resetState(Chr *owner, Scene *scene) {
+ warning("STUB: Obj::resetState()");
+}
+
+Chr::Chr(Common::String name, Common::SeekableReadStream *data) {
+ _name = name;
+ _classType = CHR;
+ _design = new Design(data);
+
+ _index = 0;
+ _currentScene = NULL;
+
+ setDesignBounds(readRect(data));
+
+ _physicalStrength = data->readByte();
+ _physicalHp = data->readByte();
+ _naturalArmor = data->readByte();
+ _physicalAccuracy = data->readByte();
+
+ _spiritualStength = data->readByte();
+ _spiritialHp = data->readByte();
+ _resistanceToMagic = data->readByte();
+ _spiritualAccuracy = data->readByte();
+
+ _runningSpeed = data->readByte();
+ _rejectsOffers = data->readByte();
+ _followsOpponent = data->readByte();
+
+ data->readSByte(); // TODO: ???
+ data->readSint32BE(); // TODO: ???
+
+ _weaponDamage1 = data->readByte();
+ _weaponDamage2 = data->readByte();
+
+ data->readSByte(); // TODO: ???
+
+ if (data->readSByte() == 1)
+ _playerCharacter = true;
+ else
+ _playerCharacter = false;
+
+ _maximumCarriedObjects = data->readByte();
+ _returnTo = data->readSByte();
+
+ _winningWeapons = data->readByte();
+ _winningMagic = data->readByte();
+ _winningRun = data->readByte();
+ _winningOffer = data->readByte();
+ _losingWeapons = data->readByte();
+ _losingMagic = data->readByte();
+ _losingRun = data->readByte();
+ _losingOffer = data->readByte();
+
+ _gender = data->readSByte();
+ if (data->readSByte() == 1)
+ _nameProperNoun = true;
+ else
+ _nameProperNoun = false;
+
+ _initialScene = readPascalString(data);
+ _nativeWeapon1 = readPascalString(data);
+ _operativeVerb1 = readPascalString(data);
+ _nativeWeapon2 = readPascalString(data);
+ _operativeVerb2 = readPascalString(data);
+
+ _initialComment = readPascalString(data);
+ _scoresHitComment = readPascalString(data);
+ _receivesHitComment = readPascalString(data);
+ _makesOfferComment = readPascalString(data);
+ _rejectsOfferComment = readPascalString(data);
+ _acceptsOfferComment = readPascalString(data);
+ _dyingWords = readPascalString(data);
+
+ _initialSound = readPascalString(data);
+ _scoresHitSound = readPascalString(data);
+ _receivesHitSound = readPascalString(data);
+ _dyingSound = readPascalString(data);
+
+ _weaponSound1 = readPascalString(data);
+ _weaponSound2 = readPascalString(data);
+
+ for (int i = 0; i < NUMBER_OF_ARMOR_TYPES; i++)
+ _armor[i] = NULL;
+
+ _weapon1 = NULL;
+ _weapon2 = NULL;
+
+ // Create native weapons
+ if (!_nativeWeapon1.empty() && !_operativeVerb1.empty()) {
+ _weapon1 = new Obj;
+
+ _weapon1->_name = _nativeWeapon1;
+ _weapon1->_operativeVerb = _operativeVerb1;
+ _weapon1->_type = Obj::REGULAR_WEAPON;
+ _weapon1->_accuracy = 0;
+ _weapon1->_damage = _weaponDamage1;
+ _weapon1->_sound = _weaponSound1;
+ }
+
+ if (!_nativeWeapon2.empty() && !_operativeVerb2.empty()) {
+ _weapon2 = new Obj;
+
+ _weapon2->_name = _nativeWeapon2;
+ _weapon2->_operativeVerb = _operativeVerb2;
+ _weapon2->_type = Obj::REGULAR_WEAPON;
+ _weapon2->_accuracy = 0;
+ _weapon2->_damage = _weaponDamage2;
+ _weapon2->_sound = _weaponSound2;
+ }
+
+ delete data;
+}
+
+void Chr::resetState() {
+ _context._statVariables[PHYS_STR_BAS] = _context._statVariables[PHYS_STR_CUR] = _physicalStrength;
+ _context._statVariables[PHYS_HIT_BAS] = _context._statVariables[PHYS_HIT_CUR] = _physicalHp;
+ _context._statVariables[PHYS_ARM_BAS] = _context._statVariables[PHYS_ARM_CUR] = _naturalArmor;
+ _context._statVariables[PHYS_ACC_BAS] = _context._statVariables[PHYS_ACC_CUR] = _physicalAccuracy;
+
+ _context._statVariables[SPIR_STR_BAS] = _context._statVariables[SPIR_STR_CUR] = _spiritualStength;
+ _context._statVariables[SPIR_HIT_BAS] = _context._statVariables[SPIR_HIT_CUR] = _spiritialHp;
+ _context._statVariables[SPIR_ARM_BAS] = _context._statVariables[SPIR_ARM_CUR] = _naturalArmor;
+ _context._statVariables[SPIR_ACC_BAS] = _context._statVariables[SPIR_ACC_CUR] = _physicalAccuracy;
+
+ _context._statVariables[PHYS_SPE_BAS] = _context._statVariables[PHYS_SPE_CUR] = _runningSpeed;
+}
+
+ObjArray *Chr::getWeapons(bool includeMagic) {
+ ObjArray *list = new ObjArray;
+
+ if (_weapon1)
+ list->push_back(_weapon1);
+
+ if (_weapon2)
+ list->push_back(_weapon2);
+
+ for (uint i = 0; i < _inventory.size(); i++)
+ switch (_inventory[i]->_type) {
+ case Obj::REGULAR_WEAPON:
+ case Obj::THROW_WEAPON:
+ list->push_back(_inventory[i]);
+ break;
+ case Obj::MAGICAL_OBJECT:
+ if (includeMagic)
+ list->push_back(_inventory[i]);
+ break;
+ default:
+ break;
+ }
+
+ return list;
+}
+
+ObjArray *Chr::getMagicalObjects() {
+ ObjArray *list = new ObjArray;
+
+ for (uint i = 0; i < _inventory.size(); i++)
+ if (_inventory[i]->_type == Obj::MAGICAL_OBJECT)
+ list->push_back(_inventory[i]);
+
+ return list;
+}
+
+void Chr::wearObjs() {
+ for (uint i = 0; i < _inventory.size(); i++)
+ wearObjIfPossible(_inventory[i]);
+}
+
+int Chr::wearObjIfPossible(Obj *obj) {
+ switch (obj->_type) {
+ case Obj::HELMET:
+ if (_armor[HEAD_ARMOR] == NULL) {
+ _armor[HEAD_ARMOR] = obj;
+ return Chr::HEAD_ARMOR;
+ }
+ break;
+ case Obj::CHEST_ARMOR:
+ if (_armor[BODY_ARMOR] == NULL) {
+ _armor[BODY_ARMOR] = obj;
+ return Chr::BODY_ARMOR;
+ }
+ break;
+ case Obj::SHIELD:
+ if (_armor[SHIELD_ARMOR] == NULL) {
+ _armor[SHIELD_ARMOR] = obj;
+ return Chr::SHIELD_ARMOR;
+ }
+ break;
+ case Obj::SPIRITUAL_ARMOR:
+ if (_armor[MAGIC_ARMOR] == NULL) {
+ _armor[MAGIC_ARMOR] = obj;
+ return Chr::MAGIC_ARMOR;
+ }
+ break;
+ default:
+ return -1;
+ }
+
+ return -1;
+}
+
+const char *Chr::getDefiniteArticle(bool capitalize) {
+ if (!_nameProperNoun)
+ return capitalize ? "The " : "the ";
+
+ return "";
+}
+
+bool Chr::isWearing(Obj *obj) {
+ for (int i = 0; i < NUMBER_OF_ARMOR_TYPES; i++)
+ if (_armor[i] == obj)
+ return true;
+
+ return false;
+}
+
+} // End of namespace Wage
diff --git a/engines/wage/entities.h b/engines/wage/entities.h
new file mode 100644
index 0000000000..9e706f0d58
--- /dev/null
+++ b/engines/wage/entities.h
@@ -0,0 +1,338 @@
+/* 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_ENTITIES_H
+#define WAGE_ENTITIES_H
+
+namespace Graphics {
+ class ManagedSurface;
+}
+
+namespace Wage {
+
+class Design;
+class Script;
+
+enum StatVariable {
+/** The base physical accuracy of the player. */
+ PHYS_ACC_BAS = 0,
+/** The current physical accuracy of the player. */
+ PHYS_ACC_CUR = 1,
+/** The base physical armor of the player. */
+ PHYS_ARM_BAS = 2,
+/** The current physical armor of the player. */
+ PHYS_ARM_CUR = 3,
+/** The base physical hit points of the player. */
+ PHYS_HIT_BAS = 4,
+/** The current physical hit points of the player. */
+ PHYS_HIT_CUR = 5,
+/** The base physical speed of the player. */
+ PHYS_SPE_BAS = 6,
+/** The current physical speed of the player. */
+ PHYS_SPE_CUR = 7,
+/** The base physical strength of the player. */
+ PHYS_STR_BAS = 8,
+/** The current physical strength of the player. */
+ PHYS_STR_CUR = 9,
+/** The base spiritual accuracy of the player. */
+ SPIR_ACC_BAS = 10,
+/** The current spiritual accuracy of the player. */
+ SPIR_ACC_CUR = 11,
+/** The base spiritual armor of the player. */
+ SPIR_ARM_BAS = 12,
+/** The current spiritual armor of the player. */
+ SPIR_ARM_CUR = 13,
+/** The base spiritual hit points of the player. */
+ SPIR_HIT_BAS = 14,
+/** The current spiritual hit points of the player. */
+ SPIR_HIT_CUR = 15,
+/** The base spiritual strength of the player. */
+ SPIR_STR_BAS = 16,
+/** The current spiritual strength of the player. */
+ SPIR_STR_CUR = 17
+};
+
+class Context {
+public:
+ Context();
+
+ int16 _visits; // Number of scenes visited, including repeated visits
+ int16 _kills; // Number of characters killed
+ int16 _experience;
+ bool _frozen;
+ int16 _userVariables[26 * 9];
+ int16 _statVariables[18];
+};
+
+class Designed {
+public:
+ Designed() : _design(NULL), _designBounds(NULL), _classType(UNKNOWN) {}
+ ~Designed();
+
+ Common::String _name;
+ Design *_design;
+ Common::Rect *_designBounds;
+ OperandType _classType;
+
+ Common::Rect *getDesignBounds() {
+ return _designBounds == NULL ? NULL : new Common::Rect(*_designBounds);
+ }
+
+ void setDesignBounds(Common::Rect *bounds);
+
+ Common::String toString() { if (!this) return "<NULL>"; return _name; }
+};
+
+class Chr : public Designed {
+public:
+ enum ChrDestination {
+ RETURN_TO_STORAGE = 0,
+ RETURN_TO_RANDOM_SCENE = 1,
+ RETURN_TO_INITIAL_SCENE = 2
+ };
+
+ enum ChrPart {
+ HEAD = 0,
+ CHEST = 1,
+ SIDE = 2
+ };
+
+ enum ChrArmorType {
+ HEAD_ARMOR = 0,
+ BODY_ARMOR = 1,
+ SHIELD_ARMOR = 2,
+ MAGIC_ARMOR = 3,
+ NUMBER_OF_ARMOR_TYPES = 4
+ };
+
+ Chr(Common::String name, Common::SeekableReadStream *data);
+
+ int _index;
+ Common::String _initialScene;
+ int _gender;
+ bool _nameProperNoun;
+ bool _playerCharacter;
+ uint _maximumCarriedObjects;
+ int _returnTo;
+
+ int _physicalStrength;
+ int _physicalHp;
+ int _naturalArmor;
+ int _physicalAccuracy;
+ int _spiritualStength;
+ int _spiritialHp;
+ int _resistanceToMagic;
+ int _spiritualAccuracy;
+ int _runningSpeed;
+ uint _rejectsOffers;
+ int _followsOpponent;
+
+ Common::String _initialSound;
+ Common::String _scoresHitSound;
+ Common::String _receivesHitSound;
+ Common::String _dyingSound;
+
+ Common::String _nativeWeapon1;
+ Common::String _operativeVerb1;
+ int _weaponDamage1;
+ Common::String _weaponSound1;
+
+ Common::String _nativeWeapon2;
+ Common::String _operativeVerb2;
+ int _weaponDamage2;
+ Common::String _weaponSound2;
+
+ int _winningWeapons;
+ int _winningMagic;
+ int _winningRun;
+ int _winningOffer;
+ int _losingWeapons;
+ int _losingMagic;
+ int _losingRun;
+ int _losingOffer;
+
+ Common::String _initialComment;
+ Common::String _scoresHitComment;
+ Common::String _receivesHitComment;
+ Common::String _makesOfferComment;
+ Common::String _rejectsOfferComment;
+ Common::String _acceptsOfferComment;
+ Common::String _dyingWords;
+
+ Scene *_currentScene;
+ ObjArray _inventory;
+
+ Obj *_armor[NUMBER_OF_ARMOR_TYPES];
+
+ Context _context;
+
+ ObjArray *getWeapons(bool includeMagic);
+ ObjArray *getMagicalObjects();
+ const char *getDefiniteArticle(bool capitalize);
+
+ Obj *_weapon1;
+ Obj *_weapon2;
+
+public:
+ int wearObjIfPossible(Obj *obj);
+ void wearObjs();
+
+ void resetState();
+
+ bool isWearing(Obj *obj);
+};
+
+class Obj : public Designed {
+public:
+ Obj();
+ Obj(Common::String name, Common::SeekableReadStream *data);
+ ~Obj();
+
+ enum ObjectType {
+ REGULAR_WEAPON = 1,
+ THROW_WEAPON = 2,
+ MAGICAL_OBJECT = 3,
+ HELMET = 4,
+ SHIELD = 5,
+ CHEST_ARMOR = 6,
+ SPIRITUAL_ARMOR = 7,
+ MOBILE_OBJECT = 8,
+ IMMOBILE_OBJECT = 9
+ };
+
+ enum AttackType {
+ CAUSES_PHYSICAL_DAMAGE = 0,
+ CAUSES_SPIRITUAL_DAMAGE = 1,
+ CAUSES_PHYSICAL_AND_SPIRITUAL_DAMAGE = 2,
+ HEALS_PHYSICAL_DAMAGE = 3,
+ HEALS_SPIRITUAL_DAMAGE = 4,
+ HEALS_PHYSICAL_AND_SPIRITUAL_DAMAGE = 5,
+ FREEZES_OPPONENT = 6
+ };
+
+public:
+ int _index;
+ bool _namePlural;
+ uint _value;
+ int _attackType;
+ int _numberOfUses;
+ bool _returnToRandomScene;
+ Common::String _sceneOrOwner;
+ Common::String _clickMessage;
+ Common::String _failureMessage;
+ Common::String _useMessage;
+
+ Scene *_currentScene;
+ Chr *_currentOwner;
+
+ int _type;
+ uint _accuracy;
+ Common::String _operativeVerb;
+ int _damage;
+ Common::String _sound;
+
+public:
+ void setCurrentOwner(Chr *currentOwner) {
+ _currentOwner = currentOwner;
+ if (currentOwner != NULL)
+ _currentScene = NULL;
+ }
+
+ void setCurrentScene(Scene *currentScene) {
+ _currentScene = currentScene;
+ if (currentScene != NULL)
+ _currentOwner = NULL;
+ }
+
+ Chr *removeFromChr();
+ Designed *removeFromCharOrScene();
+
+ void resetState(Chr *owner, Scene *scene);
+};
+
+class Scene : public Designed {
+public:
+ enum SceneTypes {
+ PERIODIC = 0,
+ RANDOM = 1
+ };
+
+ Script *_script;
+ Common::String _text;
+ Common::Rect *_textBounds;
+ int _fontSize;
+ int _fontType; // 3 => Geneva, 22 => Courier, param to TextFont() function
+ bool _blocked[4];
+ Common::String _messages[4];
+ int _soundFrequency; // times a minute, max 3600
+ int _soundType;
+ Common::String _soundName;
+ int _worldX;
+ int _worldY;
+ bool _visited;
+
+ ObjList _objs;
+ ChrList _chrs;
+
+ Scene();
+ 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::ManagedSurface *screen, int x, int y);
+
+ const char *getFontName();
+};
+
+} // End of namespace Wage
+
+#endif
diff --git a/engines/wage/gui-console.cpp b/engines/wage/gui-console.cpp
new file mode 100644
index 0000000000..8b6fe43a17
--- /dev/null
+++ b/engines/wage/gui-console.cpp
@@ -0,0 +1,563 @@
+/* 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/events.h"
+#include "common/timer.h"
+#include "common/unzip.h"
+#include "graphics/cursorman.h"
+#include "graphics/fonts/bdf.h"
+#include "graphics/palette.h"
+
+#include "wage/wage.h"
+#include "wage/design.h"
+#include "wage/entities.h"
+#include "wage/macwindow.h"
+#include "wage/macmenu.h"
+#include "wage/gui.h"
+#include "wage/world.h"
+
+namespace Wage {
+
+const Graphics::Font *Gui::getConsoleFont() {
+ char fontName[128];
+ Scene *scene = _engine->_world->_player->_currentScene;
+
+ snprintf(fontName, 128, "%s-%d", scene->getFontName(), scene->_fontSize);
+
+ return _wm.getFont(fontName, Graphics::FontManager::kConsoleFont);
+}
+
+void Gui::clearOutput() {
+ _out.clear();
+ _lines.clear();
+ _consoleFullRedraw = true;
+}
+
+void Gui::appendText(const char *s) {
+ Common::String str(s);
+ _consoleDirty = true;
+
+ if (!str.contains('\n')) {
+ _out.push_back(str);
+ flowText(str);
+ return;
+ }
+
+ // Okay, we got new lines, need to split it
+ // and push substrings individually
+ Common::String tmp;
+
+ for (uint i = 0; i < str.size(); i++) {
+ if (str[i] == '\n') {
+ _out.push_back(tmp);
+ flowText(tmp);
+ tmp.clear();
+ continue;
+ }
+
+ tmp += str[i];
+ }
+
+ _out.push_back(tmp);
+ flowText(tmp);
+}
+
+enum {
+ kConWOverlap = 20,
+ kConHOverlap = 20,
+ kConWPadding = 3,
+ kConHPadding = 4,
+ kConOverscan = 3
+};
+
+void Gui::flowText(Common::String &str) {
+ Common::StringArray wrappedLines;
+ int textW = _consoleWindow->getInnerDimensions().width() - kConWPadding * 2;
+ const Graphics::Font *font = getConsoleFont();
+
+ font->wordWrapText(str, textW, wrappedLines);
+
+ if (wrappedLines.empty()) // Sometimes we have empty lines
+ _lines.push_back("");
+
+ for (Common::StringArray::const_iterator j = wrappedLines.begin(); j != wrappedLines.end(); ++j)
+ _lines.push_back(*j);
+
+ uint pos = _scrollPos;
+ _scrollPos = MAX<int>(0, (_lines.size() - 1 - _consoleNumLines) * _consoleLineHeight);
+
+ _cursorX = kConWPadding;
+
+ if (_scrollPos)
+ _cursorY = (_consoleNumLines) * _consoleLineHeight + kConHPadding;
+ else
+ _cursorY = (_lines.size() - 1) * _consoleLineHeight + kConHPadding;
+
+ if (pos != _scrollPos)
+ _consoleFullRedraw = true;
+
+ if (!_engine->_temporarilyHidden)
+ draw();
+}
+
+void Gui::renderConsole(Graphics::ManagedSurface *g, const Common::Rect &r) {
+ bool fullRedraw = _consoleFullRedraw;
+ bool textReflow = false;
+ int surfW = r.width() + kConWOverlap * 2;
+ int surfH = r.height() + kConHOverlap * 2;
+
+ Common::Rect boundsR(kConWOverlap - kConOverscan, kConHOverlap - kConOverscan,
+ r.width() + kConWOverlap + kConOverscan, r.height() + kConHOverlap + kConOverscan);
+
+ if (_console.w != surfW || _console.h != surfH) {
+ if (_console.w != surfW)
+ textReflow = true;
+
+ _console.free();
+
+ _console.create(surfW, surfH, Graphics::PixelFormat::createFormatCLUT8());
+ fullRedraw = true;
+ }
+
+ if (fullRedraw)
+ _console.clear(kColorWhite);
+
+ const Graphics::Font *font = getConsoleFont();
+
+ _consoleLineHeight = font->getFontHeight();
+ int textW = r.width() - kConWPadding * 2;
+ int textH = r.height() - kConHPadding * 2;
+
+ if (textReflow) {
+ _lines.clear();
+
+ for (uint i = 0; i < _out.size(); i++)
+ flowText(_out[i]);
+ }
+
+ const int firstLine = _scrollPos / _consoleLineHeight;
+ const int lastLine = MIN((_scrollPos + textH) / _consoleLineHeight + 1, _lines.size());
+ const int xOff = kConWOverlap;
+ const int yOff = kConHOverlap;
+ int x1 = xOff + kConWPadding;
+ int y1 = yOff - (_scrollPos % _consoleLineHeight) + kConHPadding;
+
+ if (fullRedraw)
+ _consoleNumLines = (r.height() - 2 * kConWPadding) / _consoleLineHeight - 2;
+
+ for (int line = firstLine; line < lastLine; line++) {
+ const char *str = _lines[line].c_str();
+ int color = kColorBlack;
+
+ if ((line > _selectionStartY && line < _selectionEndY) ||
+ (line > _selectionEndY && line < _selectionStartY)) {
+ color = kColorWhite;
+ Common::Rect trect(0, y1, _console.w, y1 + _consoleLineHeight);
+
+ Design::drawFilledRect(&_console, trect, kColorBlack, _wm.getPatterns(), kPatternSolid);
+ }
+
+ if (line == _selectionStartY || line == _selectionEndY) {
+ if (_selectionStartY != _selectionEndY) {
+ int color1 = kColorBlack;
+ int color2 = kColorWhite;
+ int midpoint = _selectionStartX;
+
+ if (_selectionStartY > _selectionEndY)
+ SWAP(color1, color2);
+
+ if (line == _selectionEndY) {
+ SWAP(color1, color2);
+ midpoint = _selectionEndX;
+ }
+
+ Common::String beg(_lines[line].c_str(), &_lines[line].c_str()[midpoint]);
+ Common::String end(&_lines[line].c_str()[midpoint]);
+
+ int rectW = font->getStringWidth(beg) + kConWPadding + kConWOverlap;
+ Common::Rect trect(0, y1, _console.w, y1 + _consoleLineHeight);
+ if (color1 == kColorWhite)
+ trect.right = rectW;
+ else
+ trect.left = rectW;
+
+ 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);
+ } else {
+ int startPos = _selectionStartX;
+ int endPos = _selectionEndX;
+
+ if (startPos > endPos)
+ SWAP(startPos, endPos);
+
+ Common::String beg(_lines[line].c_str(), &_lines[line].c_str()[startPos]);
+ Common::String mid(&_lines[line].c_str()[startPos], &_lines[line].c_str()[endPos]);
+ Common::String end(&_lines[line].c_str()[endPos]);
+
+ int rectW1 = font->getStringWidth(beg) + kConWPadding + kConWOverlap;
+ int rectW2 = rectW1 + font->getStringWidth(mid);
+ Common::Rect trect(rectW1, y1, rectW2, y1 + _consoleLineHeight);
+
+ 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);
+ font->drawString(&_console, end, x1 + rectW2 - kConWPadding - kConWOverlap, y1, textW, kColorBlack);
+ }
+ } else {
+ if (*str)
+ font->drawString(&_console, _lines[line], x1, y1, textW, color);
+ }
+
+ y1 += _consoleLineHeight;
+ }
+
+ // Now we need to clip it to the screen
+ int xcon = r.left - kConOverscan;
+ int ycon = r.top - kConOverscan;
+ if (xcon < 0) {
+ boundsR.left -= xcon;
+ xcon = 0;
+ }
+ if (ycon < 0) {
+ boundsR.top -= ycon;
+ ycon = 0;
+ }
+ if (xcon + boundsR.width() >= g->w)
+ boundsR.right -= xcon + boundsR.width() - g->w;
+ if (ycon + boundsR.height() >= g->h)
+ boundsR.bottom -= ycon + boundsR.height() - g->h;
+
+ Common::Rect rr(r);
+ if (rr.right > _screen.w - 1)
+ rr.right = _screen.w - 1;
+ if (rr.bottom > _screen.h - 1)
+ rr.bottom = _screen.h - 1;
+
+ g->copyRectToSurface(_console, xcon, ycon, boundsR);
+}
+
+void Gui::drawInput() {
+ if (!_screen.getPixels())
+ return;
+
+ _wm.setActive(_consoleWindow->getId());
+
+ _out.pop_back();
+ _lines.pop_back();
+ appendText(_engine->_inputText.c_str());
+ _inputTextLineNum = _out.size() - 1;
+
+ const Graphics::Font *font = getConsoleFont();
+
+ if (_engine->_inputText.contains('\n')) {
+ _consoleDirty = true;
+ } else {
+ int x = kConWPadding + _consoleWindow->getInnerDimensions().left;
+ int y = _cursorY + _consoleWindow->getInnerDimensions().top;
+
+ 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, _consoleWindow->getInnerDimensions().width(), font->getFontHeight());
+ }
+
+ _cursorX = font->getStringWidth(_out[_inputTextLineNum]) + kConHPadding;
+}
+
+void Gui::actionCopy() {
+ if (_selectionStartX == -1)
+ return;
+
+ int startX = _selectionStartX;
+ int startY = _selectionStartY;
+ int endX = _selectionEndX;
+ int endY = _selectionEndY;
+
+ if (startY > endY) {
+ SWAP(startX, endX);
+ SWAP(endX, endY);
+ }
+
+ _clipboard.clear();
+
+ for (int i = startY; i <= endY; i++) {
+ if (startY == endY) {
+ _clipboard = Common::String(&_lines[i].c_str()[startX], &_lines[i].c_str()[endX]);
+ break;
+ }
+
+ if (i == startY) {
+ _clipboard += &_lines[i].c_str()[startX];
+ _clipboard += '\n';
+ } else if (i == endY) {
+ _clipboard += Common::String(_lines[i].c_str(), &_lines[i].c_str()[endX]);
+ } else {
+ _clipboard += _lines[i];
+ _clipboard += '\n';
+ }
+ }
+
+ _menu->enableCommand(kMenuEdit, kMenuActionPaste, true);
+}
+
+void Gui::actionPaste() {
+ _undobuffer = _engine->_inputText;
+ _engine->_inputText += _clipboard;
+ drawInput();
+ _engine->_inputText = _out.back(); // Set last part of the multiline text
+
+ _menu->enableCommand(kMenuEdit, kMenuActionUndo, true);
+}
+
+void Gui::actionUndo() {
+ _engine->_inputText = _undobuffer;
+ drawInput();
+
+ _menu->enableCommand(kMenuEdit, kMenuActionUndo, false);
+}
+
+void Gui::actionClear() {
+ int startPos = _selectionStartX;
+ int endPos = _selectionEndX;
+
+ if (startPos > endPos)
+ SWAP(startPos, endPos);
+
+ Common::String beg(_lines[_selectionStartY].c_str(), &_lines[_selectionStartY].c_str()[startPos]);
+ Common::String end(&_lines[_selectionStartY].c_str()[endPos]);
+
+ _undobuffer = _engine->_inputText;
+ _engine->_inputText = beg + end;
+ drawInput();
+
+ _menu->enableCommand(kMenuEdit, kMenuActionUndo, true);
+
+ _selectionStartY = -1;
+ _selectionEndY = -1;
+}
+
+void Gui::actionCut() {
+ int startPos = _selectionStartX;
+ int endPos = _selectionEndX;
+
+ if (startPos > endPos)
+ SWAP(startPos, endPos);
+
+ Common::String beg(_lines[_selectionStartY].c_str(), &_lines[_selectionStartY].c_str()[startPos]);
+ Common::String mid(&_lines[_selectionStartY].c_str()[startPos], &_lines[_selectionStartY].c_str()[endPos]);
+ Common::String end(&_lines[_selectionStartY].c_str()[endPos]);
+
+ _undobuffer = _engine->_inputText;
+ _engine->_inputText = beg + end;
+ _clipboard = mid;
+ drawInput();
+
+ _menu->enableCommand(kMenuEdit, kMenuActionUndo, true);
+ _menu->enableCommand(kMenuEdit, kMenuActionPaste, true);
+
+ _selectionStartY = -1;
+ _selectionEndY = -1;
+}
+
+void Gui::disableUndo() {
+ _menu->enableCommand(kMenuEdit, kMenuActionUndo, false);
+}
+
+void Gui::disableAllMenus() {
+ _menu->disableAllMenus();
+}
+
+void Gui::enableNewGameMenus() {
+ _menu->enableCommand(kMenuFile, kMenuActionNew, true);
+ _menu->enableCommand(kMenuFile, kMenuActionOpen, true);
+ _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
new file mode 100644
index 0000000000..099279158f
--- /dev/null
+++ b/engines/wage/gui.cpp
@@ -0,0 +1,359 @@
+/* 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/timer.h"
+#include "common/system.h"
+#include "graphics/cursorman.h"
+#include "graphics/primitives.h"
+
+#include "wage/wage.h"
+#include "wage/design.h"
+#include "wage/entities.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 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;
+
+ int x = gui->_cursorX;
+ int y = gui->_cursorY;
+
+ if (x == 0 && y == 0)
+ return;
+
+ if (!gui->_screen.getPixels())
+ return;
+
+ x += gui->_consoleWindow->getInnerDimensions().left;
+ y += gui->_consoleWindow->getInnerDimensions().top;
+
+ gui->_screen.vLine(x, y, y + kCursorHeight, gui->_cursorState ? kColorBlack : kColorWhite);
+
+ if (!gui->_cursorOff)
+ gui->_cursorState = !gui->_cursorState;
+
+ gui->_cursorRect.left = x;
+ gui->_cursorRect.right = MIN<uint16>(x + 1, gui->_screen.w);
+ gui->_cursorRect.top = y;
+ gui->_cursorRect.bottom = MIN<uint16>(y + kCursorHeight, gui->_screen.h);
+
+ 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;
+ _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
+
+ _cursorX = 0;
+ _cursorY = 0;
+ _cursorState = false;
+ _cursorOff = false;
+
+ _inTextSelection = false;
+ _selectionStartX = _selectionStartY = -1;
+ _selectionEndX = _selectionEndY = -1;
+
+ _inputTextLineNum = 0;
+
+ g_system->getTimerManager()->installTimerProc(&cursorTimerHandler, 200000, this, "wageCursor");
+
+ _menu = _wm.addMenu();
+
+ _menu->setCommandsCallback(menuCommandsCallback, this);
+
+ _menu->addStaticMenus(menuSubItems);
+ _menu->addMenuSubItem(kMenuAbout, _engine->_world->getAboutMenuItemName(), kMenuActionAbout);
+
+ _commandsMenuId = _menu->addMenuItem(_engine->_world->_commandsMenuName.c_str());
+ regenCommandsMenu();
+
+ if (!_engine->_world->_weaponMenuDisabled) {
+ _weaponsMenuId = _menu->addMenuItem(_engine->_world->_weaponsMenuName.c_str());
+
+ regenWeaponsMenu();
+ } else {
+ _weaponsMenuId = -1;
+ }
+
+ _menu->calcDimensions();
+
+ _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);
+}
+
+void Gui::undrawCursor() {
+ _cursorOff = true;
+ _cursorState = false;
+ cursorTimerHandler(this);
+ _cursorOff = false;
+}
+
+void Gui::draw() {
+ if (_engine->_isGameOver) {
+ _wm.draw();
+
+ return;
+ }
+
+ if (!_engine->_world->_player->_currentScene)
+ return;
+
+ if (_scene != _engine->_world->_player->_currentScene) {
+ _sceneDirty = true;
+
+ _scene = _engine->_world->_player->_currentScene;
+
+ _sceneWindow->setDimensions(*_scene->_designBounds);
+ _sceneWindow->setTitle(_scene->_name);
+ _consoleWindow->setDimensions(*_scene->_textBounds);
+
+ _wm.setFullRefresh(true);
+ }
+
+ drawScene();
+ drawConsole();
+
+ _wm.draw();
+
+ 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());
+
+ _cursorDirty = false;
+ }
+
+ _sceneDirty = false;
+ _consoleDirty = false;
+ _consoleFullRedraw = false;
+}
+
+void Gui::drawScene() {
+ if (!_sceneDirty)
+ return;
+
+ _scene->paint(_sceneWindow->getSurface(), 0, 0);
+ _sceneWindow->setDirty(true);
+
+ _sceneDirty = true;
+ _consoleDirty = true;
+ _menu->setDirty(true);
+ _consoleFullRedraw = true;
+}
+
+static bool sceneWindowCallback(WindowClick click, Common::Event &event, void *g) {
+ Gui *gui = (Gui *)g;
+
+ return gui->processSceneEvents(click, event);
+}
+
+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);
+
+ if (obj != nullptr)
+ _engine->processTurn(NULL, obj);
+
+ return true;
+ }
+
+ return false;
+}
+
+// Render console
+void Gui::drawConsole() {
+ if (!_consoleDirty && !_consoleFullRedraw && !_sceneDirty)
+ return;
+
+ renderConsole(_consoleWindow->getSurface(), Common::Rect(kBorderWidth - 2, kBorderWidth - 2,
+ _consoleWindow->getDimensions().width(), _consoleWindow->getDimensions().height()));
+ _consoleWindow->setDirty(true);
+}
+
+static bool consoleWindowCallback(WindowClick click, Common::Event &event, void *g) {
+ Gui *gui = (Gui *)g;
+
+ return gui->processConsoleEvents(click, event);
+}
+
+////////////////
+// Menu stuff
+////////////////
+void Gui::regenCommandsMenu() {
+ _menu->createSubMenuFromString(_commandsMenuId, _engine->_world->_commandsMenu.c_str());
+}
+
+void Gui::regenWeaponsMenu() {
+ if (_engine->_world->_weaponMenuDisabled)
+ return;
+
+ _menu->clearSubMenu(_weaponsMenuId);
+
+ Chr *player = _engine->_world->_player;
+ ObjArray *weapons = player->getWeapons(true);
+
+ bool empty = 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->addMenuSubItem(_weaponsMenuId, command.c_str(), kMenuActionCommand, 0, 0, true);
+
+ empty = false;
+ }
+ }
+ delete weapons;
+
+ if (empty)
+ _menu->addMenuSubItem(_weaponsMenuId, "You have no weapons", 0, 0, 0, false);
+}
+
+bool Gui::processEvent(Common::Event &event) {
+ return _wm.processEvent(event);
+}
+
+void menuCommandsCallback(int action, Common::String &text, void *data) {
+ Gui *g = (Gui *)data;
+
+ g->executeMenuCommand(action, text);
+}
+
+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;
+
+ case kMenuActionCommand:
+ _engine->processTurn(&text, NULL);
+ break;
+
+ default:
+ warning("Unknown action: %d", action);
+
+ }
+}
+
+} // End of namespace Wage
diff --git a/engines/wage/gui.h b/engines/wage/gui.h
new file mode 100644
index 0000000000..ba1bb5ef3b
--- /dev/null
+++ b/engines/wage/gui.h
@@ -0,0 +1,158 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * 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_GUI_H
+#define WAGE_GUI_H
+
+#include "common/str-array.h"
+#include "graphics/font.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;
+class Scene;
+class WageEngine;
+
+enum {
+ kCursorHeight = 12
+};
+
+class Gui {
+public:
+ Gui(WageEngine *engine);
+ ~Gui();
+
+ void draw();
+ void appendText(const char *str);
+ void clearOutput();
+ bool processEvent(Common::Event &event);
+
+ void drawInput();
+ void setSceneDirty() { _sceneDirty = true; }
+ void regenCommandsMenu();
+ void regenWeaponsMenu();
+
+ void actionCopy();
+ void actionPaste();
+ void actionUndo();
+ void actionClear();
+ void actionCut();
+ void disableUndo();
+ 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 renderConsole(Graphics::ManagedSurface *g, const Common::Rect &r);
+ void flowText(Common::String &str);
+ const Graphics::Font *getConsoleFont();
+ const Graphics::Font *getTitleFont();
+ void startMarking(int x, int y);
+ int calcTextX(int x, int textLine);
+ int calcTextY(int y);
+ void updateTextSelection(int x, int y);
+
+public:
+ Graphics::ManagedSurface _screen;
+ int _cursorX, _cursorY;
+ bool _cursorState;
+
+ WageEngine *_engine;
+
+ bool _cursorDirty;
+ Common::Rect _cursorRect;
+ bool _cursorOff;
+
+ Scene *_scene;
+
+ MacWindowManager _wm;
+ MacWindow *_sceneWindow;
+ MacWindow *_consoleWindow;
+
+private:
+ Graphics::ManagedSurface _console;
+ Menu *_menu;
+ bool _sceneDirty;
+ bool _consoleDirty;
+
+ Common::StringArray _out;
+ Common::StringArray _lines;
+ uint _scrollPos;
+ int _consoleLineHeight;
+ uint _consoleNumLines;
+ bool _consoleFullRedraw;
+
+ bool _inTextSelection;
+ int _selectionStartX;
+ int _selectionStartY;
+ int _selectionEndX;
+ int _selectionEndY;
+
+ Common::String _clipboard;
+ Common::String _undobuffer;
+
+ int _inputTextLineNum;
+
+ int _commandsMenuId;
+ int _weaponsMenuId;
+};
+
+} // End of namespace Wage
+
+#endif
diff --git a/engines/wage/macmenu.cpp b/engines/wage/macmenu.cpp
new file mode 100644
index 0000000000..ed5f5070ff
--- /dev/null
+++ b/engines/wage/macmenu.cpp
@@ -0,0 +1,563 @@
+/* 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/system.h"
+#include "common/keyboard.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;
+ int style;
+ char shortcut;
+ bool enabled;
+ Common::Rect bbox;
+
+ MenuSubItem(const char *t, int a, int s = 0, char sh = 0, bool e = true) : text(t), action(a), style(s), shortcut(sh), enabled(e) {}
+};
+
+typedef Common::Array<MenuSubItem *> SubItemArray;
+
+struct MenuItem {
+ Common::String name;
+ SubItemArray subitems;
+ Common::Rect bbox;
+ Common::Rect subbbox;
+
+ MenuItem(const char *n) : name(n) {}
+};
+
+Menu::Menu(int id, const Common::Rect &bounds, MacWindowManager *wm)
+ : BaseMacWindow(id, false, wm) {
+ _font = getMenuFont();
+
+ _screen.create(bounds.width(), bounds.height(), Graphics::PixelFormat::createFormatCLUT8());
+
+ _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];
+ }
+}
+
+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);
+
+ for (int i = 0; data[i].menunum; i++) {
+ const MenuData *m = &data[i];
+
+ if (m->menunum == kMenuHighLevel) {
+ MenuItem *item = new MenuItem(m->title);
+ _items.push_back(item);
+
+ continue;
+ }
+
+ _items[m->menunum]->subitems.push_back(new MenuSubItem(m->title, m->action, 0, m->shortcut, m->enabled));
+ }
+}
+
+int Menu::addMenuItem(const char *name) {
+ MenuItem *i = new MenuItem(name);
+ _items.push_back(i);
+
+ return _items.size() - 1;
+}
+
+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;
+
+ for (uint i = 0; i < _items.size(); i++) {
+ int w = _font->getStringWidth(_items[i]->name);
+
+ if (_items[i]->bbox.bottom == 0) {
+ _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() + (_wm->hasBuiltInFonts() ? 3 : 2);
+ }
+
+ calcMenuBounds(_items[i]);
+
+ x += w + kMenuSpacing;
+ }
+}
+
+void Menu::clearSubMenu(int id) {
+ MenuItem *menu = _items[id];
+
+ for (uint j = 0; j < menu->subitems.size(); j++)
+ delete menu->subitems[j];
+
+ menu->subitems.clear();
+}
+
+void Menu::createSubMenuFromString(int id, const char *str) {
+ clearSubMenu(id);
+
+ MenuItem *menu = _items[id];
+ Common::String string(str);
+
+ Common::String item;
+
+ for (uint i = 0; i < string.size(); i++) {
+ while(i < string.size() && string[i] != ';') // Read token
+ item += string[i++];
+
+ if (item == "(-") {
+ menu->subitems.push_back(new MenuSubItem(NULL, 0));
+ } else {
+ bool enabled = true;
+ int style = 0;
+ char shortcut = 0;
+ const char *shortPtr = strrchr(item.c_str(), '/');
+ if (shortPtr != NULL) {
+ if (strlen(shortPtr) >= 2) {
+ shortcut = shortPtr[1];
+ 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());
+ }
+ }
+
+ while (item.size() >= 2 && item[item.size() - 2] == '<') {
+ char c = item.lastChar();
+ if (c == 'B') {
+ style |= kFontStyleBold;
+ } else if (c == 'I') {
+ style |= kFontStyleItalic;
+ } else if (c == 'U') {
+ style |= kFontStyleUnderline;
+ } else if (c == 'O') {
+ style |= kFontStyleOutline;
+ } else if (c == 'S') {
+ style |= kFontStyleShadow;
+ } else if (c == 'C') {
+ style |= kFontStyleCondensed;
+ } else if (c == 'E') {
+ style |= kFontStyleExtended;
+ }
+ item.deleteLastChar();
+ item.deleteLastChar();
+ }
+
+ Common::String tmpitem(item);
+ tmpitem.trim();
+ if (tmpitem[0] == '(') {
+ enabled = false;
+
+ for (uint j = 0; j < item.size(); j++)
+ if (item[j] == '(') {
+ item.deleteChar(j);
+ break;
+ }
+ }
+
+ menu->subitems.push_back(new MenuSubItem(item.c_str(), kMenuActionCommand, style, shortcut, enabled));
+ }
+
+ item.clear();
+ }
+
+ calcMenuBounds(menu);
+}
+
+const Graphics::Font *Menu::getMenuFont() {
+ return _wm->getFont("Chicago-12", Graphics::FontManager::kBigGUIFont);
+}
+
+const char *Menu::getAcceleratorString(MenuSubItem *item, const char *prefix) {
+ static char res[20];
+ *res = 0;
+
+ if (item->shortcut != 0)
+ sprintf(res, "%s%c%c", prefix, (_wm->hasBuiltInFonts() ? '^' : '\x11'), item->shortcut);
+
+ return res;
+}
+
+int Menu::calculateMenuWidth(MenuItem *menu) {
+ int maxWidth = 0;
+ for (uint i = 0; i < menu->subitems.size(); i++) {
+ MenuSubItem *item = menu->subitems[i];
+ if (!item->text.empty()) {
+ Common::String text(item->text);
+ Common::String acceleratorText(getAcceleratorString(item, " "));
+ if (!acceleratorText.empty()) {
+ text += acceleratorText;
+ }
+
+ int width = _font->getStringWidth(text);
+ if (width > maxWidth) {
+ maxWidth = width;
+ }
+ }
+ }
+ return maxWidth;
+}
+
+void Menu::calcMenuBounds(MenuItem *menu) {
+ // TODO: cache maxWidth
+ int maxWidth = calculateMenuWidth(menu);
+ int x1 = menu->bbox.left - 1;
+ int y1 = menu->bbox.bottom + 1;
+ int x2 = x1 + maxWidth + kMenuDropdownPadding * 2 - 4;
+ int y2 = y1 + menu->subitems.size() * kMenuDropdownItemHeight + 2;
+
+ menu->subbbox.left = x1;
+ menu->subbbox.top = y1;
+ menu->subbbox.right = x2;
+ menu->subbbox.bottom = y2;
+}
+
+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);
+
+ if (!_contentIsDirty && !forceRedraw)
+ return false;
+
+ _contentIsDirty = false;
+
+ _screen.clear(kColorGreen);
+
+ drawFilledRoundRect(&_screen, r, kDesktopArc, kColorWhite);
+ r.top = 7;
+ _screen.fillRect(r, kColorWhite);
+ r.top = kMenuHeight - 1;
+ r.bottom++;
+ _screen.fillRect(r, kColorGreen);
+ r.bottom--;
+ _screen.fillRect(r, kColorBlack);
+
+ for (uint i = 0; i < _items.size(); i++) {
+ int color = kColorBlack;
+ MenuItem *it = _items[i];
+
+ if ((uint)_activeItem == i) {
+ Common::Rect hbox = it->bbox;
+
+ hbox.left -= 1;
+ hbox.right += 3;
+ hbox.bottom += 1;
+
+ _screen.fillRect(hbox, kColorBlack);
+ color = kColorWhite;
+
+ if (!it->subitems.empty())
+ renderSubmenu(it);
+ }
+
+ _font->drawString(&_screen, it->name, it->bbox.left + kMenuLeftMargin, it->bbox.top + (_wm->hasBuiltInFonts() ? 2 : 1), it->bbox.width(), color);
+ }
+
+ g->transBlitFrom(_screen, kColorGreen);
+
+ g_system->copyRectToScreen(g->getPixels(), g->pitch, 0, 0, g->w, g->h);
+
+ return true;
+}
+
+void Menu::renderSubmenu(MenuItem *menu) {
+ Common::Rect *r = &menu->subbbox;
+
+ if (r->width() == 0 || r->height() == 0)
+ return;
+
+ _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;
+ for (uint i = 0; i < menu->subitems.size(); i++) {
+ Common::String text(menu->subitems[i]->text);
+ Common::String acceleratorText(getAcceleratorString(menu->subitems[i], ""));
+ int accelX = r->right - 25;
+
+ int color = kColorBlack;
+ if (i == (uint)_activeSubItem && !text.empty() && menu->subitems[i]->enabled) {
+ color = kColorWhite;
+ Common::Rect trect(r->left, y - (_wm->hasBuiltInFonts() ? 1 : 0), r->right, y + _font->getFontHeight());
+
+ _screen.fillRect(trect, kColorBlack);
+ }
+
+ if (!text.empty()) {
+ Graphics::ManagedSurface *s = &_screen;
+ int tx = x, ty = y;
+
+ if (!menu->subitems[i]->enabled) {
+ s = &_tempSurface;
+ tx = 0;
+ ty = 0;
+ accelX -= x;
+
+ _tempSurface.clear(kColorGreen);
+ }
+
+ _font->drawString(s, text, tx, ty, r->width(), color);
+
+ if (!acceleratorText.empty())
+ _font->drawString(s, acceleratorText, accelX, ty, r->width(), color);
+
+ if (!menu->subitems[i]->enabled) {
+ // I am lazy to extend drawString() with plotProc as a parameter, so
+ // fake it here
+ for (int ii = 0; ii < _tempSurface.h; ii++) {
+ const byte *src = (const byte *)_tempSurface.getBasePtr(0, ii);
+ 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;
+ src++;
+ dst++;
+ }
+ }
+ }
+ } else { // Delimiter
+ 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;
+ }
+
+ _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)) {
+ for (uint i = 0; i < _items.size(); i++)
+ if (_items[i]->bbox.contains(x, y)) {
+ if ((uint)_activeItem == i)
+ return false;
+
+ if (_activeItem != -1) { // Restore background
+ Common::Rect r(_items[_activeItem]->subbbox);
+ r.right += 3;
+ r.bottom += 3;
+
+ _wm->setFullRefresh(true);
+ }
+
+ _activeItem = i;
+ _activeSubItem = -1;
+ _menuActivated = true;
+
+ _contentIsDirty = true;
+
+ return true;
+ }
+ } else if (_menuActivated && _items[_activeItem]->subbbox.contains(x, y)) {
+ MenuItem *it = _items[_activeItem];
+ int numSubItem = (y - it->subbbox.top) / kMenuDropdownItemHeight;
+
+ if (numSubItem != _activeSubItem) {
+ _activeSubItem = numSubItem;
+
+ renderSubmenu(_items[_activeItem]);
+ _contentIsDirty = true;
+ }
+ } else if (_menuActivated && _activeItem != -1) {
+ _activeSubItem = -1;
+
+ renderSubmenu(_items[_activeItem]);
+ _contentIsDirty = true;
+ }
+
+ return false;
+}
+
+bool Menu::mouseMove(int x, int y) {
+ if (_menuActivated)
+ if (mouseClick(x, y))
+ return true;
+
+ return false;
+}
+
+bool Menu::mouseRelease(int x, int y) {
+ if (_menuActivated) {
+ _menuActivated = false;
+
+ if (_activeItem != -1 && _activeSubItem != -1 && _items[_activeItem]->subitems[_activeSubItem]->enabled)
+ (*_ccallback)(_items[_activeItem]->subitems[_activeSubItem]->action,
+ _items[_activeItem]->subitems[_activeSubItem]->text, _cdata);
+
+ _activeItem = -1;
+ _activeSubItem = -1;
+
+ _wm->setFullRefresh(true);
+
+ return true;
+ }
+
+ return false;
+}
+
+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) {
+ (*_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/macmenu.h b/engines/wage/macmenu.h
new file mode 100644
index 0000000000..e73e4c48a9
--- /dev/null
+++ b/engines/wage/macmenu.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_MACMENU_H
+#define WAGE_MACMENU_H
+
+namespace Wage {
+
+struct MenuItem;
+struct MenuSubItem;
+
+enum {
+ kFontStyleBold = 1,
+ kFontStyleItalic = 2,
+ kFontStyleUnderline = 4,
+ kFontStyleOutline = 8,
+ kFontStyleShadow = 16,
+ kFontStyleCondensed = 32,
+ kFontStyleExtended = 64
+};
+
+enum {
+ kMenuHighLevel = -1,
+ kMenuAbout = 0,
+ kMenuFile = 1,
+ kMenuEdit = 2,
+ kMenuCommands = 3,
+ kMenuWeapons = 4
+};
+
+enum {
+ kMenuActionAbout,
+ kMenuActionNew,
+ kMenuActionOpen,
+ kMenuActionClose,
+ kMenuActionSave,
+ kMenuActionSaveAs,
+ kMenuActionRevert,
+ kMenuActionQuit,
+
+ kMenuActionUndo,
+ kMenuActionCut,
+ kMenuActionCopy,
+ kMenuActionPaste,
+ kMenuActionClear,
+
+ kMenuActionCommand
+};
+
+struct MenuData {
+ int menunum;
+ const char *title;
+ int action;
+ byte shortcut;
+ bool enabled;
+};
+
+class Menu : public BaseMacWindow {
+public:
+ Menu(int id, const Common::Rect &bounds, MacWindowManager *wm);
+ ~Menu();
+
+ 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 enableCommand(int menunum, int action, bool state);
+ void disableAllMenus();
+
+ void setActive(bool active) { _menuActivated = active; }
+ bool hasAllFocus() { return _menuActivated; }
+
+ Common::Rect _bbox;
+
+private:
+ Graphics::ManagedSurface _screen;
+ Graphics::ManagedSurface _tempSurface;
+
+private:
+ const Graphics::Font *getMenuFont();
+ const char *getAcceleratorString(MenuSubItem *item, const char *prefix);
+ int calculateMenuWidth(MenuItem *menu);
+ void calcMenuBounds(MenuItem *menu);
+ void renderSubmenu(MenuItem *menu);
+
+ 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;
+
+ 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
+
+#endif
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
new file mode 100644
index 0000000000..e150d5f27e
--- /dev/null
+++ b/engines/wage/module.mk
@@ -0,0 +1,31 @@
+MODULE := engines/wage
+
+MODULE_OBJS := \
+ combat.o \
+ debugger.o \
+ design.o \
+ detection.o \
+ dialog.o \
+ entities.o \
+ gui.o \
+ gui-console.o \
+ macmenu.o \
+ macwindow.o \
+ macwindowmanager.o \
+ randomhat.o \
+ script.o \
+ sound.o \
+ util.o \
+ wage.o \
+ world.o
+
+MODULE_DIRS += \
+ engines/wage
+
+# This module can be built as a plugin
+ifeq ($(ENABLE_WAGE), DYNAMIC_PLUGIN)
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/engines/wage/randomhat.cpp b/engines/wage/randomhat.cpp
new file mode 100644
index 0000000000..9371140398
--- /dev/null
+++ b/engines/wage/randomhat.cpp
@@ -0,0 +1,83 @@
+/* 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/random.h"
+
+#include "common/hashmap.h"
+#include "wage/randomhat.h"
+
+namespace Wage {
+
+void RandomHat::addTokens(int type, int count) {
+ _tokens.setVal(type, _tokens.getVal(type, 0) + count);
+}
+
+int RandomHat::countTokens() {
+ int count = 0;
+ for (Common::HashMap<int, int>::const_iterator it = _tokens.begin(); it != _tokens.end(); ++it)
+ count += it->_value;
+
+ return count;
+}
+
+int RandomHat::drawToken() {
+ int total = countTokens();
+ if (total > 0) {
+ int random = _rnd->getRandomNumber(total - 1);
+ int count = 0;
+ for (Common::HashMap<int, int>::iterator it = _tokens.begin(); it != _tokens.end(); ++it) {
+ if (random >= count && random < count + it->_value) {
+ it->_value--;
+ return it->_key;
+ }
+ count += it->_value;
+ }
+ }
+ return kTokNone;
+}
+
+} // End of namespace Wage
diff --git a/engines/wage/randomhat.h b/engines/wage/randomhat.h
new file mode 100644
index 0000000000..254cd2ae8d
--- /dev/null
+++ b/engines/wage/randomhat.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.
+ *
+ * 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_RANDOMHAT_H
+#define WAGE_RANDOMHAT_H
+
+namespace Wage {
+
+enum {
+ kTokWeapons = -400,
+ kTokMagic = -300,
+ kTokRun = -200,
+ kTokOffer = -100,
+ kTokNone = -100000
+};
+
+class RandomHat {
+public:
+ RandomHat(Common::RandomSource *rnd) : _rnd(rnd) {}
+
+ void addTokens(int type, int count);
+ int drawToken();
+
+private:
+ Common::RandomSource *_rnd;
+ Common::HashMap<int, int> _tokens;
+
+ int countTokens();
+};
+
+} // End of namespace Wage
+
+#endif
diff --git a/engines/wage/script.cpp b/engines/wage/script.cpp
new file mode 100644
index 0000000000..61336dce88
--- /dev/null
+++ b/engines/wage/script.cpp
@@ -0,0 +1,1175 @@
+/* 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 "wage/wage.h"
+#include "wage/entities.h"
+#include "wage/script.h"
+#include "wage/world.h"
+
+#include "common/stream.h"
+
+namespace Wage {
+
+Common::String Script::Operand::toString() {
+ switch(_type) {
+ case NUMBER:
+ return Common::String::format("%d", _value.number);
+ case STRING:
+ case TEXT_INPUT:
+ return *_value.string;
+ case OBJ:
+ return _value.obj->toString();
+ case CHR:
+ return _value.chr->toString();
+ case SCENE:
+ return _value.scene->toString();
+ case CLICK_INPUT:
+ return _value.inputClick->toString();
+ default:
+ error("Unhandled operand type: _type");
+ }
+}
+
+Script::Script(Common::SeekableReadStream *data) : _data(data) {
+ _engine = NULL;
+ _world = NULL;
+
+ _loopCount = 0;
+ _inputText = NULL;
+ _inputClick = NULL;
+
+ _handled = false;
+
+ convertToText();
+}
+
+Script::~Script() {
+ for (uint i = 0; i < _scriptText.size(); i++) {
+ delete _scriptText[i];
+ }
+
+ delete _data;
+}
+
+void Script::print() {
+ for (uint i = 0; i < _scriptText.size(); i++) {
+ debug(4, "%d [%04x]: %s", i, _scriptText[i]->offset, _scriptText[i]->line.c_str());
+ }
+}
+
+void Script::printLine(int offset) {
+ for (uint i = 0; i < _scriptText.size(); i++)
+ if (_scriptText[i]->offset >= offset) {
+ debug(4, "%d [%04x]: %s", i, _scriptText[i]->offset, _scriptText[i]->line.c_str());
+ break;
+ }
+}
+
+bool Script::execute(World *world, int loopCount, Common::String *inputText, Designed *inputClick, WageEngine *engine) {
+ _world = world;
+ _loopCount = loopCount;
+ _inputText = inputText;
+ _inputClick = inputClick;
+ _engine = engine;
+ _handled = false;
+ Common::String input;
+
+ if (inputText)
+ input = *inputText;
+
+ _data->seek(12);
+ while (_data->pos() < _data->size()) {
+ printLine(_data->pos());
+
+ byte command = _data->readByte();
+
+ switch(command) {
+ case 0x80: // IF
+ processIf();
+ break;
+ case 0x87: // EXIT
+ debug(6, "exit at offset %d", _data->pos() - 1);
+
+ return true;
+ case 0x89: // MOVE
+ {
+ Scene *currentScene = _world->_player->_currentScene;
+ processMove();
+ if (_world->_player->_currentScene != currentScene)
+ return true;
+ break;
+ }
+ case 0x8B: // PRINT
+ {
+ Operand *op = readOperand();
+ // TODO check op type is string or number, or something good...
+ _handled = true;
+ _engine->appendText(op->toString().c_str());
+ delete op;
+ byte d = _data->readByte();
+ if (d != 0xFD)
+ warning("Operand 0x8B (PRINT) End Byte != 0xFD");
+ break;
+ }
+ case 0x8C: // SOUND
+ {
+ Operand *op = readOperand();
+ // TODO check op type is string.
+ _handled = true;
+ _engine->playSound(op->toString());
+ delete op;
+ byte d = _data->readByte();
+ if (d != 0xFD)
+ warning("Operand 0x8B (PRINT) End Byte != 0xFD");
+ break;
+ }
+ case 0x8E: // LET
+ processLet();
+ break;
+ case 0x95: // MENU
+ {
+ Operand *op = readStringOperand(); // allows empty menu
+ // TODO check op type is string.
+ _engine->setMenu(op->toString());
+ delete op;
+ byte d = _data->readByte();
+ if (d != 0xFD)
+ warning("Operand 0x8B (PRINT) End Byte != 0xFD");
+ }
+ case 0x88: // END
+ break;
+ default:
+ debug(0, "Unknown opcode: %d", _data->pos());
+ }
+ }
+
+ if (_world->_globalScript != this) {
+ debug(1, "Executing global script...");
+ bool globalHandled = _world->_globalScript->execute(_world, _loopCount, &input, _inputClick, _engine);
+ if (globalHandled)
+ _handled = true;
+ } else if (!input.empty()) {
+ if (input.contains("north")) {
+ _handled = _engine->handleMoveCommand(NORTH, "north");
+ } else if (input.contains("east")) {
+ _handled = _engine->handleMoveCommand(EAST, "east");
+ } else if (input.contains("south")) {
+ _handled = _engine->handleMoveCommand(SOUTH, "south");
+ } else if (input.contains("west")) {
+ _handled = _engine->handleMoveCommand(WEST, "west");
+ } else if (input.hasPrefix("take ")) {
+ _handled = _engine->handleTakeCommand(&input.c_str()[5]);
+ } else if (input.hasPrefix("get ")) {
+ _handled = _engine->handleTakeCommand(&input.c_str()[4]);
+ } else if (input.hasPrefix("pick up ")) {
+ _handled = _engine->handleTakeCommand(&input.c_str()[8]);
+ } else if (input.hasPrefix("drop ")) {
+ _handled = _engine->handleDropCommand(&input.c_str()[5]);
+ } else if (input.hasPrefix("aim ")) {
+ _handled = _engine->handleAimCommand(&input.c_str()[4]);
+ } else if (input.hasPrefix("wear ")) {
+ _handled = _engine->handleWearCommand(&input.c_str()[5]);
+ } else if (input.hasPrefix("put on ")) {
+ _handled = _engine->handleWearCommand(&input.c_str()[7]);
+ } else if (input.hasPrefix("offer ")) {
+ _handled = _engine->handleOfferCommand(&input.c_str()[6]);
+ } else if (input.contains("look")) {
+ _handled = _engine->handleLookCommand();
+ } else if (input.contains("inventory")) {
+ _handled = _engine->handleInventoryCommand();
+ } else if (input.contains("status")) {
+ _handled = _engine->handleStatusCommand();
+ } else if (input.contains("rest") || input.equals("wait")) {
+ _handled = _engine->handleRestCommand();
+ } else if (_engine->getOffer() != NULL && input.contains("accept")) {
+ _handled = _engine->handleAcceptCommand();
+ } else {
+ Chr *player = _world->_player;
+ ObjArray *weapons = player->getWeapons(true);
+ for (ObjArray::const_iterator weapon = weapons->begin(); weapon != weapons->end(); ++weapon) {
+ if (_engine->tryAttack(*weapon, input)) {
+ _handled = _engine->handleAttack(*weapon);
+ break;
+ }
+ }
+
+ delete weapons;
+ }
+ // TODO: weapons, offer, etc...
+ } else if (_inputClick->_classType == OBJ) {
+ Obj *obj = (Obj *)_inputClick;
+ if (obj->_type != Obj::IMMOBILE_OBJECT) {
+ _engine->takeObj(obj);
+ } else {
+ _engine->appendText(obj->_clickMessage.c_str());
+ }
+
+ _handled = true;
+ }
+
+ return _handled;
+}
+
+Script::Operand *Script::readOperand() {
+ byte operandType = _data->readByte();
+
+ debug(7, "%x: readOperand: 0x%x", _data->pos(), operandType);
+
+ Context *cont = &_world->_player->_context;
+ switch (operandType) {
+ case 0xA0: // TEXT$
+ return new Operand(_inputText, TEXT_INPUT);
+ case 0xA1:
+ return new Operand(_inputClick, CLICK_INPUT);
+ case 0xC0: // STORAGE@
+ return new Operand(_world->_storageScene, SCENE);
+ case 0xC1: // SCENE@
+ return new Operand(_world->_player->_currentScene, SCENE);
+ case 0xC2: // PLAYER@
+ return new Operand(_world->_player, CHR);
+ case 0xC3: // MONSTER@
+ return new Operand(_engine->getMonster(), CHR);
+ case 0xC4: // RANDOMSCN@
+ return new Operand(_world->_orderedScenes[_engine->_rnd->getRandomNumber(_world->_orderedScenes.size())], SCENE);
+ case 0xC5: // RANDOMCHR@
+ return new Operand(_world->_orderedChrs[_engine->_rnd->getRandomNumber(_world->_orderedChrs.size())], CHR);
+ case 0xC6: // RANDOMOBJ@
+ return new Operand(_world->_orderedObjs[_engine->_rnd->getRandomNumber(_world->_orderedObjs.size())], OBJ);
+ case 0xB0: // VISITS#
+ return new Operand(cont->_visits, NUMBER);
+ case 0xB1: // RANDOM# for Star Trek, but VISITS# for some other games?
+ return new Operand(1 + _engine->_rnd->getRandomNumber(100), NUMBER);
+ case 0xB5: // RANDOM# // A random number between 1 and 100.
+ return new Operand(1 + _engine->_rnd->getRandomNumber(100), NUMBER);
+ case 0xB2: // LOOP#
+ return new Operand(_loopCount, NUMBER);
+ case 0xB3: // VICTORY#
+ return new Operand(cont->_kills, NUMBER);
+ case 0xB4: // BADCOPY#
+ return new Operand(0, NUMBER); // \?\?\??
+ case 0xFF:
+ {
+ // user variable
+ int value = _data->readByte();
+
+ // TODO: Verify that we're using the right index.
+ return new Operand(cont->_userVariables[value - 1], NUMBER);
+ }
+ case 0xD0:
+ return new Operand(cont->_statVariables[PHYS_STR_BAS], NUMBER);
+ case 0xD1:
+ return new Operand(cont->_statVariables[PHYS_HIT_BAS], NUMBER);
+ case 0xD2:
+ return new Operand(cont->_statVariables[PHYS_ARM_BAS], NUMBER);
+ case 0xD3:
+ return new Operand(cont->_statVariables[PHYS_ACC_BAS], NUMBER);
+ case 0xD4:
+ return new Operand(cont->_statVariables[SPIR_STR_BAS], NUMBER);
+ case 0xD5:
+ return new Operand(cont->_statVariables[SPIR_HIT_BAS], NUMBER);
+ case 0xD6:
+ return new Operand(cont->_statVariables[SPIR_ARM_BAS], NUMBER);
+ case 0xD7:
+ return new Operand(cont->_statVariables[SPIR_ACC_BAS], NUMBER);
+ case 0xD8:
+ return new Operand(cont->_statVariables[PHYS_SPE_BAS], NUMBER);
+ case 0xE0:
+ return new Operand(cont->_statVariables[PHYS_STR_CUR], NUMBER);
+ case 0xE1:
+ return new Operand(cont->_statVariables[PHYS_HIT_CUR], NUMBER);
+ case 0xE2:
+ return new Operand(cont->_statVariables[PHYS_ARM_CUR], NUMBER);
+ case 0xE3:
+ return new Operand(cont->_statVariables[PHYS_ACC_CUR], NUMBER);
+ case 0xE4:
+ return new Operand(cont->_statVariables[SPIR_STR_CUR], NUMBER);
+ case 0xE5:
+ return new Operand(cont->_statVariables[SPIR_HIT_CUR], NUMBER);
+ case 0xE6:
+ return new Operand(cont->_statVariables[SPIR_ARM_CUR], NUMBER);
+ case 0xE7:
+ return new Operand(cont->_statVariables[SPIR_ACC_CUR], NUMBER);
+ case 0xE8:
+ return new Operand(cont->_statVariables[PHYS_SPE_CUR], NUMBER);
+ default:
+ if (operandType >= 0x20 && operandType < 0x80) {
+ _data->seek(-1, SEEK_CUR);
+ return readStringOperand();
+ } else {
+ debug("Dunno what %x is (index=%d)!\n", operandType, _data->pos()-1);
+ }
+ return NULL;
+ }
+}
+
+void Script::assign(byte operandType, int uservar, uint16 value) {
+ Context *cont = &_world->_player->_context;
+
+ switch (operandType) {
+ case 0xFF:
+ cont->_userVariables[uservar - 1] = value;
+ break;
+ case 0xD0:
+ cont->_statVariables[PHYS_STR_BAS] = value;
+ break;
+ case 0xD1:
+ cont->_statVariables[PHYS_HIT_BAS] = value;
+ break;
+ case 0xD2:
+ cont->_statVariables[PHYS_ARM_BAS] = value;
+ break;
+ case 0xD3:
+ cont->_statVariables[PHYS_ACC_BAS] = value;
+ break;
+ case 0xD4:
+ cont->_statVariables[SPIR_STR_BAS] = value;
+ break;
+ case 0xD5:
+ cont->_statVariables[SPIR_HIT_BAS] = value;
+ break;
+ case 0xD6:
+ cont->_statVariables[SPIR_ARM_BAS] = value;
+ break;
+ case 0xD7:
+ cont->_statVariables[SPIR_ACC_BAS] = value;
+ break;
+ case 0xD8:
+ cont->_statVariables[PHYS_SPE_BAS] = value;
+ break;
+ case 0xE0:
+ cont->_statVariables[PHYS_STR_CUR] = value;
+ break;
+ case 0xE1:
+ cont->_statVariables[PHYS_HIT_CUR] = value;
+ break;
+ case 0xE2:
+ cont->_statVariables[PHYS_ARM_CUR] = value;
+ break;
+ case 0xE3:
+ cont->_statVariables[PHYS_ACC_CUR] = value;
+ break;
+ case 0xE4:
+ cont->_statVariables[SPIR_STR_CUR] = value;
+ break;
+ case 0xE5:
+ cont->_statVariables[SPIR_HIT_CUR] = value;
+ break;
+ case 0xE6:
+ cont->_statVariables[SPIR_ARM_CUR] = value;
+ break;
+ case 0xE7:
+ cont->_statVariables[SPIR_ACC_CUR] = value;
+ break;
+ case 0xE8:
+ cont->_statVariables[PHYS_SPE_CUR] = value;
+ break;
+ default:
+ debug("No idea what I'm supposed to assign! (%x at %d)!\n", operandType, _data->pos()-1);
+ }
+}
+
+Script::Operand *Script::readStringOperand() {
+ Common::String *str;
+ bool allDigits = true;
+
+ str = new Common::String();
+
+ while (true) {
+ byte c = _data->readByte();
+ if (c >= 0x20 && c < 0x80)
+ *str += c;
+ else
+ break;
+ if (c < '0' || c > '9')
+ allDigits = false;
+ }
+ _data->seek(-1, SEEK_CUR);
+
+ if (allDigits && !str->empty()) {
+ int r = atol(str->c_str());
+ delete str;
+
+ return new Operand(r, NUMBER);
+ } else {
+ // TODO: This string could be a room name or something like that.
+ return new Operand(str, STRING);
+ }
+}
+
+const char *Script::readOperator() {
+ byte cmd = _data->readByte();
+
+ debug(7, "readOperator: 0x%x", cmd);
+ switch (cmd) {
+ case 0x81:
+ return "=";
+ case 0x82:
+ return "<";
+ case 0x83:
+ return ">";
+ case 0x8f:
+ return "+";
+ case 0x90:
+ return "-";
+ case 0x91:
+ return "*";
+ case 0x92:
+ return "/";
+ case 0x93:
+ return "==";
+ case 0x94:
+ return ">>";
+ case 0xfd:
+ return ";";
+ default:
+ warning("UNKNOWN OP %x", cmd);
+ }
+ return NULL;
+}
+
+void Script::processIf() {
+ int logicalOp = 0; // 0 => initial, 1 => and, 2 => or
+ bool result = true;
+ bool done = false;
+
+ do {
+ Operand *lhs = readOperand();
+ const char *op = readOperator();
+ Operand *rhs = readOperand();
+
+ bool condResult = eval(lhs, op, rhs);
+
+ delete lhs;
+ delete rhs;
+
+ if (logicalOp == 1) {
+ result = (result && condResult);
+ } else if (logicalOp == 2) {
+ result = (result || condResult);
+ } else { // logicalOp == 0
+ result = condResult;
+ }
+
+ byte logical = _data->readByte();
+
+ if (logical == 0x84) {
+ logicalOp = 1; // and
+ } else if (logical == 0x85) {
+ logicalOp = 2; // or
+ } else if (logical == 0xFE) {
+ done = true; // then
+ }
+ } while (!done);
+
+ if (result == false) {
+ skipBlock();
+ }
+}
+
+void Script::skipIf() {
+ do {
+ Operand *lhs = readOperand();
+ readOperator();
+ Operand *rhs = readOperand();
+
+ delete lhs;
+ delete rhs;
+ } while (_data->readByte() != 0xFE);
+}
+
+void Script::skipBlock() {
+ int nesting = 1;
+
+ while (true) {
+ byte op = _data->readByte();
+
+ if (_data->eos())
+ return;
+
+ if (op == 0x80) { // IF
+ nesting++;
+ skipIf();
+ } else if (op == 0x88 || op == 0x87) { // END or EXIT
+ nesting--;
+ if (nesting == 0) {
+ return;
+ }
+ } else switch (op) {
+ case 0x8B: // PRINT
+ case 0x8C: // SOUND
+ case 0x8E: // LET
+ case 0x95: // MENU
+ while (_data->readByte() != 0xFD)
+ ;
+ }
+ }
+}
+
+enum {
+ kCompEqNumNum,
+ kCompEqObjScene,
+ kCompEqChrScene,
+ kCompEqObjChr,
+ kCompEqChrChr,
+ kCompEqSceneScene,
+ kCompEqStringTextInput,
+ kCompEqTextInputString,
+ kCompEqNumberTextInput,
+ kCompEqTextInputNumber,
+ kCompLtNumNum,
+ kCompLtStringTextInput,
+ kCompLtTextInputString,
+ kCompLtObjChr,
+ kCompLtChrObj,
+ kCompLtObjScene,
+ kCompGtNumNum,
+ kCompGtStringString,
+ kCompGtChrScene,
+ kMoveObjChr,
+ kMoveObjScene,
+ kMoveChrScene
+};
+
+static const char *typeNames[] = {
+ "OBJ",
+ "CHR",
+ "SCENE",
+ "NUMBER",
+ "STRING",
+ "CLICK_INPUT",
+ "TEXT_INPUT"
+};
+
+static const char *operandTypeToStr(int type) {
+ if (type < 0 || type > 6)
+ return "UNKNOWN";
+
+ return typeNames[type];
+}
+
+struct Comparator {
+ char op;
+ OperandType o1;
+ OperandType o2;
+ int cmp;
+} static comparators[] = {
+ { '=', NUMBER, NUMBER, kCompEqNumNum },
+ { '=', OBJ, SCENE, kCompEqObjScene },
+ { '=', CHR, SCENE, kCompEqChrScene },
+ { '=', OBJ, CHR, kCompEqObjChr },
+ { '=', CHR, CHR, kCompEqChrChr },
+ { '=', SCENE, SCENE, kCompEqSceneScene },
+ { '=', STRING, TEXT_INPUT, kCompEqStringTextInput },
+ { '=', TEXT_INPUT, STRING, kCompEqTextInputString },
+ { '=', NUMBER, TEXT_INPUT, kCompEqNumberTextInput },
+ { '=', TEXT_INPUT, NUMBER, kCompEqTextInputNumber },
+
+ { '<', NUMBER, NUMBER, kCompLtNumNum },
+ { '<', STRING, TEXT_INPUT, kCompLtStringTextInput },
+ { '<', TEXT_INPUT, STRING, kCompLtTextInputString },
+ { '<', OBJ, CHR, kCompLtObjChr },
+ { '<', CHR, OBJ, kCompLtChrObj },
+ { '<', OBJ, SCENE, kCompLtObjScene },
+ { '<', CHR, CHR, kCompEqChrChr }, // Same logic as =
+ { '<', SCENE, SCENE, kCompEqSceneScene },
+
+ { '>', NUMBER, NUMBER, kCompGtNumNum },
+ { '>', TEXT_INPUT, STRING, kCompLtTextInputString }, // Same logic as <
+ //FIXME: this prevents the below cases from working due to exact
+ //matches taking precedence over conversions...
+ //{ '>', STRING, STRING, kCompGtStringString }, // Same logic as <
+ { '>', OBJ, CHR, kCompLtObjChr }, // Same logic as <
+ { '>', OBJ, SCENE, kCompLtObjScene }, // Same logic as <
+ { '>', CHR, SCENE, kCompGtChrScene },
+
+ { 'M', OBJ, CHR, kMoveObjChr },
+ { 'M', OBJ, SCENE, kMoveObjScene },
+ { 'M', CHR, SCENE, kMoveChrScene },
+ { 0, OBJ, OBJ, 0 }
+};
+
+bool Script::compare(Operand *o1, Operand *o2, int comparator) {
+ switch(comparator) {
+ case kCompEqNumNum:
+ return o1->_value.number == o2->_value.number;
+ case kCompEqObjScene:
+ for (ObjList::const_iterator it = o2->_value.scene->_objs.begin(); it != o2->_value.scene->_objs.end(); ++it)
+ if (*it == o1->_value.obj)
+ return true;
+ return false;
+ case kCompEqChrScene:
+ for (ChrList::const_iterator it = o2->_value.scene->_chrs.begin(); it != o2->_value.scene->_chrs.end(); ++it)
+ if (*it == o1->_value.chr)
+ return true;
+ return false;
+ case kCompEqObjChr:
+ for (ObjArray::const_iterator it = o2->_value.chr->_inventory.begin(); it != o2->_value.chr->_inventory.end(); ++it)
+ if (*it == o1->_value.obj)
+ return true;
+ return false;
+ case kCompEqChrChr:
+ return o1->_value.chr == o2->_value.chr;
+ case kCompEqSceneScene:
+ return o1->_value.scene == o2->_value.scene;
+ case kCompEqStringTextInput:
+ if (_inputText == NULL) {
+ return false;
+ } else {
+ Common::String s1(*_inputText), s2(*o1->_value.string);
+ s1.toLowercase();
+ s2.toLowercase();
+
+ return s1.contains(s2);
+ }
+ case kCompEqTextInputString:
+ return compare(o2, o1, kCompEqStringTextInput);
+ case kCompEqNumberTextInput:
+ if (_inputText == NULL) {
+ return false;
+ } else {
+ Common::String s1(*_inputText), s2(o1->toString());
+ s1.toLowercase();
+ s2.toLowercase();
+
+ return s1.contains(s2);
+ }
+ case kCompEqTextInputNumber:
+ if (_inputText == NULL) {
+ return false;
+ } else {
+ Common::String s1(*_inputText), s2(o2->toString());
+ s1.toLowercase();
+ s2.toLowercase();
+
+ return s1.contains(s2);
+ }
+ case kCompLtNumNum:
+ return o1->_value.number < o2->_value.number;
+ case kCompLtStringTextInput:
+ return !compare(o1, o2, kCompEqStringTextInput);
+ case kCompLtTextInputString:
+ return !compare(o2, o1, kCompEqStringTextInput);
+ case kCompLtObjChr:
+ return o1->_value.obj->_currentOwner != o2->_value.chr;
+ case kCompLtChrObj:
+ return compare(o2, o1, kCompLtObjChr);
+ case kCompLtObjScene:
+ return o1->_value.obj->_currentScene != o2->_value.scene;
+ case kCompGtNumNum:
+ return o1->_value.number > o2->_value.number;
+ case kCompGtStringString:
+ return o1->_value.string == o2->_value.string;
+ case kCompGtChrScene:
+ return (o1->_value.chr != NULL && o1->_value.chr->_currentScene != o2->_value.scene);
+ case kMoveObjChr:
+ if (o1->_value.obj->_currentOwner != o2->_value.chr) {
+ _world->move(o1->_value.obj, o2->_value.chr);
+ _handled = true; // TODO: Is this correct?
+ }
+ break;
+ case kMoveObjScene:
+ if (o1->_value.obj->_currentScene != o2->_value.scene) {
+ _world->move(o1->_value.obj, o2->_value.scene);
+ // Note: This shouldn't call setHandled() - see
+ // Sultan's Palace 'Food and Drink' scene.
+ }
+ break;
+ case kMoveChrScene:
+ _world->move(o1->_value.chr, o2->_value.scene);
+ _handled = true; // TODO: Is this correct?
+ break;
+ }
+
+ return false;
+}
+
+bool Script::evaluatePair(Operand *lhs, const char *op, Operand *rhs) {
+ debug(7, "HANDLING CASE: [lhs=%s/%s, op=%s rhs=%s/%s]",
+ operandTypeToStr(lhs->_type), lhs->toString().c_str(), op, operandTypeToStr(rhs->_type), rhs->toString().c_str());
+
+ for (int cmp = 0; comparators[cmp].op != 0; cmp++) {
+ if (comparators[cmp].op != op[0])
+ continue;
+
+ if (comparators[cmp].o1 == lhs->_type && comparators[cmp].o2 == rhs->_type)
+ return compare(lhs, rhs, comparators[cmp].cmp);
+ }
+
+ // Now, try partial matches.
+ Operand *c1, *c2;
+ for (int cmp = 0; comparators[cmp].op != 0; cmp++) {
+ if (comparators[cmp].op != op[0])
+ continue;
+
+ if (comparators[cmp].o1 == lhs->_type &&
+ (c2 = convertOperand(rhs, comparators[cmp].o2)) != NULL) {
+ bool res = compare(lhs, c2, comparators[cmp].cmp);
+ delete c2;
+ return res;
+ } else if (comparators[cmp].o2 == rhs->_type &&
+ (c1 = convertOperand(lhs, comparators[cmp].o1)) != NULL) {
+ bool res = compare(c1, rhs, comparators[cmp].cmp);
+ delete c1;
+ return res;
+ }
+ }
+
+ // Now, try double conversion.
+ for (int cmp = 0; comparators[cmp].op != 0; cmp++) {
+ if (comparators[cmp].op != op[0])
+ continue;
+
+ if (comparators[cmp].o1 == lhs->_type || comparators[cmp].o2 == rhs->_type)
+ continue;
+
+ if ((c1 = convertOperand(lhs, comparators[cmp].o1)) != NULL) {
+ if ((c2 = convertOperand(rhs, comparators[cmp].o2)) != NULL) {
+ bool res = compare(c1, c2, comparators[cmp].cmp);
+ delete c1;
+ delete c2;
+ return res;
+ }
+ delete c1;
+ }
+ }
+
+ warning("UNHANDLED CASE: [lhs=%s/%s, op=%s rhs=%s/%s]",
+ operandTypeToStr(lhs->_type), lhs->toString().c_str(), op, operandTypeToStr(rhs->_type), rhs->toString().c_str());
+
+ return false;
+}
+
+bool Script::eval(Operand *lhs, const char *op, Operand *rhs) {
+ bool result = false;
+
+ if (lhs->_type == CLICK_INPUT || rhs->_type == CLICK_INPUT) {
+ return evalClickCondition(lhs, op, rhs);
+ } else if (!strcmp(op, "==") || !strcmp(op, ">>")) {
+ // TODO: check if >> can be used for click inputs and if == can be used for other things
+ // exact string match
+ if (lhs->_type == TEXT_INPUT) {
+ if ((rhs->_type != STRING && rhs->_type != NUMBER) || _inputText == NULL) {
+ result = false;
+ } else {
+ result = _inputText->equalsIgnoreCase(rhs->toString());
+ }
+ } else if (rhs->_type == TEXT_INPUT) {
+ if ((lhs->_type != STRING && lhs->_type != NUMBER) || _inputText == NULL) {
+ result = false;
+ } else {
+ result = _inputText->equalsIgnoreCase(lhs->toString());
+ }
+ } else {
+ error("UNHANDLED CASE: [lhs=%s/%s, rhs=%s/%s]",
+ operandTypeToStr(lhs->_type), lhs->toString().c_str(), operandTypeToStr(rhs->_type), rhs->toString().c_str());
+ }
+ if (!strcmp(op, ">>")) {
+ result = !result;
+ }
+
+ return result;
+ } else {
+ return evaluatePair(lhs, op, rhs);
+ }
+
+ return false;
+}
+
+Script::Operand *Script::convertOperand(Operand *operand, int type) {
+ if (operand->_type == type)
+ error("Incorrect conversion to type %d", type);
+
+ if (type == SCENE) {
+ if (operand->_type == STRING || operand->_type == NUMBER) {
+ Common::String key(operand->toString());
+ key.toLowercase();
+ if (_world->_scenes.contains(key))
+ return new Operand(_world->_scenes[key], SCENE);
+ }
+ } else if (type == OBJ) {
+ if (operand->_type == STRING || operand->_type == NUMBER) {
+ Common::String key = operand->toString();
+ key.toLowercase();
+ if (_world->_objs.contains(key))
+ return new Operand(_world->_objs[key], OBJ);
+ } else if (operand->_type == CLICK_INPUT) {
+ if (_inputClick->_classType == OBJ)
+ return new Operand(_inputClick, OBJ);
+ }
+ } else if (type == CHR) {
+ if (operand->_type == STRING || operand->_type == NUMBER) {
+ Common::String key = operand->toString();
+ key.toLowercase();
+ if (_world->_chrs.contains(key))
+ return new Operand(_world->_chrs[key], CHR);
+ } else if (operand->_type == CLICK_INPUT) {
+ if (_inputClick->_classType == CHR)
+ return new Operand(_inputClick, CHR);
+ }
+ }
+
+ return NULL;
+}
+
+bool Script::evalClickEquality(Operand *lhs, Operand *rhs, bool partialMatch) {
+ bool result = false;
+ if (lhs->_value.obj == NULL || rhs->_value.obj == NULL) {
+ result = false;
+ } else if (lhs->_value.obj == rhs->_value.obj) {
+ result = true;
+ } else if (rhs->_type == STRING) {
+ Common::String str = rhs->toString();
+ str.toLowercase();
+
+ debug(9, "evalClickEquality(%s, %s, %d)", lhs->_value.designed->_name.c_str(), rhs->_value.designed->_name.c_str(), partialMatch);
+ debug(9, "l: %s r: %s)", operandTypeToStr(lhs->_type), operandTypeToStr(rhs->_type));
+ debug(9, "class: %d", lhs->_value.inputClick->_classType);
+
+ if (lhs->_value.inputClick->_classType == CHR || lhs->_value.inputClick->_classType == OBJ) {
+ Common::String name = lhs->_value.designed->_name;
+ name.toLowercase();
+
+ if (partialMatch)
+ result = name.contains(str);
+ else
+ result = name.equals(str);
+ }
+
+ debug(9, "result: %d", result);
+ }
+ return result;
+}
+
+bool Script::evalClickCondition(Operand *lhs, const char *op, Operand *rhs) {
+ // TODO: check if >> can be used for click inputs
+ if (strcmp(op, "==") && strcmp(op, "=") && strcmp(op, "<") && strcmp(op, ">")) {
+ error("Unknown operation '%s' for Script::evalClickCondition", op);
+ }
+
+ bool partialMatch = strcmp(op, "==");
+ bool result;
+ if (lhs->_type == CLICK_INPUT) {
+ result = evalClickEquality(lhs, rhs, partialMatch);
+ } else {
+ result = evalClickEquality(rhs, lhs, partialMatch);
+ }
+ if (!strcmp(op, "<") || !strcmp(op, ">")) {
+ // CLICK$<FOO only matches if there was a click
+ if (_inputClick == NULL) {
+ result = false;
+ } else {
+ result = !result;
+ }
+ }
+ return result;
+}
+
+void Script::processMove() {
+ Operand *what = readOperand();
+ byte skip = _data->readByte();
+ if (skip != 0x8a)
+ error("Incorrect operator for MOVE: %02x", skip);
+
+ Operand *to = readOperand();
+
+ skip = _data->readByte();
+ if (skip != 0xfd)
+ error("No end for MOVE: %02x", skip);
+
+ evaluatePair(what, "M", to);
+
+ delete what;
+ delete to;
+}
+
+void Script::processLet() {
+ const char *lastOp = NULL;
+ int16 result = 0;
+ int operandType = _data->readByte();
+ int uservar = 0;
+
+ if (operandType == 0xff) {
+ uservar = _data->readByte();
+ }
+
+ byte eq = _data->readByte(); // skip "=" operator
+
+ debug(7, "processLet: 0x%x, uservar: 0x%x, eq: 0x%x", operandType, uservar, eq);
+
+ do {
+ Operand *operand = readOperand();
+ // TODO assert that value is NUMBER
+ int16 value = operand->_value.number;
+ delete operand;
+ if (lastOp != NULL) {
+ if (lastOp[0] == '+')
+ result += value;
+ else if (lastOp[0] == '-')
+ result -= value;
+ else if (lastOp[0] == '/')
+ result = (int16)(value == 0 ? 0 : result / value);
+ else if (lastOp[0] == '*')
+ result *= value;
+ } else {
+ result = value;
+ }
+ lastOp = readOperator();
+
+ if (lastOp[0] == ';')
+ break;
+ } while (true);
+ //System.out.println("processLet " + buildStringFromOffset(oldIndex - 1, index - oldIndex + 1) + "}");
+
+ assign(operandType, uservar, result);
+}
+
+enum {
+ BLOCK_START,
+ BLOCK_END,
+ STATEMENT,
+ OPERATOR,
+ OPCODE
+};
+
+struct Mapping {
+ const char *cmd;
+ int type;
+} static const mapping[] = {
+ { "IF{", STATEMENT }, // 0x80
+ { "=", OPERATOR },
+ { "<", OPERATOR },
+ { ">", OPERATOR },
+ { "}AND{", OPCODE },
+ { "}OR{", OPCODE },
+ { "\?\?\?(0x86)", OPCODE },
+ { "EXIT\n", BLOCK_END },
+ { "END\n", BLOCK_END }, // 0x88
+ { "MOVE{", STATEMENT },
+ { "}TO{", OPCODE },
+ { "PRINT{", STATEMENT },
+ { "SOUND{", STATEMENT },
+ { "\?\?\?(0x8d)", OPCODE },
+ { "LET{", STATEMENT },
+ { "+", OPERATOR },
+ { "-", OPERATOR }, // 0x90
+ { "*", OPERATOR },
+ { "/", OPERATOR },
+ { "==", OPERATOR },
+ { ">>", OPERATOR },
+ { "MENU{", STATEMENT },
+ { "\?\?\?(0x96)", OPCODE },
+ { "\?\?\?(0x97)", OPCODE },
+ { "\?\?\?(0x98)", OPCODE }, // 0x98
+ { "\?\?\?(0x99)", OPCODE },
+ { "\?\?\?(0x9a)", OPCODE },
+ { "\?\?\?(0x9b)", OPCODE },
+ { "\?\?\?(0x9c)", OPCODE },
+ { "\?\?\?(0x9d)", OPCODE },
+ { "\?\?\?(0x9e)", OPCODE },
+ { "\?\?\?(0x9f)", OPCODE },
+ { "TEXT$", OPCODE }, // 0xa0
+ { "CLICK$", OPCODE },
+ { "\?\?\?(0xa2)", OPCODE },
+ { "\?\?\?(0xa3)", OPCODE },
+ { "\?\?\?(0xa4)", OPCODE },
+ { "\?\?\?(0xa5)", OPCODE },
+ { "\?\?\?(0xa6)", OPCODE },
+ { "\?\?\?(0xa7)", OPCODE },
+ { "\?\?\?(0xa8)", OPCODE }, // 0xa8
+ { "\?\?\?(0xa9)", OPCODE },
+ { "\?\?\?(0xaa)", OPCODE },
+ { "\?\?\?(0xab)", OPCODE },
+ { "\?\?\?(0xac)", OPCODE },
+ { "\?\?\?(0xad)", OPCODE },
+ { "\?\?\?(0xae)", OPCODE },
+ { "\?\?\?(0xaf)", OPCODE },
+ { "VISITS#", OPCODE }, // 0xb0 // The number of scenes the player has visited, including repeated visits.
+ { "RANDOM#", OPCODE }, // RANDOM# for Star Trek, but VISITS# for some other games?
+ { "LOOP#", OPCODE }, // The number of commands the player has given in the current scene.
+ { "VICTORY#", OPCODE }, // The number of characters killed.
+ { "BADCOPY#", OPCODE },
+ { "RANDOM#", OPCODE }, // A random number between 1 and 100.
+ { "\?\?\?(0xb6)", OPCODE },
+ { "\?\?\?(0xb7)", OPCODE },
+ { "\?\?\?(0xb8)", OPCODE }, // 0xb8
+ { "\?\?\?(0xb9)", OPCODE },
+ { "\?\?\?(0xba)", OPCODE },
+ { "\?\?\?(0xbb)", OPCODE },
+ { "\?\?\?(0xbc)", OPCODE },
+ { "\?\?\?(0xbd)", OPCODE },
+ { "\?\?\?(0xbe)", OPCODE },
+ { "\?\?\?(0xbf)", OPCODE },
+ { "STORAGE@", OPCODE }, // 0xc0
+ { "SCENE@", OPCODE },
+ { "PLAYER@", OPCODE },
+ { "MONSTER@", OPCODE },
+ { "RANDOMSCN@", OPCODE },
+ { "RANDOMCHR@", OPCODE },
+ { "RANDOMOBJ@", OPCODE },
+ { "\?\?\?(0xc7)", OPCODE },
+ { "\?\?\?(0xc8)", OPCODE }, // 0xc8
+ { "\?\?\?(0xc9)", OPCODE },
+ { "\?\?\?(0xca)", OPCODE },
+ { "\?\?\?(0xcb)", OPCODE },
+ { "\?\?\?(0xcc)", OPCODE },
+ { "\?\?\?(0xcd)", OPCODE },
+ { "\?\?\?(0xce)", OPCODE },
+ { "\?\?\?(0xcf)", OPCODE },
+ { "PHYS.STR.BAS#", OPCODE }, // 0xd0
+ { "PHYS.HIT.BAS#", OPCODE },
+ { "PHYS.ARM.BAS#", OPCODE },
+ { "PHYS.ACC.BAS#", OPCODE },
+ { "SPIR.STR.BAS#", OPCODE },
+ { "SPIR.HIT.BAS#", OPCODE },
+ { "SPIR.ARM.BAS#", OPCODE },
+ { "SPIR.ACC.BAS#", OPCODE },
+ { "PHYS.SPE.BAS#", OPCODE }, // 0xd8
+ { "\?\?\?(0xd9)", OPCODE },
+ { "\?\?\?(0xda)", OPCODE },
+ { "\?\?\?(0xdb)", OPCODE },
+ { "\?\?\?(0xdc)", OPCODE },
+ { "\?\?\?(0xdd)", OPCODE },
+ { "\?\?\?(0xde)", OPCODE },
+ { "\?\?\?(0xdf)", OPCODE },
+ { "PHYS.STR.CUR#", OPCODE }, // 0xe0
+ { "PHYS.HIT.CUR#", OPCODE },
+ { "PHYS.ARM.CUR#", OPCODE },
+ { "PHYS.ACC.CUR#", OPCODE },
+ { "SPIR.STR.CUR#", OPCODE },
+ { "SPIR.HIT.CUR#", OPCODE },
+ { "SPIR.ARM.CUR#", OPCODE },
+ { "SPIR.ACC.CUR#", OPCODE },
+ { "PHYS.SPE.CUR#", OPCODE }, // 0xe8
+ { "\?\?\?(0xe9)", OPCODE },
+ { "\?\?\?(0xea)", OPCODE },
+ { "\?\?\?(0xeb)", OPCODE },
+ { "\?\?\?(0xec)", OPCODE },
+ { "\?\?\?(0xed)", OPCODE },
+ { "\?\?\?(0xee)", OPCODE },
+ { "\?\?\?(0xef)", OPCODE },
+ { "\?\?\?(0xf0)", OPCODE },
+ { "\?\?\?(0xf1)", OPCODE },
+ { "\?\?\?(0xf2)", OPCODE },
+ { "\?\?\?(0xf3)", OPCODE },
+ { "\?\?\?(0xf4)", OPCODE },
+ { "\?\?\?(0xf5)", OPCODE },
+ { "\?\?\?(0xf6)", OPCODE },
+ { "\?\?\?(0xf7)", OPCODE },
+ { "\?\?\?(0xf8)", OPCODE }, // 0xf8
+ { "\?\?\?(0xf9)", OPCODE },
+ { "\?\?\?(0xfa)", OPCODE },
+ { "\?\?\?(0xfb)", OPCODE },
+ { "\?\?\?(0xfc)", OPCODE },
+ { "}\n", OPCODE },
+ { "}THEN\n", BLOCK_START },
+ { "\?\?\?(0xff)", OPCODE } // Uservar
+};
+
+void Script::convertToText() {
+ _data->seek(12);
+
+ int indentLevel = 0;
+ ScriptText *scr = new ScriptText;
+ scr->offset = _data->pos();
+
+ while(true) {
+ int c = _data->readByte();
+
+ if (_data->eos())
+ break;
+
+ if (c < 0x80) {
+ if (c < 0x20)
+ error("convertToText: Unknown code 0x%02x at %d", c, _data->pos());
+
+ do {
+ scr->line += c;
+ c = _data->readByte();
+ } while (c < 0x80);
+
+ _data->seek(-1, SEEK_CUR);
+ } else if (c == 0xff) {
+ int value = _data->readByte();
+ value -= 1;
+ scr->line += (char)('A' + (value / 9));
+ scr->line += (char)('0' + (value % 9) + 1);
+ scr->line += '#';
+ } else {
+ const char *cmd = mapping[c - 0x80].cmd;
+ int type = mapping[c - 0x80].type;
+
+ if (type == STATEMENT) {
+ for (int i = 0; i < indentLevel; i++)
+ scr->line += ' ';
+ } else if (type == BLOCK_START) {
+ indentLevel += 2;
+ } else if (type == BLOCK_END) {
+ indentLevel -= 2;
+ for (int i = 0; i < indentLevel; i++)
+ scr->line += ' ';
+ }
+
+ scr->line += cmd;
+
+ if (strchr(cmd, '\n')) {
+ scr->line.deleteLastChar();
+
+ _scriptText.push_back(scr);
+
+ scr = new ScriptText;
+ scr->offset = _data->pos();
+ }
+ }
+ }
+
+ if (!scr->line.empty())
+ _scriptText.push_back(scr);
+ else
+ delete scr;
+}
+
+} // End of namespace Wage
diff --git a/engines/wage/script.h b/engines/wage/script.h
new file mode 100644
index 0000000000..de9476228c
--- /dev/null
+++ b/engines/wage/script.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_SCRIPT_H
+#define WAGE_SCRIPT_H
+
+namespace Wage {
+
+class Script {
+public:
+ Script(Common::SeekableReadStream *data);
+ ~Script();
+
+private:
+ Common::SeekableReadStream *_data;
+
+ WageEngine *_engine;
+ World *_world;
+ int _loopCount;
+ Common::String *_inputText;
+ Designed *_inputClick;
+ bool _handled;
+
+ class Operand {
+ public:
+ union {
+ Obj *obj;
+ Chr *chr;
+ Designed *designed;
+ Scene *scene;
+ int16 number;
+ Common::String *string;
+ Designed *inputClick;
+ } _value;
+ OperandType _type;
+
+ Operand(Obj *value, OperandType type) {
+ _value.obj = value;
+ assert(type == OBJ);
+ _type = type;
+ }
+
+ Operand(Chr *value, OperandType type) {
+ _value.chr = value;
+ assert(type == CHR);
+ _type = type;
+ }
+
+ Operand(Scene *value, OperandType type) {
+ _value.scene = value;
+ assert(type == SCENE);
+ _type = type;
+ }
+
+ Operand(int value, OperandType type) {
+ _value.number = value;
+ assert(type == NUMBER);
+ _type = type;
+ }
+
+ Operand(Common::String *value, OperandType type) {
+ _value.string = value;
+ assert(type == STRING || type == TEXT_INPUT);
+ _type = type;
+ }
+
+ Operand(Designed *value, OperandType type) {
+ _value.inputClick = value;
+ assert(type == CLICK_INPUT);
+ _type = type;
+ }
+
+ ~Operand() {
+ if (_type == STRING)
+ delete _value.string;
+ }
+
+ Common::String toString();
+ };
+
+ struct ScriptText {
+ int offset;
+ Common::String line;
+ };
+
+public:
+ void print();
+ void printLine(int offset);
+ bool execute(World *world, int loopCount, Common::String *inputText, Designed *inputClick, WageEngine *engine);
+
+private:
+ Operand *readOperand();
+ Operand *readStringOperand();
+ const char *readOperator();
+ void processIf();
+ void skipBlock();
+ void skipIf();
+ bool compare(Operand *o1, Operand *o2, int comparator);
+ bool eval(Operand *lhs, const char *op, Operand *rhs);
+ bool evaluatePair(Operand *lhs, const char *op, Operand *rhs);
+ Operand *convertOperand(Operand *operand, int type);
+ bool evalClickCondition(Operand *lhs, const char *op, Operand *rhs);
+ bool evalClickEquality(Operand *lhs, Operand *rhs, bool partialMatch);
+ void processMove();
+ void processLet();
+
+ void assign(byte operandType, int uservar, uint16 value);
+
+ void convertToText();
+
+public:
+ Common::Array<ScriptText *> _scriptText;
+};
+
+} // End of namespace Wage
+
+#endif
diff --git a/engines/wage/sound.cpp b/engines/wage/sound.cpp
new file mode 100644
index 0000000000..bcb274cab9
--- /dev/null
+++ b/engines/wage/sound.cpp
@@ -0,0 +1,86 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * 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/stream.h"
+
+#include "wage/wage.h"
+#include "wage/sound.h"
+
+namespace Wage {
+
+static const int8 deltas[] = { 0,-49,-36,-25,-16,-9,-4,-1,0,1,4,9,16,25,36,49 };
+
+Sound::Sound(Common::String name, Common::SeekableReadStream *data) : _name(name) {
+ int size = data->size() - 20;
+ _data = (byte *)calloc(2 * size, 1);
+
+ data->skip(20); // Skip header
+
+ byte value = 0x80;
+ for (int i = 0; i < size; i++) {
+ byte d = data->readByte();
+ value += deltas[d & 0xf];
+ _data[i * 2] = value;
+ value += deltas[(d >> 4) & 0xf];
+ _data[i * 2 + 1] = value;
+ }
+}
+
+Sound::~Sound() {
+ free(_data);
+}
+
+void WageEngine::playSound(Common::String soundName) {
+ warning("STUB: WageEngine::playSound(%s)", soundName.c_str());
+}
+
+void WageEngine::updateSoundTimerForScene(Scene *scene, bool firstTime) {
+ //warning("STUB: WageEngine::updateSoundTimerForScene()");
+}
+
+
+} // End of namespace Wage
diff --git a/engines/wage/sound.h b/engines/wage/sound.h
new file mode 100644
index 0000000000..eccfe33170
--- /dev/null
+++ b/engines/wage/sound.h
@@ -0,0 +1,64 @@
+/* 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_SOUND_H
+#define WAGE_SOUND_H
+
+namespace Wage {
+
+class Sound {
+public:
+ Sound(Common::String name, Common::SeekableReadStream *data);
+ ~Sound();
+
+ Common::String _name;
+ byte *_data;
+};
+
+} // End of namespace Wage
+
+#endif
diff --git a/engines/wage/util.cpp b/engines/wage/util.cpp
new file mode 100644
index 0000000000..8c8af6652e
--- /dev/null
+++ b/engines/wage/util.cpp
@@ -0,0 +1,138 @@
+/* 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/stream.h"
+
+#include "wage/wage.h"
+
+namespace Wage {
+
+Common::String readPascalString(Common::SeekableReadStream *in) {
+ Common::String s;
+ char *buf;
+ int len;
+ int i;
+
+ len = in->readByte();
+ buf = (char *)malloc(len + 1);
+ for (i = 0; i < len; i++) {
+ buf[i] = in->readByte();
+ if (buf[i] == 0x0d)
+ buf[i] = '\n';
+ }
+
+ buf[i] = 0;
+
+ s = buf;
+ free(buf);
+
+ return s;
+}
+
+Common::Rect *readRect(Common::SeekableReadStream *in) {
+ int x1, y1, x2, y2;
+
+ y1 = in->readUint16BE();
+ x1 = in->readUint16BE();
+ 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);
+}
+
+const char *getIndefiniteArticle(const Common::String &word) {
+ switch (word[0]) {
+ case 'a': case 'A':
+ case 'e': case 'E':
+ case 'i': case 'I':
+ case 'o': case 'O':
+ case 'u': case 'U':
+ return "an ";
+ }
+ return "a ";
+}
+
+enum {
+ GENDER_MALE = 0,
+ GENDER_FEMALE = 1,
+ GENDER_NEUTRAL = 2
+};
+
+const char *prependGenderSpecificPronoun(int gender) {
+ if (gender == GENDER_MALE)
+ return "his ";
+ else if (gender == GENDER_FEMALE)
+ return "her ";
+ else
+ return "its ";
+}
+
+const char *getGenderSpecificPronoun(int gender, bool capitalize) {
+ if (gender == GENDER_MALE)
+ return capitalize ? "He" : "he";
+ else if (gender == GENDER_FEMALE)
+ return capitalize ? "She" : "she";
+ else
+ 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
new file mode 100644
index 0000000000..567e2768d8
--- /dev/null
+++ b/engines/wage/wage.cpp
@@ -0,0 +1,502 @@
+/* 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/debug-channels.h"
+#include "common/error.h"
+#include "common/events.h"
+#include "common/system.h"
+
+#include "engines/engine.h"
+#include "engines/util.h"
+
+#include "wage/wage.h"
+#include "wage/entities.h"
+#include "wage/gui.h"
+#include "wage/dialog.h"
+#include "wage/script.h"
+#include "wage/world.h"
+
+namespace Wage {
+
+WageEngine::WageEngine(OSystem *syst, const ADGameDescription *desc) : Engine(syst), _gameDescription(desc) {
+ _rnd = new Common::RandomSource("wage");
+
+ _aim = -1;
+ _opponentAim = -1;
+ _temporarilyHidden = false;
+ _isGameOver = false;
+ _monster = NULL;
+ _running = NULL;
+ _lastScene = NULL;
+
+ _loopCount = 0;
+ _turn = 0;
+
+ _commandWasQuick = false;
+
+ _shouldQuit = false;
+
+ _gui = NULL;
+ _world = NULL;
+ _console = NULL;
+ _offer = NULL;
+
+ _resManager = NULL;
+ _debugger = NULL;
+
+ debug("WageEngine::WageEngine()");
+}
+
+WageEngine::~WageEngine() {
+ debug("WageEngine::~WageEngine()");
+
+ DebugMan.clearAllDebugChannels();
+ delete _world;
+ delete _resManager;
+ delete _gui;
+ delete _rnd;
+ delete _console;
+}
+
+Common::Error WageEngine::run() {
+ debug("WageEngine::init");
+
+ initGraphics(512, 342, true);
+
+ // Create debugger console. It requires GFX to be initialized
+ _console = new Console(this);
+
+ _debugger = new Debugger(this);
+
+ // Your main event loop should be (invoked from) here.
+ _resManager = new Common::MacResManager();
+ if (!_resManager->open(getGameFile()))
+ error("Could not open %s as a resource fork", getGameFile());
+
+ _world = new World(this);
+
+ if (!_world->loadWorld(_resManager))
+ return Common::kNoGameDataFoundError;
+
+ _gui = new Gui(this);
+
+ _temporarilyHidden = true;
+ performInitialSetup();
+ Common::String input("look");
+ processTurn(&input, NULL);
+ _temporarilyHidden = false;
+
+ _shouldQuit = false;
+
+ while (!_shouldQuit) {
+ _debugger->onFrame();
+
+ processEvents();
+
+ _gui->draw();
+ g_system->updateScreen();
+ g_system->delayMillis(50);
+ }
+
+ return Common::kNoError;
+}
+
+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_KEYDOWN:
+ switch (event.kbd.keycode) {
+ case Common::KEYCODE_BACKSPACE:
+ if (!_inputText.empty()) {
+ _inputText.deleteLastChar();
+ _gui->drawInput();
+ }
+ break;
+
+ case Common::KEYCODE_RETURN:
+ if (_inputText.empty())
+ break;
+
+ processTurn(&_inputText, NULL);
+ _gui->disableUndo();
+ break;
+
+ default:
+ if (event.kbd.ascii == '~') {
+ _debugger->attach();
+ break;
+ }
+
+ if (event.kbd.ascii >= 0x20 && event.kbd.ascii <= 0x7f) {
+ _inputText += (char)event.kbd.ascii;
+ _gui->drawInput();
+ }
+
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void WageEngine::setMenu(Common::String menu) {
+ _world->_commandsMenu = menu;
+
+ _gui->regenCommandsMenu();
+}
+
+void WageEngine::appendText(const char *str) {
+ _gui->appendText(str);
+
+ _inputText.clear();
+}
+
+void WageEngine::gameOver() {
+ DialogButtonArray buttons;
+
+ buttons.push_back(new DialogButton("OK", 66, 67, 68, 28));
+
+ Dialog gameOverDialog(_gui, 199, _world->_gameOverMessage->c_str(), &buttons, 0);
+
+ gameOverDialog.run();
+
+ doClose();
+
+ _gui->disableAllMenus();
+ _gui->enableNewGameMenus();
+}
+
+bool WageEngine::saveDialog() {
+ DialogButtonArray buttons;
+
+ buttons.push_back(new DialogButton("No", 19, 67, 68, 28));
+ buttons.push_back(new DialogButton("Yes", 112, 67, 68, 28));
+ buttons.push_back(new DialogButton("Cancel", 205, 67, 68, 28));
+
+ Dialog save(_gui, 291, "Save changes before closing?", &buttons, 1);
+
+ int button = save.run();
+
+ if (button == 2) // Cancel
+ return false;
+
+ if (button == 1)
+ saveGame();
+
+ doClose();
+
+ return true;
+}
+
+void WageEngine::saveGame() {
+ warning("STUB: saveGame()");
+}
+
+void WageEngine::performInitialSetup() {
+ debug(5, "Resetting Objs: %d", _world->_orderedObjs.size());
+ for (uint i = 0; i < _world->_orderedObjs.size() - 1; i++)
+ _world->move(_world->_orderedObjs[i], _world->_storageScene, true);
+
+ _world->move(_world->_orderedObjs[_world->_orderedObjs.size() - 1], _world->_storageScene);
+
+ debug(5, "Resetting Chrs: %d", _world->_orderedChrs.size());
+ for (uint i = 0; i < _world->_orderedChrs.size() - 1; i++)
+ _world->move(_world->_orderedChrs[i], _world->_storageScene, true);
+
+ _world->move(_world->_orderedChrs[_world->_orderedChrs.size() - 1], _world->_storageScene);
+
+ debug(5, "Resetting Owners: %d", _world->_orderedObjs.size());
+ for (uint i = 0; i < _world->_orderedObjs.size(); i++) {
+ Obj *obj = _world->_orderedObjs[i];
+ if (!isStorageScene(obj->_sceneOrOwner)) {
+ Common::String location = obj->_sceneOrOwner;
+ location.toLowercase();
+ 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());
+ } else {
+ // TODO: Add check for max items.
+ _world->move(obj, _world->_chrs[location]);
+ }
+ }
+ }
+ }
+
+ bool playerPlaced = false;
+ for (uint i = 0; i < _world->_orderedChrs.size(); i++) {
+ Chr *chr = _world->_orderedChrs[i];
+ if (!isStorageScene(chr->_initialScene)) {
+ Common::String key = chr->_initialScene;
+ key.toLowercase();
+ if (_world->_scenes.contains(key) && _world->_scenes[key] != NULL) {
+ _world->move(chr, _world->_scenes[key]);
+
+ if (chr->_playerCharacter)
+ debug(0, "Initial scene: %s", key.c_str());
+ } else {
+ _world->move(chr, _world->getRandomScene());
+ }
+ if (chr->_playerCharacter) {
+ playerPlaced = true;
+ }
+ }
+ chr->wearObjs();
+ }
+ if (!playerPlaced) {
+ _world->move(_world->_player, _world->getRandomScene());
+ }
+}
+
+void WageEngine::doClose() {
+ warning("STUB: doClose()");
+}
+
+Scene *WageEngine::getSceneByName(Common::String &location) {
+ if (location.equals("random@")) {
+ return _world->getRandomScene();
+ } else {
+ if (_world->_scenes.contains(location))
+ return _world->_scenes[location];
+ else
+ return NULL;
+ }
+}
+
+void WageEngine::onMove(Designed *what, Designed *from, Designed *to) {
+ Chr *player = _world->_player;
+ Scene *currentScene = player->_currentScene;
+ if (currentScene == _world->_storageScene && !_temporarilyHidden) {
+ if (!_isGameOver) {
+ _isGameOver = true;
+ gameOver();
+ }
+ return;
+ }
+
+ if (from == currentScene || to == currentScene ||
+ (what->_classType == CHR && ((Chr *)what)->_currentScene == currentScene) ||
+ (what->_classType == OBJ && ((Obj *)what)->_currentScene == currentScene))
+ _gui->setSceneDirty();
+
+ if ((from == player || to == player) && !_temporarilyHidden)
+ _gui->regenWeaponsMenu();
+
+ if (what != player && what->_classType == CHR) {
+ Chr *chr = (Chr *)what;
+ if (to == _world->_storageScene) {
+ int returnTo = chr->_returnTo;
+ if (returnTo != Chr::RETURN_TO_STORAGE) {
+ Common::String returnToSceneName;
+ if (returnTo == Chr::RETURN_TO_INITIAL_SCENE) {
+ returnToSceneName = chr->_initialScene;
+ returnToSceneName.toLowercase();
+ } else {
+ returnToSceneName = "random@";
+ }
+ Scene *scene = getSceneByName(returnToSceneName);
+ if (scene != NULL && scene != _world->_storageScene) {
+ _world->move(chr, scene);
+ // To avoid sleeping twice, return if the above move command would cause a sleep.
+ if (scene == currentScene)
+ return;
+ }
+ }
+ } else if (to == player->_currentScene) {
+ if (getMonster() == NULL) {
+ _monster = chr;
+ encounter(player, chr);
+ }
+ }
+ }
+ if (!_temporarilyHidden) {
+ if (to == currentScene || from == currentScene) {
+ redrawScene();
+ g_system->updateScreen();
+ g_system->delayMillis(100);
+ }
+ }
+}
+
+void WageEngine::redrawScene() {
+ Scene *currentScene = _world->_player->_currentScene;
+
+ if (currentScene != NULL) {
+ bool firstTime = (_lastScene != currentScene);
+
+ _gui->draw();
+ updateSoundTimerForScene(currentScene, firstTime);
+ }
+}
+
+void WageEngine::processTurnInternal(Common::String *textInput, Designed *clickInput) {
+ Scene *playerScene = _world->_player->_currentScene;
+ if (playerScene == _world->_storageScene)
+ return;
+
+ bool shouldEncounter = false;
+
+ if (playerScene != _lastScene) {
+ _loopCount = 0;
+ _lastScene = playerScene;
+ _monster = NULL;
+ _running = NULL;
+ _offer = NULL;
+
+ for (ChrList::const_iterator it = playerScene->_chrs.begin(); it != playerScene->_chrs.end(); ++it) {
+ if (!(*it)->_playerCharacter) {
+ _monster = *it;
+ shouldEncounter = true;
+ break;
+ }
+ }
+ }
+
+ bool monsterWasNull = (_monster == NULL);
+ Script *script = playerScene->_script != NULL ? playerScene->_script : _world->_globalScript;
+ bool handled = script->execute(_world, _loopCount++, textInput, clickInput, this);
+
+ playerScene = _world->_player->_currentScene;
+
+ if (playerScene == _world->_storageScene)
+ return;
+
+ if (playerScene != _lastScene) {
+ _temporarilyHidden = true;
+ _gui->clearOutput();
+ regen();
+ Common::String input("look");
+ processTurnInternal(&input, NULL);
+ redrawScene();
+ _temporarilyHidden = false;
+ } else if (_loopCount == 1) {
+ redrawScene();
+ if (shouldEncounter && getMonster() != NULL) {
+ encounter(_world->_player, _monster);
+ }
+ } else if (textInput != NULL && !handled) {
+ if (monsterWasNull && getMonster() != NULL)
+ return;
+
+ const char *rant = _rnd->getRandomNumber(1) ? "What?" : "Huh?";
+
+ appendText(rant);
+ _commandWasQuick = true;
+ }
+}
+
+void WageEngine::processTurn(Common::String *textInput, Designed *clickInput) {
+ _commandWasQuick = false;
+ Scene *prevScene = _world->_player->_currentScene;
+ Chr *prevMonster = getMonster();
+ Common::String input;
+
+ if (textInput)
+ input = *textInput;
+
+ input.toLowercase();
+ if (input.equals("e"))
+ input = "east";
+ else if (input.equals("w"))
+ input = "west";
+ else if (input.equals("n"))
+ input = "north";
+ else if (input.equals("s"))
+ input = "south";
+
+ processTurnInternal(&input, clickInput);
+ Scene *playerScene = _world->_player->_currentScene;
+
+ if (prevScene != playerScene && playerScene != _world->_storageScene) {
+ if (prevMonster != NULL) {
+ bool followed = false;
+ if (getMonster() == NULL) {
+ // TODO: adjacent scenes doesn't contain up/down etc... verify that monsters can't follow these...
+ if (_world->scenesAreConnected(playerScene, prevMonster->_currentScene)) {
+ int chance = _rnd->getRandomNumber(255);
+ followed = (chance < prevMonster->_followsOpponent);
+ }
+ }
+
+ char buf[512];
+
+ if (followed) {
+ snprintf(buf, 512, "%s%s follows you.", prevMonster->getDefiniteArticle(true), prevMonster->_name.c_str());
+ appendText(buf);
+
+ _world->move(prevMonster, playerScene);
+ } else {
+ snprintf(buf, 512, "You escape %s%s.", prevMonster->getDefiniteArticle(false), prevMonster->_name.c_str());
+ appendText(buf);
+ }
+ }
+ }
+ if (!_commandWasQuick && getMonster() != NULL) {
+ performCombatAction(getMonster(), _world->_player);
+ }
+
+ _inputText.clear();
+ _gui->appendText("");
+}
+
+
+} // End of namespace Wage
diff --git a/engines/wage/wage.h b/engines/wage/wage.h
new file mode 100644
index 0000000000..eb50a2e3dd
--- /dev/null
+++ b/engines/wage/wage.h
@@ -0,0 +1,232 @@
+/* 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_WAGE_H
+#define WAGE_WAGE_H
+
+#include "engines/engine.h"
+#include "common/debug.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 {
+
+class Console;
+class Chr;
+class Designed;
+class Dialog;
+class Gui;
+class Obj;
+class Scene;
+class World;
+
+typedef Common::Array<Obj *> ObjArray;
+typedef Common::Array<Chr *> ChrArray;
+typedef Common::List<Obj *> ObjList;
+typedef Common::List<Chr *> ChrList;
+
+#define STORAGESCENE "STORAGE@"
+
+enum OperandType {
+ OBJ = 0,
+ CHR = 1,
+ SCENE = 2,
+ NUMBER = 3,
+ STRING = 4,
+ CLICK_INPUT = 5,
+ TEXT_INPUT = 6,
+ UNKNOWN = 100
+};
+
+enum Directions {
+ NORTH = 0,
+ SOUTH = 1,
+ EAST = 2,
+ WEST = 3
+};
+
+// our engine debug levels
+enum {
+ kWageDebugExample = 1 << 0,
+ kWageDebugExample2 = 1 << 1
+ // next new level must be 1 << 2 (4)
+ // the current limitation is 32 debug levels (1 << 31 is the last one)
+};
+
+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);
+bool isStorageScene(const Common::String &name);
+
+class WageEngine : public Engine {
+ friend class Dialog;
+public:
+ WageEngine(OSystem *syst, const ADGameDescription *gameDesc);
+ ~WageEngine();
+
+ virtual bool hasFeature(EngineFeature f) const;
+
+ virtual Common::Error run();
+
+ bool canLoadGameStateCurrently();
+ bool canSaveGameStateCurrently();
+
+ const char *getGameFile() const;
+ void processTurn(Common::String *textInput, Designed *clickInput);
+ void regen();
+
+private:
+ bool loadWorld(Common::MacResManager *resMan);
+ void performInitialSetup();
+ void wearObjs(Chr *chr);
+ void processTurnInternal(Common::String *textInput, Designed *clickInput);
+ void performCombatAction(Chr *npc, Chr *player);
+ int getValidMoveDirections(Chr *npc);
+ void performAttack(Chr *attacker, Chr *victim, Obj *weapon);
+ void performMagic(Chr *attacker, Chr *victim, Obj *magicalObject);
+ void performMove(Chr *chr, int validMoves);
+ void performOffer(Chr *attacker, Chr *victim);
+ void performTake(Chr *npc, Obj *obj);
+ void decrementUses(Obj *obj);
+ bool attackHit(Chr *attacker, Chr *victim, Obj *weapon, int targetIndex);
+ void performHealingMagic(Chr *chr, Obj *magicalObject);
+
+ void doClose();
+ void updateSoundTimerForScene(Scene *scene, bool firstTime);
+
+public:
+ void takeObj(Obj *obj);
+
+ bool handleMoveCommand(Directions dir, const char *dirName);
+ bool handleLookCommand();
+ Common::String *getGroundItemsList(Scene *scene);
+ void appendObjNames(Common::String &str, const ObjArray &objs);
+ bool handleInventoryCommand();
+ bool handleStatusCommand();
+ bool handleRestCommand();
+ bool handleAcceptCommand();
+
+ bool handleTakeCommand(const char *target);
+ bool handleDropCommand(const char *target);
+ bool handleAimCommand(const char *target);
+ bool handleWearCommand(const char *target);
+ bool handleOfferCommand(const char *target);
+
+ void wearObj(Obj *o, int pos);
+
+ bool tryAttack(const Obj *weapon, const Common::String &input);
+ bool handleAttack(Obj *weapon);
+
+ void printPlayerCondition(Chr *player);
+ const char *getPercentMessage(double percent);
+
+public:
+ Common::RandomSource *_rnd;
+
+ Debugger *_debugger;
+
+ Gui *_gui;
+ World *_world;
+
+ Scene *_lastScene;
+ int _loopCount;
+ int _turn;
+ Chr *_monster;
+ Chr *_running;
+ Obj *_offer;
+ int _aim;
+ int _opponentAim;
+ bool _temporarilyHidden;
+ bool _isGameOver;
+ bool _commandWasQuick;
+
+ Common::String _inputText;
+
+ void playSound(Common::String soundName);
+ void setMenu(Common::String soundName);
+ void appendText(const char *str);
+ void gameOver();
+ bool saveDialog();
+ Obj *getOffer();
+ Chr *getMonster();
+ void processEvents();
+ Scene *getSceneByName(Common::String &location);
+ void onMove(Designed *what, Designed *from, Designed *to);
+ void encounter(Chr *player, Chr *chr);
+ void redrawScene();
+ void saveGame();
+
+ virtual GUI::Debugger *getDebugger() { return _debugger; }
+
+private:
+ Console *_console;
+
+ const ADGameDescription *_gameDescription;
+
+ Common::MacResManager *_resManager;
+
+ bool _shouldQuit;
+};
+
+// Example console class
+class Console : public GUI::Debugger {
+public:
+ Console(WageEngine *vm) {}
+ virtual ~Console(void) {}
+};
+
+} // End of namespace Wage
+
+#endif
diff --git a/engines/wage/world.cpp b/engines/wage/world.cpp
new file mode 100644
index 0000000000..0e40e114b4
--- /dev/null
+++ b/engines/wage/world.cpp
@@ -0,0 +1,541 @@
+/* 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/file.h"
+
+#include "wage/wage.h"
+#include "wage/entities.h"
+#include "wage/script.h"
+#include "wage/sound.h"
+#include "wage/world.h"
+
+namespace Wage {
+
+World::World(WageEngine *engine) {
+ _storageScene = new Scene;
+ _storageScene->_name = STORAGESCENE;
+
+ _orderedScenes.push_back(_storageScene);
+ _scenes[STORAGESCENE] = _storageScene;
+
+ _gameOverMessage = nullptr;
+ _saveBeforeQuitMessage = nullptr;
+ _saveBeforeCloseMessage = nullptr;
+ _revertMessage = nullptr;
+
+ _globalScript = nullptr;
+ _player = nullptr;
+
+ _weaponMenuDisabled = true;
+
+ _engine = engine;
+
+ _patterns = new Patterns;
+}
+
+World::~World() {
+ for (uint i = 0; i < _orderedObjs.size(); i++)
+ delete _orderedObjs[i];
+
+ for (uint i = 0; i < _orderedChrs.size(); i++)
+ delete _orderedChrs[i];
+
+ for (uint i = 0; i < _orderedSounds.size(); i++)
+ delete _orderedSounds[i];
+
+ for (uint i = 0; i < _orderedScenes.size(); i++)
+ delete _orderedScenes[i];
+
+ for (uint i = 0; i < _patterns->size(); i++)
+ free(_patterns->operator[](i));
+
+ delete _patterns;
+
+ delete _globalScript;
+
+ delete _gameOverMessage;
+ delete _saveBeforeQuitMessage;
+ delete _saveBeforeCloseMessage;
+ delete _revertMessage;
+
+}
+
+bool World::loadWorld(Common::MacResManager *resMan) {
+ Common::MacResIDArray resArray;
+ 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;
+
+ // Load global script
+ res = resMan->getResource(MKTAG('G','C','O','D'), resArray[0]);
+ _globalScript = new Script(res);
+
+ // TODO: read creator
+
+ // Load main configuration
+ if ((resArray = resMan->getResIDArray(MKTAG('V','E','R','S'))).size() == 0)
+ return false;
+
+ _name = resMan->getBaseFileName();
+
+ if (resArray.size() > 1)
+ warning("Too many VERS resources");
+
+ if (!resArray.empty()) {
+ debug(3, "Loading version info");
+
+ res = resMan->getResource(MKTAG('V','E','R','S'), resArray[0]);
+
+ res->skip(10);
+ byte b = res->readByte();
+ _weaponMenuDisabled = (b != 0);
+ if (b != 0 && b != 1)
+ error("Unexpected value for weapons menu");
+
+ res->skip(3);
+ _aboutMessage = readPascalString(res);
+
+ if (!scumm_stricmp(resMan->getBaseFileName().c_str(), "Scepters"))
+ res->skip(1); // ????
+
+ _soundLibrary1 = readPascalString(res);
+ _soundLibrary2 = readPascalString(res);
+
+ delete res;
+ }
+
+ Common::String *message;
+ if ((message = loadStringFromDITL(resMan, 2910, 1)) != NULL) {
+ message->trim();
+ debug(2, "_gameOverMessage: %s", message->c_str());
+ _gameOverMessage = message;
+ }
+ if ((message = loadStringFromDITL(resMan, 2480, 3)) != NULL) {
+ message->trim();
+ debug(2, "_saveBeforeQuitMessage: %s", message->c_str());
+ _saveBeforeQuitMessage = message;
+ }
+ if ((message = loadStringFromDITL(resMan, 2490, 3)) != NULL) {
+ message->trim();
+ debug(2, "_saveBeforeCloseMessage: %s", message->c_str());
+ _saveBeforeCloseMessage = message;
+ }
+ if ((message = loadStringFromDITL(resMan, 2940, 2)) != NULL) {
+ message->trim();
+ debug(2, "_revertMessage: %s", message->c_str());
+ _revertMessage = message;
+ }
+
+ // Load scenes
+ resArray = resMan->getResIDArray(MKTAG('A','S','C','N'));
+ debug(3, "Loading %d scenes", resArray.size());
+
+ for (iter = resArray.begin(); iter != resArray.end(); ++iter) {
+ res = resMan->getResource(MKTAG('A','S','C','N'), *iter);
+ Scene *scene = new Scene(resMan->getResName(MKTAG('A','S','C','N'), *iter), res);
+
+ res = resMan->getResource(MKTAG('A','C','O','D'), *iter);
+ if (res != NULL)
+ scene->_script = new Script(res);
+
+ res = resMan->getResource(MKTAG('A','T','X','T'), *iter);
+ if (res != NULL) {
+ scene->_textBounds = readRect(res);
+ scene->_fontType = res->readUint16BE();
+ scene->_fontSize = res->readUint16BE();
+
+ Common::String text;
+ while (res->pos() < res->size()) {
+ char c = res->readByte();
+ if (c == 0x0d)
+ c = '\n';
+ text += c;
+ }
+ scene->_text = text;
+
+ delete res;
+ }
+ addScene(scene);
+ }
+
+ // Load Objects
+ resArray = resMan->getResIDArray(MKTAG('A','O','B','J'));
+ debug(3, "Loading %d objects", resArray.size());
+
+ for (iter = resArray.begin(); iter != resArray.end(); ++iter) {
+ res = resMan->getResource(MKTAG('A','O','B','J'), *iter);
+ addObj(new Obj(resMan->getResName(MKTAG('A','O','B','J'), *iter), res));
+ }
+
+ // Load Characters
+ resArray = resMan->getResIDArray(MKTAG('A','C','H','R'));
+ debug(3, "Loading %d characters", resArray.size());
+
+ for (iter = resArray.begin(); iter != resArray.end(); ++iter) {
+ res = resMan->getResource(MKTAG('A','C','H','R'), *iter);
+ Chr *chr = new Chr(resMan->getResName(MKTAG('A','C','H','R'), *iter), res);
+
+ addChr(chr);
+ // TODO: What if there's more than one player character?
+ if (chr->_playerCharacter)
+ _player = chr;
+ }
+
+ // Load Sounds
+ resArray = resMan->getResIDArray(MKTAG('A','S','N','D'));
+ debug(3, "Loading %d sounds", resArray.size());
+
+ for (iter = resArray.begin(); iter != resArray.end(); ++iter) {
+ res = resMan->getResource(MKTAG('A','S','N','D'), *iter);
+ addSound(new Sound(resMan->getResName(MKTAG('A','S','N','D'), *iter), res));
+ }
+
+ if (!_soundLibrary1.empty()) {
+ loadExternalSounds(_soundLibrary1);
+ }
+ if (!_soundLibrary2.empty()) {
+ loadExternalSounds(_soundLibrary2);
+ }
+
+ // Load Patterns
+ res = resMan->getResource(MKTAG('P','A','T','#'), 900);
+ if (res != NULL) {
+ int count = res->readUint16BE();
+ debug(3, "Loading %d patterns", count);
+
+ for (int i = 0; i < count; i++) {
+ byte *pattern = (byte *)malloc(8);
+
+ res->read(pattern, 8);
+ _patterns->push_back(pattern);
+ }
+
+ delete res;
+ } else {
+ /* Enchanted Scepters did not use the PAT# resource for the textures. */
+ res = resMan->getResource(MKTAG('C','O','D','E'), 1);
+ if (res != NULL) {
+ res->skip(0x55ac);
+ for (int i = 0; i < 29; i++) {
+ byte *pattern = (byte *)malloc(8);
+
+ res->read(pattern, 8);
+ _patterns->push_back(pattern);
+ }
+ }
+ delete res;
+ }
+
+ res = resMan->getResource(MKTAG('M','E','N','U'), 2001);
+ if (res != NULL) {
+ Common::StringArray *menu = readMenu(res);
+ _aboutMenuItemName.clear();
+ Common::String string = menu->operator[](1);
+
+ for (uint i = 0; i < string.size() && string[i] != ';'; i++) // Read token
+ _aboutMenuItemName += string[i];
+
+ delete menu;
+ delete res;
+ }
+ res = resMan->getResource(MKTAG('M','E','N','U'), 2004);
+ if (res != NULL) {
+ Common::StringArray *menu = readMenu(res);
+ _commandsMenuName = menu->operator[](0);
+ _commandsMenu = menu->operator[](1);
+ delete menu;
+ delete res;
+ }
+ res = resMan->getResource(MKTAG('M','E','N','U'), 2005);
+ if (res != NULL) {
+ Common::StringArray *menu = readMenu(res);
+ _weaponsMenuName = menu->operator[](0);
+ delete menu;
+ delete res;
+ }
+ // TODO: Read Apple menu and get the name of that menu item..
+
+ // store global info in state object for use with save/load actions
+ //world.setCurrentState(initialState); // pass off the state object to the world
+
+ return true;
+}
+
+void World::addSound(Sound *sound) {
+ Common::String s = sound->_name;
+ s.toLowercase();
+ _sounds[s] = sound;
+ _orderedSounds.push_back(sound);
+}
+
+Common::StringArray *World::readMenu(Common::SeekableReadStream *res) {
+ res->skip(10);
+ int enableFlags = res->readUint32BE();
+ Common::String menuName = readPascalString(res);
+ Common::String menuItem = readPascalString(res);
+ int menuItemNumber = 1;
+ Common::String menu;
+ byte itemData[4];
+
+ while (!menuItem.empty()) {
+ if (!menu.empty()) {
+ menu += ';';
+ }
+ if ((enableFlags & (1 << menuItemNumber)) == 0) {
+ menu += '(';
+ }
+ menu += menuItem;
+ res->read(itemData, 4);
+ static const char styles[] = {'B', 'I', 'U', 'O', 'S', 'C', 'E', 0};
+ for (int i = 0; styles[i] != 0; i++) {
+ if ((itemData[3] & (1 << i)) != 0) {
+ menu += '<';
+ menu += styles[i];
+ }
+ }
+ if (itemData[1] != 0) {
+ menu += '/';
+ menu += (char)itemData[1];
+ }
+ menuItem = readPascalString(res);
+ menuItemNumber++;
+ }
+
+ Common::StringArray *result = new Common::StringArray;
+ result->push_back(menuName);
+ result->push_back(menu);
+
+ debug(4, "menuName: %s", menuName.c_str());
+ debug(4, "menu: %s", menu.c_str());
+
+ return result;
+}
+
+void World::loadExternalSounds(Common::String fname) {
+ Common::File in;
+
+ in.open(fname);
+ if (!in.isOpen()) {
+ warning("Cannot load sound file <%s>", fname.c_str());
+ return;
+ }
+ in.close();
+
+ Common::MacResManager resMan;
+ resMan.open(fname);
+
+ Common::MacResIDArray resArray;
+ Common::SeekableReadStream *res;
+ Common::MacResIDArray::const_iterator iter;
+
+ resArray = resMan.getResIDArray(MKTAG('A','S','N','D'));
+ for (iter = resArray.begin(); iter != resArray.end(); ++iter) {
+ res = resMan.getResource(MKTAG('A','S','N','D'), *iter);
+ addSound(new Sound(resMan.getResName(MKTAG('A','S','N','D'), *iter), res));
+ }
+}
+
+Common::String *World::loadStringFromDITL(Common::MacResManager *resMan, int resourceId, int itemIndex) {
+ Common::SeekableReadStream *res = resMan->getResource(MKTAG('D','I','T','L'), resourceId);
+ if (res) {
+ int itemCount = res->readSint16BE();
+ for (int i = 0; i <= itemCount; i++) {
+ // int placeholder; short rect[4]; byte flags; pstring str;
+ res->skip(13);
+ Common::String message = readPascalString(res);
+ if (i == itemIndex) {
+ Common::String *msg = new Common::String(message);
+ delete res;
+ return msg;
+ }
+ }
+
+ delete res;
+ }
+
+ return NULL;
+}
+
+static bool invComparator(const Obj *l, const Obj *r) {
+ return l->_index < r->_index;
+}
+
+void World::move(Obj *obj, Chr *chr) {
+ if (obj == NULL)
+ return;
+
+ Designed *from = obj->removeFromCharOrScene();
+ obj->_currentOwner = chr;
+ chr->_inventory.push_back(obj);
+
+ Common::sort(chr->_inventory.begin(), chr->_inventory.end(), invComparator);
+
+ _engine->onMove(obj, from, chr);
+}
+
+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 o1Immobile;
+}
+
+void World::move(Obj *obj, Scene *scene, bool skipSort) {
+ if (obj == NULL)
+ return;
+
+ Designed *from = obj->removeFromCharOrScene();
+ obj->_currentScene = scene;
+ scene->_objs.push_back(obj);
+
+ if (!skipSort)
+ Common::sort(scene->_objs.begin(), scene->_objs.end(), objComparator);
+
+ _engine->onMove(obj, from, scene);
+}
+
+static bool chrComparator(const Chr *l, const Chr *r) {
+ return l->_index < r->_index;
+}
+
+void World::move(Chr *chr, Scene *scene, bool skipSort) {
+ if (chr == NULL)
+ return;
+ Scene *from = chr->_currentScene;
+ if (from == scene)
+ return;
+ if (from != NULL)
+ from->_chrs.remove(chr);
+ scene->_chrs.push_back(chr);
+
+ if (!skipSort)
+ Common::sort(scene->_chrs.begin(), scene->_chrs.end(), chrComparator);
+
+ if (scene == _storageScene) {
+ chr->resetState();
+ } else if (chr->_playerCharacter) {
+ scene->_visited = true;
+ _player->_context._visits++;
+ }
+ chr->_currentScene = scene;
+
+ _engine->onMove(chr, from, scene);
+}
+
+Scene *World::getRandomScene() {
+ // Not including storage:
+ return _orderedScenes[1 + _engine->_rnd->getRandomNumber(_orderedScenes.size() - 2)];
+}
+
+Scene *World::getSceneAt(int x, int y) {
+ for (uint i = 0; i < _orderedScenes.size(); i++) {
+ Scene *scene = _orderedScenes[i];
+
+ if (scene != _storageScene && scene->_worldX == x && scene->_worldY == y) {
+ return scene;
+ }
+ }
+ return NULL;
+}
+
+static const int directionsX[] = { 0, 0, 1, -1 };
+static const int directionsY[] = { -1, 1, 0, 0 };
+
+bool World::scenesAreConnected(Scene *scene1, Scene *scene2) {
+ if (!scene1 || !scene2)
+ return false;
+
+ int x = scene2->_worldX;
+ int y = scene2->_worldY;
+
+ for (int dir = 0; dir < 4; dir++)
+ if (!scene2->_blocked[dir])
+ if (getSceneAt(x + directionsX[dir], y + directionsY[dir]) == scene1)
+ return true;
+
+ return false;
+}
+
+const char *World::getAboutMenuItemName() {
+ static char menu[256];
+
+ *menu = '\0';
+
+ if (_aboutMenuItemName.empty()) {
+ sprintf(menu, "About %s...", _name.c_str());
+ } else { // Replace '@' with name
+ const char *str = _aboutMenuItemName.c_str();
+ const char *pos = strchr(str, '@');
+ if (pos) {
+ strncat(menu, str, (pos - str));
+ strncat(menu, _name.c_str(), 255);
+ strncat(menu, pos + 1, 255);
+ }
+ }
+
+ return menu;
+}
+
+} // End of namespace Wage
diff --git a/engines/wage/world.h b/engines/wage/world.h
new file mode 100644
index 0000000000..468bedbc59
--- /dev/null
+++ b/engines/wage/world.h
@@ -0,0 +1,138 @@
+/* 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_WORLD_H
+#define WAGE_WORLD_H
+
+#include "wage/macwindowmanager.h"
+
+namespace Wage {
+
+class Sound;
+
+class World {
+public:
+ World(WageEngine *engine);
+ ~World();
+
+ bool loadWorld(Common::MacResManager *resMan);
+ void loadExternalSounds(Common::String fname);
+ Common::String *loadStringFromDITL(Common::MacResManager *resMan, int resourceId, int itemIndex);
+ void move(Obj *obj, Chr *chr);
+ void move(Obj *obj, Scene *scene, bool skipSort = false);
+ void move(Chr *chr, Scene *scene, bool skipSort = false);
+ Scene *getRandomScene();
+ Scene *getSceneAt(int x, int y);
+ bool scenesAreConnected(Scene *scene1, Scene *scene2);
+ const char *getAboutMenuItemName();
+
+ WageEngine *_engine;
+
+ Common::String _name;
+ Common::String _aboutMessage;
+ Common::String _soundLibrary1;
+ Common::String _soundLibrary2;
+
+ bool _weaponMenuDisabled;
+ Script *_globalScript;
+ Common::HashMap<Common::String, Scene *> _scenes;
+ Common::HashMap<Common::String, Obj *> _objs;
+ Common::HashMap<Common::String, Chr *> _chrs;
+ Common::HashMap<Common::String, Sound *> _sounds;
+ Common::Array<Scene *> _orderedScenes;
+ ObjArray _orderedObjs;
+ ChrArray _orderedChrs;
+ Common::Array<Sound *> _orderedSounds;
+ Patterns *_patterns;
+ Scene *_storageScene;
+ Chr *_player;
+ //List<MoveListener> moveListeners;
+
+ Common::String *_gameOverMessage;
+ Common::String *_saveBeforeQuitMessage;
+ Common::String *_saveBeforeCloseMessage;
+ Common::String *_revertMessage;
+
+ Common::String _aboutMenuItemName;
+ Common::String _commandsMenuName;
+ Common::String _commandsMenu;
+ Common::String _weaponsMenuName;
+
+ void addScene(Scene *room) {
+ if (!room->_name.empty()) {
+ Common::String s = room->_name;
+ s.toLowercase();
+ _scenes[s] = room;
+ }
+ _orderedScenes.push_back(room);
+ }
+
+ void addObj(Obj *obj) {
+ Common::String s = obj->_name;
+ s.toLowercase();
+ _objs[s] = obj;
+ obj->_index = _orderedObjs.size();
+ _orderedObjs.push_back(obj);
+ }
+
+ void addChr(Chr *chr) {
+ Common::String s = chr->_name;
+ s.toLowercase();
+ _chrs[s] = chr;
+ chr->_index = _orderedChrs.size();
+ _orderedChrs.push_back(chr);
+ }
+
+ void addSound(Sound *sound);
+
+private:
+ Common::StringArray *readMenu(Common::SeekableReadStream *res);
+};
+
+} // End of namespace Wage
+
+#endif
diff --git a/engines/wintermute/ad/ad_actor.cpp b/engines/wintermute/ad/ad_actor.cpp
index 9d5a35464a..4661d3bca0 100644
--- a/engines/wintermute/ad/ad_actor.cpp
+++ b/engines/wintermute/ad/ad_actor.cpp
@@ -958,13 +958,13 @@ bool AdActor::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack,
stack->correctParams(1);
ScValue *val = stack->pop();
if (!val->isNative()) {
- script->runtimeError("actor.%s method accepts an entity refrence only", name);
+ script->runtimeError("actor.%s method accepts an entity reference only", name);
stack->pushNULL();
return STATUS_OK;
}
AdObject *obj = (AdObject *)val->getNative();
if (!obj || obj->getType() != OBJECT_ENTITY) {
- script->runtimeError("actor.%s method accepts an entity refrence only", name);
+ script->runtimeError("actor.%s method accepts an entity reference only", name);
stack->pushNULL();
return STATUS_OK;
}
diff --git a/engines/wintermute/ad/ad_entity.cpp b/engines/wintermute/ad/ad_entity.cpp
index 1bbadeb7f7..0909d7ef91 100644
--- a/engines/wintermute/ad/ad_entity.cpp
+++ b/engines/wintermute/ad/ad_entity.cpp
@@ -1134,4 +1134,7 @@ bool AdEntity::setSprite(const char *filename) {
}
}
+Common::String AdEntity::debuggerToString() const {
+ return Common::String::format("%p: Entity \"%s\"; (X,Y): (%d, %d), rotate(%d): %f deg, scale(%d): (%f, %f)%%", (const void *)this, getName(), _posX, _posY, _rotatable, _rotate, _zoomable, _scaleX, _scaleY);
+}
} // End of namespace Wintermute
diff --git a/engines/wintermute/ad/ad_entity.h b/engines/wintermute/ad/ad_entity.h
index 7e1525b7c1..678608af36 100644
--- a/engines/wintermute/ad/ad_entity.h
+++ b/engines/wintermute/ad/ad_entity.h
@@ -60,6 +60,7 @@ public:
virtual bool scSetProperty(const char *name, ScValue *value) override;
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override;
virtual const char *scToString() override;
+ Common::String debuggerToString() const override;
private:
int32 _walkToX;
int32 _walkToY;
diff --git a/engines/wintermute/ad/ad_game.cpp b/engines/wintermute/ad/ad_game.cpp
index 3c4383f55e..088184b0f6 100644
--- a/engines/wintermute/ad/ad_game.cpp
+++ b/engines/wintermute/ad/ad_game.cpp
@@ -2261,7 +2261,7 @@ bool AdGame::onMouseRightUp() {
bool AdGame::displayDebugInfo() {
char str[100];
if (_gameRef->_debugDebugMode) {
- sprintf(str, "Mouse: %d, %d (scene: %d, %d)", _mousePos.x, _mousePos.y, _mousePos.x + _scene->getOffsetLeft(), _mousePos.y + _scene->getOffsetTop());
+ sprintf(str, "Mouse: %d, %d (scene: %d, %d)", _mousePos.x, _mousePos.y, _mousePos.x + (_scene ? _scene->getOffsetLeft() : 0), _mousePos.y + (_scene ? _scene->getOffsetTop() : 0));
_systemFont->drawText((byte *)str, 0, 90, _renderer->getWidth(), TAL_RIGHT);
sprintf(str, "Scene: %s (prev: %s)", (_scene && _scene->getName()) ? _scene->getName() : "???", _prevSceneName ? _prevSceneName : "???");
@@ -2280,4 +2280,7 @@ bool AdGame::onScriptShutdown(ScScript *script) {
return STATUS_OK;
}
+Common::String AdGame::debuggerToString() const {
+ return Common::String::format("%p: Game \"%s\"", (const void *)this, getName());
+}
} // End of namespace Wintermute
diff --git a/engines/wintermute/ad/ad_game.h b/engines/wintermute/ad/ad_game.h
index ebb37e9a07..0e5abc9b3b 100644
--- a/engines/wintermute/ad/ad_game.h
+++ b/engines/wintermute/ad/ad_game.h
@@ -130,6 +130,7 @@ public:
virtual bool scSetProperty(const char *name, ScValue *value) override;
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override;
bool validMouse();
+ Common::String debuggerToString() const override;
private:
virtual bool externalCall(ScScript *script, ScStack *stack, ScStack *thisStack, char *name) override;
diff --git a/engines/wintermute/ad/ad_scene.cpp b/engines/wintermute/ad/ad_scene.cpp
index 02a6aeb801..b57faef69b 100644
--- a/engines/wintermute/ad/ad_scene.cpp
+++ b/engines/wintermute/ad/ad_scene.cpp
@@ -2998,4 +2998,9 @@ bool AdScene::getRegionObjects(AdRegion *region, BaseArray<AdObject *> &objects,
return STATUS_OK;
}
+
+Common::String AdScene::debuggerToString() const {
+ return Common::String::format("%p: Scene \"%s\", paralax: %d, autoscroll: %d", (const void *)this, getName(), _paralaxScrolling, _autoScroll);
+}
} // End of namespace Wintermute
+
diff --git a/engines/wintermute/ad/ad_scene.h b/engines/wintermute/ad/ad_scene.h
index 1ca52bdda9..71567d2475 100644
--- a/engines/wintermute/ad/ad_scene.h
+++ b/engines/wintermute/ad/ad_scene.h
@@ -160,7 +160,7 @@ public:
virtual bool scSetProperty(const char *name, ScValue *value) override;
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override;
virtual const char *scToString() override;
-
+ virtual Common::String debuggerToString() const override;
private:
bool persistState(bool saving = true);
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_frame.cpp b/engines/wintermute/base/base_frame.cpp
index 471185f2d2..910ab64a76 100644
--- a/engines/wintermute/base/base_frame.cpp
+++ b/engines/wintermute/base/base_frame.cpp
@@ -764,4 +764,7 @@ const char *BaseFrame::scToString() {
return "[frame]";
}
+Common::String BaseFrame::debuggerToString() const {
+ return Common::String::format("%p: Frame \"%s\": #subframes %d ", (const void *)this, getName(), _subframes.size());
+}
} // End of namespace Wintermute
diff --git a/engines/wintermute/base/base_frame.h b/engines/wintermute/base/base_frame.h
index ff9e67a166..8d261c9e71 100644
--- a/engines/wintermute/base/base_frame.h
+++ b/engines/wintermute/base/base_frame.h
@@ -65,6 +65,8 @@ public:
virtual bool scSetProperty(const char *name, ScValue *value) override;
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override;
virtual const char *scToString() override;
+ virtual Common::String debuggerToString() const override;
+
private:
bool _keyframe;
bool _editorExpanded;
diff --git a/engines/wintermute/base/base_game.cpp b/engines/wintermute/base/base_game.cpp
index 668053bb3a..ce4c5fdda5 100644
--- a/engines/wintermute/base/base_game.cpp
+++ b/engines/wintermute/base/base_game.cpp
@@ -71,6 +71,10 @@
#include "common/system.h"
#include "common/file.h"
+#if EXTENDED_DEBUGGER_ENABLED == true
+#include "engines/wintermute/base/scriptables/debuggable/debuggable_script_engine.h"
+#endif
+
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
@@ -398,7 +402,11 @@ bool BaseGame::initialize1() {
break;
}
+#if EXTENDED_DEBUGGER_ENABLED == true
+ _scEngine = new DebuggableScEngine(this);
+#else
_scEngine = new ScEngine(this);
+#endif
if (_scEngine == nullptr) {
break;
}
diff --git a/engines/wintermute/base/base_game.h b/engines/wintermute/base/base_game.h
index e535cc9618..409cc20ba4 100644
--- a/engines/wintermute/base/base_game.h
+++ b/engines/wintermute/base/base_game.h
@@ -34,7 +34,11 @@
#include "engines/wintermute/persistent.h"
#include "engines/wintermute/coll_templ.h"
#include "engines/wintermute/math/rect32.h"
+#include "engines/wintermute/debugger.h"
#include "common/events.h"
+#if EXTENDED_DEBUGGER_ENABLED == true
+#include "engines/wintermute/base/scriptables/debuggable/debuggable_script_engine.h"
+#endif
namespace Wintermute {
@@ -148,7 +152,11 @@ public:
BaseRenderer *_renderer;
BaseSoundMgr *_soundMgr;
+#if EXTENDED_DEBUGGER_ENABLED == true
+ DebuggableScEngine *_scEngine;
+#else
ScEngine *_scEngine;
+#endif
BaseScriptable *_mathClass;
BaseSurfaceStorage *_surfaceStorage;
BaseFontStorage *_fontStorage;
diff --git a/engines/wintermute/base/base_keyboard_state.cpp b/engines/wintermute/base/base_keyboard_state.cpp
index f672c83d39..d26685a256 100644
--- a/engines/wintermute/base/base_keyboard_state.cpp
+++ b/engines/wintermute/base/base_keyboard_state.cpp
@@ -200,6 +200,12 @@ const char *BaseKeyboardState::scToString() {
bool BaseKeyboardState::readKey(Common::Event *event) {
//_currentPrintable = (event->type == SDL_TEXTINPUT); // TODO
_currentCharCode = keyCodeToVKey(event);
+ // convert all lowercase keys to uppercase to make it easier for handling later on for consistency
+ if (Common::isLower(_currentCharCode) && (event->kbd.hasFlags(Common::KBD_SHIFT) || event->kbd.flags & Common::KBD_CAPS)) {
+ if (!(event->kbd.keycode >= Common::KEYCODE_F1 && event->kbd.keycode <= Common::KEYCODE_F12)) {
+ _currentCharCode = toupper(_currentCharCode);
+ }
+ }
// Verify that this is a printable ISO-8859-character (including the upper charset)
if ((_currentCharCode <= 0x7E && _currentCharCode >= 0x20) || (_currentCharCode <= 0xFF && _currentCharCode >= 0xA0)) {
_currentPrintable = true;
@@ -263,7 +269,11 @@ bool BaseKeyboardState::isCurrentPrintable() const {
//////////////////////////////////////////////////////////////////////////
enum VKeyCodes {
+ kVkBack = 8,
+ kVkTab = 9,
+
kVkReturn = 13,
+ kVkPause = 19,
kVkEscape = 27,
@@ -274,6 +284,7 @@ enum VKeyCodes {
kVkUp = 38,
kVkRight = 39,
kVkDown = 40,
+ kVkInsert = 45,
kVkF1 = 112,
kVkF2 = 113,
@@ -297,26 +308,53 @@ uint32 BaseKeyboardState::keyCodeToVKey(Common::Event *event) {
return 0;
}
+ // return ASCII value if key pressed is an alphanumeric key
+ // number keys pressed on numpad are handled in next block
+ if (Common::isAlnum(event->kbd.keycode)) {
+ return event->kbd.ascii;
+ }
+
+ // if NumLock is active, return ASCII for numpad keys
+ // keys pressed on numpad without NumLock are considered as normal keycodes, handled in the next block
+ if (Common::isDigit(event->kbd.ascii) && ((event->kbd.flags & Common::KBD_NUM) != 0)) {
+ return event->kbd.ascii;
+ }
+
switch (event->kbd.keycode) {
+ case Common::KEYCODE_BACKSPACE:
+ return kVkBack;
+ case Common::KEYCODE_TAB:
+ return kVkTab;
case Common::KEYCODE_RETURN:
case Common::KEYCODE_KP_ENTER:
return kVkReturn;
+ case Common::KEYCODE_PAUSE:
+ return kVkPause;
case Common::KEYCODE_ESCAPE:
return kVkEscape;
case Common::KEYCODE_SPACE:
return kVkSpace;
case Common::KEYCODE_END:
+ case Common::KEYCODE_KP1:
return kVkEnd;
case Common::KEYCODE_HOME:
+ case Common::KEYCODE_KP7:
return kVkHome;
case Common::KEYCODE_LEFT:
+ case Common::KEYCODE_KP4:
return kVkLeft;
case Common::KEYCODE_RIGHT:
+ case Common::KEYCODE_KP6:
return kVkRight;
case Common::KEYCODE_UP:
+ case Common::KEYCODE_KP8:
return kVkUp;
case Common::KEYCODE_DOWN:
+ case Common::KEYCODE_KP2:
return kVkDown;
+ case Common::KEYCODE_INSERT:
+ case Common::KEYCODE_KP0:
+ return kVkInsert;
case Common::KEYCODE_F1:
return kVkF1;
case Common::KEYCODE_F2:
@@ -342,8 +380,12 @@ uint32 BaseKeyboardState::keyCodeToVKey(Common::Event *event) {
case Common::KEYCODE_F12:
return kVkF12;
default:
- warning("Key not handled: %d '%c'", event->kbd.keycode, event->kbd.keycode);
- return event->kbd.keycode;
+ // check if any non-sticky keys were used, otherwise key is unknown to us
+ if ((event->kbd.flags & Common::KBD_NON_STICKY) == 0) {
+ warning("Key pressed is not recognized, ASCII returned (%d '%c').", event->kbd.keycode, event->kbd.keycode);
+ }
+ // return ASCII if no match, since it could be used for typing
+ return event->kbd.ascii;
break;
}
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/base_region.cpp b/engines/wintermute/base/base_region.cpp
index 9a31f5cd66..02ab365eff 100644
--- a/engines/wintermute/base/base_region.cpp
+++ b/engines/wintermute/base/base_region.cpp
@@ -532,4 +532,7 @@ bool BaseRegion::mimic(BaseRegion *region, float scale, int x, int y) {
return createRegion() ? STATUS_OK : STATUS_FAILED;
}
+Common::String BaseRegion::debuggerToString() const {
+ return Common::String::format("%p: Region \"%s\": Rect (top, right, bottom, left): (%d, %d, %d, %d), active: %d ", (const void *)this, getName(), _rect.top, _rect.right, _rect.bottom, _rect.left, _active);
+}
} // End of namespace Wintermute
diff --git a/engines/wintermute/base/base_region.h b/engines/wintermute/base/base_region.h
index fc3389c501..4cb5dd85d6 100644
--- a/engines/wintermute/base/base_region.h
+++ b/engines/wintermute/base/base_region.h
@@ -59,6 +59,8 @@ public:
virtual bool scSetProperty(const char *name, ScValue *value) override;
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override;
virtual const char *scToString() override;
+ virtual Common::String debuggerToString() const override;
+
private:
float _lastMimicScale;
int32 _lastMimicX;
diff --git a/engines/wintermute/base/base_script_holder.cpp b/engines/wintermute/base/base_script_holder.cpp
index 5b1c961479..7427a9b082 100644
--- a/engines/wintermute/base/base_script_holder.cpp
+++ b/engines/wintermute/base/base_script_holder.cpp
@@ -42,7 +42,7 @@ IMPLEMENT_PERSISTENT(BaseScriptHolder, false)
//////////////////////////////////////////////////////////////////////
BaseScriptHolder::BaseScriptHolder(BaseGame *inGame) : BaseScriptable(inGame) {
setName("<unnamed>");
-
+ _ready = false;
_freezable = true;
_filename = nullptr;
}
@@ -312,7 +312,11 @@ bool BaseScriptHolder::addScript(const char *filename) {
if (!scr) {
if (_gameRef->_editorForceScripts) {
// editor hack
+#if EXTENDED_DEBUGGER_ENABLED
+ scr = new DebuggableScript(_gameRef, _gameRef->_scEngine);
+#else
scr = new ScScript(_gameRef, _gameRef->_scEngine);
+#endif
scr->_filename = new char[strlen(filename) + 1];
strcpy(scr->_filename, filename);
scr->_state = SCRIPT_ERROR;
@@ -462,8 +466,15 @@ void BaseScriptHolder::makeFreezable(bool freezable) {
ScScript *BaseScriptHolder::invokeMethodThread(const char *methodName) {
for (int i = _scripts.size() - 1; i >= 0; i--) {
if (_scripts[i]->canHandleMethod(methodName)) {
-
+#if EXTENDED_DEBUGGER_ENABLED == true
+ DebuggableScEngine* debuggableEngine;
+ debuggableEngine = dynamic_cast<DebuggableScEngine*>(_scripts[i]->_engine);
+ // TODO: Not pretty
+ assert(debuggableEngine);
+ ScScript *thread = new DebuggableScript(_gameRef, debuggableEngine);
+#else
ScScript *thread = new ScScript(_gameRef, _scripts[i]->_engine);
+#endif
if (thread) {
bool ret = thread->createMethodThread(_scripts[i], methodName);
if (DID_SUCCEED(ret)) {
diff --git a/engines/wintermute/base/base_scriptable.cpp b/engines/wintermute/base/base_scriptable.cpp
index c65d30d941..01f6f9e02f 100644
--- a/engines/wintermute/base/base_scriptable.cpp
+++ b/engines/wintermute/base/base_scriptable.cpp
@@ -188,4 +188,9 @@ ScScript *BaseScriptable::invokeMethodThread(const char *methodName) {
return nullptr;
}
+Common::String BaseScriptable::debuggerToString() const {
+ return Common::String::format("%p: BaseScriptable %s", (const void *)this, getName());
+}
+
+
} // End of namespace Wintermute
diff --git a/engines/wintermute/base/base_scriptable.h b/engines/wintermute/base/base_scriptable.h
index b32668d6c8..7b4f269871 100644
--- a/engines/wintermute/base/base_scriptable.h
+++ b/engines/wintermute/base/base_scriptable.h
@@ -63,6 +63,7 @@ public:
virtual void scSetBool(bool val);
virtual int scCompare(BaseScriptable *val);
virtual void scDebuggerDesc(char *buf, int bufSize);
+ virtual Common::String debuggerToString() const;
int32 _refCount;
ScValue *_scValue;
ScValue *_scProp;
diff --git a/engines/wintermute/base/base_sprite.cpp b/engines/wintermute/base/base_sprite.cpp
index 09e138a1fd..f282004a59 100644
--- a/engines/wintermute/base/base_sprite.cpp
+++ b/engines/wintermute/base/base_sprite.cpp
@@ -826,4 +826,7 @@ bool BaseSprite::killAllSounds() {
return STATUS_OK;
}
+Common::String BaseSprite::debuggerToString() const {
+ return Common::String::format("%p: Sprite \"%s\"", (const void *)this, getName());
+}
} // End of namespace Wintermute
diff --git a/engines/wintermute/base/base_sprite.h b/engines/wintermute/base/base_sprite.h
index ec71512ec9..2313b7b3dc 100644
--- a/engines/wintermute/base/base_sprite.h
+++ b/engines/wintermute/base/base_sprite.h
@@ -69,6 +69,7 @@ public:
virtual bool scSetProperty(const char *name, ScValue *value) override;
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override;
virtual const char *scToString() override;
+ Common::String debuggerToString() const override;
private:
BaseObject *_owner;
bool _canBreak;
diff --git a/engines/wintermute/base/base_sub_frame.cpp b/engines/wintermute/base/base_sub_frame.cpp
index 4388942064..8068e61168 100644
--- a/engines/wintermute/base/base_sub_frame.cpp
+++ b/engines/wintermute/base/base_sub_frame.cpp
@@ -268,7 +268,7 @@ bool BaseSubFrame::draw(int x, int y, BaseObject *registerOwner, float zoomX, fl
Common::Point origin(x, y);
Common::Point newOrigin;
Rect32 oldRect1 = getRect();
- Common::Rect oldRect(oldRect1.top, oldRect1.left, oldRect1.bottom, oldRect1.right);
+ Common::Rect oldRect(oldRect1.left, oldRect1.top, oldRect1.right, oldRect1.bottom);
Common::Point newHotspot;
Graphics::TransformStruct transform = Graphics::TransformStruct(zoomX, zoomY, (uint32)rotate, _hotspotX, _hotspotY, blendMode, alpha, _mirrorX, _mirrorY, 0, 0);
Rect32 newRect = Graphics::TransformTools::newRect(oldRect, transform, &newHotspot);
@@ -673,4 +673,8 @@ bool BaseSubFrame::setSurfaceSimple() {
}
}
+Common::String BaseSubFrame::debuggerToString() const {
+ return Common::String::format("%p: BaseSubFrame \"%s\" - Mirror:(%d, %d), Hotspot:(%d, %d), ", (const void *)this, getName(), _mirrorX, _mirrorY, _hotspotX, _hotspotY);
+}
+
} // End of namespace Wintermute
diff --git a/engines/wintermute/base/base_sub_frame.h b/engines/wintermute/base/base_sub_frame.h
index f156c332d6..0fd38f9548 100644
--- a/engines/wintermute/base/base_sub_frame.h
+++ b/engines/wintermute/base/base_sub_frame.h
@@ -86,6 +86,7 @@ public:
virtual bool scSetProperty(const char *name, ScValue *value);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
virtual const char *scToString();
+ Common::String debuggerToString() const override;
};
diff --git a/engines/wintermute/base/base_viewport.cpp b/engines/wintermute/base/base_viewport.cpp
index bf3700a14e..aed0355eb9 100644
--- a/engines/wintermute/base/base_viewport.cpp
+++ b/engines/wintermute/base/base_viewport.cpp
@@ -96,4 +96,7 @@ int BaseViewport::getHeight() const {
return _rect.bottom - _rect.top;
}
+Common::String BaseViewport::debuggerToString() const {
+ return Common::String::format("%p: BaseViewport: (top, right, bottom, left): (%d, %d, %d, %d)", (const void *)this, _rect.top, _rect.right, _rect.bottom, _rect.left);
+}
} // End of namespace Wintermute
diff --git a/engines/wintermute/base/base_viewport.h b/engines/wintermute/base/base_viewport.h
index eae756f9c6..c2e8727ad8 100644
--- a/engines/wintermute/base/base_viewport.h
+++ b/engines/wintermute/base/base_viewport.h
@@ -48,6 +48,7 @@ public:
BaseObject *_mainObject;
BaseViewport(BaseGame *inGame = nullptr);
virtual ~BaseViewport();
+ virtual Common::String debuggerToString() const;
private:
Rect32 _rect;
};
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/file/base_file.cpp b/engines/wintermute/base/file/base_file.cpp
index 2927c908e2..4589721e7e 100644
--- a/engines/wintermute/base/file/base_file.cpp
+++ b/engines/wintermute/base/file/base_file.cpp
@@ -57,7 +57,7 @@ bool BaseFile::isEOF() {
Common::SeekableReadStream *BaseFile::getMemStream() {
uint32 oldPos = getPos();
seek(0);
- byte *data = new byte[getSize()];
+ byte *data = (byte *)malloc(getSize());
read(data, getSize());
seek(oldPos);
Common::MemoryReadStream *memStream = new Common::MemoryReadStream(data, getSize(), DisposeAfterUse::YES);
diff --git a/engines/wintermute/base/file/base_save_thumb_file.cpp b/engines/wintermute/base/file/base_save_thumb_file.cpp
index acd5363e89..54f7ee7c62 100644
--- a/engines/wintermute/base/file/base_save_thumb_file.cpp
+++ b/engines/wintermute/base/file/base_save_thumb_file.cpp
@@ -70,11 +70,12 @@ bool BaseSaveThumbFile::open(const Common::String &filename) {
delete[] tempFilename;
BasePersistenceManager *pm = new BasePersistenceManager();
- Common::String slotFilename = pm->getFilenameForSlot(slot);
if (!pm) {
return STATUS_FAILED;
}
+ Common::String slotFilename = pm->getFilenameForSlot(slot);
+
if (DID_FAIL(pm->initLoad(slotFilename))) {
delete pm;
return STATUS_FAILED;
diff --git a/engines/wintermute/base/font/base_font_truetype.cpp b/engines/wintermute/base/font/base_font_truetype.cpp
index f27b565a7f..fa6973c58f 100644
--- a/engines/wintermute/base/font/base_font_truetype.cpp
+++ b/engines/wintermute/base/font/base_font_truetype.cpp
@@ -581,7 +581,7 @@ bool BaseFontTT::initFont() {
}
if (file) {
- _deletableFont = Graphics::loadTTFFont(*file, _fontHeight, 96); // Use the same dpi as WME (96 vs 72).
+ _deletableFont = Graphics::loadTTFFont(*file, _fontHeight, Graphics::kTTFSizeModeCharacter, 96); // Use the same dpi as WME (96 vs 72).
_font = _deletableFont;
BaseFileManager::getEngineInstance()->closeFile(file);
file = nullptr;
@@ -607,7 +607,7 @@ bool BaseFontTT::initFont() {
if (themeArchive->hasFile(fallbackFilename)) {
file = nullptr;
file = themeArchive->createReadStreamForMember(fallbackFilename);
- _deletableFont = Graphics::loadTTFFont(*file, _fontHeight, 96); // Use the same dpi as WME (96 vs 72).
+ _deletableFont = Graphics::loadTTFFont(*file, _fontHeight, Graphics::kTTFSizeModeCharacter, 96); // Use the same dpi as WME (96 vs 72).
_font = _deletableFont;
}
// We're not using BaseFileManager, so clean up after ourselves:
diff --git a/engines/wintermute/base/gfx/base_surface.cpp b/engines/wintermute/base/gfx/base_surface.cpp
index f8b96b5baf..3aa500b224 100644
--- a/engines/wintermute/base/gfx/base_surface.cpp
+++ b/engines/wintermute/base/gfx/base_surface.cpp
@@ -75,11 +75,6 @@ bool BaseSurface::displayHalfTrans(int x, int y, Rect32 rect) {
}
//////////////////////////////////////////////////////////////////////////
-bool BaseSurface::displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const Graphics::TransformStruct &transform) {
- return displayTransform(x, y, rect, newRect, transform);
-}
-
-//////////////////////////////////////////////////////////////////////////
bool BaseSurface::create(int width, int height) {
return STATUS_FAILED;
}
diff --git a/engines/wintermute/base/scriptables/debuggable/debuggable_script.cpp b/engines/wintermute/base/scriptables/debuggable/debuggable_script.cpp
new file mode 100644
index 0000000000..5a2291894f
--- /dev/null
+++ b/engines/wintermute/base/scriptables/debuggable/debuggable_script.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/tokenizer.h"
+#include "debuggable_script.h"
+#include "engines/wintermute/base/scriptables/script_stack.h"
+#include "engines/wintermute/base/scriptables/script_value.h"
+#include "engines/wintermute/base/scriptables/debuggable/debuggable_script_engine.h"
+#include "engines/wintermute/debugger/breakpoint.h"
+#include "engines/wintermute/debugger/script_monitor.h"
+#include "engines/wintermute/debugger/watch_instance.h"
+
+namespace Wintermute {
+
+DebuggableScript::DebuggableScript(BaseGame *inGame, DebuggableScEngine *engine) : ScScript(inGame, engine), _engine(engine), _stepDepth(kDefaultStepDepth) {
+ _engine->_watches.subscribe(this);
+ for (uint i = 0; i < _engine->_watches.size(); i++) {
+ _watchInstances.push_back(new WatchInstance(_engine->_watches[i], this));
+ }
+}
+
+DebuggableScript::~DebuggableScript() {
+ for (uint i = 0; i < _watchInstances.size(); i++) {
+ delete _watchInstances[i];
+ }
+ _engine->_watches.unsubscribe(this);
+}
+void DebuggableScript::preInstHook(uint32 inst) {}
+
+void DebuggableScript::postInstHook(uint32 inst) {
+ if (inst == II_DBG_LINE) {
+ for (uint j = 0; j < _engine->_breakpoints.size(); j++) {
+ _engine->_breakpoints[j]->evaluate(this);
+ }
+
+ if (_callStack->_sP <= _stepDepth) {
+ _engine->_monitor->notifyStep(this);
+ }
+ }
+
+ for (uint i = 0; i < _watchInstances.size(); i++) {
+ this->_watchInstances[i]->evaluate();
+ }
+
+}
+
+void DebuggableScript::setStepDepth(int depth) {
+ _stepDepth = depth;
+}
+
+void DebuggableScript::step() {
+ setStepDepth(_callStack->_sP);
+ // TODO double check
+}
+
+void DebuggableScript::stepContinue() {
+ setStepDepth(kDefaultStepDepth);
+}
+
+void DebuggableScript::stepFinish() {
+ setStepDepth(_callStack->_sP - 1);
+}
+
+ScValue *DebuggableScript::resolveName(const Common::String &name) {
+
+ Common::String trimmed = name;
+ trimmed.trim();
+ Common::StringTokenizer st = Common::StringTokenizer(trimmed.c_str(), ".");
+ Common::String nextToken;
+
+ nextToken = st.nextToken();
+
+
+ char cstr[256]; // TODO not pretty
+ Common::strlcpy(cstr, nextToken.c_str(), nextToken.size() + 1);
+ cstr[255] = '\0'; // We 0-terminate it just in case it's > 256 chars.
+
+ ScValue *value = getVar(cstr);
+ ScValue *res = new ScValue(_gameRef);
+
+ if (value == nullptr) {
+ return res;
+ }
+
+ nextToken = st.nextToken();
+
+ while (nextToken.size() > 0 && (value->isObject() || value->isNative())) {
+ value = value->getProp(nextToken.c_str());
+ nextToken = st.nextToken();
+ if (value == nullptr) {
+ return res;
+ }
+ }
+
+ res->copy(value);
+
+ return res;
+}
+
+uint DebuggableScript::dbgGetLine() const {
+ return _currentLine;
+}
+
+Common::String DebuggableScript::dbgGetFilename() const {
+ return _filename;
+}
+
+void DebuggableScript::updateWatches() {
+ // We drop obsolete watches
+ for (uint i = 0; i < _watchInstances.size(); i++) {
+ Watch *findMe = _watchInstances[i]->_watch;
+ if (Common::find(_engine->_watches.begin(), _engine->_watches.end(), findMe) == _engine->_watches.end()) {
+ // Not found on engine-wide list, must have been removed from watches. Must remove it from local list.
+ delete _watchInstances[i];
+ _watchInstances.remove_at(i);
+ }
+ }
+
+ // We add any new watches
+ for (uint i = 0; i < _engine->_watches.size(); i++) {
+ Watch *findMe = _engine->_watches[i];
+ if (Common::find(_engine->_watches.begin(), _engine->_watches.end(), findMe) == _engine->_watches.end()) {
+ // Not found on local list, must be a new one.
+ _watchInstances.push_back(new WatchInstance(_engine->_watches[i], this));
+ }
+ }
+}
+} // End of namespace Wintermute
+
diff --git a/engines/wintermute/base/scriptables/debuggable/debuggable_script.h b/engines/wintermute/base/scriptables/debuggable/debuggable_script.h
new file mode 100644
index 0000000000..b32a5ca4af
--- /dev/null
+++ b/engines/wintermute/base/scriptables/debuggable/debuggable_script.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 DEBUGGABLE_SCRIPT_H_
+#define DEBUGGABLE_SCRIPT_H_
+#include "engines/wintermute/base/scriptables/script.h"
+
+namespace Wintermute {
+class ScriptMonitor;
+class Watch;
+class WatchInstance;
+class DebuggableScEngine;
+
+class DebuggableScript : public ScScript {
+ static const int kDefaultStepDepth = -2;
+ int32 _stepDepth;
+ DebuggableScEngine *_engine;
+ BaseArray<WatchInstance *> _watchInstances;
+ virtual void preInstHook(uint32 inst) override;
+ virtual void postInstHook(uint32 inst) override;
+ void setStepDepth(int depth);
+public:
+ DebuggableScript(BaseGame *inGame, DebuggableScEngine *engine);
+ virtual ~DebuggableScript();
+ ScValue *resolveName(const Common::String &name);
+ /**
+ * Return argument to last II_DBG_LINE encountered
+ */
+ virtual uint dbgGetLine() const;
+ virtual Common::String dbgGetFilename() const;
+ /**
+ * Execute one more instruction
+ */
+ void step();
+ /**
+ * Continue execution
+ */
+ void stepContinue();
+ /**
+ * Continue execution until the activation record on top of the stack is popped
+ */
+ void stepFinish();
+ void updateWatches();
+};
+
+} // End of namespace Wintermute
+
+#endif /* DEBUGGABLE_SCRIPT_H_ */
diff --git a/engines/wintermute/base/scriptables/debuggable/debuggable_script_engine.cpp b/engines/wintermute/base/scriptables/debuggable/debuggable_script_engine.cpp
new file mode 100644
index 0000000000..28a00cd4ae
--- /dev/null
+++ b/engines/wintermute/base/scriptables/debuggable/debuggable_script_engine.cpp
@@ -0,0 +1,35 @@
+/* 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 "debuggable_script_engine.h"
+#include "debuggable_script.h"
+#include "engines/wintermute/debugger/watch_instance.h"
+
+namespace Wintermute {
+
+DebuggableScEngine::DebuggableScEngine(BaseGame *inGame) : ScEngine(inGame), _monitor(nullptr) {}
+
+void DebuggableScEngine::attachMonitor(ScriptMonitor *monitor) {
+ _monitor = monitor;
+}
+
+} // End of namespace Wintermute
diff --git a/engines/wintermute/base/scriptables/debuggable/debuggable_script_engine.h b/engines/wintermute/base/scriptables/debuggable/debuggable_script_engine.h
new file mode 100644
index 0000000000..a4d9d2bfe7
--- /dev/null
+++ b/engines/wintermute/base/scriptables/debuggable/debuggable_script_engine.h
@@ -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.
+ *
+ */
+
+#ifndef DEBUGGABLE_SCRIPT_ENGINE_H_
+#define DEBUGGABLE_SCRIPT_ENGINE_H_
+#include "engines/wintermute/base/scriptables/script_engine.h"
+#include "engines/wintermute/coll_templ.h"
+#include "common/algorithm.h"
+#include "engines/wintermute/base/scriptables/debuggable/debuggable_script.h"
+
+namespace Wintermute {
+
+class Breakpoint;
+class Watch;
+class DebuggableScript;
+class DebuggableScEngine;
+class ScriptMonitor;
+
+class PublisherWArray : private Common::Array<Watch *> {
+ Common::Array<DebuggableScript *> _subscribers;
+ void notifySubscribers() {
+ for (uint i = 0; i < _subscribers.size(); i++) {
+ _subscribers[i]->updateWatches();
+ }
+ }
+public:
+ void subscribe(DebuggableScript *script) {
+ if (Common::find(_subscribers.begin(), _subscribers.end(), script) == _subscribers.end()) {
+ // If not already contained
+ _subscribers.push_back(script);
+ }
+ }
+
+ void unsubscribe(DebuggableScript *script) {
+ int location = -1;
+ for (uint i = 0; i < _subscribers.size() && location == -1; i++) {
+ if (_subscribers[i] == script) {
+ location = i;
+ }
+ }
+ if (location >= 0) {
+ _subscribers.remove_at(location);
+ } else {
+ // TODO: If this happens... it's funny. Some script out there forgot to subscribe.
+ }
+ }
+
+ void push_back(Watch *newElement) {
+ Common::Array<Watch *>::push_back(newElement);
+ notifySubscribers();
+ }
+
+ size_type size() {
+ return Common::Array<Watch *>::size();
+ }
+
+ iterator begin() {
+ return Common::Array<Watch *>::begin();
+ }
+
+ iterator end() {
+ return Common::Array<Watch *>::end();
+ }
+
+ Watch *&operator[](size_type idx) {
+ return Common::Array<Watch *>::operator[](idx);
+ }
+ Watch *remove_at(size_type idx) {
+ Watch *res = Common::Array<Watch *>::remove_at(idx);
+ notifySubscribers();
+ return res;
+ }
+};
+
+class DebuggableScEngine : public ScEngine {
+ Common::Array<Breakpoint *> _breakpoints;
+ PublisherWArray _watches;
+ ScriptMonitor *_monitor;
+public:
+ DebuggableScEngine(BaseGame *inGame);
+ void attachMonitor(ScriptMonitor *);
+
+ friend class DebuggerController;
+ friend class DebuggableScript;
+ friend class ScScript;
+ friend class WatchableScriptArray;
+};
+
+} // End of namespace Wintermute
+
+#endif /* DEBUGGABLE_SCRIPT_ENGINE_H_ */
diff --git a/engines/wintermute/base/scriptables/script.cpp b/engines/wintermute/base/scriptables/script.cpp
index 44fd117e61..938ec031da 100644
--- a/engines/wintermute/base/scriptables/script.cpp
+++ b/engines/wintermute/base/scriptables/script.cpp
@@ -32,7 +32,9 @@
#include "engines/wintermute/base/scriptables/script_engine.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
#include "common/memstream.h"
-
+#if EXTENDED_DEBUGGER_ENABLED == true
+#include "engines/wintermute/base/scriptables/debuggable/debuggable_script.h"
+#endif
namespace Wintermute {
IMPLEMENT_PERSISTENT(ScScript, false)
@@ -522,6 +524,9 @@ bool ScScript::executeInstruction() {
ScValue *op2;
uint32 inst = getDWORD();
+
+ preInstHook(inst);
+
switch (inst) {
case II_DEF_VAR:
@@ -1092,6 +1097,7 @@ bool ScScript::executeInstruction() {
ret = STATUS_FAILED;
} // switch(instruction)
+ postInstHook(inst);
//delete op;
return ret;
@@ -1314,8 +1320,15 @@ ScScript *ScScript::invokeEventHandler(const Common::String &eventName, bool unb
if (!pos) {
return nullptr;
}
-
+#if EXTENDED_DEBUGGER_ENABLED == true
+ // TODO: Not pretty
+ DebuggableScEngine* debuggableEngine;
+ debuggableEngine = dynamic_cast<DebuggableScEngine*>(_engine);
+ assert(debuggableEngine);
+ ScScript *thread = new DebuggableScript(_gameRef, debuggableEngine);
+#else
ScScript *thread = new ScScript(_gameRef, _engine);
+#endif
if (thread) {
bool ret = thread->createThread(this, pos, eventName);
if (DID_SUCCEED(ret)) {
@@ -1434,18 +1447,6 @@ bool ScScript::finishThreads() {
return STATUS_OK;
}
-
-//////////////////////////////////////////////////////////////////////////
-// IWmeDebugScript interface implementation
-int ScScript::dbgGetLine() {
- return _currentLine;
-}
-
-//////////////////////////////////////////////////////////////////////////
-const char *ScScript::dbgGetFilename() {
- return _filename;
-}
-
//////////////////////////////////////////////////////////////////////////
void ScScript::afterLoad() {
if (_buffer == nullptr) {
@@ -1466,4 +1467,8 @@ void ScScript::afterLoad() {
}
}
+void ScScript::preInstHook(uint32 inst) {}
+
+void ScScript::postInstHook(uint32 inst) {}
+
} // End of namespace Wintermute
diff --git a/engines/wintermute/base/scriptables/script.h b/engines/wintermute/base/scriptables/script.h
index 1edeae5b55..c1d1cce4ee 100644
--- a/engines/wintermute/base/scriptables/script.h
+++ b/engines/wintermute/base/scriptables/script.h
@@ -33,12 +33,15 @@
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/base/scriptables/dcscript.h" // Added by ClassView
#include "engines/wintermute/coll_templ.h"
+#include "engines/wintermute/persistent.h"
namespace Wintermute {
class BaseScriptHolder;
class BaseObject;
class ScEngine;
class ScStack;
+class ScValue;
+
class ScScript : public BaseClass {
public:
BaseArray<int> _breakpoints;
@@ -50,7 +53,7 @@ public:
bool copyParameters(ScStack *stack);
void afterLoad();
-private:
+protected:
ScValue *_operand;
ScValue *_reg1;
public:
@@ -125,7 +128,7 @@ public:
ScValue *_globals;
ScEngine *_engine;
int32 _currentLine;
- bool executeInstruction();
+ virtual bool executeInstruction();
char *getString();
uint32 getDWORD();
double getFloat();
@@ -162,11 +165,8 @@ private:
bool initScript();
bool initTables();
-
-// IWmeDebugScript interface implementation
-public:
- virtual int dbgGetLine();
- virtual const char *dbgGetFilename();
+ virtual void preInstHook(uint32 inst);
+ virtual void postInstHook(uint32 inst);
};
} // End of namespace Wintermute
diff --git a/engines/wintermute/base/scriptables/script_engine.cpp b/engines/wintermute/base/scriptables/script_engine.cpp
index cdf55a304c..26122094f1 100644
--- a/engines/wintermute/base/scriptables/script_engine.cpp
+++ b/engines/wintermute/base/scriptables/script_engine.cpp
@@ -144,7 +144,15 @@ ScScript *ScEngine::runScript(const char *filename, BaseScriptHolder *owner) {
}
// add new script
+#if EXTENDED_DEBUGGER_ENABLED == true
+ DebuggableScEngine* debuggableEngine;
+ debuggableEngine = dynamic_cast<DebuggableScEngine*>(this);
+ // TODO: Not pretty
+ assert(debuggableEngine);
+ ScScript *script = new DebuggableScript(_gameRef, debuggableEngine);
+#else
ScScript *script = new ScScript(_gameRef, this);
+#endif
bool ret = script->create(filename, compBuffer, compSize, owner);
if (DID_FAIL(ret)) {
_gameRef->LOG(ret, "Error running script '%s'...", filename);
diff --git a/engines/wintermute/base/scriptables/script_engine.h b/engines/wintermute/base/scriptables/script_engine.h
index bdb139e1f8..8b7e4acd19 100644
--- a/engines/wintermute/base/scriptables/script_engine.h
+++ b/engines/wintermute/base/scriptables/script_engine.h
@@ -66,20 +66,6 @@ public:
Common::String _filename;
};
- class CScBreakpoint {
- public:
- CScBreakpoint(const char *filename) {
- _filename = filename;
- }
-
- ~CScBreakpoint() {
- _lines.clear();
- }
-
- Common::String _filename;
- BaseArray<int> _lines;
- };
-
public:
bool clearGlobals(bool includingNatives = false);
bool tickUnbreakable();
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/debugger.cpp b/engines/wintermute/debugger.cpp
index 5b617d9db9..c643c33246 100644
--- a/engines/wintermute/debugger.cpp
+++ b/engines/wintermute/debugger.cpp
@@ -21,29 +21,289 @@
*/
#include "engines/wintermute/debugger.h"
-#include "engines/wintermute/wintermute.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/base_file_manager.h"
-#include "engines/wintermute/base/base_game.h"
+#include "engines/wintermute/base/scriptables/script_value.h"
+#include "engines/wintermute/debugger/debugger_controller.h"
+#include "engines/wintermute/wintermute.h"
+
+#define CONTROLLER _engineRef->_dbgController
namespace Wintermute {
Console::Console(WintermuteEngine *vm) : GUI::Debugger(), _engineRef(vm) {
registerCmd("show_fps", WRAP_METHOD(Console, Cmd_ShowFps));
registerCmd("dump_file", WRAP_METHOD(Console, Cmd_DumpFile));
+ registerCmd("show_fps", WRAP_METHOD(Console, Cmd_ShowFps));
+ registerCmd("dump_file", WRAP_METHOD(Console, Cmd_DumpFile));
+ registerCmd("help", WRAP_METHOD(Console, Cmd_Help));
+ // Actual (script) debugger commands
+ registerCmd(STEP_CMD, WRAP_METHOD(Console, Cmd_Step));
+ registerCmd(CONTINUE_CMD, WRAP_METHOD(Console, Cmd_Continue));
+ registerCmd(FINISH_CMD, WRAP_METHOD(Console, Cmd_Finish));
+ registerCmd(WATCH_CMD, WRAP_METHOD(Console, Cmd_Watch));
+ registerCmd(BREAK_CMD, WRAP_METHOD(Console, Cmd_AddBreakpoint));
+ registerCmd(LIST_CMD, WRAP_METHOD(Console, Cmd_List));
+ registerCmd(REMOVE_BREAKPOINT_CMD, WRAP_METHOD(Console, Cmd_RemoveBreakpoint));
+ registerCmd(DISABLE_BREAKPOINT_CMD, WRAP_METHOD(Console, Cmd_DisableBreakpoint));
+ registerCmd(ENABLE_BREAKPOINT_CMD, WRAP_METHOD(Console, Cmd_EnableBreakpoint));
+ registerCmd(REMOVE_WATCH_CMD, WRAP_METHOD(Console, Cmd_RemoveWatch));
+ registerCmd(DISABLE_WATCH_CMD, WRAP_METHOD(Console, Cmd_DisableWatch));
+ registerCmd(ENABLE_WATCH_CMD, WRAP_METHOD(Console, Cmd_EnableWatch));
+ registerCmd(PRINT_CMD, WRAP_METHOD(Console, Cmd_Print));
+ registerCmd(SET_CMD, WRAP_METHOD(Console, Cmd_Set));
+ registerCmd(INFO_CMD, WRAP_METHOD(Console, Cmd_Info));
+ registerCmd(SET_PATH_CMD, WRAP_METHOD(Console, Cmd_SourcePath));
+ registerCmd(TOP_CMD, WRAP_METHOD(Console, Cmd_Top));
}
Console::~Console(void) {
+}
+
+bool Console::Cmd_Help(int argc, const char **argv) {
+ if (argc == 1) {
+ // Debugger::Cmd_Help(argc, argv);
+ debugPrintf("\nType help somecommand to get specific help.\n");
+ } else {
+ printUsage(argv[1]);
+ }
+ return true;
+}
+void Console::printUsage(const Common::String &command) {
+ // TODO: This is horrible and would probably benefit from a map or something.
+ if (command.equals(BREAK_CMD)) {
+ debugPrintf("Usage: %s <file path> <line> to break at line <line> of file <file path>\n", command.c_str());
+ } else if (command.equals(REMOVE_BREAKPOINT_CMD)) {
+ debugPrintf("Usage: %s <id> to remove breakpoint #id\n", command.c_str());
+ } else if (command.equals(ENABLE_BREAKPOINT_CMD)) {
+ debugPrintf("Usage: %s <id> to enable breakpoint #id\n", command.c_str());
+ } else if (command.equals(DISABLE_BREAKPOINT_CMD)) {
+ debugPrintf("Usage: %s <id> to disable breakpoint #id\n", command.c_str());
+ } else if (command.equals(REMOVE_WATCH_CMD)) {
+ debugPrintf("Usage: %s <id> to remove watchpoint #id\n", command.c_str());
+ } else if (command.equals(ENABLE_WATCH_CMD)) {
+ debugPrintf("Usage: %s <id> to enable watchpoint #id\n", command.c_str());
+ } else if (command.equals(DISABLE_WATCH_CMD)) {
+ debugPrintf("Usage: %s <id> to disable watchpoint #id\n", command.c_str());
+ } else if (command.equals(INFO_CMD)) {
+ debugPrintf("Usage: %s [watch|breakpoints]\n", command.c_str());
+ } else if (command.equals(WATCH_CMD)) {
+ debugPrintf("Usage: %s <file path> <name> to watch for <name> in file <file path>\n", command.c_str());
+ } else if (command.equals(STEP_CMD)) {
+ debugPrintf("Usage: %s to step\n", command.c_str());
+ } else if (command.equals(CONTINUE_CMD)) {
+ debugPrintf("Usage: %s to continue\n", command.c_str());
+ } else if (command.equals(FINISH_CMD)) {
+ debugPrintf("Usage: %s to finish\n", command.c_str());
+ } else if (command.equals(PRINT_CMD)) {
+ debugPrintf("Usage: %s <name> to print value of <name>\n", command.c_str());
+ } else if (command.equals(SET_CMD)) {
+ debugPrintf("Usage: %s <name> = <value> to set <name> to <value>\n", command.c_str());
+ } else {
+ debugPrintf("No help about this command, sorry.");
+ }
+}
+
+bool Console::Cmd_AddBreakpoint(int argc, const char **argv) {
+ if (argc == 3) {
+ Wintermute::Error error = CONTROLLER->addBreakpoint(argv[1], atoi(argv[2]));
+ printError(argv[0], error);
+ } else {
+ printUsage(argv[0]);
+ }
+ return true;
+}
+
+bool Console::Cmd_RemoveBreakpoint(int argc, const char **argv) {
+ if (argc == 2) {
+ Error error = CONTROLLER->removeBreakpoint(atoi(argv[1]));
+ printError(argv[0], error);
+ } else {
+ printUsage(argv[0]);
+ }
+ return true;
+}
+
+bool Console::Cmd_EnableBreakpoint(int argc, const char **argv) {
+ if (argc == 2) {
+ Error error = CONTROLLER->enableBreakpoint(atoi(argv[1]));
+ printError(argv[0], error);
+ } else {
+ printUsage(argv[0]);
+ }
+ return true;
+}
+
+bool Console::Cmd_DisableBreakpoint(int argc, const char **argv) {
+ if (argc == 2) {
+ Error error = CONTROLLER->disableBreakpoint(atoi(argv[1]));
+ debugPrintf("%s: %s\n", argv[0], error.getErrorDisplayStr().c_str());
+ } else {
+ printUsage(argv[0]);
+ }
+ return true;
+}
+
+bool Console::Cmd_RemoveWatch(int argc, const char **argv) {
+ if (argc == 2) {
+ Error error = CONTROLLER->removeWatchpoint(atoi(argv[1]));
+ printError(argv[0], error);
+ } else {
+ printUsage(argv[0]);
+ }
+
+ return true;
+}
+
+bool Console::Cmd_EnableWatch(int argc, const char **argv) {
+ if (argc == 2) {
+ Error error = CONTROLLER->enableWatchpoint(atoi(argv[1]));
+ printError(argv[0], error);
+ } else {
+ printUsage(argv[0]);
+ }
+ return true;
+}
+
+bool Console::Cmd_DisableWatch(int argc, const char **argv) {
+ if (argc == 2) {
+ Error error = CONTROLLER->disableWatchpoint(atoi(argv[1]));
+ printError(argv[0], error);
+ } else {
+ printUsage(argv[0]);
+ }
+ return true;
+}
+
+bool Console::Cmd_Watch(int argc, const char **argv) {
+ if (argc == 3) {
+ Error error = CONTROLLER->addWatch(argv[1], argv[2]);
+ printError(argv[0], error);
+ } else {
+ printUsage(argv[0]);
+ }
+ return true;
+}
+
+bool Console::Cmd_Info(int argc, const char **argv) {
+ if (argc == 2 && !strncmp(argv[1], "breakpoints", 10)) {
+ Common::Array<BreakpointInfo> breakpoints = CONTROLLER->getBreakpoints();
+ for (uint i = 0; i < breakpoints.size(); i++) {
+ debugPrintf("%d %s:%d x%d, enabled: %d \n", i, breakpoints[i]._filename.c_str(), breakpoints[i]._line, breakpoints[i]._hits, breakpoints[i]._enabled);
+ }
+ return 1;
+ } else if (argc == 2 && !strncmp(argv[1], WATCH_CMD, 5)) {
+ Common::Array<WatchInfo>watchlist = CONTROLLER->getWatchlist();
+ for (uint i = 0; i < watchlist.size(); i++) {
+ debugPrintf("%d %s:%s x%d \n", i, watchlist[i]._filename.c_str(), watchlist[i]._symbol.c_str(), watchlist[i]._hits);
+ }
+ return 1;
+ } else {
+ printUsage(argv[0]);
+ return 1;
+ }
+}
+
+bool Console::Cmd_Step(int argc, const char **argv) {
+ if (argc == 1) {
+ Error error = CONTROLLER->step();
+ if (error.getErrorLevel() == SUCCESS) {
+ return false;
+ } else {
+ printError(argv[0], error);
+ return true;
+ }
+ } else {
+ printUsage(argv[0]);
+ return true;
+ }
+}
+
+bool Console::Cmd_Continue(int argc, const char **argv) {
+ if (argc == 1) {
+ Error error = CONTROLLER->stepContinue();
+ if (error.getErrorLevel() == SUCCESS) {
+ return false;
+ } else {
+ printError(argv[0], error);
+ return true;
+ }
+ } else {
+ printUsage(argv[0]);
+ return true;
+ }
+}
+
+bool Console::Cmd_Finish(int argc, const char **argv) {
+ if (argc == 1) {
+ Error error = CONTROLLER->stepFinish();
+ printError(argv[0], error);
+ if (error.getErrorLevel() == SUCCESS) {
+ return false;
+ } else {
+ printError(argv[0], error);
+ return true;
+ }
+ } else {
+ printUsage(argv[0]);
+ return true;
+ }
+}
+
+bool Console::Cmd_List(int argc, const char **argv) {
+ Error error = printSource();
+ if (error.getErrorLevel() != SUCCESS) {
+ printError(argv[0], error);
+ }
+ return true;
+}
+
+bool Console::Cmd_Print(int argc, const char **argv) {
+ if (argc == 2) {
+ Error error = Error(SUCCESS, OK, 0);
+ Common::String temp = CONTROLLER->readValue(argv[1], &error);
+ if (error.getErrorLevel() == SUCCESS) {
+ debugPrintf("%s = %s \n", argv[1], temp.c_str());
+ return true;
+ } else {
+ printError(argv[0], error);
+ return true;
+ }
+ } else {
+ printUsage(argv[0]);
+ return true;
+ }
+}
+
+
+bool Console::Cmd_Set(int argc, const char **argv) {
+ if (argc == 4 && !strncmp("=", argv[2], 1)) {
+ ScValue *val = nullptr;
+ Error error = CONTROLLER->setValue(argv[1], argv[3], val);
+ if (error.getErrorLevel() == SUCCESS) {
+ assert(val);
+ debugPrintf("%s = %s\n", argv[1], val->getString());
+ } else {
+ printError(argv[0], error);
+ }
+ } else {
+ printUsage(argv[0]);
+ }
+ return true;
}
bool Console::Cmd_ShowFps(int argc, const char **argv) {
- if (argc > 1) {
+ if (argc == 2) {
if (Common::String(argv[1]) == "true") {
- _engineRef->_game->setShowFPS(true);
+ CONTROLLER->showFps(true);
} else if (Common::String(argv[1]) == "false") {
- _engineRef->_game->setShowFPS(false);
+ CONTROLLER->showFps(false);
+ } else {
+ debugPrintf("%s: argument 1 must be \"true\" or \"false\"\n", argv[0]);
}
+ } else {
+ debugPrintf("Usage: %s [true|false]\n", argv[0]);
}
return true;
}
@@ -81,4 +341,80 @@ bool Console::Cmd_DumpFile(int argc, const char **argv) {
return true;
}
+
+bool Console::Cmd_SourcePath(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("Usage: %s <source path>\n", argv[0]);
+ return true;
+ } else {
+ if (CONTROLLER->setSourcePath(Common::String(argv[1])).getErrorCode() == OK) {
+ debugPrintf("Source path set to '%s'\n", CONTROLLER->getSourcePath().c_str());
+ } else {
+ debugPrintf("Error setting source path. Note that \"\" is illegal.");
+ }
+ return true;
+ }
+}
+
+void Console::notifyBreakpoint(const char *filename, int line) {
+ debugPrintf("Breakpoint hit %s: %d\n", filename, line);
+ printSource(0);
+ attach();
+ onFrame();
+}
+
+void Console::notifyStep(const char *filename, int line) {
+ debugPrintf("Step: %s:%d\n", filename, line);
+ printSource(0);
+ attach();
+ onFrame();
+}
+
+void Console::notifyWatch(const char *filename, const char *symbol, const char *newValue) {
+ debugPrintf("Watch: %s:%s <---- %s\n", filename, symbol, newValue);
+ printSource(0);
+ attach();
+ onFrame();
+}
+
+Error Console::printSource(int n) {
+
+ Error* error = nullptr;
+ Listing *listing = CONTROLLER->getListing(error);
+ Error err(*error);
+ delete error;
+
+ if (err.getErrorLevel() == SUCCESS || err.getErrorLevel() == WARNING) {
+ Common::Array<ListingLine> lines = listing->getLines(CONTROLLER->getLastLine(), n/2, n/2);
+ for (uint i = 0; i < lines.size(); i++) {
+ if (lines[i].number == CONTROLLER->getLastLine()) {
+ debugPrintf(" -> ");
+ } else {
+ debugPrintf(" ");
+ }
+ debugPrintf("%d", lines[i].number);
+ debugPrintf("%s", lines[i].text.c_str());
+ debugPrintf("\n");
+ }
+ }
+
+ delete listing;
+ return err;
+}
+
+bool Console::Cmd_Top(int argc, const char **argv) {
+ Common::Array<TopEntry> entries = CONTROLLER->getTop();
+ for (uint i = 0; i < entries.size(); i++) {
+ if (entries[i].current) {
+ debugPrintf("%d*: %s\n", i, entries[i].filename.c_str());
+ } else {
+ debugPrintf("%d: %s\n", i, entries[i].filename.c_str());
+ }
+ }
+ return true;
+}
+
+void Console::printError(const Common::String &command, Error error) {
+ debugPrintf("%s: %s\n", command.c_str(), error.getErrorDisplayStr().c_str());
+}
} // End of namespace Wintermute
diff --git a/engines/wintermute/debugger.h b/engines/wintermute/debugger.h
index 625da0ce41..e5008bee3b 100644
--- a/engines/wintermute/debugger.h
+++ b/engines/wintermute/debugger.h
@@ -23,20 +23,134 @@
#ifndef WINTERMUTE_DEBUGGER_H
#define WINTERMUTE_DEBUGGER_H
+#define EXTENDED_DEBUGGER_ENABLED true
+
#include "gui/debugger.h"
-namespace Wintermute {
+#if EXTENDED_DEBUGGER_ENABLED == true
+#include "engines/wintermute/base/scriptables/debuggable/debuggable_script.h"
+#else
+#include "engines/wintermute/base/scriptables/script.h"
+#endif
+
+#define DEFAULT_SOURCE_PADDING 5
+
+#define STEP_CMD "step"
+#define CONTINUE_CMD "continue"
+#define FINISH_CMD "finish"
+#define WATCH_CMD "watch"
+#define BREAK_CMD "break"
+#define LIST_CMD "list"
+#define REMOVE_BREAKPOINT_CMD "del"
+#define DISABLE_BREAKPOINT_CMD "disable"
+#define ENABLE_BREAKPOINT_CMD "enable"
+#define REMOVE_WATCH_CMD "delw"
+#define DISABLE_WATCH_CMD "disablew"
+#define ENABLE_WATCH_CMD "enablew"
+#define INFO_CMD "info"
+#define SET_CMD "set"
+#define PRINT_CMD "print"
+#define SET_PATH_CMD "set_path"
+#define TOP_CMD "top"
+
+namespace Wintermute {
class WintermuteEngine;
+class Adapter;
+class DebuggerController;
+class Error;
+
class Console : public GUI::Debugger {
public:
Console(WintermuteEngine *vm);
virtual ~Console();
-
+ /*
+ * Debug commands
+ */
+ bool Cmd_Help(int argc, const char **argv);
bool Cmd_ShowFps(int argc, const char **argv);
bool Cmd_DumpFile(int argc, const char **argv);
+
+#if EXTENDED_DEBUGGER_ENABLED == true
+ /**
+ * Step - break again on next line
+ */
+ bool Cmd_Step(int argc, const char **argv);
+ /**
+ * Continue execution
+ */
+ bool Cmd_Continue(int argc, const char **argv);
+ /**
+ * Only break again when the current function is finished
+ * (activation record is popped)
+ */
+ bool Cmd_Finish(int argc, const char **argv);
+ bool Cmd_Print(int argc, const char **argv);
+ bool Cmd_Set(int argc, const char **argv);
+ // Breakpoints
+ bool Cmd_AddBreakpoint(int argc, const char **argv);
+ bool Cmd_RemoveBreakpoint(int argc, const char **argv);
+ bool Cmd_EnableBreakpoint(int argc, const char **argv);
+ bool Cmd_DisableBreakpoint(int argc, const char **argv);
+ /**
+ * Add a watch.
+ *
+ * It monitors the value of some variable x against its
+ * last known state and it breaks if it has changed since.
+ *
+ */
+ bool Cmd_Watch(int argc, const char **argv);
+ bool Cmd_RemoveWatch(int argc, const char **argv);
+ bool Cmd_EnableWatch(int argc, const char **argv);
+ bool Cmd_DisableWatch(int argc, const char **argv);
+ /**
+ * Print info re:watch and breakpoints.
+ * This differs from e.g. gdb in that we have separate lists.
+ */
+ bool Cmd_Info(int argc, const char **argv);
+ /**
+ * Print source
+ */
+ bool Cmd_List(int argc, const char **argv);
+ /**
+ * Set (DOS-style) source path for debugging.
+ * This is where you will (optionally) put your sources
+ * to enable printing of sources as you step through the
+ * scripts.
+ *
+ * Please note that we have no checksum or anything
+ * to make sure your source files are up to date.
+ *
+ * YOU HAVE to make sure of that.
+ *
+ * You have been warned! :)
+ */
+ bool Cmd_SourcePath(int argc, const char **argv);
+
+ /**
+ * Top
+ */
+ bool Cmd_Top(int argc, const char **argv);
+
+ Error printSource(int n = DEFAULT_SOURCE_PADDING);
+
+ /**
+ * Hooks for the controller to open the console
+ */
+ void notifyBreakpoint(const char *filename, int line);
+ void notifyStep(const char *filename, int line);
+ /**
+ * To be called by the adapter when a watched variable
+ * is changed.
+ * Opens a console and prints info and listing if available.
+ */
+ void notifyWatch(const char *filename, const char *symbol, const char *newValue);
+#endif
+
private:
- WintermuteEngine *_engineRef;
+ const WintermuteEngine *_engineRef;
+ void printError(const Common::String &command, Error error);
+ void printUsage(const Common::String &command);
};
}
diff --git a/engines/wintermute/debugger/breakpoint.cpp b/engines/wintermute/debugger/breakpoint.cpp
new file mode 100644
index 0000000000..7f2a02b0ea
--- /dev/null
+++ b/engines/wintermute/debugger/breakpoint.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 "breakpoint.h"
+#include "engines/wintermute/base/scriptables/debuggable/debuggable_script.h"
+#include "script_monitor.h"
+
+namespace Wintermute {
+
+Breakpoint::Breakpoint(const Common::String &filename, uint line, ScriptMonitor *monitor) :
+ _filename(filename), _line(line), _monitor(monitor), _enabled(0), _hits(0) {}
+
+void Breakpoint::hit(DebuggableScript *script) {
+ _hits++;
+ _monitor->onBreakpoint(this, script);
+}
+
+Common::String Breakpoint::getFilename() const {
+ return _filename;
+}
+int Breakpoint::getLine() const {
+ return _line;
+}
+int Breakpoint::getHits() const {
+ return _hits;
+}
+bool Breakpoint::isEnabled() const {
+ return _enabled;
+}
+void Breakpoint::enable() {
+ _enabled = true;
+}
+void Breakpoint::disable() {
+ _enabled = false;
+}
+
+void Breakpoint::evaluate(DebuggableScript *script) {
+ if (isEnabled() &&
+ getLine() == script->_currentLine &&
+ !getFilename().compareTo(script->_filename)) {
+ hit(script);
+ }
+}
+
+Breakpoint::~Breakpoint() {
+ // Nothing to take care of in here
+}
+
+} // End of namespace Wintermute
diff --git a/engines/wintermute/debugger/breakpoint.h b/engines/wintermute/debugger/breakpoint.h
new file mode 100644
index 0000000000..3757791ba3
--- /dev/null
+++ b/engines/wintermute/debugger/breakpoint.h
@@ -0,0 +1,58 @@
+/* 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 BREAKPOINT_H_
+#define BREAKPOINT_H_
+#include "common/str.h"
+
+namespace Wintermute {
+
+class ScriptMonitor;
+class DebuggableScript;
+
+class Breakpoint {
+ const Common::String _filename;
+ const uint _line;
+ uint _hits;
+ bool _enabled;
+ ScriptMonitor *_monitor;
+ void hit(DebuggableScript *script);
+public:
+ Breakpoint(const Common::String &filename, uint line, ScriptMonitor *monitor);
+ /**
+ * This should be called inside the interpreter; the breakpoint is evaluated
+ * in the context of script, and, if it is enabled and filename & line match,
+ * the attached ScriptMonitor is notified.
+ */
+ void evaluate(DebuggableScript* script);
+ Common::String getFilename() const;
+ int getLine() const;
+ int getHits() const;
+ bool isEnabled() const;
+ void enable();
+ void disable();
+ virtual ~Breakpoint();
+};
+
+} // End of namespace Wintermute
+
+#endif /* BREAKPOINT_H_ */
diff --git a/engines/wintermute/debugger/debugger_controller.cpp b/engines/wintermute/debugger/debugger_controller.cpp
new file mode 100644
index 0000000000..aef96ed9c9
--- /dev/null
+++ b/engines/wintermute/debugger/debugger_controller.cpp
@@ -0,0 +1,325 @@
+/* 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/algorithm.h"
+#include "common/str.h"
+#include "common/tokenizer.h"
+#include "engines/wintermute/debugger.h"
+#include "engines/wintermute/base/base_file_manager.h"
+#include "engines/wintermute/base/base_engine.h"
+#include "engines/wintermute/base/base_game.h"
+#include "engines/wintermute/base/scriptables/script.h"
+#include "engines/wintermute/base/scriptables/script_value.h"
+#include "engines/wintermute/base/scriptables/script_stack.h"
+#include "engines/wintermute/debugger/breakpoint.h"
+#include "engines/wintermute/debugger/debugger_controller.h"
+#include "engines/wintermute/debugger/watch.h"
+#include "engines/wintermute/debugger/listing_providers/blank_listing_provider.h"
+#include "engines/wintermute/debugger/listing_providers/cached_source_listing_provider.h"
+#include "engines/wintermute/debugger/listing_providers/source_listing.h"
+#define SCENGINE _engine->_game->_scEngine
+#define DEBUGGER _engine->_debugger
+
+namespace Wintermute {
+
+DebuggerController::~DebuggerController() {
+ delete _sourceListingProvider;
+}
+
+DebuggerController::DebuggerController(WintermuteEngine *vm) : _engine(vm) {
+ _sourceListingProvider = new CachedSourceListingProvider();
+ clear();
+}
+
+bool DebuggerController::bytecodeExists(const Common::String &filename) {
+ uint32 compSize;
+ byte *compBuffer = SCENGINE->getCompiledScript(filename.c_str(), &compSize);
+ if (!compBuffer) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+Error DebuggerController::addBreakpoint(const char *filename, int line) {
+ assert(SCENGINE);
+ if (bytecodeExists(filename)) {
+ SCENGINE->_breakpoints.push_back(new Breakpoint(filename, line, this));
+ return Error(SUCCESS, OK);
+ } else {
+ return Error(ERROR, NO_SUCH_BYTECODE);
+ }
+}
+
+Error DebuggerController::removeBreakpoint(uint id) {
+ assert(SCENGINE);
+ if (SCENGINE->_breakpoints.size() > id) {
+ SCENGINE->_breakpoints.remove_at(id);
+ return Error(SUCCESS, OK);
+ } else {
+ return Error(ERROR, NO_SUCH_BREAKPOINT, id);
+ }
+}
+
+Error DebuggerController::disableBreakpoint(uint id) {
+ assert(SCENGINE);
+ if (SCENGINE->_breakpoints.size() > id) {
+ SCENGINE->_breakpoints[id]->disable();
+ return Error(SUCCESS, OK);
+ } else {
+ return Error(ERROR, NO_SUCH_BREAKPOINT, id);
+ }
+}
+
+Error DebuggerController::enableBreakpoint(uint id) {
+ assert(SCENGINE);
+ if (SCENGINE->_breakpoints.size() > id) {
+ SCENGINE->_breakpoints[id]->enable();
+ return Error(SUCCESS, OK);
+ } else {
+ return Error(ERROR, NO_SUCH_BREAKPOINT, id);
+ }
+}
+
+Error DebuggerController::removeWatchpoint(uint id) {
+ assert(SCENGINE);
+ if (SCENGINE->_watches.size() > id) {
+ SCENGINE->_watches.remove_at(id);
+ return Error(SUCCESS, OK);
+ } else {
+ return Error(ERROR, NO_SUCH_BREAKPOINT, id);
+ }
+}
+
+
+Error DebuggerController::disableWatchpoint(uint id) {
+ assert(SCENGINE);
+ if (SCENGINE->_watches.size() > id) {
+ SCENGINE->_watches[id]->disable();
+ return Error(SUCCESS, OK);
+ } else {
+ return Error(ERROR, NO_SUCH_BREAKPOINT, id);
+ }
+}
+
+Error DebuggerController::enableWatchpoint(uint id) {
+ assert(SCENGINE);
+ if (SCENGINE->_watches.size() > id) {
+ SCENGINE->_watches[id]->enable();
+ return Error(SUCCESS, OK);
+ } else {
+ return Error(ERROR, NO_SUCH_BREAKPOINT, id);
+ }
+
+}
+
+Error DebuggerController::addWatch(const char *filename, const char *symbol) {
+ assert(SCENGINE);
+ if (!bytecodeExists(filename)) {
+ return Error(ERROR, NO_SUCH_BYTECODE, filename);
+ }
+ SCENGINE->_watches.push_back(new Watch(filename, symbol, this));
+ return Error(SUCCESS, OK, "Watchpoint added");
+}
+
+void DebuggerController::onBreakpoint(const Breakpoint *breakpoint, DebuggableScript *script) {
+ _lastScript = script;
+ _lastLine = script->_currentLine;
+ DEBUGGER->notifyBreakpoint(script->dbgGetFilename().c_str(), script->_currentLine);
+}
+
+void DebuggerController::notifyStep(DebuggableScript *script) {
+ _lastScript = script;
+ _lastLine = script->_currentLine;
+ DEBUGGER->notifyStep(script->dbgGetFilename().c_str(), script->_currentLine);
+}
+
+void DebuggerController::onWatch(const Watch *watch, DebuggableScript *script) {
+ _lastScript = script; // If script has changed do we still care?
+ _lastLine = script->_currentLine;
+ Common::String symbol = watch->getSymbol();
+ DEBUGGER->notifyWatch(script->dbgGetFilename().c_str(), symbol.c_str(), script->resolveName(symbol)->getString());
+}
+
+Error DebuggerController::step() {
+ if (!_lastScript) {
+ return Error(ERROR, NOT_ALLOWED);
+ }
+ _lastScript->step();
+ clear();
+ return Error(SUCCESS, OK);
+}
+
+Error DebuggerController::stepContinue() {
+ if (!_lastScript) {
+ return Error(ERROR, NOT_ALLOWED);
+ }
+ _lastScript->stepContinue();
+ return Error(SUCCESS, OK);
+}
+
+Error DebuggerController::stepFinish() {
+ if (!_lastScript) {
+ return Error(ERROR, NOT_ALLOWED);
+ }
+ _lastScript->stepFinish();
+ clear();
+ return Error(SUCCESS, OK);
+}
+
+void DebuggerController::clear() {
+ _lastScript = nullptr;
+ _lastLine = -1;
+}
+
+Common::String DebuggerController::readValue(const Common::String &name, Error *error) {
+ if (!_lastScript) {
+ delete error;
+ error = new Error(ERROR, NOT_ALLOWED);
+ return Common::String();
+ }
+ char cstr[256]; // TODO not pretty
+ Common::strlcpy(cstr, name.c_str(), name.size() + 1);
+ cstr[255] = '\0'; // We 0-terminate it just in case it's longer than 255.
+ return _lastScript->resolveName(cstr)->getString();
+}
+
+Error DebuggerController::setValue(const Common::String &name, const Common::String &value, ScValue *&var) {
+ if (!_lastScript) {
+ return Error(ERROR, NOT_ALLOWED);
+ }
+
+ Common::String trimmed = value;
+ trimmed.trim();
+ char cstr[256];
+ Common::strlcpy(cstr, name.c_str(), name.size() + 1); // TODO not pretty
+
+ var = _lastScript->getVar(cstr);
+ if (var->_type == VAL_INT) {
+ char *endptr;
+ int res = strtol(trimmed.c_str(), &endptr, 10); // TODO: Hex too?
+ if (endptr == trimmed.c_str()) {
+ return Error(ERROR, PARSE_ERROR);
+ } else if (endptr == trimmed.c_str() + trimmed.size()) {
+ // We've parsed all of it, have we?
+ var->setInt(res);
+ } else {
+ assert(false);
+ return Error(ERROR, PARSE_ERROR);
+ // Something funny happened here.
+ }
+ } else if (var->_type == VAL_FLOAT) {
+ char *endptr;
+ float res = (float)strtod(trimmed.c_str(), &endptr);
+ if (endptr == trimmed.c_str()) {
+ return Error(ERROR, PARSE_ERROR);
+ } else if (endptr == trimmed.c_str() + trimmed.size()) {
+ // We've parsed all of it, have we?
+ var->setFloat(res);
+ } else {
+ return Error(ERROR, PARSE_ERROR);
+ assert(false);
+ // Something funny happened here.
+ }
+ } else if (var->_type == VAL_BOOL) {
+ Common::String str = Common::String(trimmed);
+ bool valAsBool;
+ if (Common::parseBool(trimmed, valAsBool)) {
+ var->setBool(valAsBool);
+ } else {
+ return Error(ERROR, PARSE_ERROR);
+ }
+ } else if (var->_type == VAL_STRING) {
+ var->setString(trimmed);
+ } else {
+ return Error(ERROR, NOT_YET_IMPLEMENTED);
+ }
+ return Error(SUCCESS, OK);
+}
+
+void DebuggerController::showFps(bool show) {
+ _engine->_game->setShowFPS(show);
+}
+
+Common::Array<BreakpointInfo> DebuggerController::getBreakpoints() const {
+ assert(SCENGINE);
+ Common::Array<BreakpointInfo> breakpoints;
+ for (uint i = 0; i < SCENGINE->_breakpoints.size(); i++) {
+ BreakpointInfo bpInfo;
+ bpInfo._filename = SCENGINE->_breakpoints[i]->getFilename();
+ bpInfo._line = SCENGINE->_breakpoints[i]->getLine();
+ bpInfo._hits = SCENGINE->_breakpoints[i]->getHits();
+ bpInfo._enabled = SCENGINE->_breakpoints[i]->isEnabled();
+ breakpoints.push_back(bpInfo);
+ }
+ return breakpoints;
+}
+
+Common::Array<WatchInfo> DebuggerController::getWatchlist() const {
+ Common::Array<WatchInfo> watchlist;
+ for (uint i = 0; i < SCENGINE->_watches.size(); i++) {
+ WatchInfo watchInfo;
+ watchInfo._filename = SCENGINE->_watches[i]->getFilename();
+ watchInfo._symbol = SCENGINE->_watches[i]->getSymbol();
+ watchlist.push_back(watchInfo);
+ }
+ return watchlist;
+}
+
+uint32 DebuggerController::getLastLine() const {
+ return _lastLine;
+}
+
+Common::String DebuggerController::getSourcePath() const {
+ return _sourceListingProvider->getPath();
+}
+
+Error DebuggerController::setSourcePath(const Common::String &sourcePath) {
+ ErrorCode err = _sourceListingProvider->setPath(sourcePath);
+ return Error((err == OK ? SUCCESS : ERROR), err);
+}
+
+Listing* DebuggerController::getListing(Error* &error) {
+ delete (error);
+ if (_lastScript == nullptr) {
+ error = new Error(ERROR, NOT_ALLOWED);
+ return nullptr;
+ }
+ ErrorCode err;
+ Listing* res = _sourceListingProvider->getListing(SCENGINE->_currentScript->_filename, err);
+ error = new Error(err == OK ? SUCCESS : ERROR, err);
+ return res;
+}
+
+Common::Array<TopEntry> DebuggerController::getTop() const {
+ Common::Array<TopEntry> res;
+ assert(SCENGINE);
+ for (uint i = 0; i < SCENGINE->_scripts.size(); i++) {
+ TopEntry entry;
+ entry.filename = SCENGINE->_scripts[i]->_filename;
+ entry.current = (SCENGINE->_scripts[i] == SCENGINE->_currentScript);
+ res.push_back(entry);
+ }
+ return res;
+}
+
+} // end of namespace Wintermute
diff --git a/engines/wintermute/debugger/debugger_controller.h b/engines/wintermute/debugger/debugger_controller.h
new file mode 100644
index 0000000000..345b42f0cb
--- /dev/null
+++ b/engines/wintermute/debugger/debugger_controller.h
@@ -0,0 +1,119 @@
+/* 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 WINTERMUTE_DEBUGGER_ADAPTER_H
+#define WINTERMUTE_DEBUGGER_ADAPTER_H
+
+#include "common/str.h"
+#include "engines/wintermute/coll_templ.h"
+#include "engines/wintermute/wintermute.h"
+#include "engines/wintermute/debugger/listing_providers/source_listing_provider.h"
+#include "script_monitor.h"
+#include "error.h"
+#include "listing.h"
+namespace Wintermute {
+
+class ScScript;
+class DebuggableScript;
+class ScValue;
+
+struct BreakpointInfo {
+ Common::String _filename;
+ int _line;
+ int _hits;
+ bool _enabled;
+};
+
+struct WatchInfo {
+ Common::String _filename;
+ Common::String _symbol;
+ int _hits;
+ bool _enabled;
+};
+
+struct TopEntry {
+ bool current;
+ Common::String filename;
+ int watches;
+ int breakpointInfo;
+};
+
+class DebuggerController : public ScriptMonitor {
+ SourceListingProvider *_sourceListingProvider;
+ const WintermuteEngine *_engine;
+ DebuggableScript *_lastScript;
+ uint32 _lastDepth;
+ uint32 _lastLine;
+ void clear();
+ bool bytecodeExists(const Common::String &filename);
+public:
+ DebuggerController(WintermuteEngine *vm);
+ ~DebuggerController();
+ Common::Array<TopEntry> getTop() const;
+ /**
+ * Get the last line # we've stopped at
+ */
+ uint32 getLastLine() const;
+ Error addBreakpoint(const char *filename, int line);
+ Error removeBreakpoint(uint id);
+ Error disableBreakpoint(uint id);
+ Error enableBreakpoint(uint id);
+ Error addWatch(const char *filename, const char *symbol);
+ Error removeWatchpoint(uint id);
+ Error disableWatchpoint(uint id);
+ Error enableWatchpoint(uint id);
+ Common::Array<BreakpointInfo> getBreakpoints() const;
+ Common::Array<WatchInfo> getWatchlist() const;
+ /**
+ * @brief step one instruction
+ */
+ Error step();
+ /**
+ * @brief continue execution and don't step until next breakpoint
+ */
+ Error stepContinue();
+ /**
+ * @brief continue execution and don't step until the current activation record is popped
+ */
+ Error stepFinish();
+ /**
+ * @brief read value for a variable accessible from within the current scope.
+ */
+ Common::String readValue(const Common::String &name, Error *error);
+ /**
+ * @brief set value for a variable accessible from within the current scope.
+ */
+ Error setValue(const Common::String &name, const Common::String &value, ScValue*&var);
+ Error setSourcePath(const Common::String &sourcePath);
+ Common::String getSourcePath() const;
+ Listing *getListing(Error* &err);
+ void showFps(bool show);
+ /**
+ * Inherited from ScriptMonitor
+ */
+ void onBreakpoint(const Breakpoint *breakpoint, DebuggableScript *script);
+ void onWatch(const Watch *watch, DebuggableScript *script);
+ void notifyStep(DebuggableScript *script) override;
+};
+}
+
+#endif // WINTERMUTE_DEBUGGER_H
diff --git a/engines/wintermute/debugger/error.cpp b/engines/wintermute/debugger/error.cpp
new file mode 100644
index 0000000000..dd6e41c7bc
--- /dev/null
+++ b/engines/wintermute/debugger/error.cpp
@@ -0,0 +1,137 @@
+/* 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 "error.h"
+#include "engines/wintermute/debugger.h"
+
+namespace Wintermute {
+
+Error::Error(ErrorLevel errorLevel,
+ ErrorCode errorCode,
+ Common::String errorExtraString,
+ int errorExtraInt) :
+ _errorLevel(errorLevel),
+ _errorCode(errorCode),
+ _errorExtraInt(errorExtraInt),
+ _errorExtraString(errorExtraString){}
+
+Error::Error(ErrorLevel errorLevel,
+ ErrorCode errorCode,
+ int errorExtraInt) :
+ _errorLevel(errorLevel),
+ _errorCode(errorCode),
+ _errorExtraInt(errorExtraInt),
+ _errorExtraString(""){}
+
+Error::Error(ErrorLevel errorLevel,
+ ErrorCode errorCode) :
+ _errorLevel(errorLevel),
+ _errorCode(errorCode),
+ _errorExtraInt(0),
+ _errorExtraString(""){}
+
+Error::Error(ErrorLevel errorLevel,
+ ErrorCode errorCode,
+ Common::String errorExtraString) :
+ _errorLevel(errorLevel),
+ _errorCode(errorCode),
+ _errorExtraInt(0),
+ _errorExtraString(errorExtraString){}
+
+ErrorLevel Error::getErrorLevel() const {
+ return _errorLevel;
+}
+
+ErrorCode Error::getErrorCode() const {
+ return _errorCode;
+}
+
+Common::String Error::getErrorLevelStr() const {
+ switch (this->_errorLevel) {
+ case SUCCESS:
+ return "SUCCESS";
+ break;
+ case NOTICE:
+ return "NOTICE";
+ break;
+ case WARNING:
+ return "WARNING";
+ break;
+ case ERROR:
+ return "ERROR";
+ break;
+ }
+ return "SUCCESS";
+}
+
+Common::String Error::getErrorDisplayStr() const {
+
+ Common::String errorStr;
+
+ switch (this->_errorLevel) {
+ case SUCCESS:
+ errorStr += "OK!";
+ break;
+ case WARNING:
+ errorStr += "WARNING: ";
+ break;
+ case ERROR:
+ errorStr += "ERROR: ";
+ break;
+ case NOTICE:
+ errorStr += "NOTICE: ";
+ break;
+ default:
+ // Um...
+ break;
+ }
+
+ switch (this->_errorCode) {
+ case OK:
+ break;
+ case NOT_ALLOWED:
+ errorStr += "Could not execute requested operation. This is allowed only after a break.";
+ break;
+ case NO_SUCH_SOURCE:
+ errorStr += Common::String::format("Can't find source for %s. Double check you source path.", this->_errorExtraString.c_str());
+ break;
+ case NO_SUCH_BYTECODE:
+ errorStr += Common::String::format("No such script: %s. Can't find bytecode; double check the script path.", this->_errorExtraString.c_str());
+ break;
+ case SOURCE_PATH_NOT_SET:
+ errorStr += Common::String("Source path not set. Source won't be displayed. Try 'help " + Common::String(SET_PATH_CMD) + "'.");
+ break;
+ case NO_SUCH_BREAKPOINT:
+ errorStr += Common::String::format("No such breakpoint %d.", this->_errorExtraInt);
+ break;
+ case WRONG_TYPE:
+ errorStr += Common::String::format("Incompatible type: %s.", this->_errorExtraString.c_str());
+ break;
+ default:
+ errorStr += Common::String::format("Unknown condition %d", this->_errorCode);
+ break;
+ }
+
+ return errorStr;
+}
+
+} // End namespace Wintermute
diff --git a/engines/wintermute/debugger/error.h b/engines/wintermute/debugger/error.h
new file mode 100644
index 0000000000..4e5b973445
--- /dev/null
+++ b/engines/wintermute/debugger/error.h
@@ -0,0 +1,73 @@
+/* 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 ERROR_H_
+#define ERROR_H_
+
+#include "common/str.h"
+
+namespace Wintermute {
+
+enum ErrorLevel {
+ SUCCESS,
+ NOTICE,
+ WARNING,
+ ERROR
+};
+
+enum ErrorCode {
+ OK,
+ NO_SUCH_SOURCE,
+ COULD_NOT_OPEN,
+ NO_SUCH_LINE,
+ NOT_ALLOWED,
+ NO_SUCH_BYTECODE,
+ DUPLICATE_BREAKPOINT,
+ NO_SUCH_BREAKPOINT,
+ WRONG_TYPE,
+ PARSE_ERROR,
+ NOT_YET_IMPLEMENTED,
+ SOURCE_PATH_NOT_SET,
+ ILLEGAL_PATH,
+ UNKNOWN_ERROR
+};
+
+
+class Error {
+ const ErrorLevel _errorLevel;
+ const ErrorCode _errorCode;
+ const int _errorExtraInt;
+ const Common::String _errorExtraString;
+public:
+ Error(ErrorLevel, ErrorCode);
+ Error(ErrorLevel, ErrorCode, int errorExtraInt);
+ Error(ErrorLevel, ErrorCode, Common::String errorExtraString);
+ Error(ErrorLevel, ErrorCode, Common::String errorExtraString, int errorExtraInt);
+ ErrorLevel getErrorLevel() const;
+ ErrorCode getErrorCode() const;
+ Common::String getErrorLevelStr() const;
+ Common::String getErrorDisplayStr() const;
+};
+
+} // End of namespace Wintermute
+
+#endif /* ERROR_H_ */
diff --git a/engines/wintermute/debugger/listing.cpp b/engines/wintermute/debugger/listing.cpp
new file mode 100644
index 0000000000..b8707fb842
--- /dev/null
+++ b/engines/wintermute/debugger/listing.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 "listing.h"
+#include "common/array.h"
+
+namespace Wintermute {
+
+Common::Array<ListingLine> Listing::getLines(uint begin, uint end) {
+ assert(begin <= end);
+ Common::Array<ListingLine> ret;
+ for (uint i = begin; i <= end; i++) {
+ ListingLine listingline;
+ listingline.number = i;
+ listingline.text = getLine(i);
+ ret.push_back(listingline);
+ }
+ return ret;
+}
+
+Common::Array<ListingLine> Listing::getLines(uint centre, uint before, uint after) {
+ uint begin = MAX(centre - before, (uint)1); // Line numbers start from 1
+ uint end = MIN(centre + after, (uint)(getLength() - 1)); // Line numbers start from 1
+ return getLines(begin, end);
+}
+
+} // End of namespace Wintermute
diff --git a/engines/wintermute/debugger/listing.h b/engines/wintermute/debugger/listing.h
new file mode 100644
index 0000000000..2ef21b702d
--- /dev/null
+++ b/engines/wintermute/debugger/listing.h
@@ -0,0 +1,64 @@
+/* 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 LISTING_H_
+#define LISTING_H_
+
+#include "common/array.h"
+
+
+namespace Common {
+
+class String;
+
+}
+
+namespace Wintermute {
+
+struct ListingLine {
+ uint number;
+ Common::String text;
+};
+
+class Listing {
+public:
+ virtual ~Listing() {};
+ /**
+ * @brief get the listing length (in lines)
+ */
+ virtual uint getLength() const = 0;
+ /**
+ * @brief return a specific line from a listing
+ * @param n line number
+ */
+ virtual Common::String getLine(uint n) = 0;
+ /**
+ * @brief shorthand to get a lump of lines instead of calling getLine a number of times
+ * Generally you won't need to redefine these
+ */
+ virtual Common::Array<ListingLine> getLines(uint centre, uint before, uint after);
+ virtual Common::Array<ListingLine> getLines(uint beginning, uint end);
+};
+
+} // End of namespace Wintermute
+
+#endif /* LISTING_H_ */
diff --git a/engines/wintermute/debugger/listing_provider.h b/engines/wintermute/debugger/listing_provider.h
new file mode 100644
index 0000000000..b5ea23e49b
--- /dev/null
+++ b/engines/wintermute/debugger/listing_provider.h
@@ -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.
+ *
+ */
+
+#ifndef LISTING_PROVIDER_H_
+#define LISTING_PROVIDER_H_
+
+#include "listing.h"
+#include "engines/wintermute/debugger/error.h"
+
+namespace Wintermute {
+
+class ListingProvider {
+public:
+ virtual ~ListingProvider() {};
+ /**
+ * Get a listing. When implementing this, the result should be safe to delete for the caller.
+ */
+ virtual Listing *getListing(const Common::String &filename, ErrorCode &error) = 0;
+};
+
+} // End of namespace Wintermute
+
+#endif /* LISTING_PROVIDER_H_ */
diff --git a/engines/wintermute/debugger/listing_providers/basic_source_listing_provider.cpp b/engines/wintermute/debugger/listing_providers/basic_source_listing_provider.cpp
new file mode 100644
index 0000000000..30d29ee23e
--- /dev/null
+++ b/engines/wintermute/debugger/listing_providers/basic_source_listing_provider.cpp
@@ -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.
+ *
+ */
+
+#include "basic_source_listing_provider.h"
+#include "engines/wintermute/base/base_file_manager.h"
+
+namespace Wintermute {
+BasicSourceListingProvider::BasicSourceListingProvider() : _fsDirectory(nullptr) {
+}
+
+BasicSourceListingProvider::~BasicSourceListingProvider() {
+}
+
+SourceListing *BasicSourceListingProvider::getListing(const Common::String &filename, ErrorCode &_err) {
+ _err = OK;
+ if (!_fsDirectory) {
+ _err = SOURCE_PATH_NOT_SET;
+ return nullptr;
+ };
+
+ Common::String unixFilename;
+
+ for (uint i = 0; i < filename.size(); i++) {
+ if (filename[i] == '\\') {
+ unixFilename.insertChar('/', unixFilename.size());
+ } else {
+ unixFilename.insertChar(filename[i], unixFilename.size());
+ }
+ }
+
+ Common::SeekableReadStream *file = _fsDirectory->createReadStreamForMember(unixFilename);
+ Common::Array<Common::String> strings;
+
+ if (!file) {
+ _err = NO_SUCH_SOURCE;
+ } else {
+ if (file->err()) {
+ _err = UNKNOWN_ERROR;
+ }
+ while (!file->eos()) {
+ strings.push_back(file->readLine());
+ if (file->err()) {
+ _err = UNKNOWN_ERROR;
+ }
+ }
+ }
+
+ if (_err == OK) {
+ return new SourceListing(strings);
+ } else {
+ return nullptr;
+ }
+}
+
+ErrorCode BasicSourceListingProvider::setPath(const Common::String &path) {
+ if (path == "")
+ return ILLEGAL_PATH;
+ delete _fsDirectory;
+ Common::FSNode node(path);
+ if (node.exists() && node.isDirectory()) {
+ _fsDirectory = new Common::FSDirectory(node, 64);
+ return OK;
+ } else {
+ return COULD_NOT_OPEN;
+ }
+}
+
+Common::String BasicSourceListingProvider::getPath() const {
+ if (!_fsDirectory) return "";
+ return _fsDirectory->getFSNode().getPath();
+}
+
+}
diff --git a/engines/wintermute/debugger/listing_providers/basic_source_listing_provider.h b/engines/wintermute/debugger/listing_providers/basic_source_listing_provider.h
new file mode 100644
index 0000000000..e242205578
--- /dev/null
+++ b/engines/wintermute/debugger/listing_providers/basic_source_listing_provider.h
@@ -0,0 +1,44 @@
+/* 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 BASIC_SOURCE_LISTING_PROVIDER_H_
+#define BASIC_SOURCE_LISTING_PROVIDER_H_
+
+#include "engines/wintermute/debugger/listing_provider.h"
+#include "source_listing_provider.h"
+#include "source_listing.h"
+#include "common/fs.h"
+
+namespace Wintermute {
+
+class BasicSourceListingProvider : public SourceListingProvider {
+ Common::FSDirectory *_fsDirectory;
+public:
+ BasicSourceListingProvider();
+ virtual ~BasicSourceListingProvider();
+ SourceListing *getListing(const Common::String &filename, ErrorCode &err);
+ ErrorCode setPath(const Common::String &path);
+ Common::String getPath() const;
+};
+
+}
+#endif /* BASIC_SOURCE_LISTING_PROVIDER_H_ */
diff --git a/engines/wintermute/debugger/listing_providers/blank_listing.cpp b/engines/wintermute/debugger/listing_providers/blank_listing.cpp
new file mode 100644
index 0000000000..928c91dc7f
--- /dev/null
+++ b/engines/wintermute/debugger/listing_providers/blank_listing.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 "blank_listing.h"
+#include "limits.h"
+
+namespace Wintermute {
+
+BlankListing::BlankListing(const Common::String filename) : _filename(filename) {}
+
+uint BlankListing::getLength() const { return UINT_MAX; }
+
+Common::String BlankListing::getLine(uint n) {
+ return "<no source for " + _filename + " ~~~ line: " + Common::String::format("%d", n) + ">";
+}
+BlankListing::~BlankListing() {}
+
+}
+
diff --git a/engines/wintermute/debugger/listing_providers/blank_listing.h b/engines/wintermute/debugger/listing_providers/blank_listing.h
new file mode 100644
index 0000000000..8c5ea19aa7
--- /dev/null
+++ b/engines/wintermute/debugger/listing_providers/blank_listing.h
@@ -0,0 +1,39 @@
+/* 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 BLANK_LISTING_H_
+#define BLANK_LISTING_H_
+#include "engines/wintermute/debugger/listing.h"
+
+namespace Wintermute {
+class BlankListing : public Listing {
+ const Common::String _filename;
+public:
+ BlankListing(const Common::String filename);
+ virtual ~BlankListing();
+ virtual uint getLength() const;
+ virtual Common::String getLine(uint n);
+};
+
+} // End of namespace Wintermute
+
+#endif
diff --git a/engines/wintermute/debugger/listing_providers/blank_listing_provider.cpp b/engines/wintermute/debugger/listing_providers/blank_listing_provider.cpp
new file mode 100644
index 0000000000..58e9e7e156
--- /dev/null
+++ b/engines/wintermute/debugger/listing_providers/blank_listing_provider.cpp
@@ -0,0 +1,35 @@
+/* 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 "blank_listing_provider.h"
+#include "blank_listing.h"
+namespace Wintermute {
+BlankListingProvider::BlankListingProvider() {}
+
+BlankListingProvider::~BlankListingProvider() {}
+
+Listing *BlankListingProvider::getListing(const Common::String &filename, ErrorCode &error) {
+ Listing *l = new BlankListing(filename);
+ error = OK;
+ return l; // Delete this sometime please.
+}
+} // End of namespace Wintermute
diff --git a/engines/wintermute/debugger/listing_providers/blank_listing_provider.h b/engines/wintermute/debugger/listing_providers/blank_listing_provider.h
new file mode 100644
index 0000000000..e583455c92
--- /dev/null
+++ b/engines/wintermute/debugger/listing_providers/blank_listing_provider.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 BLANK_LISTING_PROVIDER_H_
+#define BLANK_LISTING_PROVIDER_H_
+
+#include "engines/wintermute/debugger/listing.h"
+#include "engines/wintermute/debugger/listing_provider.h"
+#include "engines/wintermute/debugger/error.h"
+
+namespace Wintermute {
+class BlankListingProvider : public ListingProvider {
+public:
+ BlankListingProvider();
+ ~BlankListingProvider();
+ Listing *getListing(const Common::String &filename, ErrorCode &error);
+};
+} // End of namespace Wintermute
+#endif
diff --git a/engines/wintermute/debugger/listing_providers/cached_source_listing_provider.cpp b/engines/wintermute/debugger/listing_providers/cached_source_listing_provider.cpp
new file mode 100644
index 0000000000..20fe708380
--- /dev/null
+++ b/engines/wintermute/debugger/listing_providers/cached_source_listing_provider.cpp
@@ -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.
+ *
+ */
+
+#include "cached_source_listing_provider.h"
+#include "basic_source_listing_provider.h"
+#include "blank_listing_provider.h"
+#include "source_listing.h"
+
+namespace Wintermute {
+
+CachedSourceListingProvider::CachedSourceListingProvider() {
+ _sourceListingProvider = new BasicSourceListingProvider();
+ _fallbackListingProvider = new BlankListingProvider();
+}
+
+CachedSourceListingProvider::~CachedSourceListingProvider() {
+ delete _sourceListingProvider;
+ delete _fallbackListingProvider;
+ for (Common::HashMap<Common::String, SourceListing*>::iterator it = _cached.begin();
+ it != _cached.end(); it++) {
+ delete (it->_value);
+ }
+}
+
+Listing *CachedSourceListingProvider::getListing(const Common::String &filename, Wintermute::ErrorCode &error) {
+ if (_cached.contains(filename)) {
+ error = OK;
+ SourceListing *copy = new SourceListing(*_cached.getVal(filename));
+ return copy;
+ } else {
+ ErrorCode inner;
+ SourceListing *res = _sourceListingProvider->getListing(filename, inner);
+ if (inner == OK) {
+ SourceListing *copy = new SourceListing(*res);
+ _cached.setVal(filename, copy); // The cached copy is deleted on destruction
+ return res;
+ } else {
+ delete res;
+ return _fallbackListingProvider->getListing(filename, error);
+ }
+ }
+}
+
+void CachedSourceListingProvider::invalidateCache() {
+ for (Common::HashMap<Common::String, SourceListing*>::iterator it = _cached.begin();
+ it != _cached.end(); it++) {
+ delete (it->_value);
+ }
+ _cached.clear();
+}
+
+ErrorCode CachedSourceListingProvider::setPath(const Common::String &path) {
+ invalidateCache();
+ return _sourceListingProvider->setPath(path);
+}
+
+Common::String CachedSourceListingProvider::getPath() const {
+ return _sourceListingProvider->getPath();
+}
+
+} // End of namespace Wintermute
diff --git a/engines/wintermute/debugger/listing_providers/cached_source_listing_provider.h b/engines/wintermute/debugger/listing_providers/cached_source_listing_provider.h
new file mode 100644
index 0000000000..6e4925f2b4
--- /dev/null
+++ b/engines/wintermute/debugger/listing_providers/cached_source_listing_provider.h
@@ -0,0 +1,52 @@
+/* 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 CACHED_LISTING_PROVIDER_H_
+#define CACHED_LISTING_PROVIDER_H_
+
+#include "common/hashmap.h"
+#include "common/hash-str.h"
+#include "engines/wintermute/debugger/error.h"
+#include "source_listing_provider.h"
+
+namespace Wintermute {
+
+class BasicSourceListingProvider;
+class BlankListingProvider;
+class Listing;
+
+class CachedSourceListingProvider : public SourceListingProvider {
+ BasicSourceListingProvider *_sourceListingProvider;
+ BlankListingProvider *_fallbackListingProvider;
+ Common::HashMap<Common::String, SourceListing *> _cached;
+ void invalidateCache();
+public:
+ CachedSourceListingProvider();
+ virtual ~CachedSourceListingProvider();
+ ErrorCode setPath(const Common::String &path);
+ Common::String getPath() const;
+ Listing *getListing(const Common::String &filename, ErrorCode &err);
+};
+
+} // End of namespace Wintermute
+
+#endif /* CACHED_LISTING_PROVIDER_H_ */
diff --git a/engines/wintermute/debugger/listing_providers/source_listing.cpp b/engines/wintermute/debugger/listing_providers/source_listing.cpp
new file mode 100644
index 0000000000..ff81e20f02
--- /dev/null
+++ b/engines/wintermute/debugger/listing_providers/source_listing.cpp
@@ -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.
+ *
+ */
+
+#include "source_listing.h"
+
+namespace Wintermute {
+
+SourceListing::SourceListing(const Common::Array<Common::String> &strings) : _strings(strings) {}
+
+SourceListing::~SourceListing() {}
+
+uint SourceListing::getLength() const {
+ return _strings.size();
+}
+
+Common::String SourceListing::getLine(uint n) {
+ uint index = n - 1; // Line numbers start from 1, arrays from 0
+ /*
+ * Clients should not ask for a line number that
+ * is not in the source file.
+ * 0 is undefined, n - 1 is undefined.
+ * It is easy for the client to check that n > 0
+ * and n < getLength(), so it should just not happen.
+ * We return '^', after vim, to misbehaving clients.
+ */
+ if (n == 0) {
+ return Common::String("^");
+ }
+ if (index < getLength()) {
+ return _strings[index];
+ } else {
+ return Common::String("^");
+ }
+}
+
+} // End of namespace Wintermute
+
+
diff --git a/engines/wintermute/debugger/listing_providers/source_listing.h b/engines/wintermute/debugger/listing_providers/source_listing.h
new file mode 100644
index 0000000000..bf08578218
--- /dev/null
+++ b/engines/wintermute/debugger/listing_providers/source_listing.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.
+ *
+ */
+
+#ifndef SOURCE_LISTING_H_
+#define SOURCE_LISTING_H_
+#include "engines/wintermute/debugger/listing.h"
+
+namespace Wintermute {
+class SourceListing : public Listing {
+ const Common::Array<Common::String> _strings;
+public:
+ SourceListing(const Common::Array<Common::String> &strings);
+ virtual ~SourceListing();
+ virtual uint getLength() const;
+ virtual Common::String getLine(uint n);
+};
+}
+#endif /* DUMMY_LISTING_H_ */
diff --git a/engines/wintermute/debugger/listing_providers/source_listing_provider.h b/engines/wintermute/debugger/listing_providers/source_listing_provider.h
new file mode 100644
index 0000000000..18f05e56ed
--- /dev/null
+++ b/engines/wintermute/debugger/listing_providers/source_listing_provider.h
@@ -0,0 +1,49 @@
+/* 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 SOURCE_LISTING_PROVIDER_H_
+#define SOURCE_LISTING_PROVIDER_H_
+
+#include "engines/wintermute/debugger/error.h"
+#include "engines/wintermute/debugger/listing_provider.h"
+#include "common/str.h"
+
+namespace Wintermute {
+
+class SourceListing;
+class Listing;
+
+class SourceListingProvider : ListingProvider {
+public:
+ virtual ~SourceListingProvider() {};
+ /**
+ * Get a listing. When implementing this, the result should be safe to delete for the caller.
+ */
+ virtual Listing *getListing(const Common::String &filename, ErrorCode &err) = 0;
+ virtual ErrorCode setPath(const Common::String &path) = 0;
+ virtual Common::String getPath() const = 0;
+
+};
+
+} // End of namespace Wintermute
+
+#endif /* SOURCE_LISTING_PROVIDER_H_ */
diff --git a/engines/wintermute/debugger/script_monitor.cpp b/engines/wintermute/debugger/script_monitor.cpp
new file mode 100644
index 0000000000..2e9370c923
--- /dev/null
+++ b/engines/wintermute/debugger/script_monitor.cpp
@@ -0,0 +1,26 @@
+/* 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 "script_monitor.h"
+
+namespace Wintermute {
+}
diff --git a/engines/wintermute/debugger/script_monitor.h b/engines/wintermute/debugger/script_monitor.h
new file mode 100644
index 0000000000..e9559e2ade
--- /dev/null
+++ b/engines/wintermute/debugger/script_monitor.h
@@ -0,0 +1,43 @@
+/* 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 SCRIPTMONITOR_H_
+#define SCRIPTMONITOR_H_
+
+namespace Wintermute {
+
+class DebuggableScript;
+class Breakpoint;
+class Watch;
+
+class ScriptMonitor {
+public:
+
+ virtual ~ScriptMonitor() {};
+ virtual void notifyStep(DebuggableScript* script) = 0;
+ virtual void onBreakpoint(const Breakpoint* breakpoint, DebuggableScript* script) = 0;
+ virtual void onWatch(const Watch* watch, DebuggableScript* script) = 0;
+};
+
+} // End of namespace Wintermute
+
+#endif /* SCRIPTMONITOR_H_ */
diff --git a/engines/wintermute/debugger/watch.cpp b/engines/wintermute/debugger/watch.cpp
new file mode 100644
index 0000000000..410756fdc8
--- /dev/null
+++ b/engines/wintermute/debugger/watch.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 "watch.h"
+#include "watch_instance.h"
+#include "script_monitor.h"
+
+namespace Wintermute {
+
+Watch::Watch(const Common::String &filename, const Common::String &symbol, ScriptMonitor* monitor) : _enabled(false), _filename(filename), _symbol(symbol), _monitor(monitor) {}
+
+Watch::~Watch() { /* Nothing to take care of in here */ }
+
+void Watch::trigger(WatchInstance* instance) {
+ _monitor->onWatch(this, instance->_script);
+}
+
+Common::String Watch::getFilename() const { return _filename; }
+Common::String Watch::getSymbol() const { return _symbol; }
+bool Watch::isEnabled() const { return _enabled; }
+void Watch::enable() { _enabled = true; }
+void Watch::disable() { _enabled = false; }
+}
diff --git a/engines/wintermute/debugger/watch.h b/engines/wintermute/debugger/watch.h
new file mode 100644
index 0000000000..cbffe43b41
--- /dev/null
+++ b/engines/wintermute/debugger/watch.h
@@ -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.
+ *
+ */
+
+#ifndef WATCH_H_
+#define WATCH_H_
+
+#include "common/str.h"
+
+namespace Wintermute {
+
+class ScValue;
+class ScScript;
+class WatchInstance;
+class ScriptMonitor;
+
+class Watch {
+ const Common::String _filename;
+ const Common::String _symbol;
+ int _enabled;
+ ScriptMonitor *_monitor;
+public:
+ Watch(const Common::String &filename, const Common::String &symbol, ScriptMonitor*);
+ Common::String getFilename() const;
+ Common::String getSymbol() const;
+ bool isEnabled() const;
+ void enable();
+ void disable();
+ void trigger(WatchInstance*);
+ virtual ~Watch();
+};
+}
+#endif /* WATCH_H_ */
diff --git a/engines/wintermute/debugger/watch_instance.cpp b/engines/wintermute/debugger/watch_instance.cpp
new file mode 100644
index 0000000000..2d31221ad4
--- /dev/null
+++ b/engines/wintermute/debugger/watch_instance.cpp
@@ -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.
+ *
+ */
+
+#include "watch_instance.h"
+#include "engines/wintermute/base/scriptables/script_value.h"
+#include "engines/wintermute/base/scriptables/debuggable/debuggable_script.h"
+#include "engines/wintermute/debugger/watch.h"
+
+namespace Wintermute {
+
+WatchInstance::WatchInstance(Watch* watch, DebuggableScript* script) : _watch(watch), _script(script), _lastValue(nullptr) {}
+WatchInstance::~WatchInstance() { delete _lastValue; }
+
+void WatchInstance::evaluate() {
+ if (_watch->isEnabled()) {
+ if (!_watch->getFilename().compareTo(_script->_filename)) {
+
+ if(_lastValue == nullptr) {
+ _lastValue = new ScValue(_script->_gameRef);
+ // ^^ This here is NULL by default
+ }
+ ScValue* currentValue = _script->resolveName(_watch->getSymbol());
+ if(ScValue::compare(
+ currentValue,
+ _lastValue
+ )) {
+ _lastValue->copy(currentValue);
+ _watch->trigger(this);
+ }
+ delete currentValue;
+ }
+ }
+}
+} // End of namespace Wintermute
diff --git a/engines/wintermute/debugger/watch_instance.h b/engines/wintermute/debugger/watch_instance.h
new file mode 100644
index 0000000000..84fb62968d
--- /dev/null
+++ b/engines/wintermute/debugger/watch_instance.h
@@ -0,0 +1,44 @@
+/* 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 WATCH_INSTANCE_H_
+#define WATCH_INSTANCE_H_
+
+namespace Wintermute {
+class Watch;
+class ScValue;
+class DebuggableScript;
+
+class WatchInstance {
+ Watch* _watch;
+ ScValue *_lastValue;
+ DebuggableScript* _script;
+public:
+ WatchInstance (Watch* watch, DebuggableScript* script);
+ ~WatchInstance();
+ void evaluate();
+friend class DebuggableScript;
+friend class Watch;
+};
+} // End of namespace Wintermute
+
+#endif /* WATCH_INSTANCE_H_ */
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 4e3320159a..ca30204462 100644
--- a/engines/wintermute/detection_tables.h
+++ b/engines/wintermute/detection_tables.h
@@ -140,9 +140,18 @@ static const WMEGameDescription gameDescriptions[] = {
// Five Lethal Demons
WME_WINENTRY("5ld", "",
WME_ENTRY1s("data.dcp", "1037a77cbd001e0644898addc022322c", 15407750), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
- // Five Magical Amulets
+ // Five Magical Amulets (Czech)
WME_WINENTRY("5ma", "",
- WME_ENTRY1s("data.dcp", "0134e92bcd5fd2837df3971087e96067", 163316498), Common::EN_ANY, ADGF_UNSTABLE, WME_1_7_0),
+ WME_ENTRY2s("czech.dcp", "7b2515a8ceb955c72bc14f0f1fca869e", 184,
+ "data.dcp", "0134e92bcd5fd2837df3971087e96067", 163316498), Common::CZ_CZE, ADGF_UNSTABLE, WME_1_7_0),
+ // Five Magical Amulets (English)
+ WME_WINENTRY("5ma", "",
+ WME_ENTRY2s("english.dcp", "2f97bca09260ba23b645da9f0855ce7f", 893681,
+ "data.dcp", "0134e92bcd5fd2837df3971087e96067", 163316498), Common::EN_ANY, ADGF_UNSTABLE, WME_1_7_0),
+ // Five Magical Amulets (Polish)
+ WME_WINENTRY("5ma", "",
+ WME_ENTRY2s("polish.dcp", "bb877d48795471a17f25b0b5109100d1", 1132197,
+ "data.dcp", "0134e92bcd5fd2837df3971087e96067", 163316498), Common::PL_POL, ADGF_UNSTABLE, WME_1_7_0),
// Actual Destination
WME_WINENTRY("actualdest", "",
WME_ENTRY1s("data.dcp", "6926f44b26f21ceb1d840eaab9aeb510", 9081740), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
@@ -172,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),
@@ -334,6 +346,22 @@ static const WMEGameDescription gameDescriptions[] = {
// Oknytt
WME_WINENTRY("oknytt", "Version 1.0",
WME_ENTRY1s("data.dcp", "6456cf8f429905c83f07509f9da536dd", 109502959), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
+ // Oknytt (Version 1.13 English) (These are detected along with d_sounds.dcp to avoid mass-detecting in the languages-subfolder.)
+ WME_WINENTRY("oknytt", "Version 1.13",
+ WME_ENTRY2s("english.dcp", "d2afd722c78cfe66b7d4250d11f6ae16", 293274135,
+ "d_sounds.dcp", "7d04dff8ca11174486bd4b7a80fdcabb", 154943401), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
+ // Oknytt (Version 1.13 German)
+ WME_WINENTRY("oknytt", "Version 1.13",
+ WME_ENTRY2s("german.dcp", "0fc6401d8d76b04f6da49206ecafa0dc", 304292574,
+ "d_sounds.dcp", "7d04dff8ca11174486bd4b7a80fdcabb", 154943401), Common::DE_DEU, ADGF_UNSTABLE, LATEST_VERSION),
+ // Oknytt (Version 1.13 Russian)
+ WME_WINENTRY("oknytt", "Version 1.13",
+ WME_ENTRY2s("russian.dcp", "dd24a1c0b36a82e2b02fb6c1050d4aad", 362681669,
+ "d_sounds.dcp", "7d04dff8ca11174486bd4b7a80fdcabb", 154943401), Common::RU_RUS, ADGF_UNSTABLE, LATEST_VERSION),
+ // Oknytt (Version 1.13 Spanish)
+ WME_WINENTRY("oknytt", "Version 1.13",
+ WME_ENTRY2s("spanish.dcp", "10c46152cb29581671f3b6b7c229c957", 319406572,
+ "d_sounds.dcp", "7d04dff8ca11174486bd4b7a80fdcabb", 154943401), Common::ES_ESP, ADGF_UNSTABLE, LATEST_VERSION),
// Night Train Demo
WME_WINENTRY("nighttrain", "",
WME_ENTRY1s("data.dcp", "5a027ef84b083a730c9a4c85ec1d3a32", 131760816), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION),
diff --git a/engines/wintermute/module.mk b/engines/wintermute/module.mk
index 4c95314a02..2c9c2e0180 100644
--- a/engines/wintermute/module.mk
+++ b/engines/wintermute/module.mk
@@ -27,6 +27,8 @@ MODULE_OBJS := \
ad/ad_talk_holder.o \
ad/ad_talk_node.o \
ad/ad_waypoint_group.o \
+ base/scriptables/debuggable/debuggable_script.o \
+ base/scriptables/debuggable/debuggable_script_engine.o \
base/scriptables/script.o \
base/scriptables/script_engine.o \
base/scriptables/script_stack.o \
@@ -88,6 +90,18 @@ MODULE_OBJS := \
base/saveload.o \
base/save_thumb_helper.o \
base/timer.o \
+ debugger/breakpoint.o \
+ debugger/debugger_controller.o \
+ debugger/error.o \
+ debugger/listing_providers/blank_listing.o \
+ debugger/listing_providers/blank_listing_provider.o \
+ debugger/listing_providers/basic_source_listing_provider.o \
+ debugger/listing_providers/cached_source_listing_provider.o \
+ debugger/listing_providers/source_listing.o \
+ debugger/listing.o \
+ debugger/script_monitor.o \
+ debugger/watch.o \
+ debugger/watch_instance.o \
detection.o \
math/math_util.o \
math/matrix4.o \
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/utils/convert_utf.cpp b/engines/wintermute/utils/convert_utf.cpp
index 7ebc011d01..cdb48103d0 100644
--- a/engines/wintermute/utils/convert_utf.cpp
+++ b/engines/wintermute/utils/convert_utf.cpp
@@ -55,8 +55,6 @@ static const UTF32 halfMask = 0x3FFUL;
#define UNI_SUR_HIGH_END (UTF32)0xDBFF
#define UNI_SUR_LOW_START (UTF32)0xDC00
#define UNI_SUR_LOW_END (UTF32)0xDFFF
-#define false 0
-#define true 1
/* --------------------------------------------------------------------- */
@@ -311,7 +309,7 @@ ConversionResult ConvertUTF16toUTF8(
* definition of UTF-8 goes up to 4-byte sequences.
*/
-static Boolean isLegalUTF8(const UTF8 *source, int length) {
+static bool isLegalUTF8(const UTF8 *source, int length) {
UTF8 a;
const UTF8 *srcptr = source + length;
switch (length) {
@@ -356,7 +354,7 @@ static Boolean isLegalUTF8(const UTF8 *source, int length) {
* Exported function to return whether a UTF-8 sequence is legal or not.
* This is not used here; it's just exported.
*/
-Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
+bool isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
int length = trailingBytesForUTF8[*source] + 1;
if (source + length > sourceEnd) {
return false;
diff --git a/engines/wintermute/utils/convert_utf.h b/engines/wintermute/utils/convert_utf.h
index a5f34456f5..d2e54f4af4 100644
--- a/engines/wintermute/utils/convert_utf.h
+++ b/engines/wintermute/utils/convert_utf.h
@@ -96,7 +96,6 @@ namespace Wintermute {
typedef uint32 UTF32; /* at least 32 bits */
typedef uint16 UTF16; /* at least 16 bits */
typedef uint8 UTF8; /* typically 8 bits */
-typedef uint8 Boolean; /* 0 or 1 */
/* Some fundamental constants */
#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
@@ -141,7 +140,7 @@ ConversionResult ConvertUTF32toUTF16(
const UTF32 **sourceStart, const UTF32 *sourceEnd,
UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags);
-Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
+bool isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
} // End of namespace Wintermute
diff --git a/engines/wintermute/wintermute.cpp b/engines/wintermute/wintermute.cpp
index e35bb60c3d..05dfb961cb 100644
--- a/engines/wintermute/wintermute.cpp
+++ b/engines/wintermute/wintermute.cpp
@@ -41,6 +41,7 @@
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/scriptables/script_engine.h"
+#include "engines/wintermute/debugger/debugger_controller.h"
namespace Wintermute {
@@ -49,6 +50,7 @@ namespace Wintermute {
WintermuteEngine::WintermuteEngine() : Engine(g_system) {
_game = new AdGame("");
_debugger = nullptr;
+ _dbgController = nullptr;
_trigDebug = false;
_gameDescription = nullptr;
}
@@ -76,6 +78,7 @@ WintermuteEngine::WintermuteEngine(OSystem *syst, const WMEGameDescription *desc
_game = nullptr;
_debugger = nullptr;
+ _dbgController = nullptr;
_trigDebug = false;
}
@@ -112,6 +115,7 @@ Common::Error WintermuteEngine::run() {
}
// Create debugger console. It requires GFX to be initialized
+ _dbgController = new DebuggerController(this);
_debugger = new Console(this);
// DebugMan.enableDebugChannel("enginelog");
@@ -133,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;
@@ -171,7 +175,6 @@ int WintermuteEngine::init() {
}
_game->initialize3();
-
// initialize sound manager (non-fatal if we fail)
ret = _game->_soundMgr->initialize();
if (DID_FAIL(ret)) {
@@ -200,6 +203,8 @@ int WintermuteEngine::init() {
_game->loadGame(slot);
}
+ _game->_scEngine->attachMonitor(_dbgController);
+
// all set, ready to go
return 0;
}
diff --git a/engines/wintermute/wintermute.h b/engines/wintermute/wintermute.h
index f8f5fc7deb..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"
@@ -33,6 +33,8 @@ namespace Wintermute {
class Console;
class BaseGame;
class SystemClassRegistry;
+class DebuggerController;
+
// our engine debug channels
enum {
kWintermuteDebugLog = 1 << 0, // The debug-logs from the original engine
@@ -49,7 +51,7 @@ public:
WintermuteEngine();
~WintermuteEngine();
- virtual GUI::Debugger *getDebugger() { return _debugger; }
+ virtual Wintermute::Console *getConsole() { return _debugger; }
void trigDebugger() { _trigDebug = true; }
virtual Common::Error run();
@@ -66,11 +68,13 @@ private:
int init();
void deinit();
int messageLoop();
- GUI::Debugger *_debugger;
+ Wintermute::Console *_debugger;
BaseGame *_game;
+ Wintermute::DebuggerController *_dbgController;
const WMEGameDescription *_gameDescription;
friend class Console;
+ friend class DebuggerController;
};
} // End of namespace Wintermute
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 f44e653c2a..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 {
@@ -82,20 +82,20 @@ public:
bool ZVisionMetaEngine::hasFeature(MetaEngineFeature f) const {
return
- (f == kSupportsListSaves) ||
- (f == kSupportsLoadingDuringStartup) ||
- (f == kSupportsDeleteSave) ||
- (f == kSavesSupportMetaInfo) ||
- (f == kSavesSupportThumbnail) ||
- (f == kSavesSupportCreationDate);
- //(f == kSavesSupportPlayTime);
+ (f == kSupportsListSaves) ||
+ (f == kSupportsLoadingDuringStartup) ||
+ (f == kSupportsDeleteSave) ||
+ (f == kSavesSupportMetaInfo) ||
+ (f == kSavesSupportThumbnail) ||
+ (f == kSavesSupportCreationDate);
+ //(f == kSavesSupportPlayTime);
}
bool ZVision::ZVision::hasFeature(EngineFeature f) const {
- return
- (f == kSupportsRTL) ||
- (f == kSupportsLoadingDuringRuntime) ||
- (f == kSupportsSavingDuringRuntime);
+ return
+ (f == kSupportsRTL) ||
+ (f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsSavingDuringRuntime);
}
Common::Error ZVision::ZVision::loadGameState(int slot) {
@@ -128,33 +128,34 @@ SaveStateList ZVisionMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
ZVision::SaveGameHeader header;
Common::String pattern = target;
- pattern += ".???";
+ pattern += ".###";
Common::StringArray filenames;
filenames = saveFileMan->listSavefiles(pattern.c_str());
- Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)*/
SaveStateList saveList;
// We only use readSaveGameHeader() here, which doesn't need an engine callback
ZVision::SaveManager *zvisionSaveMan = new ZVision::SaveManager(NULL);
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);
-
- if (slotNum >= 0 && slotNum <= 999) {
- Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
- if (in) {
- if (zvisionSaveMan->readSaveGameHeader(in, header)) {
- saveList.push_back(SaveStateDescriptor(slotNum, header.saveName));
- }
- delete in;
- }
- }
+ // Obtain the last 3 digits of the filename, since they correspond to the save slot
+ int slotNum = atoi(file->c_str() + file->size() - 3);
+
+ if (slotNum >= 0 && slotNum <= 999) {
+ Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
+ if (in) {
+ if (zvisionSaveMan->readSaveGameHeader(in, header)) {
+ saveList.push_back(SaveStateDescriptor(slotNum, header.saveName));
+ }
+ delete in;
+ }
+ }
}
delete zvisionSaveMan;
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
@@ -164,26 +165,7 @@ int ZVisionMetaEngine::getMaximumSaveSlot() const {
void ZVisionMetaEngine::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 ZVisionMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
@@ -191,48 +173,48 @@ SaveStateDescriptor ZVisionMetaEngine::querySaveMetaInfos(const char *target, in
Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(filename.c_str());
if (in) {
- ZVision::SaveGameHeader header;
+ ZVision::SaveGameHeader header;
// We only use readSaveGameHeader() here, which doesn't need an engine callback
ZVision::SaveManager *zvisionSaveMan = new ZVision::SaveManager(NULL);
bool successfulRead = zvisionSaveMan->readSaveGameHeader(in, header);
delete zvisionSaveMan;
- delete in;
+ delete in;
- if (successfulRead) {
- SaveStateDescriptor desc(slot, header.saveName);
+ if (successfulRead) {
+ SaveStateDescriptor desc(slot, header.saveName);
// Do not allow save slot 0 (used for auto-saving) to be deleted or
// overwritten.
desc.setDeletableFlag(slot != 0);
desc.setWriteProtectedFlag(slot == 0);
- desc.setThumbnail(header.thumbnail);
+ desc.setThumbnail(header.thumbnail);
- if (header.version > 0) {
- int day = header.saveDay;
- int month = header.saveMonth;
- int year = header.saveYear;
+ if (header.version > 0) {
+ int day = header.saveDay;
+ int month = header.saveMonth;
+ int year = header.saveYear;
- desc.setSaveDate(year, month, day);
+ desc.setSaveDate(year, month, day);
- int hour = header.saveHour;
- int minutes = header.saveMinutes;
+ int hour = header.saveHour;
+ int minutes = header.saveMinutes;
- desc.setSaveTime(hour, minutes);
+ desc.setSaveTime(hour, minutes);
- //desc.setPlayTime(header.playTime * 1000);
- }
+ //desc.setPlayTime(header.playTime * 1000);
+ }
- return desc;
- }
+ return desc;
+ }
}
return SaveStateDescriptor();
}
#if PLUGIN_ENABLED_DYNAMIC(ZVISION)
-REGISTER_PLUGIN_DYNAMIC(ZVISION, PLUGIN_TYPE_ENGINE, ZVisionMetaEngine);
+ REGISTER_PLUGIN_DYNAMIC(ZVISION, PLUGIN_TYPE_ENGINE, ZVisionMetaEngine);
#else
-REGISTER_PLUGIN_STATIC(ZVISION, PLUGIN_TYPE_ENGINE, ZVisionMetaEngine);
+ REGISTER_PLUGIN_STATIC(ZVISION, PLUGIN_TYPE_ENGINE, ZVisionMetaEngine);
#endif
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/text/truetype_font.cpp b/engines/zvision/text/truetype_font.cpp
index acb053ea8d..ccb86d9440 100644
--- a/engines/zvision/text/truetype_font.cpp
+++ b/engines/zvision/text/truetype_font.cpp
@@ -123,7 +123,7 @@ bool StyledTTFont::loadFont(const Common::String &fontName, int32 point, uint st
!file.open(freeFontName) && !_engine->getSearchManager()->openFile(file, freeFontName))
error("Unable to open font file %s (Liberation Font alternative: %s, FreeFont alternative: %s)", newFontName.c_str(), liberationFontName.c_str(), freeFontName.c_str());
- Graphics::Font *newFont = Graphics::loadTTFFont(file, point, 60, (sharp ? Graphics::kTTFRenderModeMonochrome : Graphics::kTTFRenderModeNormal)); // 66 dpi for 640 x 480 on 14" display
+ Graphics::Font *newFont = Graphics::loadTTFFont(file, point, Graphics::kTTFSizeModeCell, 0, (sharp ? Graphics::kTTFRenderModeMonochrome : Graphics::kTTFRenderModeNormal));
if (newFont == nullptr) {
return false;
}
diff --git a/engines/zvision/zvision.cpp b/engines/zvision/zvision.cpp
index 779fdc4464..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"
@@ -136,9 +136,6 @@ void ZVision::registerDefaultSettings() {
ConfMan.registerDefault(settingsKeys[i].name, settingsKeys[i].defaultBoolValue);
}
}
-
- ConfMan.registerDefault("originalsaveload", false);
- ConfMan.registerDefault("doublefps", false);
}
void ZVision::loadSettings() {
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 81a0c04441..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);
}
/****************************
@@ -441,13 +603,56 @@ template<typename PixelType>
void VectorRendererSpec<PixelType>::
gradientFill(PixelType *ptr, int width, int x, int y) {
bool ox = ((y & 1) == 1);
- int stripSize;
int curGrad = 0;
while (_gradIndexes[curGrad + 1] <= y)
curGrad++;
- stripSize = _gradIndexes[curGrad + 1] - _gradIndexes[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++) {
+ 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>::
+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;
@@ -465,6 +670,7 @@ gradientFill(PixelType *ptr, int width, int x, int y) {
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) ||
@@ -502,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(
@@ -553,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;
@@ -589,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();
@@ -666,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
@@ -709,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 *
@@ -773,8 +1165,8 @@ drawLine(int x1, int y1, int x2, int y2) {
SWAP(y1, y2);
}
- int dx = ABS(x2 - x1);
- int dy = ABS(y2 - y1);
+ uint dx = ABS(x2 - x1);
+ uint dy = ABS(y2 - y1);
// this is a point, not a line. stoopid.
if (dy == 0 && dx == 0)
@@ -803,7 +1195,7 @@ drawLine(int x1, int y1, int x2, int y2) {
ptr += pitch;
}
- } else if (ABS(dx) == ABS(dy)) { // diagonal lines
+ } else if (dx == dy) { // diagonal lines
// these ones also use a fixed pitch increase
pitch += (x2 > x1) ? 1 : -1;
@@ -817,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>::
@@ -856,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>::
@@ -893,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>::
@@ -919,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)
@@ -955,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)
@@ -1021,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;
+}
/********************************************************************
@@ -1034,6 +1799,11 @@ drawTriangle(int x, int y, int w, int h, TriangleOrientation orient) {
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawTabAlg(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;
@@ -1128,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>::
@@ -1190,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>::
@@ -1234,10 +2184,66 @@ 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>::
drawSquareAlg(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;
@@ -1267,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>::
@@ -1323,10 +2369,76 @@ 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>::
-drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color) {
+drawLineAlg(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;
@@ -1371,6 +2483,59 @@ drawLineAlg(int x1, int y1, int x2, int y2, int dx, int 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
@@ -1393,6 +2558,12 @@ drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color) {
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawTriangleVertAlg(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;
if (!inverted) {
@@ -1422,6 +2593,9 @@ drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color
blendPixelPtr(floor, color, 50);
#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
@@ -1560,10 +2734,221 @@ 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>::
drawTriangleFast(int x1, int y1, int size, bool inverted, PixelType color, VectorRenderer::FillMode fill_m) {
+ // Do not draw anything for empty rects.
+ if (size <= 0) {
+ return;
+ }
+
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
if (!inverted) {
@@ -1657,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)));
@@ -1684,7 +3072,80 @@ 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) {
+ return;
+ }
+
int f, ddF_x, ddF_y;
int x, y, px, py;
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
@@ -1710,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);
@@ -1751,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;
@@ -1780,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>::
@@ -1824,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);
+ }
+ }
+}
/********************************************************************
@@ -1835,6 +3455,11 @@ drawCircleAlg(int x1, int y1, int r, PixelType color, VectorRenderer::FillMode f
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawSquareShadow(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;
@@ -1870,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;
@@ -1907,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);
@@ -1943,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;
+ }
+}
/******************************************************************************/
@@ -1956,8 +3705,7 @@ drawRoundedSquareShadow(int x1, int y1, int r, int w, int h, int offset) {
/** LINES **/
template<typename PixelType>
void VectorRendererAA<PixelType>::
-drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color) {
-
+drawLineAlg(int x1, int y1, int x2, int y2, uint dx, uint dy, PixelType color) {
PixelType *ptr = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
int pitch = Base::_activeSurface->pitch / Base::_activeSurface->format.bytesPerPixel;
int xdir = (x2 > x1) ? 1 : -1;
@@ -1967,7 +3715,7 @@ drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color) {
*ptr = (PixelType)color;
if (dx > dy) {
- gradient = (uint32)(dy << 16) / (uint32)dx;
+ gradient = (dy << 16) / dx;
error_acc = 0;
while (--dx) {
@@ -1983,8 +3731,8 @@ drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color) {
this->blendPixelPtr(ptr, color, ~alpha);
this->blendPixelPtr(ptr + pitch, color, alpha);
}
- } else {
- gradient = (uint32)(dx << 16) / (uint32)dy;
+ } else if (dy != 0) {
+ gradient = (dx << 16) / dy;
error_acc = 0;
while (--dy) {
@@ -2009,6 +3757,11 @@ drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color) {
template<typename PixelType>
void VectorRendererAA<PixelType>::
drawTabAlg(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 x, y, px, py;
int pitch = Base::_activeSurface->pitch / Base::_activeSurface->format.bytesPerPixel;
int sw = 0, sp = 0, hp = 0;
@@ -2217,6 +3970,14 @@ 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;
+ }
+
int x, y;
const int pitch = Base::_activeSurface->pitch / Base::_activeSurface->format.bytesPerPixel;
int px, py;
@@ -2228,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 f47cc3997a..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
@@ -150,42 +173,76 @@ protected:
* @see VectorRendererAA::drawCircleAlg
*/
virtual void drawLineAlg(int x1, int y1, int x2, int y2,
- int dx, int dy, PixelType color);
+ 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;
@@ -278,7 +351,7 @@ protected:
*
* @see VectorRenderer::drawLineAlg()
*/
- virtual void drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color);
+ virtual void drawLineAlg(int x1, int y1, int x2, int y2, uint dx, uint dy, PixelType color);
/**
* "Wu's Circle Antialiasing Algorithm" as published by Xiaolin Wu, July 1991
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/fonts/ttf.cpp b/graphics/fonts/ttf.cpp
index dc7335f1c2..76b7f731be 100644
--- a/graphics/fonts/ttf.cpp
+++ b/graphics/fonts/ttf.cpp
@@ -33,11 +33,15 @@
#include "common/singleton.h"
#include "common/stream.h"
+#include "common/memstream.h"
#include "common/hashmap.h"
+#include "common/ptr.h"
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
+#include FT_TRUETYPE_TABLES_H
+#include FT_TRUETYPE_TAGS_H
namespace Graphics {
@@ -47,6 +51,10 @@ inline int ftCeil26_6(FT_Pos x) {
return (x + 63) / 64;
}
+inline int divRoundToNearest(int dividend, int divisor) {
+ return (dividend + (divisor / 2)) / divisor;
+}
+
} // End of anonymous namespace
class TTFLibrary : public Common::Singleton<TTFLibrary> {
@@ -101,7 +109,7 @@ public:
TTFFont();
virtual ~TTFFont();
- bool load(Common::SeekableReadStream &stream, int size, uint dpi, TTFRenderMode renderMode, const uint32 *mapping);
+ bool load(Common::SeekableReadStream &stream, int size, TTFSizeMode sizeMode, uint dpi, TTFRenderMode renderMode, const uint32 *mapping);
virtual int getFontHeight() const;
@@ -137,6 +145,12 @@ private:
bool _allowLateCaching;
void assureCached(uint32 chr) const;
+ Common::SeekableReadStream *readTTFTable(FT_ULong tag) const;
+
+ int computePointSize(int size, TTFSizeMode sizeMode) const;
+ int readPointSizeFromVDMXTable(int height) const;
+ int computePointSizeFromHeaders(int height) const;
+
FT_Int32 _loadFlags;
FT_Render_Mode _renderMode;
bool _hasKerning;
@@ -162,7 +176,7 @@ TTFFont::~TTFFont() {
}
}
-bool TTFFont::load(Common::SeekableReadStream &stream, int size, uint dpi, TTFRenderMode renderMode, const uint32 *mapping) {
+bool TTFFont::load(Common::SeekableReadStream &stream, int size, TTFSizeMode sizeMode, uint dpi, TTFRenderMode renderMode, const uint32 *mapping) {
if (!g_ttf.isInitialized())
return false;
@@ -200,7 +214,7 @@ bool TTFFont::load(Common::SeekableReadStream &stream, int size, uint dpi, TTFRe
// Check whether we have kerning support
_hasKerning = (FT_HAS_KERNING(_face) != 0);
- if (FT_Set_Char_Size(_face, 0, size * 64, dpi, dpi)) {
+ if (FT_Set_Char_Size(_face, 0, computePointSize(size, sizeMode) * 64, dpi, dpi)) {
delete[] _ttfFile;
_ttfFile = 0;
@@ -262,6 +276,126 @@ bool TTFFont::load(Common::SeekableReadStream &stream, int size, uint dpi, TTFRe
return _initialized;
}
+int TTFFont::computePointSize(int size, TTFSizeMode sizeMode) const {
+ int ptSize = 0;
+ switch (sizeMode) {
+ case kTTFSizeModeCell: {
+ ptSize = readPointSizeFromVDMXTable(size);
+
+ if (ptSize == 0) {
+ ptSize = computePointSizeFromHeaders(size);
+ }
+
+ if (ptSize == 0) {
+ warning("Unable to compute point size for font '%s'", _face->family_name);
+ ptSize = 1;
+ }
+ break;
+ }
+ case kTTFSizeModeCharacter:
+ ptSize = size;
+ break;
+ }
+
+ return ptSize;
+}
+
+Common::SeekableReadStream *TTFFont::readTTFTable(FT_ULong tag) const {
+ // Find the required buffer size by calling the load function with nullptr
+ FT_ULong size = 0;
+ FT_Error err = FT_Load_Sfnt_Table(_face, tag, 0, nullptr, &size);
+ if (err) {
+ return nullptr;
+ }
+
+ byte *buf = (byte *)malloc(size);
+ if (!buf) {
+ return nullptr;
+ }
+
+ err = FT_Load_Sfnt_Table(_face, tag, 0, buf, &size);
+ if (err) {
+ free(buf);
+ return nullptr;
+ }
+
+ return new Common::MemoryReadStream(buf, size, DisposeAfterUse::YES);
+}
+
+int TTFFont::readPointSizeFromVDMXTable(int height) const {
+ // The Vertical Device Metrics table matches font heights with point sizes.
+ // FreeType does not expose it, we have to parse it ourselves.
+ // See https://www.microsoft.com/typography/otspec/vdmx.htm
+
+ Common::ScopedPtr<Common::SeekableReadStream> vdmxBuf(readTTFTable(TTAG_VDMX));
+ if (!vdmxBuf) {
+ return 0;
+ }
+
+ // Read the main header
+ vdmxBuf->skip(4); // Skip the version
+ uint16 numRatios = vdmxBuf->readUint16BE();
+
+ // Compute the starting position for the group table positions table
+ int32 offsetTableStart = vdmxBuf->pos() + 4 * numRatios;
+
+ // Search the ratio table for the 1:1 ratio, or the default record (0, 0, 0)
+ int32 selectedRatio = -1;
+ for (uint16 i = 0; i < numRatios; i++) {
+ vdmxBuf->skip(1); // Skip the charset subset
+ uint8 xRatio = vdmxBuf->readByte();
+ uint8 yRatio1 = vdmxBuf->readByte();
+ uint8 yRatio2 = vdmxBuf->readByte();
+
+ if ((xRatio == 1 && yRatio1 <= 1 && yRatio2 >= 1)
+ || (xRatio == 0 && yRatio1 == 0 && yRatio2 == 0)) {
+ selectedRatio = i;
+ break;
+ }
+ }
+ if (selectedRatio < 0) {
+ return 0;
+ }
+
+ // Read from group table positions table to get the group table offset
+ vdmxBuf->seek(offsetTableStart + sizeof(uint16) * selectedRatio);
+ uint16 groupOffset = vdmxBuf->readUint16BE();
+
+ // Read the group table header
+ vdmxBuf->seek(groupOffset);
+ uint16 numRecords = vdmxBuf->readUint16BE();
+ vdmxBuf->skip(2); // Skip the table bounds
+
+ // Search a record matching the required height
+ for (uint16 i = 0; i < numRecords; i++) {
+ uint16 pointSize = vdmxBuf->readUint16BE();
+ int16 yMax = vdmxBuf->readSint16BE();
+ int16 yMin = vdmxBuf->readSint16BE();
+
+ if (yMax + -yMin > height) {
+ return 0;
+ }
+ if (yMax + -yMin == height) {
+ return pointSize;
+ }
+ }
+
+ return 0;
+}
+
+int TTFFont::computePointSizeFromHeaders(int height) const {
+ TT_OS2 *os2Header = (TT_OS2 *)FT_Get_Sfnt_Table(_face, ft_sfnt_os2);
+ TT_HoriHeader *horiHeader = (TT_HoriHeader *)FT_Get_Sfnt_Table(_face, ft_sfnt_hhea);
+
+ if (os2Header && (os2Header->usWinAscent + os2Header->usWinDescent != 0)) {
+ return divRoundToNearest(_face->units_per_EM * height, os2Header->usWinAscent + os2Header->usWinDescent);
+ } else if (horiHeader && (horiHeader->Ascender + horiHeader->Descender != 0)) {
+ return divRoundToNearest(_face->units_per_EM * height, horiHeader->Ascender + horiHeader->Descender);
+ }
+
+ return 0;
+}
+
int TTFFont::getFontHeight() const {
return _height;
}
@@ -521,10 +655,10 @@ void TTFFont::assureCached(uint32 chr) const {
}
}
-Font *loadTTFFont(Common::SeekableReadStream &stream, int size, uint dpi, TTFRenderMode renderMode, const uint32 *mapping) {
+Font *loadTTFFont(Common::SeekableReadStream &stream, int size, TTFSizeMode sizeMode, uint dpi, TTFRenderMode renderMode, const uint32 *mapping) {
TTFFont *font = new TTFFont();
- if (!font->load(stream, size, dpi, renderMode, mapping)) {
+ if (!font->load(stream, size, sizeMode, dpi, renderMode, mapping)) {
delete font;
return 0;
}
diff --git a/graphics/fonts/ttf.h b/graphics/fonts/ttf.h
index bd25b69f21..4110486357 100644
--- a/graphics/fonts/ttf.h
+++ b/graphics/fonts/ttf.h
@@ -56,10 +56,32 @@ enum TTFRenderMode {
};
/**
+ * This specifies how the font size is defined.
+ */
+enum TTFSizeMode {
+ /**
+ * Character height only.
+ *
+ * This matches rendering obtained when calling
+ * CreateFont in Windows with negative height values.
+ */
+ kTTFSizeModeCharacter,
+
+ /**
+ * Full cell height.
+ *
+ * This matches rendering obtained when calling
+ * CreateFont in Windows with positive height values.
+ */
+ kTTFSizeModeCell
+};
+
+/**
* Loads a TTF font file from a given data stream object.
*
* @param stream Stream object to load font data from.
* @param size The point size to load.
+ * @param sizeMode The point size definition used for the size parameter.
* @param dpi The dpi to use for size calculations, by default 72dpi
* are used.
* @param renderMode FreeType2 mode used to render glyphs. @see TTFRenderMode
@@ -71,7 +93,7 @@ enum TTFRenderMode {
* supported.
* @return 0 in case loading fails, otherwise a pointer to the Font object.
*/
-Font *loadTTFFont(Common::SeekableReadStream &stream, int size, uint dpi = 0, TTFRenderMode renderMode = kTTFRenderModeLight, const uint32 *mapping = 0);
+Font *loadTTFFont(Common::SeekableReadStream &stream, int size, TTFSizeMode sizeMode = kTTFSizeModeCharacter, uint dpi = 0, TTFRenderMode renderMode = kTTFRenderModeLight, const uint32 *mapping = 0);
void shutdownTTF();
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 2705322c79..7331a56c93 100644
--- a/graphics/module.mk
+++ b/graphics/module.mk
@@ -12,9 +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/pixelformat.cpp b/graphics/pixelformat.cpp
new file mode 100644
index 0000000000..0a46411254
--- /dev/null
+++ b/graphics/pixelformat.cpp
@@ -0,0 +1,64 @@
+/* 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/pixelformat.h"
+#include "common/algorithm.h"
+
+namespace Graphics {
+
+Common::String PixelFormat::toString() const {
+ if (bytesPerPixel == 1)
+ return "CLUT8";
+
+ // We apply a trick to simplify the code here. We encode all the shift,
+ // loss, and component name in the component entry. By having the shift as
+ // highest entry we can sort according to shift.
+ // This works because in valid RGB PixelFormats shift values needs to be
+ // distinct except when the loss is 8. However, components with loss value
+ // of 8 are not printed, thus their position does not matter.
+ int component[4];
+ component[0] = (rShift << 16) | (rLoss << 8) | 'R';
+ component[1] = (gShift << 16) | (gLoss << 8) | 'G';
+ component[2] = (bShift << 16) | (bLoss << 8) | 'B';
+ component[3] = (aShift << 16) | (aLoss << 8) | 'A';
+
+ // Sort components according to descending shift value.
+ Common::sort(component, component + ARRAYSIZE(component), Common::Greater<int>());
+
+ Common::String letters, digits;
+ for (int i = 0; i < ARRAYSIZE(component); ++i) {
+ const int componentLoss = (component[i] >> 8) & 0xFF;
+ // A loss of 8 means that the component does not exist.
+ if (componentLoss == 8) {
+ continue;
+ }
+
+ const char componentName = component[i] & 0xFF;
+
+ letters += componentName;
+ digits += '0' + 8 - componentLoss;
+ }
+
+ return letters + digits;
+}
+
+} // End of namespace Graphics
diff --git a/graphics/pixelformat.h b/graphics/pixelformat.h
index 00db6702fc..9dd06241b7 100644
--- a/graphics/pixelformat.h
+++ b/graphics/pixelformat.h
@@ -24,6 +24,7 @@
#define GRAPHICS_PIXELFORMAT_H
#include "common/scummsys.h"
+#include "common/str.h"
namespace Graphics {
@@ -260,6 +261,8 @@ struct PixelFormat {
// Unsupported
return 0;
}
+
+ Common::String toString() const;
};
} // End of namespace Graphics
diff --git a/graphics/primitives.cpp b/graphics/primitives.cpp
index 564bdb9673..ac1c58b1d8 100644
--- a/graphics/primitives.cpp
+++ b/graphics/primitives.cpp
@@ -20,7 +20,9 @@
*
*/
+#include "common/algorithm.h"
#include "common/util.h"
+#include "graphics/primitives.h"
namespace Graphics {
@@ -62,6 +64,22 @@ void drawLine(int x0, int y0, int x1, int y1, int color, void (*plotProc)(int, i
}
}
+void drawHLine(int x1, int x2, int y, int color, void (*plotProc)(int, int, int, void *), void *data) {
+ if (x1 > x2)
+ SWAP(x1, x2);
+
+ for (int x = x1; x <= x2; x++)
+ (*plotProc)(x, y, color, data);
+}
+
+void drawVLine(int x, int y1, int y2, int color, void (*plotProc)(int, int, int, void *), void *data) {
+ if (y1 > y2)
+ SWAP(y1, y2);
+
+ for (int y = y1; y <= y2; y++)
+ (*plotProc)(x, y, color, data);
+}
+
void drawThickLine(int x0, int y0, int x1, int y1, int penX, int penY, int color, void (*plotProc)(int, int, int, void *), void *data) {
assert(penX > 0 && penY > 0);
@@ -79,4 +97,335 @@ void drawThickLine(int x0, int y0, int x1, int y1, int penX, int penY, int color
drawLine(x0 + x, y0 + y, x1 + x, y1 + y, color, plotProc, data);
}
+/* Bresenham as presented in Foley & Van Dam */
+/* Code is based on GD lib http://libgd.github.io/ */
+void drawThickLine2(int x1, int y1, int x2, int y2, int thick, int color, void (*plotProc)(int, int, int, void *), void *data) {
+ int incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
+ int wid;
+ int w, wstart;
+
+ int dx = abs(x2 - x1);
+ int dy = abs(y2 - y1);
+
+ if (dx == 0) {
+ if (y1 > y2)
+ SWAP(y1, y2);
+ Common::Rect r(x1, y1, x1 + thick - 1, y2);
+ drawFilledRect(r, color, plotProc, data);
+ return;
+ } else if (dy == 0) {
+ if (x1 > x2)
+ SWAP(x1, x2);
+ Common::Rect r(x1, y1, x2, y1 + thick - 1);
+ drawFilledRect(r, color, plotProc, data);
+ return;
+ }
+
+ if (dy <= dx) {
+ /* More-or-less horizontal. use wid for vertical stroke */
+ /* Doug Claar: watch out for NaN in atan2 (2.0.5) */
+
+ /* 2.0.12: Michael Schwartz: divide rather than multiply;
+ TBB: but watch out for /0! */
+ double ac = cos(atan2((double)dy, (double)dx));
+ if (ac != 0) {
+ wid = thick / ac;
+ } else {
+ wid = 1;
+ }
+ if (wid == 0) {
+ wid = 1;
+ }
+ d = 2 * dy - dx;
+ incr1 = 2 * dy;
+ incr2 = 2 * (dy - dx);
+ if (x1 > x2) {
+ x = x2;
+ y = y2;
+ ydirflag = (-1);
+ xend = x1;
+ } else {
+ x = x1;
+ y = y1;
+ ydirflag = 1;
+ xend = x2;
+ }
+
+ /* Set up line thickness */
+ wstart = y - wid / 2;
+ for (w = wstart; w < wstart + wid; w++)
+ (*plotProc)(x, y, color, data);
+
+ if (((y2 - y1) * ydirflag) > 0) {
+ while (x < xend) {
+ x++;
+ if (d < 0) {
+ d += incr1;
+ } else {
+ y++;
+ d += incr2;
+ }
+ wstart = y - wid / 2;
+ for (w = wstart; w < wstart + wid; w++)
+ (*plotProc)(x, w, color, data);
+ }
+ } else {
+ while (x < xend) {
+ x++;
+ if (d < 0) {
+ d += incr1;
+ } else {
+ y--;
+ d += incr2;
+ }
+ wstart = y - wid / 2;
+ for (w = wstart; w < wstart + wid; w++)
+ (*plotProc)(x, w, color, data);
+ }
+ }
+ } else {
+ /* More-or-less vertical. use wid for horizontal stroke */
+ /* 2.0.12: Michael Schwartz: divide rather than multiply;
+ TBB: but watch out for /0! */
+ double as = sin(atan2((double)dy, (double)dx));
+ if (as != 0) {
+ wid = thick / as;
+ } else {
+ wid = 1;
+ }
+ if (wid == 0)
+ wid = 1;
+
+ d = 2 * dx - dy;
+ incr1 = 2 * dx;
+ incr2 = 2 * (dx - dy);
+ if (y1 > y2) {
+ y = y2;
+ x = x2;
+ yend = y1;
+ xdirflag = (-1);
+ } else {
+ y = y1;
+ x = x1;
+ yend = y2;
+ xdirflag = 1;
+ }
+
+ /* Set up line thickness */
+ wstart = x - wid / 2;
+ for (w = wstart; w < wstart + wid; w++)
+ (*plotProc)(w, y, color, data);
+
+ if (((x2 - x1) * xdirflag) > 0) {
+ while (y < yend) {
+ y++;
+ if (d < 0) {
+ d += incr1;
+ } else {
+ x++;
+ d += incr2;
+ }
+ wstart = x - wid / 2;
+ for (w = wstart; w < wstart + wid; w++)
+ (*plotProc)(w, y, color, data);
+ }
+ } else {
+ while (y < yend) {
+ y++;
+ if (d < 0) {
+ d += incr1;
+ } else {
+ x--;
+ d += incr2;
+ }
+ wstart = x - wid / 2;
+ for (w = wstart; w < wstart + wid; w++)
+ (*plotProc)(w, y, color, data);
+ }
+ }
+ }
+}
+
+void drawFilledRect(Common::Rect &rect, int color, void (*plotProc)(int, int, int, void *), void *data) {
+ for (int y = rect.top; y <= rect.bottom; y++)
+ drawHLine(rect.left, rect.right, y, color, plotProc, data);
+}
+
+// http://members.chello.at/easyfilter/bresenham.html
+void drawRoundRect(Common::Rect &rect, int arc, int color, bool filled, void (*plotProc)(int, int, int, void *), void *data) {
+ if (rect.height() < rect.width()) {
+ int x = -arc, y = 0, err = 2-2*arc; /* II. Quadrant */
+ int dy = rect.height() - arc * 2;
+ int r = arc;
+ int stop = 0;
+ int lastx = 0, lasty = 0;
+ if (dy < 0)
+ stop = -dy / 2;
+
+ do {
+ if (filled) {
+ drawHLine(rect.left+x+r, rect.right-x-r, rect.top-y+r-stop, color, plotProc, data);
+ drawHLine(rect.left+x+r, rect.right-x-r, rect.bottom+y-r+stop, color, plotProc, data);
+ } else {
+ (*plotProc)(rect.left+x+r, rect.top-y+r-stop, color, data);
+ (*plotProc)(rect.right-x-r, rect.top-y+r-stop, color, data);
+ (*plotProc)(rect.left+x+r, rect.bottom+y-r+stop, color, data);
+ (*plotProc)(rect.right-x-r, rect.bottom+y-r+stop, color, data);
+
+ lastx = x;
+ lasty = y;
+ }
+ arc = err;
+ if (arc <= y) err += ++y*2+1; /* e_xy+e_y < 0 */
+ if (arc > x || err > y) err += ++x*2+1; /* e_xy+e_x > 0 or no 2nd y-step */
+ if (stop && y > stop)
+ break;
+ } while (x < 0);
+
+ if (!filled) {
+ x = lastx;
+ y = lasty;
+
+ drawHLine(rect.left+x+r, rect.right-x-r, rect.top-y+r-stop, color, plotProc, data);
+ drawHLine(rect.left+x+r, rect.right-x-r, rect.bottom+y-r+stop, color, plotProc, data);
+ }
+
+ for (int i = 0; i < dy; i++) {
+ if (filled) {
+ drawHLine(rect.left, rect.right, rect.top + r + i, color, plotProc, data);
+ } else {
+ (*plotProc)(rect.left, rect.top + r + i, color, data);
+ (*plotProc)(rect.right, rect.top + r + i, color, data);
+ }
+ }
+ } else {
+ int y = -arc, x = 0, err = 2-2*arc; /* II. Quadrant */
+ int dx = rect.width() - arc * 2;
+ int r = arc;
+ int stop = 0;
+ int lastx = 0, lasty = 0;
+ if (dx < 0)
+ stop = -dx / 2;
+
+ do {
+ if (filled) {
+ drawVLine(rect.left-x+r-stop, rect.top+y+r, rect.bottom-y-r, color, plotProc, data);
+ drawVLine(rect.right+x-r+stop, rect.top+y+r, rect.bottom-y-r, color, plotProc, data);
+ } else {
+ (*plotProc)(rect.left-x+r-stop, rect.top+y+r, color, data);
+ (*plotProc)(rect.left-x+r-stop, rect.bottom-y-r, color, data);
+ (*plotProc)(rect.right+x-r+stop, rect.top+y+r, color, data);
+ (*plotProc)(rect.right+x-r+stop, rect.bottom-y-r, color, data);
+
+ lastx = x;
+ lasty = y;
+ }
+
+ arc = err;
+ if (arc <= x) err += ++x*2+1; /* e_xy+e_y < 0 */
+ if (arc > y || err > x) err += ++y*2+1; /* e_xy+e_x > 0 or no 2nd y-step */
+ if (stop && x > stop)
+ break;
+ } while (y < 0);
+
+ if (!filled) {
+ x = lastx;
+ y = lasty;
+ drawVLine(rect.left-x+r-stop, rect.top+y+r, rect.bottom-y-r, color, plotProc, data);
+ drawVLine(rect.right+x-r+stop, rect.top+y+r, rect.bottom-y-r, color, plotProc, data);
+ }
+
+ for (int i = 0; i < dx; i++) {
+ if (filled) {
+ drawVLine(rect.left + r + i, rect.top, rect.bottom, color, plotProc, data);
+ } else {
+ (*plotProc)(rect.left + r + i, rect.top, color, data);
+ (*plotProc)(rect.left + r + i, rect.bottom, color, data);
+ }
+ }
+ }
+}
+
+// Based on public-domain code by Darel Rex Finley, 2007
+// http://alienryderflex.com/polygon_fill/
+void drawPolygonScan(int *polyX, int *polyY, int npoints, Common::Rect &bbox, int color, void (*plotProc)(int, int, int, void *), void *data) {
+ int *nodeX = (int *)calloc(npoints, sizeof(int));
+ int i, j;
+
+ // Loop through the rows of the image.
+ for (int pixelY = bbox.top; pixelY < bbox.bottom; pixelY++) {
+ // Build a list of nodes.
+ int nodes = 0;
+ j = npoints - 1;
+
+ for (i = 0; i < npoints; i++) {
+ if ((polyY[i] < pixelY && polyY[j] >= pixelY) || (polyY[j] < pixelY && polyY[i] >= pixelY)) {
+ nodeX[nodes++] = (int)(polyX[i] + (double)(pixelY - polyY[i]) / (double)(polyY[j]-polyY[i]) *
+ (double)(polyX[j] - polyX[i]) + 0.5);
+ }
+ j = i;
+ }
+
+ // Sort the nodes
+ Common::sort(nodeX, &nodeX[nodes]);
+
+ // Fill the pixels between node pairs.
+ for (i = 0; i < nodes; i += 2) {
+ if (nodeX[i ] >= bbox.right)
+ break;
+ if (nodeX[i + 1] > bbox.left) {
+ nodeX[i] = MAX<int16>(nodeX[i], bbox.left);
+ nodeX[i + 1] = MIN<int16>(nodeX[i + 1], bbox.right);
+
+ drawHLine(nodeX[i], nodeX[i + 1], pixelY, color, plotProc, data);
+ }
+ }
+ }
+
+ free(nodeX);
+}
+
+// http://members.chello.at/easyfilter/bresenham.html
+void drawEllipse(int x0, int y0, int x1, int y1, int color, bool filled, void (*plotProc)(int, int, int, void *), void *data) {
+ int a = abs(x1-x0), b = abs(y1-y0), b1 = b&1; /* values of diameter */
+ long dx = 4*(1-a)*b*b, dy = 4*(b1+1)*a*a; /* error increment */
+ long err = dx+dy+b1*a*a, e2; /* error of 1.step */
+
+ if (x0 > x1) { x0 = x1; x1 += a; } /* if called with swapped points */
+ if (y0 > y1) y0 = y1; /* .. exchange them */
+ y0 += (b+1)/2; y1 = y0-b1; /* starting pixel */
+ a *= 8*a; b1 = 8*b*b;
+
+ do {
+ if (filled) {
+ drawHLine(x0, x1, y0, color, plotProc, data);
+ drawHLine(x0, x1, y1, color, plotProc, data);
+ } else {
+ (*plotProc)(x1, y0, color, data); /* I. Quadrant */
+ (*plotProc)(x0, y0, color, data); /* II. Quadrant */
+ (*plotProc)(x0, y1, color, data); /* III. Quadrant */
+ (*plotProc)(x1, y1, color, data); /* IV. Quadrant */
+ }
+ e2 = 2*err;
+ if (e2 <= dy) { y0++; y1--; err += dy += a; } /* y step */
+ if (e2 >= dx || 2*err > dy) { x0++; x1--; err += dx += b1; } /* x step */
+ } while (x0 <= x1);
+
+ while (y0-y1 < b) { /* too early stop of flat ellipses a=1 */
+ if (filled) {
+ drawHLine(x0-1, x0-1, y0, color, plotProc, data); /* -> finish tip of ellipse */
+ drawHLine(x1+1, x1+1, y0, color, plotProc, data);
+ drawHLine(x0-1, x0-1, y1, color, plotProc, data);
+ drawHLine(x1+1, x1+1, y1, color, plotProc, data);
+ } else {
+ (*plotProc)(x0-1, y0, color, data); /* -> finish tip of ellipse */
+ (*plotProc)(x1+1, y0, color, data);
+ (*plotProc)(x0-1, y1, color, data);
+ (*plotProc)(x1+1, y1, color, data);
+ }
+ y0++;
+ y1--;
+ }
+}
+
} // End of namespace Graphics
diff --git a/graphics/primitives.h b/graphics/primitives.h
index a3e8ab1565..62dc10bfdf 100644
--- a/graphics/primitives.h
+++ b/graphics/primitives.h
@@ -23,10 +23,21 @@
#ifndef GRAPHICS_PRIMITIVES_H
#define GRAPHICS_PRIMITIVES_H
+#include "common/rect.h"
+
namespace Graphics {
void drawLine(int x0, int y0, int x1, int y1, int color, void (*plotProc)(int, int, int, void *), void *data);
+void drawHLine(int x1, int x2, int y, int color, void (*plotProc)(int, int, int, void *), void *data);
+void drawVLine(int x, int y1, int y2, int color, void (*plotProc)(int, int, int, void *), void *data);
void drawThickLine(int x0, int y0, int x1, int y1, int penX, int penY, int color, void (*plotProc)(int, int, int, void *), void *data);
+void drawThickLine2(int x1, int y1, int x2, int y2, int thick, int color,
+ void (*plotProc)(int, int, int, void *), void *data);
+void drawFilledRect(Common::Rect &rect, int color, void (*plotProc)(int, int, int, void *), void *data);
+void drawRoundRect(Common::Rect &rect, int arc, int color, bool filled, void (*plotProc)(int, int, int, void *), void *data);
+void drawPolygonScan(int *polyX, int *polyY, int npoints, Common::Rect &bbox, int color,
+ void (*plotProc)(int, int, int, void *), void *data);
+void drawEllipse(int x0, int y0, int x1, int y1, int color, bool filled, void (*plotProc)(int, int, int, void *), void *data);
} // End of namespace Graphics
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/thumbnail.cpp b/graphics/thumbnail.cpp
index 802ad09cbb..a3037e5ad5 100644
--- a/graphics/thumbnail.cpp
+++ b/graphics/thumbnail.cpp
@@ -67,7 +67,7 @@ HeaderState loadHeader(Common::SeekableReadStream &in, ThumbnailHeader &header,
header.size = in.readUint32BE();
header.version = in.readByte();
- // Do a check whether any read errors had occured. If so we cannot use the
+ // Do a check whether any read errors had occurred. If so we cannot use the
// values obtained for size and version because they might be bad.
if (in.err() || in.eos()) {
// TODO: We fake that there is no header. This is actually not quite
diff --git a/graphics/transparent_surface.cpp b/graphics/transparent_surface.cpp
index f6e8cacb8b..c2903d42c3 100644
--- a/graphics/transparent_surface.cpp
+++ b/graphics/transparent_surface.cpp
@@ -41,8 +41,6 @@
namespace Graphics {
-static const int kAShift = 0;//img->format.aShift;
-
static const int kBModShift = 0;//img->format.bShift;
static const int kGModShift = 8;//img->format.gShift;
static const int kRModShift = 16;//img->format.rShift;
@@ -118,7 +116,7 @@ void doBlitBinaryFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32
in = ino;
for (uint32 j = 0; j < width; j++) {
uint32 pix = *(uint32 *)in;
- int a = (pix >> kAShift) & 0xff;
+ int a = in[kAIndex];
if (a != 0) { // Full opacity (Any value not exactly 0 is Opaque here)
*(uint32 *)out = pix;
@@ -338,7 +336,7 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p
retSize.setWidth(0);
retSize.setHeight(0);
// Check if we need to draw anything at all
- int ca = (color >> 24) & 0xff;
+ int ca = (color >> kAModShift) & 0xff;
if (ca == 0) {
return retSize;
@@ -464,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 efb28149a5..c0d3d26e52 100644
--- a/graphics/transparent_surface.h
+++ b/graphics/transparent_surface.h
@@ -50,22 +50,22 @@ namespace Graphics {
@brief The possible flipping parameters for the blit method.
*/
enum FLIP_FLAGS {
- /// The image will not be flipped.
- FLIP_NONE = 0,
- /// The image will be flipped at the horizontal axis.
- FLIP_H = 1,
- /// The image will be flipped at the vertical axis.
- FLIP_V = 2,
- /// The image will be flipped at the horizontal and vertical axis.
- FLIP_HV = FLIP_H | FLIP_V,
- /// The image will be flipped at the horizontal and vertical axis.
- FLIP_VH = FLIP_H | FLIP_V
+ /// The image will not be flipped.
+ FLIP_NONE = 0,
+ /// The image will be flipped at the horizontal axis.
+ FLIP_H = 1,
+ /// The image will be flipped at the vertical axis.
+ FLIP_V = 2,
+ /// The image will be flipped at the horizontal and vertical axis.
+ FLIP_HV = FLIP_H | FLIP_V,
+ /// The image will be flipped at the horizontal and vertical axis.
+ FLIP_VH = FLIP_H | FLIP_V
};
enum AlphaType {
- ALPHA_OPAQUE = 0,
- ALPHA_BINARY = 1,
- ALPHA_FULL = 2
+ ALPHA_OPAQUE = 0,
+ ALPHA_BINARY = 1,
+ ALPHA_FULL = 2
};
/**
@@ -75,6 +75,18 @@ struct TransparentSurface : public Graphics::Surface {
TransparentSurface();
TransparentSurface(const Graphics::Surface &surf, bool copyData = false);
+ /**
+ * Returns the pixel format all operations of TransparentSurface support.
+ *
+ * Unlike Surface TransparentSurface only works with a fixed pixel format.
+ * This format can be queried using this static function.
+ *
+ * @return Supported pixel format.
+ */
+ static PixelFormat getSupportedPixelFormat() {
+ return PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
+ }
+
void setColorKey(char r, char g, char b);
void disableColorKey();
@@ -111,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 ed01204180..c850a6a02e 100644
--- a/gui/ThemeEngine.cpp
+++ b/gui/ThemeEngine.cpp
@@ -44,21 +44,21 @@
namespace GUI {
-const char * const ThemeEngine::kImageLogo = "logo.bmp";
-const char * const ThemeEngine::kImageLogoSmall = "logo_small.bmp";
-const char * const ThemeEngine::kImageSearch = "search.bmp";
-const char * const ThemeEngine::kImageEraser = "eraser.bmp";
-const char * const ThemeEngine::kImageDelbtn = "delbtn.bmp";
-const char * const ThemeEngine::kImageList = "list.bmp";
-const char * const ThemeEngine::kImageGrid = "grid.bmp";
-const char * const ThemeEngine::kImageStopbtn = "stopbtn.bmp";
-const char * const ThemeEngine::kImageEditbtn = "editbtn.bmp";
-const char * const ThemeEngine::kImageSwitchModebtn = "switchbtn.bmp";
-const char * const ThemeEngine::kImageFastReplaybtn = "fastreplay.bmp";
-const char * const ThemeEngine::kImageStopSmallbtn = "stopbtn_small.bmp";
-const char * const ThemeEngine::kImageEditSmallbtn = "editbtn_small.bmp";
-const char * const ThemeEngine::kImageSwitchModeSmallbtn = "switchbtn_small.bmp";
-const char * const ThemeEngine::kImageFastReplaySmallbtn = "fastreplay_small.bmp";
+const char *const ThemeEngine::kImageLogo = "logo.bmp";
+const char *const ThemeEngine::kImageLogoSmall = "logo_small.bmp";
+const char *const ThemeEngine::kImageSearch = "search.bmp";
+const char *const ThemeEngine::kImageEraser = "eraser.bmp";
+const char *const ThemeEngine::kImageDelButton = "delbtn.bmp";
+const char *const ThemeEngine::kImageList = "list.bmp";
+const char *const ThemeEngine::kImageGrid = "grid.bmp";
+const char *const ThemeEngine::kImageStopButton = "stopbtn.bmp";
+const char *const ThemeEngine::kImageEditButton = "editbtn.bmp";
+const char *const ThemeEngine::kImageSwitchModeButton = "switchbtn.bmp";
+const char *const ThemeEngine::kImageFastReplayButton = "fastreplay.bmp";
+const char *const ThemeEngine::kImageStopSmallButton = "stopbtn_small.bmp";
+const char *const ThemeEngine::kImageEditSmallButton = "editbtn_small.bmp";
+const char *const ThemeEngine::kImageSwitchModeSmallButton = "switchbtn_small.bmp";
+const char *const ThemeEngine::kImageFastReplaySmallButton = "fastreplay_small.bmp";
struct TextDrawData {
const Graphics::Font *_fontPtr;
@@ -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);
}
@@ -739,12 +807,23 @@ bool ThemeEngine::loadDefaultXML() {
// Use the Python script "makedeftheme.py" to convert a normal XML theme
// into the "default.inc" file, which is ready to be included in the code.
#ifndef DISABLE_GUI_BUILTIN_THEME
- const char *defaultXML =
#include "themes/default.inc"
- ;
+ int xmllen = 0;
+
+ for (int i = 0; i < ARRAYSIZE(defaultXML); i++)
+ xmllen += strlen(defaultXML[i]);
+
+ byte *tmpXML = (byte *)malloc(xmllen + 1);
+ tmpXML[0] = '\0';
+
+ for (int i = 0; i < ARRAYSIZE(defaultXML); i++)
+ strncat((char *)tmpXML, defaultXML[i], xmllen);
+
+ if (!_parser->loadBuffer(tmpXML, xmllen)) {
+ free(tmpXML);
- if (!_parser->loadBuffer((const byte *)defaultXML, strlen(defaultXML)))
return false;
+ }
_themeName = "ScummVM Classic Theme (Builtin Version)";
_themeId = "builtin";
@@ -753,6 +832,8 @@ bool ThemeEngine::loadDefaultXML() {
bool result = _parser->parse();
_parser->close();
+ free(tmpXML);
+
return result;
#else
warning("The built-in theme is not enabled in the current build. Please load an external theme");
@@ -843,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;
@@ -862,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;
@@ -877,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
@@ -901,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;
@@ -908,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;
@@ -934,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;
@@ -960,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;
@@ -980,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;
@@ -1001,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;
@@ -1033,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;
@@ -1044,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;
@@ -1065,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;
@@ -1072,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;
@@ -1095,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;
@@ -1123,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;
@@ -1196,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;
@@ -1210,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);
@@ -1246,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) {
@@ -1446,7 +1919,7 @@ const Graphics::Font *ThemeEngine::loadScalableFont(const Common::String &filena
for (Common::ArchiveMemberList::const_iterator i = members.begin(), end = members.end(); i != end; ++i) {
Common::SeekableReadStream *stream = (*i)->createReadStream();
if (stream) {
- font = Graphics::loadTTFFont(*stream, pointsize, 0, Graphics::kTTFRenderModeLight,
+ font = Graphics::loadTTFFont(*stream, pointsize, Graphics::kTTFSizeModeCharacter, 0, Graphics::kTTFRenderModeLight,
#ifdef USE_TRANSLATION
TransMan.getCharsetMapping()
#else
diff --git a/gui/ThemeEngine.h b/gui/ThemeEngine.h
index 68be2e0b26..3c259b4f9d 100644
--- a/gui/ThemeEngine.h
+++ b/gui/ThemeEngine.h
@@ -36,7 +36,7 @@
#include "graphics/pixelformat.h"
-#define SCUMMVM_THEME_VERSION_STR "SCUMMVM_STX0.8.20"
+#define SCUMMVM_THEME_VERSION_STR "SCUMMVM_STX0.8.21"
class OSystem;
@@ -228,17 +228,17 @@ public:
static const char *const kImageLogoSmall; ///< ScummVM logo used in the GMM
static const char *const kImageSearch; ///< Search tool image used in the launcher
static const char *const kImageEraser; ///< Clear input image used in the launcher
- static const char *const kImageDelbtn; ///< Delete characters in the predictive dialog
+ static const char *const kImageDelButton; ///< Delete characters in the predictive dialog
static const char *const kImageList; ///< List image used in save/load chooser selection
static const char *const kImageGrid; ///< Grid image used in save/load chooser selection
- static const char *const kImageStopbtn; ///< Stop recording button in recorder onscreen dialog
- static const char *const kImageEditbtn; ///< Edit recording metadata in recorder onscreen dialog
- static const char *const kImageSwitchModebtn; ///< Switch mode button in recorder onscreen dialog
- static const char *const kImageFastReplaybtn; ///< Fast playback mode button in recorder onscreen dialog
- static const char *const kImageStopSmallbtn; ///< Stop recording button in recorder onscreen dialog (for 320xY)
- static const char *const kImageEditSmallbtn; ///< Edit recording metadata in recorder onscreen dialog (for 320xY)
- static const char *const kImageSwitchModeSmallbtn; ///< Switch mode button in recorder onscreen dialog (for 320xY)
- static const char *const kImageFastReplaySmallbtn; ///< Fast playback mode button in recorder onscreen dialog (for 320xY)
+ static const char *const kImageStopButton; ///< Stop recording button in recorder onscreen dialog
+ static const char *const kImageEditButton; ///< Edit recording metadata in recorder onscreen dialog
+ static const char *const kImageSwitchModeButton; ///< Switch mode button in recorder onscreen dialog
+ static const char *const kImageFastReplayButton; ///< Fast playback mode button in recorder onscreen dialog
+ static const char *const kImageStopSmallButton; ///< Stop recording button in recorder onscreen dialog (for 320xY)
+ static const char *const kImageEditSmallButton; ///< Edit recording metadata in recorder onscreen dialog (for 320xY)
+ static const char *const kImageSwitchModeSmallButton; ///< Switch mode button in recorder onscreen dialog (for 320xY)
+ static const char *const kImageFastReplaySmallButton; ///< Fast playback mode button in recorder onscreen dialog (for 320xY)
/**
* Graphics mode enumeration.
@@ -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/about.cpp b/gui/about.cpp
index daec2b7e48..211542adb3 100644
--- a/gui/about.cpp
+++ b/gui/about.cpp
@@ -57,7 +57,7 @@ enum {
static const char *copyright_text[] = {
"",
-"C0""Copyright (C) 2001-2015 The ScummVM Team",
+"C0""Copyright (C) 2001-2016 The ScummVM Team",
"C0""http://www.scummvm.org",
"",
"C0""ScummVM is the legal property of its developers, whose names are too numerous to list here. Please refer to the COPYRIGHT file distributed with this binary.",
diff --git a/gui/credits.h b/gui/credits.h
index 7ae12bf599..c2c4c84ec6 100644
--- a/gui/credits.h
+++ b/gui/credits.h
@@ -58,10 +58,11 @@ static const char *credits[] = {
"C1""AGI",
"C0""Stuart George",
"C0""Matthew Hoops",
+"C2""(retired)",
"C0""Filippos Karapetis",
+"C0""Martin Kiewitz",
"C0""Pawel Kolodziejski",
"C0""Walter van Niftrik",
-"C2""(retired)",
"C0""Kari Salminen",
"C0""Eugene Sandulenko",
"C0""David Symonds",
@@ -77,12 +78,20 @@ static const char *credits[] = {
"C0""Ludvig Strigeus",
"C2""(retired)",
"",
+"C1""Access",
+"A0""Arnaud Boutonne",
+"C0""Arnaud Boutonn\351",
+"C0""Paul Gilbert",
+"",
"C1""Avalanche",
"A0""Peter Bozso",
"C0""Peter Bozs\363",
"A0""Arnaud Boutonne",
"C0""Arnaud Boutonn\351",
"",
+"C1""BBVS",
+"C0""Benjamin Haisch",
+"",
"C1""CGE",
"A0""Arnaud Boutonne",
"C0""Arnaud Boutonn\351",
@@ -119,6 +128,7 @@ static const char *credits[] = {
"C1""Drascula",
"C0""Filippos Karapetis",
"C0""Pawel Kolodziejski",
+"C0""Thierry Crozat",
"",
"C1""DreamWeb",
"A0""Torbjorn Andersson",
@@ -129,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",
@@ -165,6 +180,7 @@ static const char *credits[] = {
"",
"C1""Lastexpress",
"C0""Matthew Hoops",
+"C2""(retired)",
"C0""Jordi Vilalta Prat",
"C0""Julien Templier",
"",
@@ -184,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",
@@ -203,6 +220,7 @@ static const char *credits[] = {
"",
"C1""Pegasus",
"C0""Matthew Hoops",
+"C2""(retired)",
"",
"C1""Queen",
"C0""David Eriksson",
@@ -228,11 +246,14 @@ static const char *credits[] = {
"C0""Filippos Karapetis",
"C0""Martin Kiewitz",
"C0""Walter van Niftrik",
-"C2""(retired)",
"C0""Willem Jan Palenstijn",
"C0""Jordi Vilalta Prat",
"C0""Lars Skovlund",
"",
+"C1""Sherlock",
+"C0""Paul Gilbert",
+"C0""Martin Kiewitz",
+"",
"C1""Sky",
"A0""Robert Goeffringmann",
"C0""Robert G\366ffringmann",
@@ -332,15 +353,21 @@ static const char *credits[] = {
"C1""Android",
"C0""Andre Heider",
"C0""Angus Lees",
+"C0""Lubomyr Lisen",
"",
"C1""Dreamcast",
"C0""Marcus Comstedt",
"",
+"C1""GCW0",
+"C0""Eugene Sandulenko",
+"",
"C1""GPH Devices (GP2X, GP2XWiz & Caanoo)",
"C0""John Willis",
"",
-"C1""iPhone",
+"C1""iPhone / iPad",
"C0""Oystein Eftevaag",
+"A0""Vincent Benony",
+"C0""Vincent B\351nony",
"",
"C1""LinuxMoto",
"C0""Lubomyr Lisen",
@@ -350,6 +377,9 @@ static const char *credits[] = {
"C2""(retired)",
"C0""Tarek Soliman",
"",
+"C1""Nintendo 3DS",
+"C0""Thomas Edvalson",
+"",
"C1""Nintendo 64",
"C0""Fabio Battaglia",
"",
@@ -398,6 +428,9 @@ static const char *credits[] = {
"C1""Wii",
"C0""Andre Heider",
"",
+"C1""Raspberry Pi",
+"C0""Manuel Alfayate",
+"",
"",
"C1""Other subsystems",
"C1""Infrastructure",
@@ -458,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",
@@ -516,6 +549,7 @@ static const char *credits[] = {
"C0""Max Horn",
"C2""(retired)",
"C0""Oystein Eftevaag",
+"C0""Thierry Crozat",
"",
"C1""Mandriva",
"C0""Dominik Scherer",
@@ -872,5 +906,9 @@ static const char *credits[] = {
"C0""",
"C0""Bob Bell, Michel Kripalani, Tommy Yune, from Presto Studios for providing the source code of The Journeyman Project: Pegasus Prime.",
"C0""",
+"C0""Electronic Arts IP Preservation Team, particularly Stefan Serbicki, and Vasyl Tsvirkunov of Electronic Arts for providing the source code of the two Lost Files of Sherlock Holmes games. James M. Ferguson and Barry Duncan for their tenacious efforts to recover the sources.",
+"C0""",
+"C0""The mindFactory team for writing Broken Sword 2.5, a splendid fan-made sequel, and for sharing the source code with us.",
+"C0""",
"",
};
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/filebrowser-dialog.cpp b/gui/filebrowser-dialog.cpp
new file mode 100644
index 0000000000..93395ba909
--- /dev/null
+++ b/gui/filebrowser-dialog.cpp
@@ -0,0 +1,160 @@
+/* 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 "gui/filebrowser-dialog.h"
+
+#include "common/system.h"
+#include "common/algorithm.h"
+#include "common/savefile.h"
+#include "common/str-array.h"
+
+#include "common/translation.h"
+
+#include "gui/widgets/list.h"
+#include "gui/message.h"
+
+namespace GUI {
+
+enum {
+ kChooseCmd = 'Chos'
+};
+
+FileBrowserDialog::FileBrowserDialog(const char *title, const char *fileExtension, int mode)
+ : Dialog("FileBrowser"), _mode(mode), _fileExt(fileExtension) {
+
+ _fileMask = "*.";
+ _fileMask += fileExtension;
+ _fileList = NULL;
+
+ new StaticTextWidget(this, "FileBrowser.Headline", title ? title :
+ mode == kFBModeLoad ? _("Choose file for loading") : _("Enter filename for saving"));
+
+ _fileName = new EditTextWidget(this, "FileBrowser.Filename", "");
+
+ if (mode == kFBModeLoad)
+ _fileName->setEnabled(false);
+
+ // Add file list
+ _fileList = new ListWidget(this, "FileBrowser.List");
+ _fileList->setNumberingMode(kListNumberingOff);
+ _fileList->setEditable(false);
+
+ _backgroundType = GUI::ThemeEngine::kDialogBackgroundPlain;
+
+ // Buttons
+ new ButtonWidget(this, "FileBrowser.Cancel", _("Cancel"), 0, kCloseCmd);
+ new ButtonWidget(this, "FileBrowser.Choose", _("Choose"), 0, kChooseCmd);
+}
+
+void FileBrowserDialog::open() {
+ // Call super implementation
+ Dialog::open();
+
+ updateListing();
+}
+
+void FileBrowserDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
+ switch (cmd) {
+ case kChooseCmd:
+ if (_fileName->getEditString().empty())
+ break;
+
+ normalieFileName();
+
+ if (!isProceedSave())
+ break;
+
+ setResult(1);
+ close();
+ break;
+ case kListSelectionChangedCmd:
+ _fileName->setEditString(_fileList->getList().operator[](_fileList->getSelected()).c_str());
+ _fileName->draw();
+ break;
+ case kListItemActivatedCmd:
+ case kListItemDoubleClickedCmd:
+ normalieFileName();
+
+ if (!isProceedSave())
+ break;
+
+ setResult(1);
+ close();
+ break;
+ default:
+ Dialog::handleCommand(sender, cmd, data);
+ }
+}
+
+void FileBrowserDialog::normalieFileName() {
+ Common::String filename = _fileName->getEditString();
+
+ if (filename.matchString(_fileMask))
+ return;
+
+ _fileName->setEditString(filename + "." + _fileExt);
+}
+
+
+bool FileBrowserDialog::isProceedSave() {
+ bool matched = false;
+
+ if (_mode == kFBModeLoad)
+ return true;
+
+ for (ListWidget::StringArray::const_iterator file = _fileList->getList().begin(); file != _fileList->getList().end(); ++file) {
+ if (*file == _fileName->getEditString()) {
+ matched = true;
+ break;
+ }
+ }
+
+ if (matched) {
+ GUI::MessageDialog alert(_("Do you really want to overwrite the file?"), _("Yes"), _("No"));
+
+ if (alert.runModal() != GUI::kMessageOK)
+ return false;
+ }
+
+ return true;
+}
+
+void FileBrowserDialog::updateListing() {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+
+ ListWidget::StringArray list;
+
+ Common::StringArray filenames = saveFileMan->listSavefiles(_fileMask);
+ Common::sort(filenames.begin(), filenames.end());
+
+ for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
+ list.push_back(file->c_str());
+ }
+
+ _fileList->setList(list);
+ _fileList->scrollTo(0);
+
+ // Finally, redraw
+ draw();
+}
+
+} // End of namespace GUI
diff --git a/gui/filebrowser-dialog.h b/gui/filebrowser-dialog.h
new file mode 100644
index 0000000000..5916d76c80
--- /dev/null
+++ b/gui/filebrowser-dialog.h
@@ -0,0 +1,64 @@
+/* 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 FILEBROWSER_DIALOG_H
+#define FILEBROWSER_DIALOG_H
+
+#include "gui/dialog.h"
+#include "gui/widgets/edittext.h"
+
+namespace GUI {
+
+class ListWidget;
+class EditTextWidget;
+class CommandSender;
+
+enum {
+ kFBModeLoad = 0,
+ kFBModeSave
+};
+
+class FileBrowserDialog : public Dialog {
+public:
+ FileBrowserDialog(const char *title, const char *fileExtension, int mode);
+
+ virtual void open();
+
+ virtual void handleCommand(CommandSender *sender, uint32 cmd, uint32 data);
+
+ const char *getResult() { return Dialog::getResult() ? _fileName->getEditString().c_str() : NULL; }
+
+protected:
+ EditTextWidget *_fileName;
+ ListWidget *_fileList;
+ Common::String _fileMask;
+ Common::String _fileExt;
+ int _mode;
+
+ void updateListing();
+ void normalieFileName();
+ bool isProceedSave();
+};
+
+} // End of namespace GUI
+
+#endif
diff --git a/gui/gui-manager.cpp b/gui/gui-manager.cpp
index 9b6cf5a0b6..9acd9434ff 100644
--- a/gui/gui-manager.cpp
+++ b/gui/gui-manager.cpp
@@ -64,6 +64,8 @@ GuiManager::GuiManager() : _redrawStatus(kRedrawDisabled), _stateIsSaved(false),
_width = _system->getOverlayWidth();
_height = _system->getOverlayHeight();
+ _launched = false;
+
// Clear the cursor
memset(_cursor, 0xFF, sizeof(_cursor));
@@ -279,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();
@@ -302,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;
@@ -334,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();
@@ -413,7 +405,7 @@ void GuiManager::restoreState() {
}
void GuiManager::openDialog(Dialog *dialog) {
- dialog->receivedFocus();
+ giveFocusToDialog(dialog);
if (!_dialogStack.empty())
getTopDialog()->lostFocus();
@@ -437,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;
@@ -513,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);
@@ -521,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;
@@ -569,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 4186a93ccb..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(); }
@@ -98,6 +99,8 @@ public:
*/
bool checkScreenChange();
+ bool _launched;
+
protected:
enum RedrawStatus {
kRedrawDisabled = 0,
@@ -122,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;
@@ -153,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 5abf0aba26..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"));
@@ -683,6 +685,8 @@ LauncherDialog::LauncherDialog()
// Create Load dialog
_loadDialog = new SaveLoadChooser(_("Load game:"), _("Load"), false);
+
+ GUI::GuiManager::instance()._launched = true;
}
void LauncherDialog::selectTarget(const String &target) {
diff --git a/gui/module.mk b/gui/module.mk
index 338e43c6a4..6cbc63d24d 100644
--- a/gui/module.mk
+++ b/gui/module.mk
@@ -8,6 +8,7 @@ MODULE_OBJS := \
dialog.o \
error.o \
EventRecorder.o \
+ filebrowser-dialog.o \
gui-manager.o \
launcher.o \
massadd.o \
@@ -29,8 +30,21 @@ 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
+# structure to pick up the right browser implementations for iOS and Mac OS X.
+# Please keep it like this or XCode project generation will be broken.
+# FIXME: This only works because of a bug in how we handle ifdef statements in
+# create_project's module.mk parser. create_project will think that both
+# browser.o and browser_osx.o is built when both IPHONE and MACOSX is set.
+# When we do proper ifdef handling, only browser.o will be picked up, breaking
+# XCode generation.
+ifdef IPHONE
+MODULE_OBJS += \
+ browser.o
+else
ifdef MACOSX
MODULE_OBJS += \
browser_osx.o
@@ -38,6 +52,7 @@ else
MODULE_OBJS += \
browser.o
endif
+endif
ifdef ENABLE_EVENTRECORDER
MODULE_OBJS += \
@@ -51,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/onscreendialog.cpp b/gui/onscreendialog.cpp
index 0e37834136..8b338f56df 100644
--- a/gui/onscreendialog.cpp
+++ b/gui/onscreendialog.cpp
@@ -62,37 +62,37 @@ OnScreenDialog::OnScreenDialog(bool isRecord) : Dialog("OnScreenDialog") {
#ifndef DISABLE_FANCY_THEMES
if (g_gui.xmlEval()->getVar("Globals.OnScreenDialog.ShowPics") == 1 && g_gui.theme()->supportsImages()) {
- GUI::PicButtonWidget *btn;
- btn = new PicButtonWidget(this, "OnScreenDialog.StopButton", 0, kStopCmd, 0);
- btn->useThemeTransparency(true);
+ GUI::PicButtonWidget *button;
+ button = new PicButtonWidget(this, "OnScreenDialog.StopButton", 0, kStopCmd, 0);
+ button->useThemeTransparency(true);
if (g_system->getOverlayWidth() > 320)
- btn->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageStopbtn));
+ button->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageStopButton));
else
- btn->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageStopSmallbtn));
+ button->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageStopSmallButton));
if (isRecord) {
- btn = new PicButtonWidget(this, "OnScreenDialog.EditButton", 0, kEditCmd, 0);
- btn->useThemeTransparency(true);
+ button = new PicButtonWidget(this, "OnScreenDialog.EditButton", 0, kEditCmd, 0);
+ button->useThemeTransparency(true);
if (g_system->getOverlayWidth() > 320)
- btn->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageEditbtn));
+ button->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageEditButton));
else
- btn->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageEditSmallbtn));
+ button->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageEditSmallButton));
} else {
- btn = new PicButtonWidget(this, "OnScreenDialog.SwitchModeButton", 0, kSwitchModeCmd, 0);
- btn->useThemeTransparency(true);
+ button = new PicButtonWidget(this, "OnScreenDialog.SwitchModeButton", 0, kSwitchModeCmd, 0);
+ button->useThemeTransparency(true);
if (g_system->getOverlayWidth() > 320)
- btn->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageSwitchModebtn));
+ button->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageSwitchModeButton));
else
- btn->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageSwitchModeSmallbtn));
+ button->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageSwitchModeSmallButton));
- btn = new PicButtonWidget(this, "OnScreenDialog.FastReplayButton", 0, kFastModeCmd, 0);
- btn->useThemeTransparency(true);
+ button = new PicButtonWidget(this, "OnScreenDialog.FastReplayButton", 0, kFastModeCmd, 0);
+ button->useThemeTransparency(true);
if (g_system->getOverlayWidth() > 320)
- btn->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageFastReplaybtn));
+ button->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageFastReplayButton));
else
- btn->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageFastReplaySmallbtn));
+ button->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageFastReplaySmallButton));
}
} else
#endif
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 a894b02f80..933667186e 100644
--- a/gui/predictivedialog.cpp
+++ b/gui/predictivedialog.cpp
@@ -24,6 +24,7 @@
#include "gui/widget.h"
#include "gui/widgets/edittext.h"
#include "gui/gui-manager.h"
+#include "gui/ThemeEval.h"
#include "common/config-manager.h"
#include "common/translation.h"
@@ -69,74 +70,57 @@ enum {
PredictiveDialog::PredictiveDialog() : Dialog("Predictive") {
new StaticTextWidget(this, "Predictive.Headline", "Enter Text");
- _btns = (ButtonWidget **)calloc(16, sizeof(ButtonWidget *));
-
- _btns[kCancelAct] = new ButtonWidget(this, "Predictive.Cancel", _("Cancel") , 0, kCancelCmd);
- _btns[kOkAct] = new ButtonWidget(this, "Predictive.OK", _("Ok") , 0, kOkCmd);
- _btns[kBtn1Act] = new ButtonWidget(this, "Predictive.Button1", "1 `-.&" , 0, kBut1Cmd);
- _btns[kBtn2Act] = new ButtonWidget(this, "Predictive.Button2", "2 abc" , 0, kBut2Cmd);
- _btns[kBtn3Act] = new ButtonWidget(this, "Predictive.Button3", "3 def" , 0, kBut3Cmd);
- _btns[kBtn4Act] = new ButtonWidget(this, "Predictive.Button4", "4 ghi" , 0, kBut4Cmd);
- _btns[kBtn5Act] = new ButtonWidget(this, "Predictive.Button5", "5 jkl" , 0, kBut5Cmd);
- _btns[kBtn6Act] = new ButtonWidget(this, "Predictive.Button6", "6 mno" , 0, kBut6Cmd);
- _btns[kBtn7Act] = new ButtonWidget(this, "Predictive.Button7", "7 pqrs" , 0, kBut7Cmd);
- _btns[kBtn8Act] = new ButtonWidget(this, "Predictive.Button8", "8 tuv" , 0, kBut8Cmd);
- _btns[kBtn9Act] = new ButtonWidget(this, "Predictive.Button9", "9 wxyz" , 0, kBut9Cmd);
- _btns[kBtn0Act] = new ButtonWidget(this, "Predictive.Button0", "0" , 0, kBut0Cmd);
- // I18N: You must leave "#" as is, only word 'next' is translatable
- _btns[kNextAct] = new ButtonWidget(this, "Predictive.Next", _("# next") , 0, kNextCmd);
- _btns[kAddAct] = new ButtonWidget(this, "Predictive.Add", _("add") , 0, kAddCmd);
- _btns[kAddAct]->setEnabled(false);
-
- #ifndef DISABLE_FANCY_THEMES
- _btns[kDelAct] = new PicButtonWidget(this, "Predictive.Delete", _("Delete char"), kDelCmd);
- ((PicButtonWidget *)_btns[kDelAct])->useThemeTransparency(true);
- ((PicButtonWidget *)_btns[kDelAct])->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageDelbtn));
- #endif
- _btns[kDelAct] = new ButtonWidget(this, "Predictive.Delete" , _("<") , 0, kDelCmd);
- // I18N: Pre means 'Predictive', leave '*' as is
- _btns[kModeAct] = new ButtonWidget(this, "Predictive.Pre", _("* Pre"), 0, kModeCmd);
- _edittext = new EditTextWidget(this, "Predictive.Word", _search, 0, 0, 0);
+ _button[kCancelAct] = new ButtonWidget(this, "Predictive.Cancel", _("Cancel") , 0, kCancelCmd);
+ _button[kOkAct] = new ButtonWidget(this, "Predictive.OK", _("Ok") , 0, kOkCmd);
+ _button[kButton1Act] = new ButtonWidget(this, "Predictive.Button1", "1 `-.&" , 0, kBut1Cmd);
+ _button[kButton2Act] = new ButtonWidget(this, "Predictive.Button2", "2 abc" , 0, kBut2Cmd);
+ _button[kButton3Act] = new ButtonWidget(this, "Predictive.Button3", "3 def" , 0, kBut3Cmd);
+ _button[kButton4Act] = new ButtonWidget(this, "Predictive.Button4", "4 ghi" , 0, kBut4Cmd);
+ _button[kButton5Act] = new ButtonWidget(this, "Predictive.Button5", "5 jkl" , 0, kBut5Cmd);
+ _button[kButton6Act] = new ButtonWidget(this, "Predictive.Button6", "6 mno" , 0, kBut6Cmd);
+ _button[kButton7Act] = new ButtonWidget(this, "Predictive.Button7", "7 pqrs" , 0, kBut7Cmd);
+ _button[kButton8Act] = new ButtonWidget(this, "Predictive.Button8", "8 tuv" , 0, kBut8Cmd);
+ _button[kButton9Act] = new ButtonWidget(this, "Predictive.Button9", "9 wxyz" , 0, kBut9Cmd);
+ _button[kButton0Act] = new ButtonWidget(this, "Predictive.Button0", "0" , 0, kBut0Cmd);
+ // I18N: You must leave "#" as is, only word 'next' is translatable
+ _button[kNextAct] = new ButtonWidget(this, "Predictive.Next", _("# next") , 0, kNextCmd);
+ _button[kAddAct] = new ButtonWidget(this, "Predictive.Add", _("add") , 0, kAddCmd);
+ _button[kAddAct]->setEnabled(false);
+
+#ifndef DISABLE_FANCY_THEMES
+ if (g_gui.xmlEval()->getVar("Globals.Predictive.ShowDeletePic") == 1 && g_gui.theme()->supportsImages()) {
+ _button[kDelAct] = new PicButtonWidget(this, "Predictive.Delete", _("Delete char"), kDelCmd);
+ ((PicButtonWidget *)_button[kDelAct])->useThemeTransparency(true);
+ ((PicButtonWidget *)_button[kDelAct])->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageDelButton));
+ } else
+#endif
+ _button[kDelAct] = new ButtonWidget(this, "Predictive.Delete" , _("<") , 0, kDelCmd);
+ // I18N: Pre means 'Predictive', leave '*' as is
+ _button[kModeAct] = new ButtonWidget(this, "Predictive.Pre", _("* Pre"), 0, kModeCmd);
+ _editText = new EditTextWidget(this, "Predictive.Word", _search, 0, 0, 0);
_userDictHasChanged = false;
_predictiveDict.nameDict = "predictive_dictionary";
- _predictiveDict.fnameDict = "pred.dic";
- _predictiveDict.dictActLine = NULL;
+ _predictiveDict.defaultFilename = "pred.dic";
_userDict.nameDict = "user_dictionary";
- _userDict.fnameDict = "user.dic";
- _userDict.dictActLine = NULL;
-
- _unitedDict.nameDict = "";
- _unitedDict.fnameDict = "";
-
- _predictiveDict.dictLine = NULL;
- _predictiveDict.dictText = NULL;
- _predictiveDict.dictLineCount = 0;
+ _userDict.defaultFilename = "user.dic";
if (!_predictiveDict.dictText) {
loadAllDictionary(_predictiveDict);
if (!_predictiveDict.dictText)
- debug("Predictive Dialog: pred.dic not loaded");
+ debug(5, "Predictive Dialog: pred.dic not loaded");
}
- _userDict.dictLine = NULL;
- _userDict.dictText = NULL;
- _userDict.dictTextSize = 0;
- _userDict.dictLineCount = 0;
-
if (!_userDict.dictText) {
loadAllDictionary(_userDict);
if (!_userDict.dictText)
- debug("Predictive Dialog: user.dic not loaded");
+ debug(5, "Predictive Dialog: user.dic not loaded");
}
mergeDicts();
- _unitedDict.dictActLine = NULL;
- _unitedDict.dictText = NULL;
-
memset(_repeatcount, 0, sizeof(_repeatcount));
_prefix.clear();
@@ -146,18 +130,21 @@ PredictiveDialog::PredictiveDialog() : Dialog("Predictive") {
_numMatchingWords = 0;
memset(_predictiveResult, 0, sizeof(_predictiveResult));
- _lastbutton = kNoAct;
+ _lastButton = kNoAct;
_mode = kModePre;
_lastTime = 0;
_curTime = 0;
- _lastPressBtn = kNoAct;
+ _lastPressedButton = kNoAct;
_memoryList[0] = _predictiveDict.dictText;
_memoryList[1] = _userDict.dictText;
_numMemory = 0;
- _navigationwithkeys = false;
+ _navigationWithKeys = false;
+
+ _curPressedButton = kNoAct;
+ _needRefresh = true;
}
PredictiveDialog::~PredictiveDialog() {
@@ -167,8 +154,25 @@ PredictiveDialog::~PredictiveDialog() {
free(_userDict.dictLine);
free(_predictiveDict.dictLine);
free(_unitedDict.dictLine);
+}
+
+void PredictiveDialog::reflowLayout() {
+#ifndef DISABLE_FANCY_THEMES
+ removeWidget(_button[kDelAct]);
+ _button[kDelAct]->setNext(0);
+ delete _button[kDelAct];
+ _button[kDelAct] = nullptr;
+
+ if (g_gui.xmlEval()->getVar("Globals.Predictive.ShowDeletePic") == 1 && g_gui.theme()->supportsImages()) {
+ _button[kDelAct] = new PicButtonWidget(this, "Predictive.Delete", _("Delete char"), kDelCmd);
+ ((PicButtonWidget *)_button[kDelAct])->useThemeTransparency(true);
+ ((PicButtonWidget *)_button[kDelAct])->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageDelButton));
+ } else {
+ _button[kDelAct] = new ButtonWidget(this, "Predictive.Delete" , _("<") , 0, kDelCmd);
+ }
+#endif
- free(_btns);
+ Dialog::reflowLayout();
}
void PredictiveDialog::saveUserDictToFile() {
@@ -188,22 +192,22 @@ void PredictiveDialog::saveUserDictToFile() {
}
void PredictiveDialog::handleKeyUp(Common::KeyState state) {
- if (_currBtn != kNoAct && !_needRefresh) {
- _btns[_currBtn]->startAnimatePressedState();
- processBtnActive(_currBtn);
+ if (_curPressedButton != kNoAct && !_needRefresh) {
+ _button[_curPressedButton]->setUnpressedState();
+ processButton(_curPressedButton);
}
}
void PredictiveDialog::handleKeyDown(Common::KeyState state) {
- _currBtn = kNoAct;
+ _curPressedButton = kNoAct;
_needRefresh = false;
- if (getFocusWidget() == _edittext) {
- setFocusWidget(_btns[kAddAct]);
+ if (getFocusWidget() == _editText) {
+ setFocusWidget(_button[kAddAct]);
}
- if (_lastbutton == kNoAct) {
- _lastbutton = kBtn5Act;
+ if (_lastButton == kNoAct) {
+ _lastButton = kButton5Act;
}
switch (state.keycode) {
@@ -212,128 +216,128 @@ void PredictiveDialog::handleKeyDown(Common::KeyState state) {
close();
return;
case Common::KEYCODE_LEFT:
- _navigationwithkeys = true;
- if (_lastbutton == kBtn1Act || _lastbutton == kBtn4Act || _lastbutton == kBtn7Act)
- _currBtn = ButtonId(_lastbutton + 2);
- else if (_lastbutton == kDelAct)
- _currBtn = kBtn1Act;
- else if (_lastbutton == kModeAct)
- _currBtn = kNextAct;
- else if (_lastbutton == kNextAct)
- _currBtn = kBtn0Act;
- else if (_lastbutton == kAddAct)
- _currBtn = kOkAct;
- else if (_lastbutton == kCancelAct)
- _currBtn = kAddAct;
+ _navigationWithKeys = true;
+ if (_lastButton == kButton1Act || _lastButton == kButton4Act || _lastButton == kButton7Act)
+ _curPressedButton = ButtonId(_lastButton + 2);
+ else if (_lastButton == kDelAct)
+ _curPressedButton = kButton1Act;
+ else if (_lastButton == kModeAct)
+ _curPressedButton = kNextAct;
+ else if (_lastButton == kNextAct)
+ _curPressedButton = kButton0Act;
+ else if (_lastButton == kAddAct)
+ _curPressedButton = kOkAct;
+ else if (_lastButton == kCancelAct)
+ _curPressedButton = kAddAct;
else
- _currBtn = ButtonId(_lastbutton - 1);
+ _curPressedButton = ButtonId(_lastButton - 1);
- if (_mode != kModeAbc && _lastbutton == kCancelAct)
- _currBtn = kOkAct;
+ if (_mode != kModeAbc && _lastButton == kCancelAct)
+ _curPressedButton = kOkAct;
_needRefresh = true;
break;
case Common::KEYCODE_RIGHT:
- _navigationwithkeys = true;
- if (_lastbutton == kBtn3Act || _lastbutton == kBtn6Act || _lastbutton == kBtn9Act || _lastbutton == kOkAct)
- _currBtn = ButtonId(_lastbutton - 2);
- else if (_lastbutton == kDelAct)
- _currBtn = kBtn3Act;
- else if (_lastbutton == kBtn0Act)
- _currBtn = kNextAct;
- else if (_lastbutton == kNextAct)
- _currBtn = kModeAct;
- else if (_lastbutton == kAddAct)
- _currBtn = kCancelAct;
- else if (_lastbutton == kOkAct)
- _currBtn = kAddAct;
+ _navigationWithKeys = true;
+ if (_lastButton == kButton3Act || _lastButton == kButton6Act || _lastButton == kButton9Act || _lastButton == kOkAct)
+ _curPressedButton = ButtonId(_lastButton - 2);
+ else if (_lastButton == kDelAct)
+ _curPressedButton = kButton3Act;
+ else if (_lastButton == kButton0Act)
+ _curPressedButton = kNextAct;
+ else if (_lastButton == kNextAct)
+ _curPressedButton = kModeAct;
+ else if (_lastButton == kAddAct)
+ _curPressedButton = kCancelAct;
+ else if (_lastButton == kOkAct)
+ _curPressedButton = kAddAct;
else
- _currBtn = ButtonId(_lastbutton + 1);
+ _curPressedButton = ButtonId(_lastButton + 1);
- if (_mode != kModeAbc && _lastbutton == kOkAct)
- _currBtn = kCancelAct;
+ if (_mode != kModeAbc && _lastButton == kOkAct)
+ _curPressedButton = kCancelAct;
_needRefresh = true;
break;
case Common::KEYCODE_UP:
- _navigationwithkeys = true;
- if (_lastbutton <= kBtn3Act)
- _currBtn = kDelAct;
- else if (_lastbutton == kDelAct)
- _currBtn = kOkAct;
- else if (_lastbutton == kModeAct)
- _currBtn = kBtn7Act;
- else if (_lastbutton == kBtn0Act)
- _currBtn = kBtn8Act;
- else if (_lastbutton == kNextAct)
- _currBtn = kBtn9Act;
- else if (_lastbutton == kAddAct)
- _currBtn = kModeAct;
- else if (_lastbutton == kCancelAct)
- _currBtn = kBtn0Act;
- else if (_lastbutton == kOkAct)
- _currBtn = kNextAct;
+ _navigationWithKeys = true;
+ if (_lastButton <= kButton3Act)
+ _curPressedButton = kDelAct;
+ else if (_lastButton == kDelAct)
+ _curPressedButton = kOkAct;
+ else if (_lastButton == kModeAct)
+ _curPressedButton = kButton7Act;
+ else if (_lastButton == kButton0Act)
+ _curPressedButton = kButton8Act;
+ else if (_lastButton == kNextAct)
+ _curPressedButton = kButton9Act;
+ else if (_lastButton == kAddAct)
+ _curPressedButton = kModeAct;
+ else if (_lastButton == kCancelAct)
+ _curPressedButton = kButton0Act;
+ else if (_lastButton == kOkAct)
+ _curPressedButton = kNextAct;
else
- _currBtn = ButtonId(_lastbutton - 3);
+ _curPressedButton = ButtonId(_lastButton - 3);
_needRefresh = true;
break;
case Common::KEYCODE_DOWN:
- _navigationwithkeys = true;
- if (_lastbutton == kDelAct)
- _currBtn = kBtn3Act;
- else if (_lastbutton == kBtn7Act)
- _currBtn = kModeAct;
- else if (_lastbutton == kBtn8Act)
- _currBtn = kBtn0Act;
- else if (_lastbutton == kBtn9Act)
- _currBtn = kNextAct;
- else if (_lastbutton == kModeAct)
- _currBtn = kAddAct;
- else if (_lastbutton == kBtn0Act)
- _currBtn = kCancelAct;
- else if (_lastbutton == kNextAct)
- _currBtn = kOkAct;
- else if (_lastbutton == kAddAct || _lastbutton == kCancelAct || _lastbutton == kOkAct)
- _currBtn = kDelAct;
+ _navigationWithKeys = true;
+ if (_lastButton == kDelAct)
+ _curPressedButton = kButton3Act;
+ else if (_lastButton == kButton7Act)
+ _curPressedButton = kModeAct;
+ else if (_lastButton == kButton8Act)
+ _curPressedButton = kButton0Act;
+ else if (_lastButton == kButton9Act)
+ _curPressedButton = kNextAct;
+ else if (_lastButton == kModeAct)
+ _curPressedButton = kAddAct;
+ else if (_lastButton == kButton0Act)
+ _curPressedButton = kCancelAct;
+ else if (_lastButton == kNextAct)
+ _curPressedButton = kOkAct;
+ else if (_lastButton == kAddAct || _lastButton == kCancelAct || _lastButton == kOkAct)
+ _curPressedButton = kDelAct;
else
- _currBtn = ButtonId(_lastbutton + 3);
+ _curPressedButton = ButtonId(_lastButton + 3);
- if (_mode != kModeAbc && _lastbutton == kModeAct)
- _currBtn = kCancelAct;
+ if (_mode != kModeAbc && _lastButton == kModeAct)
+ _curPressedButton = kCancelAct;
_needRefresh = true;
break;
case Common::KEYCODE_KP_ENTER:
case Common::KEYCODE_RETURN:
if (state.flags & Common::KBD_CTRL) {
- _currBtn = kOkAct;
+ _curPressedButton = kOkAct;
break;
}
- if (_navigationwithkeys) {
+ if (_navigationWithKeys) {
// when the user has utilized arrow key navigation,
- // interpret enter as 'click' on the _currBtn button
- _currBtn = _lastbutton;
+ // interpret enter as 'click' on the _curPressedButton button
+ _curPressedButton = _lastButton;
_needRefresh = false;
} else {
// else it is a shortcut for 'Ok'
- _currBtn = kOkAct;
+ _curPressedButton = kOkAct;
}
break;
case Common::KEYCODE_KP_PLUS:
- _currBtn = kAddAct;
+ _curPressedButton = kAddAct;
break;
case Common::KEYCODE_BACKSPACE:
case Common::KEYCODE_KP_MINUS:
- _currBtn = kDelAct;
+ _curPressedButton = kDelAct;
break;
case Common::KEYCODE_KP_DIVIDE:
- _currBtn = kNextAct;
+ _curPressedButton = kNextAct;
break;
case Common::KEYCODE_KP_MULTIPLY:
- _currBtn = kModeAct;
+ _curPressedButton = kModeAct;
break;
case Common::KEYCODE_KP0:
- _currBtn = kBtn0Act;
+ _curPressedButton = kButton0Act;
break;
case Common::KEYCODE_KP1:
case Common::KEYCODE_KP2:
@@ -344,79 +348,79 @@ void PredictiveDialog::handleKeyDown(Common::KeyState state) {
case Common::KEYCODE_KP7:
case Common::KEYCODE_KP8:
case Common::KEYCODE_KP9:
- _currBtn = ButtonId(state.keycode - Common::KEYCODE_KP1);
+ _curPressedButton = ButtonId(state.keycode - Common::KEYCODE_KP1);
break;
default:
Dialog::handleKeyDown(state);
}
- if (_lastbutton != _currBtn)
- _btns[_lastbutton]->stopAnimatePressedState();
+ if (_lastButton != _curPressedButton)
+ _button[_lastButton]->setUnpressedState();
- if (_currBtn != kNoAct && !_needRefresh)
- _btns[_currBtn]->setPressedState();
+ if (_curPressedButton != kNoAct && !_needRefresh)
+ _button[_curPressedButton]->setPressedState();
else
- updateHighLightedButton(_currBtn);
+ updateHighLightedButton(_curPressedButton);
}
void PredictiveDialog::updateHighLightedButton(ButtonId act) {
- if (_currBtn != kNoAct) {
- _btns[_lastbutton]->setHighLighted(false);
- _lastbutton = act;
- _btns[_lastbutton]->setHighLighted(true);
+ if (_curPressedButton != kNoAct) {
+ _button[_lastButton]->setHighLighted(false);
+ _lastButton = act;
+ _button[_lastButton]->setHighLighted(true);
}
}
void PredictiveDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
- _currBtn = kNoAct;
+ _curPressedButton = kNoAct;
- _navigationwithkeys = false;
+ _navigationWithKeys = false;
- if (_lastbutton != kNoAct)
- _btns[_lastbutton]->setHighLighted(false);
+ if (_lastButton != kNoAct)
+ _button[_lastButton]->setHighLighted(false);
switch (cmd) {
case kDelCmd:
- _currBtn = kDelAct;
+ _curPressedButton = kDelAct;
break;
case kNextCmd:
- _currBtn = kNextAct;
+ _curPressedButton = kNextAct;
break;
case kAddCmd:
- _currBtn = kAddAct;
+ _curPressedButton = kAddAct;
break;
case kModeCmd:
- _currBtn = kModeAct;
+ _curPressedButton = kModeAct;
break;
case kBut1Cmd:
- _currBtn = kBtn1Act;
+ _curPressedButton = kButton1Act;
break;
case kBut2Cmd:
- _currBtn = kBtn2Act;
+ _curPressedButton = kButton2Act;
break;
case kBut3Cmd:
- _currBtn = kBtn3Act;
+ _curPressedButton = kButton3Act;
break;
case kBut4Cmd:
- _currBtn = kBtn4Act;
+ _curPressedButton = kButton4Act;
break;
case kBut5Cmd:
- _currBtn = kBtn5Act;
+ _curPressedButton = kButton5Act;
break;
case kBut6Cmd:
- _currBtn = kBtn6Act;
+ _curPressedButton = kButton6Act;
break;
case kBut7Cmd:
- _currBtn = kBtn7Act;
+ _curPressedButton = kButton7Act;
break;
case kBut8Cmd:
- _currBtn = kBtn8Act;
+ _curPressedButton = kButton8Act;
break;
case kBut9Cmd:
- _currBtn = kBtn9Act;
+ _curPressedButton = kButton9Act;
break;
case kBut0Cmd:
- _currBtn = kBtn0Act;
+ _curPressedButton = kButton0Act;
break;
case kCancelCmd:
saveUserDictToFile();
@@ -426,19 +430,18 @@ void PredictiveDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 d
_predictiveResult[0] = 0;
return;
case kOkCmd:
- _currBtn = kOkAct;
+ _curPressedButton = kOkAct;
break;
default:
Dialog::handleCommand(sender, cmd, data);
}
- if (_currBtn != kNoAct) {
- processBtnActive(_currBtn);
+ if (_curPressedButton != kNoAct) {
+ processButton(_curPressedButton);
}
}
-void PredictiveDialog::processBtnActive(ButtonId button) {
- uint8 x;
+void PredictiveDialog::processButton(ButtonId button) {
static const char *const buttonStr[] = {
"1", "2", "3",
"4", "5", "6",
@@ -457,10 +460,10 @@ void PredictiveDialog::processBtnActive(ButtonId button) {
};
if (_mode == kModeAbc) {
- if (button >= kBtn1Act && button <= kBtn9Act) {
+ if (button >= kButton1Act && button <= kButton9Act) {
if (!_lastTime)
_lastTime = g_system->getMillis();
- if (_lastPressBtn == button) {
+ if (_lastPressedButton == button) {
_curTime = g_system->getMillis();
if ((_curTime - _lastTime) < kRepeatDelay) {
button = kNextAct;
@@ -469,15 +472,15 @@ void PredictiveDialog::processBtnActive(ButtonId button) {
_lastTime = 0;
}
} else {
- _lastPressBtn = button;
+ _lastPressedButton = button;
_lastTime = g_system->getMillis();
}
}
}
- if (button >= kBtn1Act) {
- _lastbutton = button;
- if (button == kBtn0Act && _mode != kModeNum) { // Space
+ if (button >= kButton1Act) {
+ _lastButton = button;
+ if (button == kButton0Act && _mode != kModeNum) { // Space
// bring MRU word at the top of the list when changing words
if (_mode == kModePre && _unitedDict.dictActLine && _numMatchingWords > 1 && _wordNumber != 0)
bringWordtoTop(_unitedDict.dictActLine, _wordNumber);
@@ -491,9 +494,9 @@ void PredictiveDialog::processBtnActive(ButtonId button) {
_numMatchingWords = 0;
memset(_repeatcount, 0, sizeof(_repeatcount));
_lastTime = 0;
- _lastPressBtn = kNoAct;
+ _lastPressedButton = kNoAct;
_curTime = 0;
- } else if (button < kNextAct || button == kDelAct || button == kBtn0Act) { // number or backspace
+ } else if (button < kNextAct || button == kDelAct || button == kButton0Act) { // number or backspace
if (button == kDelAct) { // backspace
if (_currentCode.size()) {
_repeatcount[_currentCode.size() - 1] = 0;
@@ -505,7 +508,7 @@ void PredictiveDialog::processBtnActive(ButtonId button) {
_prefix.deleteLastChar();
}
} else if (_prefix.size() + _currentCode.size() < kMaxWordLen - 1) { // don't overflow the dialog line
- if (button == kBtn0Act) { // zero
+ if (button == kButton0Act) { // zero
_currentCode += buttonStr[9];
} else {
_currentCode += buttonStr[button];
@@ -524,7 +527,7 @@ void PredictiveDialog::processBtnActive(ButtonId button) {
_numMatchingWords = countWordsInString(_unitedDict.dictActLine);
break;
case kModeAbc:
- for (x = 0; x < _currentCode.size(); x++)
+ for (uint x = 0; x < _currentCode.size(); x++)
if (_currentCode[x] >= '1')
_temp[x] = buttons[_currentCode[x] - '1'][_repeatcount[x]];
_temp[_currentCode.size()] = 0;
@@ -543,7 +546,7 @@ void PredictiveDialog::processBtnActive(ButtonId button) {
_currentWord = Common::String(tok, _currentCode.size());
}
} else if (_mode == kModeAbc) {
- x = _currentCode.size();
+ uint x = _currentCode.size();
if (x) {
if (_currentCode.lastChar() == '1' || _currentCode.lastChar() == '7' || _currentCode.lastChar() == '9')
_repeatcount[x - 1] = (_repeatcount[x - 1] + 1) % 4;
@@ -558,25 +561,25 @@ void PredictiveDialog::processBtnActive(ButtonId button) {
if (_mode == kModeAbc)
addWordToDict();
else
- debug("Predictive Dialog: button Add doesn't work in this mode");
+ debug(5, "Predictive Dialog: button Add doesn't work in this mode");
} else if (button == kOkAct) { // Ok
// bring MRU word at the top of the list when ok'ed out of the dialog
if (_mode == kModePre && _unitedDict.dictActLine && _numMatchingWords > 1 && _wordNumber != 0)
bringWordtoTop(_unitedDict.dictActLine, _wordNumber);
} else if (button == kModeAct) { // Mode
_mode++;
- _btns[kAddAct]->setEnabled(false);
+ _button[kAddAct]->setEnabled(false);
if (_mode > kModeAbc) {
_mode = kModePre;
// I18N: Pre means 'Predictive', leave '*' as is
- _btns[kModeAct]->setLabel("* Pre");
+ _button[kModeAct]->setLabel(_("* Pre"));
} else if (_mode == kModeNum) {
// I18N: 'Num' means Numbers
- _btns[kModeAct]->setLabel("* Num");
+ _button[kModeAct]->setLabel(_("* Num"));
} else {
// I18N: 'Abc' means Latin alphabet input
- _btns[kModeAct]->setLabel("* Abc");
- _btns[kAddAct]->setEnabled(true);
+ _button[kModeAct]->setLabel(_("* Abc"));
+ _button[kAddAct]->setEnabled(true);
}
// truncate current input at mode change
@@ -588,7 +591,7 @@ void PredictiveDialog::processBtnActive(ButtonId button) {
memset(_repeatcount, 0, sizeof(_repeatcount));
_lastTime = 0;
- _lastPressBtn = kNoAct;
+ _lastPressedButton = kNoAct;
_curTime = 0;
}
}
@@ -598,21 +601,9 @@ void PredictiveDialog::processBtnActive(ButtonId button) {
if (button == kOkAct)
close();
- if (button == kCancelAct) {
- saveUserDictToFile();
- close();
- }
-}
-
-void PredictiveDialog::handleTickle() {
- if (_lastTime) {
- if ((_curTime - _lastTime) > kRepeatDelay) {
- _lastTime = 0;
- }
- }
-
- if (getTickleWidget()) {
- getTickleWidget()->handleTickle();
+ if (button == kCancelAct) {
+ saveUserDictToFile();
+ close();
}
}
@@ -621,7 +612,7 @@ void PredictiveDialog::mergeDicts() {
_unitedDict.dictLine = (char **)calloc(_unitedDict.dictLineCount, sizeof(char *));
if (!_unitedDict.dictLine) {
- debug("Predictive Dialog: cannot allocate memory for united dic");
+ debug(5, "Predictive Dialog: cannot allocate memory for united dic");
return;
}
@@ -658,7 +649,7 @@ uint8 PredictiveDialog::countWordsInString(const char *const str) {
ptr = strchr(str, ' ');
if (!ptr) {
- debug("Predictive Dialog: Invalid dictionary line");
+ debug(5, "Predictive Dialog: Invalid dictionary line");
return 0;
}
@@ -684,7 +675,7 @@ void PredictiveDialog::bringWordtoTop(char *str, int wordnum) {
buf[kMaxLineLen - 1] = 0;
char *word = strtok(buf, " ");
if (!word) {
- debug("Predictive Dialog: Invalid dictionary line");
+ debug(5, "Predictive Dialog: Invalid dictionary line");
return;
}
@@ -724,6 +715,10 @@ int PredictiveDialog::binarySearch(const char *const *const dictLine, const Comm
}
bool PredictiveDialog::matchWord() {
+ // If there is no dictionary, then there is no match.
+ if (_unitedDict.dictLineCount <= 0)
+ return false;
+
// If no text has been entered, then there is no match.
if (_currentCode.empty())
return false;
@@ -734,7 +729,7 @@ bool PredictiveDialog::matchWord() {
// The entries in the dictionary consist of a code, a space, and then
// a space-separated list of words matching this code.
- // To ex_currBtnly match a code, we therefore match the code plus the trailing
+ // To exactly match a code, we therefore match the code plus the trailing
// space in the dictionary.
Common::String code = _currentCode + " ";
@@ -929,7 +924,7 @@ void PredictiveDialog::loadDictionary(Common::SeekableReadStream *in, Dict &dict
in->read(dict.dictText, dict.dictTextSize);
dict.dictText[dict.dictTextSize] = 0;
uint32 time2 = g_system->getMillis();
- debug("Predictive Dialog: Time to read %s: %d bytes, %d ms", ConfMan.get(dict.nameDict).c_str(), dict.dictTextSize, time2 - time1);
+ debug(5, "Predictive Dialog: Time to read %s: %d bytes, %d ms", ConfMan.get(dict.nameDict).c_str(), dict.dictTextSize, time2 - time1);
delete in;
char *ptr = dict.dictText;
@@ -960,7 +955,7 @@ void PredictiveDialog::loadDictionary(Common::SeekableReadStream *in, Dict &dict
lines--;
dict.dictLineCount = lines;
- debug("Predictive Dialog: Loaded %d lines", dict.dictLineCount);
+ debug(5, "Predictive Dialog: Loaded %d lines", dict.dictLineCount);
// FIXME: We use binary search on _predictiveDict.dictLine, yet we make no at_tempt
// to ever sort this array (except for the DS port). That seems risky, doesn't it?
@@ -971,23 +966,24 @@ void PredictiveDialog::loadDictionary(Common::SeekableReadStream *in, Dict &dict
#endif
uint32 time3 = g_system->getMillis();
- debug("Predictive Dialog: Time to parse %s: %d, total: %d", ConfMan.get(dict.nameDict).c_str(), time3 - time2, time3 - time1);
+ debug(5, "Predictive Dialog: Time to parse %s: %d, total: %d", ConfMan.get(dict.nameDict).c_str(), time3 - time2, time3 - time1);
}
void PredictiveDialog::loadAllDictionary(Dict &dict) {
- ConfMan.registerDefault(dict.nameDict, dict.fnameDict);
+ ConfMan.registerDefault(dict.nameDict, dict.defaultFilename);
if (dict.nameDict == "predictive_dictionary") {
Common::File *inFile = new Common::File();
if (!inFile->open(ConfMan.get(dict.nameDict))) {
- warning("Predictive Dialog: cannot read file: %s", dict.fnameDict.c_str());
+ warning("Predictive Dialog: cannot read file: %s", dict.defaultFilename.c_str());
+ delete inFile;
return;
}
loadDictionary(inFile, dict);
} else {
Common::InSaveFile *inFile = g_system->getSavefileManager()->openForLoading(ConfMan.get(dict.nameDict));
if (!inFile) {
- warning("Predictive Dialog: cannot read file: %s", dict.fnameDict.c_str());
+ warning("Predictive Dialog: cannot read file: %s", dict.defaultFilename.c_str());
return;
}
loadDictionary(inFile, dict);
@@ -997,9 +993,9 @@ void PredictiveDialog::loadAllDictionary(Dict &dict) {
void PredictiveDialog::pressEditText() {
Common::strlcpy(_predictiveResult, _prefix.c_str(), sizeof(_predictiveResult));
Common::strlcat(_predictiveResult, _currentWord.c_str(), sizeof(_predictiveResult));
- _edittext->setEditString(_predictiveResult);
- //_edittext->setCaretPos(_prefix.size() + _currentWord.size());
- _edittext->draw();
+ _editText->setEditString(_predictiveResult);
+ //_editText->setCaretPos(_prefix.size() + _currentWord.size());
+ _editText->draw();
}
} // namespace GUI
diff --git a/gui/predictivedialog.h b/gui/predictivedialog.h
index 32d769d6ca..1f6bdf84e0 100644
--- a/gui/predictivedialog.h
+++ b/gui/predictivedialog.h
@@ -33,56 +33,65 @@ class EditTextWidget;
class ButtonWidget;
class PicButtonWidget;
-enum ButtonId {
- kBtn1Act = 0,
- kBtn2Act = 1,
- kBtn3Act = 2,
- kBtn4Act = 3,
- kBtn5Act = 4,
- kBtn6Act = 5,
- kBtn7Act = 6,
- kBtn8Act = 7,
- kBtn9Act = 8,
- kNextAct = 9,
- kAddAct = 10,
- kDelAct = 11,
- kCancelAct = 12,
- kOkAct = 13,
- kModeAct = 14,
- kBtn0Act = 15,
- kNoAct = -1
-};
-
-enum {
- kRepeatDelay = 500
-};
-
-enum {
- kMaxLineLen = 80,
- kMaxWordLen = 24,
- kMaxWord = 50
-};
-
class PredictiveDialog : public GUI::Dialog {
public:
PredictiveDialog();
~PredictiveDialog();
+ virtual void reflowLayout();
+
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; }
+
private:
+ enum ButtonId {
+ kButton1Act = 0,
+ kButton2Act = 1,
+ kButton3Act = 2,
+ kButton4Act = 3,
+ kButton5Act = 4,
+ kButton6Act = 5,
+ kButton7Act = 6,
+ kButton8Act = 7,
+ kButton9Act = 8,
+ kNextAct = 9,
+ kAddAct = 10,
+ kDelAct = 11,
+ kCancelAct = 12,
+ kOkAct = 13,
+ kModeAct = 14,
+ kButton0Act = 15,
+ kNoAct = -1
+ };
+
+ enum {
+ kButtonCount = kButton0Act + 1
+ };
+
+ enum {
+ kRepeatDelay = 500
+ };
+
+ enum {
+ kMaxLineLen = 80,
+ kMaxWordLen = 24,
+ kMaxWord = 50
+ };
+
struct Dict {
+ Dict() : dictLine(nullptr), dictText(nullptr), dictActLine(nullptr),
+ dictLineCount(0), dictTextSize(0) {}
+ ~Dict() { free(dictText); }
char **dictLine;
char *dictText;
char *dictActLine; // using only for united dict...
int32 dictLineCount;
int32 dictTextSize;
Common::String nameDict;
- Common::String fnameDict;
+ Common::String defaultFilename;
};
uint8 countWordsInString(const char *const str);
@@ -94,7 +103,7 @@ private:
bool searchWord(const char *const where, const Common::String &whatCode);
int binarySearch(const char *const *const dictLine, const Common::String &code, const int dictLineCount);
bool matchWord();
- void processBtnActive(ButtonId active);
+ void processButton(ButtonId active);
void pressEditText();
void saveUserDictToFile();
@@ -108,7 +117,7 @@ private:
Dict _userDict;
int _mode;
- ButtonId _lastbutton;
+ ButtonId _lastButton;
bool _userDictHasChanged;
@@ -121,8 +130,8 @@ private:
Common::String _prefix;
uint32 _curTime, _lastTime;
- ButtonId _lastPressBtn;
- ButtonId _currBtn;
+ ButtonId _lastPressedButton;
+ ButtonId _curPressedButton;
char _temp[kMaxWordLen + 1];
int _repeatcount[kMaxWordLen];
@@ -132,11 +141,11 @@ private:
Common::String _search;
- bool _navigationwithkeys;
+ bool _navigationWithKeys;
bool _needRefresh;
private:
- EditTextWidget *_edittext;
- ButtonWidget **_btns;
+ EditTextWidget *_editText;
+ ButtonWidget *_button[kButtonCount];
};
} // namespace GUI
diff --git a/gui/recorderdialog.cpp b/gui/recorderdialog.cpp
index 5617d2ba9a..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"
@@ -171,7 +170,7 @@ void RecorderDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
const EnginePlugin *plugin = 0;
GameDescriptor desc = EngineMan.findGame(gameId, &plugin);
g_system->getTimeAndDate(t);
- EditRecordDialog editDlg("Unknown Author", Common::String::format("%.2d.%.2d.%.4d ", t.tm_mday, t.tm_mon, 1900 + t.tm_year) + desc.description(), "");
+ EditRecordDialog editDlg(_("Unknown Author"), Common::String::format("%.2d.%.2d.%.4d ", t.tm_mday, t.tm_mon, 1900 + t.tm_year) + desc.description(), "");
if (editDlg.runModal() != kOKCmd) {
return;
}
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 aa2a24bf00..c0ea733de8 100644
--- a/gui/themes/default.inc
+++ b/gui/themes/default.inc
@@ -1,5 +1,6 @@
- "<?xml version = '1.0'?>"
-"<render_info>"
+const char *defaultXML1 = "<?xml version = '1.0'?>"
+;
+ const char *defaultXML2 = "<render_info>"
"<palette>"
"<color name='black' "
"rgb='0,0,0' "
@@ -610,7 +611,8 @@
"/>"
"</drawdata>"
"</render_info>"
-"<layout_info resolution='y>399'>"
+;
+ const char *defaultXML3 = "<layout_info resolution='y>399'>"
"<globals>"
"<def var='Line.Height' value='16' />"
"<def var='Font.Height' value='16' />"
@@ -631,6 +633,7 @@
"<def var='Tooltip.XDelta' value='16'/> "
"<def var='Tooltip.YDelta' value='16'/>"
"<def var='Predictive.Button.Width' value='60' />"
+"<def var='Predictive.ShowDeletePic' value='0'/>"
"<widget name='OptionsLabel' "
"size='110,Globals.Line.Height' "
"textalign='right' "
@@ -771,9 +774,31 @@
"</layout>"
"</layout>"
"</dialog>"
+"<dialog name='FileBrowser' overlays='screen' inset='32' shading='dim'>"
+"<layout type='vertical' padding='16,16,16,16'>"
+"<widget name='Headline' "
+"height='Globals.Line.Height' "
+"/>"
+"<widget name='Filename' "
+"height='Globals.Line.Height' "
+"/>"
+"<space size='10' />"
+"<widget name='List'/>"
+"<layout type='vertical' padding='0,0,16,0'>"
+"<layout type='horizontal' padding='0,0,0,0'>"
+"<widget name='Cancel' "
+"type='Button' "
+"/>"
+"<widget name='Choose' "
+"type='Button' "
+"/>"
+"</layout>"
+"</layout>"
+"</layout>"
+"</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' "
@@ -1051,6 +1076,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' "
"/>"
@@ -1082,7 +1118,7 @@
"</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' "
@@ -1369,7 +1405,7 @@
"</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' "
@@ -1873,7 +1909,8 @@
"</layout>"
"</dialog>"
"</layout_info>"
-"<layout_info resolution='y<400'>"
+;
+ const char *defaultXML4 = "<layout_info resolution='y<400'>"
"<globals>"
"<def var='Line.Height' value='12' />"
"<def var='Font.Height' value='10' />"
@@ -1895,6 +1932,7 @@
"<def var='Tooltip.YDelta' value='8'/>"
"<def var='Predictive.Button.Width' value='45' />"
"<def var='Predictive.Button.Height' value='15' />"
+"<def var='Predictive.ShowDeletePic' value='0'/>"
"<widget name='Button' "
"size='72,16' "
"/>"
@@ -1937,7 +1975,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' "
@@ -2031,9 +2069,31 @@
"</layout>"
"</layout>"
"</dialog>"
+"<dialog name='FileBrowser' overlays='screen' inset='16' shading='dim'>"
+"<layout type='vertical' padding='16,16,16,16'>"
+"<widget name='Headline' "
+"height='Globals.Line.Height' "
+"/>"
+"<widget name='Filename' "
+"height='Globals.Line.Height' "
+"/>"
+"<space size='5' />"
+"<widget name='List'/>"
+"<layout type='vertical' padding='0,0,16,0'>"
+"<layout type='horizontal' padding='0,0,0,0'>"
+"<widget name='Cancel' "
+"type='Button' "
+"/>"
+"<widget name='Choose' "
+"type='Button' "
+"/>"
+"</layout>"
+"</layout>"
+"</layout>"
+"</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' "
@@ -2316,6 +2376,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' "
"/>"
@@ -2347,7 +2420,7 @@
"</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' "
@@ -2643,7 +2716,7 @@
"</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' "
@@ -3105,3 +3178,5 @@
"</layout>"
"</dialog>"
"</layout_info>"
+;
+const char *defaultXML[] = { defaultXML1, defaultXML2, defaultXML3, defaultXML4 };
diff --git a/gui/themes/scummclassic.zip b/gui/themes/scummclassic.zip
index 1b555a6c27..561f2a5dd3 100644
--- a/gui/themes/scummclassic.zip
+++ b/gui/themes/scummclassic.zip
Binary files differ
diff --git a/gui/themes/scummclassic/THEMERC b/gui/themes/scummclassic/THEMERC
index 8f40cb2a7e..7e58285d08 100644
--- a/gui/themes/scummclassic/THEMERC
+++ b/gui/themes/scummclassic/THEMERC
@@ -1 +1 @@
-[SCUMMVM_STX0.8.20:ScummVM Classic Theme:No Author]
+[SCUMMVM_STX0.8.21:ScummVM Classic Theme:No Author]
diff --git a/gui/themes/scummclassic/classic_layout.stx b/gui/themes/scummclassic/classic_layout.stx
index cf8268696d..5172326859 100644
--- a/gui/themes/scummclassic/classic_layout.stx
+++ b/gui/themes/scummclassic/classic_layout.stx
@@ -49,6 +49,7 @@
<def var = 'Tooltip.YDelta' value = '16'/>
<def var = 'Predictive.Button.Width' value = '60' />
+ <def var = 'Predictive.ShowDeletePic' value = '0'/>
<widget name = 'OptionsLabel'
size = '110, Globals.Line.Height'
@@ -196,9 +197,32 @@
</layout>
</dialog>
+ <dialog name = 'FileBrowser' overlays = 'screen' inset = '32' shading = 'dim'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16'>
+ <widget name = 'Headline'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Filename'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '10' />
+ <widget name = 'List'/>
+ <layout type = 'vertical' padding = '0, 0, 16, 0'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+ <widget name = 'Choose'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </layout>
+ </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'
@@ -483,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'
/>
@@ -516,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'
@@ -673,7 +708,7 @@
/>
</layout>
</dialog>
-
+
<dialog name = 'GlobalMenu' overlays = 'screen_center'>
<layout type = 'vertical' padding = '16, 16, 16, 16' center = 'true'>
<widget name = 'Title'
@@ -815,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'
@@ -1040,7 +1075,7 @@
width = '180'
height = '170'
/>
- <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
<widget name = 'NextScreenShotButton'
width = '25'
height = '25'
@@ -1115,15 +1150,15 @@
<layout type = 'horizontal' spacing = '5' padding = '0, 0, 0, 10'>
<widget name = 'AuthorLabel'
type = 'EditRecordLabel'
- />
+ />
<widget name = 'AuthorEdit'
type = 'EditRecord'
- />
+ />
</layout>
<layout type = 'horizontal' spacing = '5' padding = '0, 0, 0, 10'>
<widget name = 'NameLabel'
type = 'EditRecordLabel'
- />
+ />
<widget name = 'NameEdit'
type = 'EditRecord'
/>
@@ -1142,11 +1177,11 @@
/>
<widget name = 'OK'
type = 'Button'
- />
+ />
</layout>
</layout>
</dialog>
-
+
<dialog name = 'ScummHelp' overlays = 'screen_center'>
<layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'>
<widget name = 'Title'
@@ -1250,7 +1285,7 @@
<layout type = 'horizontal' padding = '5, 5, 5, 5'>
<widget name = 'Word'
width = '190'
- height = 'Globals.Button.Height'
+ height = 'Globals.Button.Height'
/>
<widget name = 'Delete'
width = '20'
@@ -1315,7 +1350,7 @@
/>
</layout>
<space size = '5' />
- <layout type = 'horizontal' padding = '3, 3, 3, 3'>
+ <layout type = 'horizontal' padding = '3, 3, 3, 3'>
<widget name = 'Add'
width = 'Globals.Predictive.Button.Width'
height = 'Globals.Button.Height'
diff --git a/gui/themes/scummclassic/classic_layout_lowres.stx b/gui/themes/scummclassic/classic_layout_lowres.stx
index 506657ef31..0013b91ee2 100644
--- a/gui/themes/scummclassic/classic_layout_lowres.stx
+++ b/gui/themes/scummclassic/classic_layout_lowres.stx
@@ -51,6 +51,7 @@
<def var = 'Predictive.Button.Width' value = '45' />
<def var = 'Predictive.Button.Height' value = '15' />
+ <def var = 'Predictive.ShowDeletePic' value = '0'/>
<widget name = 'Button'
size = '72, 16'
@@ -96,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'
@@ -193,9 +194,32 @@
</layout>
</dialog>
+ <dialog name = 'FileBrowser' overlays = 'screen' inset = '16' shading = 'dim'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16'>
+ <widget name = 'Headline'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Filename'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '5' />
+ <widget name = 'List'/>
+ <layout type = 'vertical' padding = '0, 0, 16, 0'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+ <widget name = 'Choose'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </layout>
+ </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'
@@ -486,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'
/>
@@ -519,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'
@@ -685,7 +722,7 @@
/>
</layout>
</dialog>
-
+
<dialog name = 'GlobalMenu' overlays = 'screen_center'>
<layout type = 'vertical' padding = '2, 2, 2, 6' center = 'true' spacing='0'>
<widget name = 'Title'
@@ -826,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'
@@ -1086,15 +1123,15 @@
<layout type = 'horizontal' spacing = '5' padding = '0, 0, 0, 10'>
<widget name = 'AuthorLabel'
type = 'EditRecordLabel'
- />
+ />
<widget name = 'AuthorEdit'
type = 'EditRecord'
- />
+ />
</layout>
<layout type = 'horizontal' spacing = '5' padding = '0, 0, 0, 10'>
<widget name = 'NameLabel'
type = 'EditRecordLabel'
- />
+ />
<widget name = 'NameEdit'
type = 'EditRecord'
/>
@@ -1113,7 +1150,7 @@
/>
<widget name = 'OK'
type = 'Button'
- />
+ />
</layout>
</layout>
</dialog>
@@ -1220,7 +1257,7 @@
<layout type = 'horizontal' padding = '3, 3, 3, 3'>
<widget name = 'Word'
width = '120'
- height = 'Globals.Button.Height'
+ height = 'Globals.Button.Height'
/>
<widget name = 'Delete'
width = '20'
diff --git a/gui/themes/scummmodern.zip b/gui/themes/scummmodern.zip
index c7c585654d..d80c481ffc 100644
--- a/gui/themes/scummmodern.zip
+++ b/gui/themes/scummmodern.zip
Binary files differ
diff --git a/gui/themes/scummmodern/THEMERC b/gui/themes/scummmodern/THEMERC
index f4304622cb..dc98bdc00e 100644
--- a/gui/themes/scummmodern/THEMERC
+++ b/gui/themes/scummmodern/THEMERC
@@ -1 +1 @@
-[SCUMMVM_STX0.8.20:ScummVM Modern Theme:No Author]
+[SCUMMVM_STX0.8.21:ScummVM Modern Theme:No Author]
diff --git a/gui/themes/scummmodern/scummmodern_layout.stx b/gui/themes/scummmodern/scummmodern_layout.stx
index 7e61d6820e..026fa7bc64 100644
--- a/gui/themes/scummmodern/scummmodern_layout.stx
+++ b/gui/themes/scummmodern/scummmodern_layout.stx
@@ -56,6 +56,7 @@
<def var = 'Tooltip.YDelta' value = '32'/>
<def var = 'Predictive.Button.Width' value = '60' />
+ <def var = 'Predictive.ShowDeletePic' value = '1'/>
<widget name = 'OptionsLabel'
size = '115, Globals.Line.Height'
@@ -67,7 +68,7 @@
<widget name = 'Button'
size = '108, 24'
- />
+ />
<widget name = 'Slider'
size = '128, 18'
@@ -210,9 +211,32 @@
</layout>
</dialog>
+ <dialog name = 'FileBrowser' overlays = 'screen' inset = '32' shading = 'dim'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16'>
+ <widget name = 'Headline'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Filename'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '10' />
+ <widget name = 'List'/>
+ <layout type = 'vertical' padding = '0, 0, 16, 0'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+ <widget name = 'Choose'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </layout>
+ </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'
@@ -497,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'
/>
@@ -530,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'
@@ -687,7 +722,7 @@
/>
</layout>
</dialog>
-
+
<dialog name = 'GlobalMenu' overlays = 'screen_center'>
<layout type = 'vertical' padding = '16, 16, 16, 16' center = 'true'>
<widget name = 'Logo'
@@ -829,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'
@@ -1054,7 +1089,7 @@
width = '180'
height = '170'
/>
- <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
<widget name = 'NextScreenShotButton'
width = '25'
height = '25'
@@ -1130,15 +1165,15 @@
<layout type = 'horizontal' spacing = '5' padding = '0, 0, 0, 10'>
<widget name = 'AuthorLabel'
type = 'EditRecordLabel'
- />
+ />
<widget name = 'AuthorEdit'
type = 'EditRecord'
- />
+ />
</layout>
<layout type = 'horizontal' spacing = '5' padding = '0, 0, 0, 10'>
<widget name = 'NameLabel'
type = 'EditRecordLabel'
- />
+ />
<widget name = 'NameEdit'
type = 'EditRecord'
/>
@@ -1157,11 +1192,11 @@
/>
<widget name = 'OK'
type = 'Button'
- />
+ />
</layout>
</layout>
</dialog>
-
+
<dialog name = 'ScummHelp' overlays = 'screen_center'>
<layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'>
<widget name = 'Title'
@@ -1252,7 +1287,7 @@
type = 'Button'
/>
</layout>
- </dialog>
+ </dialog>
<dialog name = 'Predictive' overlays = 'screen_center'>
<layout type = 'vertical' padding = '5, 5, 5, 5' center = 'true'>
<widget name = 'Headline'
@@ -1264,7 +1299,7 @@
<layout type = 'horizontal' padding = '5, 5, 5, 5'>
<widget name = 'Word'
width = '190'
- height = 'Globals.Button.Height'
+ height = 'Globals.Button.Height'
/>
<widget name = 'Delete'
width = '20'
diff --git a/gui/themes/scummmodern/scummmodern_layout_lowres.stx b/gui/themes/scummmodern/scummmodern_layout_lowres.stx
index cee1e4af2b..169e61a9bb 100644
--- a/gui/themes/scummmodern/scummmodern_layout_lowres.stx
+++ b/gui/themes/scummmodern/scummmodern_layout_lowres.stx
@@ -41,6 +41,7 @@
<def var = 'Predictive.Button.Width' value = '45' />
<def var = 'Predictive.Button.Height' value = '15' />
+ <def var = 'Predictive.ShowDeletePic' value = '0'/>
<widget name = 'Button'
size = '72, 16'
@@ -94,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'
@@ -191,9 +192,32 @@
</layout>
</dialog>
+ <dialog name = 'FileBrowser' overlays = 'screen' inset = '16' shading = 'dim'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16'>
+ <widget name = 'Headline'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Filename'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '5' />
+ <widget name = 'List'/>
+ <layout type = 'vertical' padding = '0, 0, 16, 0'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+ <widget name = 'Choose'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </layout>
+ </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'
@@ -484,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'
/>
@@ -517,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'
@@ -683,7 +720,7 @@
/>
</layout>
</dialog>
-
+
<dialog name = 'GlobalMenu' overlays = 'screen_center'>
<layout type = 'vertical' padding = '4, 4, 4, 4' center = 'true' spacing='2'>
<widget name = 'Title'
@@ -824,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'
@@ -1105,15 +1142,15 @@
<layout type = 'horizontal' spacing = '5' padding = '0, 0, 0, 10'>
<widget name = 'AuthorLabel'
type = 'EditRecordLabel'
- />
+ />
<widget name = 'AuthorEdit'
type = 'EditRecord'
- />
+ />
</layout>
<layout type = 'horizontal' spacing = '5' padding = '0, 0, 0, 10'>
<widget name = 'NameLabel'
type = 'EditRecordLabel'
- />
+ />
<widget name = 'NameEdit'
type = 'EditRecord'
/>
@@ -1132,11 +1169,11 @@
/>
<widget name = 'OK'
type = 'Button'
- />
+ />
</layout>
</layout>
</dialog>
-
+
<dialog name = 'ScummHelp' overlays = 'screen' inset = '8'>
<layout type = 'vertical' padding = '8, 8, 8, 8'>
<widget name = 'Title'
@@ -1237,7 +1274,7 @@
<layout type = 'horizontal' padding = '0, 0, 2, 2'>
<widget name = 'Word'
width = '120'
- height = 'Globals.Button.Height'
+ height = 'Globals.Button.Height'
/>
<widget name = 'Delete'
width = '20'
diff --git a/gui/themes/scummtheme.py b/gui/themes/scummtheme.py
index 94dc08f1ef..d5fa4dfca7 100755
--- a/gui/themes/scummtheme.py
+++ b/gui/themes/scummtheme.py
@@ -35,11 +35,15 @@ def buildAllThemes():
if os.path.isdir(os.path.join('.', f)) and not f[0] == '.':
buildTheme(f)
-def parseSTX(theme_file, def_file):
+def parseSTX(theme_file, def_file, subcount):
comm = re.compile("<!--(.*?)-->", re.DOTALL)
head = re.compile("<\?(.*?)\?>")
strlitcount = 0
+ subcount += 1
+
+ def_file.write(";\n const char *defaultXML" + str(subcount) + " = ")
+
output = ""
for line in theme_file:
output += line.rstrip("\r\n\t ").lstrip()
@@ -55,8 +59,12 @@ def parseSTX(theme_file, def_file):
for line in output.splitlines():
if line and not line.isspace():
strlitcount += len(line)
+ if strlitcount > 65535:
+ subcount += 1
+ def_file.write(";\n const char *defaultXML" + str(subcount) + " = ")
+ strlitcount = len(line)
def_file.write("\"" + line + "\"\n")
- return strlitcount
+ return subcount
def buildDefTheme(themeName):
def_file = open("default.inc", "w")
@@ -64,8 +72,8 @@ def buildDefTheme(themeName):
if not os.path.isdir(themeName):
print ("Cannot open default theme dir.")
- def_file.write(""" "<?xml version = '1.0'?>"\n""")
- strlitcount = 24
+ def_file.write("""const char *defaultXML1 = "<?xml version = '1.0'?>"\n""")
+ subcount = 1
filenames = os.listdir(themeName)
filenames.sort()
@@ -73,16 +81,16 @@ def buildDefTheme(themeName):
filename = os.path.join(themeName, filename)
if os.path.isfile(filename) and filename.endswith(".stx"):
theme_file = open(filename, "r")
- strlitcount += parseSTX(theme_file, def_file)
+ subcount = parseSTX(theme_file, def_file, subcount)
theme_file.close()
- def_file.close()
+ def_file.write(";\nconst char *defaultXML[] = { defaultXML1")
+ for sub in range(2, subcount + 1):
+ def_file.write(", defaultXML" + str(sub))
- if strlitcount > 65535:
- print("WARNING: default.inc string literal is of length %d which exceeds the" % strlitcount)
- print(" maximum length of 65536 that C++ compilers are required to support.")
- print(" It is likely that bugs will occur dependent on compiler behaviour.")
- print(" To avoid this, reduce the size of the theme.")
+ def_file.write(" };\n")
+
+ def_file.close()
def printUsage():
print ("===============================")
diff --git a/gui/themes/translations.dat b/gui/themes/translations.dat
index 4225994810..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 af3e5e9b9a..4f7e584c14 100644
--- a/gui/widgets/editable.cpp
+++ b/gui/widgets/editable.cpp
@@ -79,7 +79,7 @@ bool EditableWidget::tryInsertChar(byte c, int pos) {
void EditableWidget::handleTickle() {
uint32 time = g_system->getMillis();
- if (_caretTime < time) {
+ if (_caretTime < time && isEnabled()) {
_caretTime = time + kCaretBlinkTime;
drawCaret(_caretVisible);
}
@@ -90,6 +90,9 @@ bool EditableWidget::handleKeyDown(Common::KeyState state) {
bool dirty = false;
bool forcecaret = false;
+ if (!isEnabled())
+ return false;
+
// First remove caret
if (_caretVisible)
drawCaret(true);
@@ -271,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;
@@ -300,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 550b1bd153..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) {
@@ -62,6 +66,9 @@ void EditTextWidget::reflowLayout() {
void EditTextWidget::handleMouseDown(int x, int y, int button, int clickCount) {
+ if (!isEnabled())
+ return;
+
// First remove caret
if (_caretVisible)
drawCaret(true);
@@ -90,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();
@@ -98,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/indeo3.cpp b/image/codecs/indeo3.cpp
index af9120ca93..560658d1f5 100644
--- a/image/codecs/indeo3.cpp
+++ b/image/codecs/indeo3.cpp
@@ -391,6 +391,11 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height,
int rle_v1, rle_v2, rle_v3;
uint16 res;
+ if ((width & 3) != 0) {
+ // This isn't a valid width according to http://wiki.multimedia.cx/index.php?title=Indeo_3
+ warning("Indeo3 file with width not divisible by 4. This will cause unaligned writes");
+ }
+
bit_buf = 0;
ref_vectors = NULL;
@@ -479,7 +484,7 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height,
if (cmd == 0 || ref_vectors != NULL) {
for (lp1 = 0; lp1 < blks_width; lp1++) {
for (i = 0, j = 0; i < blks_height; i++, j += width_tbl[1])
- ((uint32 *)cur_frm_pos)[j] = ((uint32 *)ref_frm_pos)[j];
+ ((uint32 *)cur_frm_pos)[j] = READ_UINT32(((uint32 *)ref_frm_pos)+j);
cur_frm_pos += 4;
ref_frm_pos += 4;
}
@@ -526,7 +531,7 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height,
switch (correction_type_sp[0][k]) {
case 0:
- *cur_lp = FROM_LE_32(((FROM_LE_32(*ref_lp) >> 1) + correction_lp[lp2 & 0x01][k]) << 1);
+ *cur_lp = FROM_LE_32(((READ_LE_UINT32(ref_lp) >> 1) + correction_lp[lp2 & 0x01][k]) << 1);
lp2++;
break;
case 1:
@@ -540,9 +545,9 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height,
//warning("Glitch");
return;
}
- res = ((FROM_LE_16(((uint16 *)(ref_lp))[0]) >> 1) + correction_lp[lp2 & 0x01][*buf1]) << 1;
+ res = ((READ_LE_UINT16(((uint16 *)(ref_lp))) >> 1) + correction_lp[lp2 & 0x01][*buf1]) << 1;
((uint16 *)cur_lp)[0] = FROM_LE_16(res);
- res = ((FROM_LE_16(((uint16 *)(ref_lp))[1]) >> 1) + correction_lp[lp2 & 0x01][k]) << 1;
+ res = ((READ_LE_UINT16(((uint16 *)(ref_lp))+1) >> 1) + correction_lp[lp2 & 0x01][k]) << 1;
((uint16 *)cur_lp)[1] = FROM_LE_16(res);
buf1++;
lp2++;
@@ -550,14 +555,14 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height,
case 2:
if (lp2 == 0) {
for (i = 0, j = 0; i < 2; i++, j += width_tbl[1])
- cur_lp[j] = ref_lp[j];
+ cur_lp[j] = READ_UINT32(ref_lp+j);
lp2 += 2;
}
break;
case 3:
if (lp2 < 2) {
for (i = 0, j = 0; i < (3 - lp2); i++, j += width_tbl[1])
- cur_lp[j] = ref_lp[j];
+ cur_lp[j] = READ_UINT32(ref_lp+j);
lp2 = 3;
}
break;
@@ -567,7 +572,7 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height,
if (rle_v1 == 1 || ref_vectors != NULL) {
for (i = 0, j = 0; i < 4; i++, j += width_tbl[1])
- cur_lp[j] = ref_lp[j];
+ cur_lp[j] = READ_UINT32(ref_lp+j);
}
RLE_V2_CHECK(buf1,rle_v2, rle_v3,lp2)
@@ -580,7 +585,7 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height,
LP2_CHECK(buf1,rle_v3,lp2)
case 4:
for (i = 0, j = 0; i < (4 - lp2); i++, j += width_tbl[1])
- cur_lp[j] = ref_lp[j];
+ cur_lp[j] = READ_UINT32(ref_lp+j);
lp2 = 4;
break;
@@ -600,7 +605,7 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height,
}
if (ref_vectors != NULL) {
for (i = 0, j = 0; i < 4; i++, j += width_tbl[1])
- cur_lp[j] = ref_lp[j];
+ cur_lp[j] = READ_UINT32(ref_lp+j);
}
lp2 = 4;
break;
@@ -645,18 +650,18 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height,
switch (correction_type_sp[lp2 & 0x01][k]) {
case 0:
- cur_lp[width_tbl[1]] = FROM_LE_32(((FROM_LE_32(*ref_lp) >> 1) + correction_lp[lp2 & 0x01][k]) << 1);
+ cur_lp[width_tbl[1]] = FROM_LE_32(((READ_LE_UINT32(ref_lp) >> 1) + correction_lp[lp2 & 0x01][k]) << 1);
if (lp2 > 0 || flag1 == 0 || strip->ypos != 0)
cur_lp[0] = ((cur_lp[-width_tbl[1]] >> 1) + (cur_lp[width_tbl[1]] >> 1)) & 0xFEFEFEFE;
else
- cur_lp[0] = FROM_LE_32(((FROM_LE_32(*ref_lp) >> 1) + correction_lp[lp2 & 0x01][k]) << 1);
+ cur_lp[0] = FROM_LE_32(((READ_LE_UINT32(ref_lp) >> 1) + correction_lp[lp2 & 0x01][k]) << 1);
lp2++;
break;
case 1:
- res = ((FROM_LE_16(((uint16 *)ref_lp)[0]) >> 1) + correction_lp[lp2 & 0x01][*buf1]) << 1;
+ res = ((READ_LE_UINT16(((uint16 *)ref_lp)) >> 1) + correction_lp[lp2 & 0x01][*buf1]) << 1;
((uint16 *)cur_lp)[width_tbl[2]] = FROM_LE_16(res);
- res = ((FROM_LE_16(((uint16 *)ref_lp)[1]) >> 1) + correction_lp[lp2 & 0x01][k]) << 1;
+ res = ((READ_LE_UINT16(((uint16 *)ref_lp)+1) >> 1) + correction_lp[lp2 & 0x01][k]) << 1;
((uint16 *)cur_lp)[width_tbl[2]+1] = FROM_LE_16(res);
if (lp2 > 0 || flag1 == 0 || strip->ypos != 0)
@@ -670,7 +675,7 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height,
case 2:
if (lp2 == 0) {
for (i = 0, j = 0; i < 4; i++, j += width_tbl[1])
- cur_lp[j] = *ref_lp;
+ cur_lp[j] = READ_UINT32(ref_lp);
lp2 += 2;
}
break;
@@ -678,7 +683,7 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height,
case 3:
if (lp2 < 2) {
for (i = 0, j = 0; i < 6 - (lp2 * 2); i++, j += width_tbl[1])
- cur_lp[j] = *ref_lp;
+ cur_lp[j] = READ_UINT32(ref_lp);
lp2 = 3;
}
break;
@@ -703,7 +708,7 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height,
if (rle_v1 == 1) {
for (i = 0, j = 0; i < 8; i++, j += width_tbl[1])
- cur_lp[j] = ref_lp[j];
+ cur_lp[j] = READ_UINT32(ref_lp+j);
}
RLE_V2_CHECK(buf1,rle_v2, rle_v3,lp2)
@@ -716,7 +721,7 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height,
LP2_CHECK(buf1,rle_v3,lp2)
case 4:
for (i = 0, j = 0; i < 8 - (lp2 * 2); i++, j += width_tbl[1])
- cur_lp[j] = *ref_lp;
+ cur_lp[j] = READ_UINT32(ref_lp);
lp2 = 4;
break;
@@ -756,8 +761,8 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height,
k = *buf1++;
cur_lp = ((uint32 *)cur_frm_pos) + width_tbl[lp2 * 2];
ref_lp = ((uint32 *)cur_frm_pos) + width_tbl[(lp2 * 2) - 1];
- lv1 = ref_lp[0];
- lv2 = ref_lp[1];
+ lv1 = READ_UINT32(ref_lp);
+ lv2 = READ_UINT32(ref_lp+1);
if (lp2 == 0 && flag1 != 0) {
#if defined(SCUMM_BIG_ENDIAN)
lv1 = lv1 & 0xFF00FF00;
@@ -936,28 +941,28 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height,
case 0:
lv1 = correctionloworder_lp[lp2 & 0x01][k];
lv2 = correctionhighorder_lp[lp2 & 0x01][k];
- cur_lp[0] = FROM_LE_32(((FROM_LE_32(ref_lp[0]) >> 1) + lv1) << 1);
- cur_lp[1] = FROM_LE_32(((FROM_LE_32(ref_lp[1]) >> 1) + lv2) << 1);
- cur_lp[width_tbl[1]] = FROM_LE_32(((FROM_LE_32(ref_lp[width_tbl[1]]) >> 1) + lv1) << 1);
- cur_lp[width_tbl[1]+1] = FROM_LE_32(((FROM_LE_32(ref_lp[width_tbl[1]+1]) >> 1) + lv2) << 1);
+ cur_lp[0] = FROM_LE_32(((READ_LE_UINT32(ref_lp) >> 1) + lv1) << 1);
+ cur_lp[1] = FROM_LE_32(((READ_LE_UINT32(ref_lp+1) >> 1) + lv2) << 1);
+ cur_lp[width_tbl[1]] = FROM_LE_32(((READ_LE_UINT32(ref_lp+width_tbl[1]) >> 1) + lv1) << 1);
+ cur_lp[width_tbl[1]+1] = FROM_LE_32(((READ_LE_UINT32(ref_lp+width_tbl[1]+1) >> 1) + lv2) << 1);
lp2++;
break;
case 1:
lv1 = correctionloworder_lp[lp2 & 0x01][*buf1++];
lv2 = correctionloworder_lp[lp2 & 0x01][k];
- cur_lp[0] = FROM_LE_32(((FROM_LE_32(ref_lp[0]) >> 1) + lv1) << 1);
- cur_lp[1] = FROM_LE_32(((FROM_LE_32(ref_lp[1]) >> 1) + lv2) << 1);
- cur_lp[width_tbl[1]] = FROM_LE_32(((FROM_LE_32(ref_lp[width_tbl[1]]) >> 1) + lv1) << 1);
- cur_lp[width_tbl[1]+1] = FROM_LE_32(((FROM_LE_32(ref_lp[width_tbl[1]+1]) >> 1) + lv2) << 1);
+ cur_lp[0] = FROM_LE_32(((READ_LE_UINT32(ref_lp) >> 1) + lv1) << 1);
+ cur_lp[1] = FROM_LE_32(((READ_LE_UINT32(ref_lp+1) >> 1) + lv2) << 1);
+ cur_lp[width_tbl[1]] = FROM_LE_32(((READ_LE_UINT32(ref_lp+width_tbl[1]) >> 1) + lv1) << 1);
+ cur_lp[width_tbl[1]+1] = FROM_LE_32(((READ_LE_UINT32(ref_lp+width_tbl[1]+1) >> 1) + lv2) << 1);
lp2++;
break;
case 2:
if (lp2 == 0) {
for (i = 0, j = 0; i < 4; i++, j += width_tbl[1]) {
- cur_lp[j] = ref_lp[j];
- cur_lp[j+1] = ref_lp[j+1];
+ cur_lp[j] = READ_UINT32(ref_lp+j);
+ cur_lp[j+1] = READ_UINT32(ref_lp+j+1);
}
lp2 += 2;
}
@@ -966,8 +971,8 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height,
case 3:
if (lp2 < 2) {
for (i = 0, j = 0; i < 6 - (lp2 * 2); i++, j += width_tbl[1]) {
- cur_lp[j] = ref_lp[j];
- cur_lp[j+1] = ref_lp[j+1];
+ cur_lp[j] = READ_UINT32(ref_lp+j);
+ cur_lp[j+1] = READ_UINT32(ref_lp+j+1);
}
lp2 = 3;
}
@@ -977,8 +982,8 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height,
if (lp2 == 0) {
RLE_V3_CHECK(buf1,rle_v1,rle_v2,rle_v3)
for (i = 0, j = 0; i < 8; i++, j += width_tbl[1]) {
- ((uint32 *)cur_frm_pos)[j] = ((uint32 *)ref_frm_pos)[j];
- ((uint32 *)cur_frm_pos)[j+1] = ((uint32 *)ref_frm_pos)[j+1];
+ ((uint32 *)cur_frm_pos)[j] = READ_UINT32(((uint32 *)ref_frm_pos)+j);
+ ((uint32 *)cur_frm_pos)[j+1] = READ_UINT32(((uint32 *)ref_frm_pos)+j+1);
}
RLE_V2_CHECK(buf1,rle_v2, rle_v3,lp2)
break;
@@ -992,8 +997,8 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height,
case 6:
case 4:
for (i = 0, j = 0; i < 8 - (lp2 * 2); i++, j += width_tbl[1]) {
- cur_lp[j] = ref_lp[j];
- cur_lp[j+1] = ref_lp[j+1];
+ cur_lp[j] = READ_UINT32(ref_lp+j);
+ cur_lp[j+1] = READ_UINT32(ref_lp+j+1);
}
lp2 = 4;
break;
@@ -1037,8 +1042,8 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height,
switch (correction_type_sp[lp2 & 0x01][k]) {
case 0:
- cur_lp[0] = FROM_LE_32(((FROM_LE_32(*ref_lp) >> 1) + correction_lp[lp2 & 0x01][k]) << 1);
- cur_lp[width_tbl[1]] = FROM_LE_32(((FROM_LE_32(ref_lp[width_tbl[1]]) >> 1) + correction_lp[lp2 & 0x01][k]) << 1);
+ cur_lp[0] = FROM_LE_32(((READ_LE_UINT32(ref_lp) >> 1) + correction_lp[lp2 & 0x01][k]) << 1);
+ cur_lp[width_tbl[1]] = FROM_LE_32(((READ_LE_UINT32(ref_lp+width_tbl[1]) >> 1) + correction_lp[lp2 & 0x01][k]) << 1);
lp2++;
break;
@@ -1051,13 +1056,13 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height,
lv1 = (uint16)(correction_lp[lp2 & 0x01][*buf1++]);
lv2 = (uint16)(correction_lp[lp2 & 0x01][k]);
- res = (uint16)(((FROM_LE_16(((uint16 *)ref_lp)[0]) >> 1) + lv1) << 1);
+ res = (uint16)(((READ_LE_UINT16(((uint16 *)ref_lp)) >> 1) + lv1) << 1);
((uint16 *)cur_lp)[0] = FROM_LE_16(res);
- res = (uint16)(((FROM_LE_16(((uint16 *)ref_lp)[1]) >> 1) + lv2) << 1);
+ res = (uint16)(((READ_LE_UINT16(((uint16 *)ref_lp)+1) >> 1) + lv2) << 1);
((uint16 *)cur_lp)[1] = FROM_LE_16(res);
- res = (uint16)(((FROM_LE_16(((uint16 *)ref_lp)[width_tbl[2]]) >> 1) + lv1) << 1);
+ res = (uint16)(((READ_LE_UINT16(((uint16 *)ref_lp)+width_tbl[2]) >> 1) + lv1) << 1);
((uint16 *)cur_lp)[width_tbl[2]] = FROM_LE_16(res);
- res = (uint16)(((FROM_LE_16(((uint16 *)ref_lp)[width_tbl[2]+1]) >> 1) + lv2) << 1);
+ res = (uint16)(((READ_LE_UINT16(((uint16 *)ref_lp)+width_tbl[2]+1) >> 1) + lv2) << 1);
((uint16 *)cur_lp)[width_tbl[2]+1] = FROM_LE_16(res);
lp2++;
break;
@@ -1065,7 +1070,7 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height,
case 2:
if (lp2 == 0) {
for (i = 0, j = 0; i < 4; i++, j += width_tbl[1])
- cur_lp[j] = ref_lp[j];
+ cur_lp[j] = READ_UINT32(ref_lp+j);
lp2 += 2;
}
break;
@@ -1073,7 +1078,7 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height,
case 3:
if (lp2 < 2) {
for (i = 0, j = 0; i < 6 - (lp2 * 2); i++, j += width_tbl[1])
- cur_lp[j] = ref_lp[j];
+ cur_lp[j] = READ_UINT32(ref_lp+j);
lp2 = 3;
}
break;
@@ -1083,7 +1088,7 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height,
RLE_V3_CHECK(buf1,rle_v1,rle_v2,rle_v3)
for (i = 0, j = 0; i < 8; i++, j += width_tbl[1])
- cur_lp[j] = ref_lp[j];
+ cur_lp[j] = READ_UINT32(ref_lp+j);
RLE_V2_CHECK(buf1,rle_v2, rle_v3,lp2)
break;
@@ -1097,7 +1102,7 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height,
case 4:
case 6:
for (i = 0, j = 0; i < 8 - (lp2 * 2); i++, j += width_tbl[1])
- cur_lp[j] = ref_lp[j];
+ cur_lp[j] = READ_UINT32(ref_lp+j);
lp2 = 4;
break;
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/codecs/msvideo1.cpp b/image/codecs/msvideo1.cpp
index 25d7395363..439f219fc5 100644
--- a/image/codecs/msvideo1.cpp
+++ b/image/codecs/msvideo1.cpp
@@ -30,14 +30,15 @@ namespace Image {
#define CHECK_STREAM_PTR(n) \
if ((stream.pos() + n) > stream.size() ) { \
- warning ("MS Video-1: Stream out of bounds (%d >= %d)", stream.pos() + n, stream.size()); \
+ warning ("MS Video-1: Stream out of bounds (%d >= %d) d%d", stream.pos() + n, stream.size(), n); \
return; \
}
MSVideo1Decoder::MSVideo1Decoder(uint16 width, uint16 height, byte bitsPerPixel) : Codec() {
_surface = new Graphics::Surface();
- // TODO: Specify the correct pixel format for 2Bpp mode.
- _surface->create(width, height, (bitsPerPixel == 8) ? Graphics::PixelFormat::createFormatCLUT8() : Graphics::PixelFormat(2, 0, 0, 0, 0, 0, 0, 0, 0));
+ _surface->create(width, height, (bitsPerPixel == 8) ? Graphics::PixelFormat::createFormatCLUT8() :
+ Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0));
+
_bitsPerPixel = bitsPerPixel;
}
@@ -125,13 +126,98 @@ void MSVideo1Decoder::decode8(Common::SeekableReadStream &stream) {
}
}
+void MSVideo1Decoder::decode16(Common::SeekableReadStream &stream) {
+ /* decoding parameters */
+ uint16 colors[8];
+ uint16 *pixels = (uint16 *)_surface->getPixels();
+ int32 stride = _surface->w;
+
+ int32 skip_blocks = 0;
+ int32 blocks_wide = _surface->w / 4;
+ int32 blocks_high = _surface->h / 4;
+ int32 total_blocks = blocks_wide * blocks_high;
+ int32 block_inc = 4;
+ int32 row_dec = stride + 4;
+
+ for (int32 block_y = blocks_high; block_y > 0; block_y--) {
+ int32 block_ptr = ((block_y * 4) - 1) * stride;
+ for (int32 block_x = blocks_wide; block_x > 0; block_x--) {
+ /* check if this block should be skipped */
+ if (skip_blocks) {
+ block_ptr += block_inc;
+ skip_blocks--;
+ total_blocks--;
+ continue;
+ }
+
+ int32 pixel_ptr = block_ptr;
+
+ /* get the next two bytes in the encoded data stream */
+ CHECK_STREAM_PTR(2);
+ byte byte_a = stream.readByte();
+ byte byte_b = stream.readByte();
+
+ /* check if the decode is finished */
+ if ((byte_a == 0) && (byte_b == 0) && (total_blocks == 0)) {
+ return;
+ } else if ((byte_b & 0xFC) == 0x84) {
+ /* skip code, but don't count the current block */
+ skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1;
+ } else if (byte_b < 0x80) {
+ /* 2- or 8-color encoding modes */
+ uint16 flags = (byte_b << 8) | byte_a;
+
+ CHECK_STREAM_PTR(4);
+ colors[0] = stream.readUint16LE();
+ colors[1] = stream.readUint16LE();
+
+ if (colors[0] & 0x8000) {
+ /* 8-color encoding */
+ CHECK_STREAM_PTR(12);
+ colors[2] = stream.readUint16LE();
+ colors[3] = stream.readUint16LE();
+ colors[4] = stream.readUint16LE();
+ colors[5] = stream.readUint16LE();
+ colors[6] = stream.readUint16LE();
+ colors[7] = stream.readUint16LE();
+
+ for (int pixel_y = 0; pixel_y < 4; pixel_y++) {
+ for (int pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
+ pixels[pixel_ptr++] =
+ colors[((pixel_y & 0x2) << 1) +
+ (pixel_x & 0x2) + ((flags & 0x1) ^ 1)];
+ pixel_ptr -= row_dec;
+ }
+ } else {
+ /* 2-color encoding */
+ for (int pixel_y = 0; pixel_y < 4; pixel_y++) {
+ for (int pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
+ pixels[pixel_ptr++] = colors[(flags & 0x1) ^ 1];
+ pixel_ptr -= row_dec;
+ }
+ }
+ } else {
+ /* otherwise, it's a 1-color block */
+ colors[0] = (byte_b << 8) | byte_a;
+
+ for (int pixel_y = 0; pixel_y < 4; pixel_y++) {
+ for (int pixel_x = 0; pixel_x < 4; pixel_x++)
+ pixels[pixel_ptr++] = colors[0];
+ pixel_ptr -= row_dec;
+ }
+ }
+
+ block_ptr += block_inc;
+ total_blocks--;
+ }
+ }
+}
+
const Graphics::Surface *MSVideo1Decoder::decodeFrame(Common::SeekableReadStream &stream) {
if (_bitsPerPixel == 8)
decode8(stream);
- else {
- // decode16(stream);
- error ("Unhandled MS Video-1 16bpp encoding");
- }
+ else
+ decode16(stream);
return _surface;
}
diff --git a/image/codecs/msvideo1.h b/image/codecs/msvideo1.h
index 2a6dcd0a9a..f52b1f3127 100644
--- a/image/codecs/msvideo1.h
+++ b/image/codecs/msvideo1.h
@@ -38,7 +38,7 @@ public:
~MSVideo1Decoder();
const Graphics::Surface *decodeFrame(Common::SeekableReadStream &stream);
- Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); }
+ Graphics::PixelFormat getPixelFormat() const { return _surface->format; }
private:
byte _bitsPerPixel;
@@ -46,7 +46,7 @@ private:
Graphics::Surface *_surface;
void decode8(Common::SeekableReadStream &stream);
- //void decode16(Common::SeekableReadStream &stream);
+ void decode16(Common::SeekableReadStream &stream);
};
} // End of namespace Image
diff --git a/image/codecs/rpza.cpp b/image/codecs/rpza.cpp
index 8d648e1cc1..db0d512f45 100644
--- a/image/codecs/rpza.cpp
+++ b/image/codecs/rpza.cpp
@@ -50,6 +50,7 @@ RPZADecoder::~RPZADecoder() {
}
delete[] _ditherPalette;
+ delete[] _colorMap;
}
#define ADVANCE_BLOCK() \
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 0eef66bd51..dc4a19da2e 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -5,10 +5,11 @@ gui/browser.cpp
gui/browser_osx.mm
gui/chooser.cpp
gui/editrecorddialog.cpp
-gui/error.cpp
+gui/filebrowser-dialog.cpp
+gui/fluidsynth-dialog.cpp
gui/gui-manager.cpp
-gui/KeysDialog.h
gui/KeysDialog.cpp
+gui/KeysDialog.h
gui/launcher.cpp
gui/massadd.cpp
gui/onscreendialog.cpp
@@ -18,50 +19,54 @@ gui/recorderdialog.cpp
gui/saveload-dialog.cpp
gui/themebrowser.cpp
gui/ThemeEngine.cpp
+gui/updates-dialog.cpp
gui/widget.cpp
-gui/fluidsynth-dialog.cpp
base/main.cpp
common/error.cpp
-common/util.cpp
+common/rendermode.cpp
+common/updates.cpp
engines/advancedDetector.cpp
engines/dialogs.cpp
engines/engine.cpp
+audio/adlib.cpp
audio/fmopl.cpp
audio/mididrv.cpp
-audio/musicplugin.cpp
-audio/null.h
-audio/null.cpp
audio/mods/paula.cpp
-audio/adlib.cpp
+audio/null.cpp
+audio/null.h
audio/softsynth/appleiigs.cpp
-audio/softsynth/sid.cpp
+audio/softsynth/cms.cpp
+audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp
audio/softsynth/mt32.cpp
audio/softsynth/pcspk.cpp
+audio/softsynth/sid.cpp
+backends/events/default/default-events.cpp
+backends/events/gph/gph-events.cpp
+backends/events/maemosdl/maemosdl-events.cpp
+backends/events/openpandora/op-events.cpp
+backends/events/symbiansdl/symbiansdl-events.cpp
+backends/events/webossdl/webossdl-events.cpp
+backends/graphics/opengl/opengl-graphics.cpp
+backends/graphics/surfacesdl/surfacesdl-graphics.cpp
+backends/graphics/wincesdl/wincesdl-graphics.cpp
backends/keymapper/remap-dialog.cpp
backends/midi/windows.cpp
backends/platform/ds/arm9/source/dsoptions.cpp
+backends/platform/ios7/ios7_osys_events.cpp
backends/platform/iphone/osys_events.cpp
backends/platform/maemo/maemo.cpp
backends/platform/sdl/macosx/appmenu_osx.mm
-backends/graphics/surfacesdl/surfacesdl-graphics.cpp
-backends/graphics/opengl/opengl-graphics.cpp
-backends/graphics/openglsdl/openglsdl-graphics.cpp
backends/platform/symbian/src/SymbianActions.cpp
-backends/platform/symbian/src/SymbianOS.cpp
-backends/events/symbiansdl/symbiansdl-events.cpp
+backends/platform/tizen/form.cpp
+backends/platform/tizen/fs.cpp
backends/platform/wii/options.cpp
backends/platform/wince/CEActionsPocket.cpp
backends/platform/wince/CEActionsSmartphone.cpp
backends/platform/wince/CELauncherDialog.cpp
backends/platform/wince/wince-sdl.cpp
-backends/events/default/default-events.cpp
-backends/events/gph/gph-events.cpp
-backends/events/openpandora/op-events.cpp
backends/updates/macosx/macosx-updates.mm
-backends/platform/tizen/form.cpp
-backends/events/maemosdl/maemosdl-events.cpp
diff --git a/po/be_BY.po b/po/be_BY.po
index 66697d9899..68e7cd35bb 100644
--- a/po/be_BY.po
+++ b/po/be_BY.po
@@ -1,23 +1,23 @@
# Belarusian translation for ScummVM.
-# Copyright (C) 2010-2015 The ScummVM Team
+# Copyright (C) 2010-2016 The ScummVM Team
# This file is distributed under the same license as the ScummVM package.
-# Ivan Lukyanov <greencis@mail.ru>, 2013-2014.
+# Ivan Lukyanov <greencis@mail.ru>, 2013-2016.
#
msgid ""
msgstr ""
-"Project-Id-Version: ScummVM 1.7.0git\n"
+"Project-Id-Version: ScummVM 1.8.0git\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2015-09-06 15:14+0200\n"
-"PO-Revision-Date: 2014-07-02 17:22+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"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=iso-8859-5\n"
"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n"
-"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
-"X-Generator: Poedit 1.5.5\n"
+"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
+"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
+"X-Generator: Poedit 1.8.7\n"
#: gui/about.cpp:94
#, c-format
@@ -38,7 +38,7 @@ msgstr "¿ÐÚÐ×ÒÐæì áåÐÒÐÝëï äÐÙÛë"
#: gui/browser.cpp:68
msgid "Show files marked with the hidden attribute"
-msgstr "¿ÐÚÐ×ÒÐæì äÐÙÛë × ÐâàëÑãâÐÜ \"áåÐÒÐæì\""
+msgstr "¿ÐÚÐ×ÒÐæì äÐÙÛë × ÐâàëÑãâÐÜ \"áåÐÒÐÝë\""
#: gui/browser.cpp:72
msgid "Go up"
@@ -54,28 +54,29 @@ msgid "Go up"
msgstr "ÃÒÕàå"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:74 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: 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/fluidsynth-dialog.cpp:152 engines/engine.cpp:483
-#: backends/platform/wii/options.cpp:48
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
-#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:191 engines/sword1/control.cpp:865
+#: 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 "°ÔÜÕÝÐ"
#: gui/browser.cpp:76 gui/browser_osx.mm:103 gui/chooser.cpp:47
-#: gui/themebrowser.cpp:56
+#: gui/filebrowser-dialog.cpp:65 gui/themebrowser.cpp:56
msgid "Choose"
msgstr "°ÑàÐæì"
#: gui/editrecorddialog.cpp:58
msgid "Author:"
-msgstr ""
+msgstr "°þâÐà:"
#: gui/editrecorddialog.cpp:59 gui/launcher.cpp:204
msgid "Name:"
@@ -83,63 +84,179 @@ msgstr "½Ð×ÒÐ:"
#: gui/editrecorddialog.cpp:60
msgid "Notes:"
-msgstr ""
+msgstr "½ÐâÐâÚö:"
-#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:75
+#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74
msgid "Ok"
-msgstr ""
+msgstr "Ok"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Choose file for loading"
+msgstr "°ÑïàëæÕ äÐÙÛ ÔÛï ×ÐÓàã×Úö"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Enter filename for saving"
+msgstr "ÃÒïÔ×öæÕ öÜï äÐÙÛÐ ÔÛï ×Ðßöáã"
+
+#: gui/filebrowser-dialog.cpp:132
+msgid "Do you really want to overwrite the file?"
+msgstr "²ë áÐßàÐþÔë ÖÐÔÐÕæÕ ßÕàÐ×ÐßöáÐæì ÓíâÐ ×ÐåÐÒÐÝÝÕ?"
+
+#: 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 "ÂÐÚ"
+
+#: 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 "½Õ"
+
+#: gui/fluidsynth-dialog.cpp:68
+msgid "Reverb"
+msgstr "ÀíÒÕàÑÕàÐæëï"
+
+#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
+msgid "Active"
+msgstr "°ÚâëþÝÐ"
+
+#: gui/fluidsynth-dialog.cpp:72
+msgid "Room:"
+msgstr "¿ÐÚÞÙ:"
+
+#: gui/fluidsynth-dialog.cpp:79
+msgid "Damp:"
+msgstr "²öÛìÓÞâÝÐáæì:"
+
+#: gui/fluidsynth-dialog.cpp:86
+msgid "Width:"
+msgstr "ÈëàëÝï:"
+
+#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
+msgid "Level:"
+msgstr "Ã×àÞÒÕÝì:"
+
+#: gui/fluidsynth-dialog.cpp:100
+msgid "Chorus"
+msgstr "ÅÞà"
+
+#: gui/fluidsynth-dialog.cpp:104
+msgid "N:"
+msgstr "N:"
+
+#: gui/fluidsynth-dialog.cpp:118
+msgid "Speed:"
+msgstr "ÅãâÚÐáæì:"
+
+#: gui/fluidsynth-dialog.cpp:125
+msgid "Depth:"
+msgstr "³ÛëÑöÝï:"
+
+#: gui/fluidsynth-dialog.cpp:132
+msgid "Type:"
+msgstr "Âëß:"
+
+#: gui/fluidsynth-dialog.cpp:135
+msgid "Sine"
+msgstr "ÁöÝãáÞöÔÐ"
+
+#: gui/fluidsynth-dialog.cpp:136
+msgid "Triangle"
+msgstr "ÂàÞåÚãâÝÐï"
+
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
+msgid "Misc"
+msgstr "ÀÞ×ÝÐÕ"
+
+#: gui/fluidsynth-dialog.cpp:140
+msgid "Interpolation:"
+msgstr "¦ÝâíàßÐÛïæëï:"
+
+#: gui/fluidsynth-dialog.cpp:143
+msgid "None (fastest)"
+msgstr "½ïÜÐ (åãâçíÙèÐÕ)"
+
+#: gui/fluidsynth-dialog.cpp:144
+msgid "Linear"
+msgstr "»öÝÕÙÝÐï"
+
+#: gui/fluidsynth-dialog.cpp:145
+msgid "Fourth-order"
+msgstr "ÇÐæÒñàâÐÓÐ ßÐàÐÔÚã"
+
+#: gui/fluidsynth-dialog.cpp:146
+msgid "Seventh-order"
+msgstr "ÁñÜÐÓÐ ßÐàÐÔÚã"
-#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset"
+msgstr "ÁÚöÝãæì"
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset all FluidSynth settings to their default values."
+msgstr "ÁÚöÝãæì ÝÐÛÐÔë FluidSynth ßÐ ×ÜÐþçÐÝÝö."
+
+#: 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 "OK"
+
+#: gui/fluidsynth-dialog.cpp:217
+msgid ""
+"Do you really want to reset all FluidSynth settings to their default values?"
+msgstr "²ë áÐßàÐþÔë ÖÐÔÐÕæÕ áÚöÝãæì ÝÐÛÐÔë FluidSynth ßÐ ×ÜÐþçÐÝÝö?"
+
+#: 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 "·ÐÚàëæì"
-#: gui/gui-manager.cpp:120
+#: gui/gui-manager.cpp:122
msgid "Mouse click"
msgstr "ºÛöÚ Üëèèã"
-#: gui/gui-manager.cpp:124 base/main.cpp:319
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "¿ÐÚÐ×Ðæì ÚÛÐÒöïâãàã"
-#: gui/gui-manager.cpp:128 base/main.cpp:323
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "¿ÕàÐßàë×ÝÐçëæì ÚÛÐÒöèë"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:87
+#: gui/gui-manager.cpp:133 base/main.cpp:335 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "¿ÕàÐÚÛîçíÝÝÕ ÝÐ þÒÕáì íÚàÐÝ"
-#: gui/KeysDialog.h:36 gui/KeysDialog.cpp:145
-msgid "Choose an action to map"
-msgstr "°ÑïàëæÕ Ô×ÕïÝÝÕ ÔÛï ßàë×ÝÐçíÝÝï"
-
#: gui/KeysDialog.cpp:41
msgid "Map"
msgstr "¿àë×ÝÐçëæì"
-#: gui/KeysDialog.cpp:42 gui/launcher.cpp:352 gui/launcher.cpp:1048
-#: gui/launcher.cpp:1052 gui/massadd.cpp:92 gui/options.cpp:1238
-#: gui/saveload-dialog.cpp:932 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:402 engines/engine.cpp:413
-#: 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/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 "OK"
-
#: gui/KeysDialog.cpp:49
msgid "Select an action and click 'Map'"
msgstr "°ÑïàëæÕ Ô×ÕïÝÝÕ ö ÚÛöÚÝöæÕ '¿àë×ÝÐçëæì'"
@@ -162,6 +279,10 @@ msgstr "ºÐÛö ÛÐáÚÐ, ÐÑïàëæÕ Ô×ÕïÝÝÕ"
msgid "Press the key to associate"
msgstr "½ÐæöáÝöæÕ ÚÛÐÒöèã ÔÛï ßàë×ÝÐçíÝÝï"
+#: gui/KeysDialog.cpp:145 gui/KeysDialog.h:36
+msgid "Choose an action to map"
+msgstr "°ÑïàëæÕ Ô×ÕïÝÝÕ ÔÛï ßàë×ÝÐçíÝÝï"
+
#: gui/launcher.cpp:193
msgid "Game"
msgstr "³ãÛìÝï"
@@ -190,7 +311,7 @@ msgstr "¿ÞþÝÐï ÝÐ×ÒÐ ÓãÛìÝö"
#: gui/launcher.cpp:206
msgctxt "lowres"
msgid "Name:"
-msgstr "½Ð×Ò:"
+msgstr "½Ð×ÒÐ:"
#: gui/launcher.cpp:210
msgid "Language:"
@@ -204,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 "<ßÐ ×ÜÐþçÐÝÝö>"
@@ -227,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 "³àä"
@@ -244,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 "°þÔëñ"
@@ -257,14 +378,14 @@ 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 "³ãçÝ"
+msgstr "³ãçÝÐáæì"
#: gui/launcher.cpp:276
msgid "Override global volume settings"
@@ -275,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 "´×Õ ÓãÛìÝï:"
+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
+msgstr "·ÐåÐÒÐÝÝö ÓãÛìÝïþ:"
+
+#: 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:95
+#: 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:69
+#: 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 ÔÛï âÐÓÞ, ÚÐÑ ÔÐÔÐæì ÝÕÚÐÛìÚö ÓãÛìÝïþ"
+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 "~´~ÐÔ. ÓãÛìÝî..."
+msgstr "~´~ÐÔÐæì ÓãÛìÝî..."
-#: gui/launcher.cpp:647
+#: gui/launcher.cpp:649
msgctxt "lowres"
msgid "~E~dit Game..."
-msgstr "½~Ð~Û. ÓãÛìÝö..."
+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:1222
+#: 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/myst.cpp:245 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/myst.cpp:245
-#: engines/mohawk/riven.cpp:718 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:792
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -492,61 +614,41 @@ msgstr ""
"²ë áÐßàÐþÔë ÖÐÔÐÕæÕ ×Ðßãáæöæì ÔíâíÚâÐà ãáöå ÓãÛìÝïþ? ³íâÐ ßÐâíÝæëïÛìÝÐ ÜÞÖÐ "
"ÔÐÔÐæì ÒïÛöÚãî ÚÞÛìÚÐáæì ÓãÛìÝïþ."
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "ÂÐÚ"
-
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "½Õ"
-
-#: gui/launcher.cpp:841
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM ÝÕ ÜÞÖÐ ÐÔÚàëæì Ð×ÝÐçÐÝãî ÔëàíÚâÞàëî!"
-#: gui/launcher.cpp:853
+#: gui/launcher.cpp:857
msgid "ScummVM could not find any game in the specified directory!"
msgstr "ScummVM ÝÕ ÜÞÖÐ ×ÝÐÙáæö ÓãÛìÝî þ Ð×ÝÐçÐÝÐÙ ÔëàíÚâÞàëö!"
-#: gui/launcher.cpp:867
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "°ÑïàëæÕ ÓãÛìÝî:"
-#: gui/launcher.cpp:941
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "²ë áÐßàÐþÔë ÖÐÔÐÕæÕ ÒëÔÐÛöæì ÝÐÛÐÔë ÔÛï ÓíâÐÙ ÓãÛìÝö?"
-#: gui/launcher.cpp:999
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "²ë ÖÐÔÐÕæÕ ×ÐÓàã×öæì ÓãÛìÝî?"
-#: gui/launcher.cpp:1048
+#: gui/launcher.cpp:1052
msgid "This game does not support loading games from the launcher."
msgstr "³íâÐï ÓãÛìÝï ÝÕ ßÐÔâàëÜÛöÒÐÕ ×ÐÓàã×Úã ×ÐåÐÒÐÝÝïþ ßàÐ× ÓÐÛÞþÝÐÕ ÜÕÝî."
-#: gui/launcher.cpp:1052
+#: gui/launcher.cpp:1056
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr "ScummVM ÝÕ ×ÜÞÓ ×ÝÐÙáæö àãåÐÒöçÞÚ ÔÛï ×ÐßãáÚã ÐÑàÐÝÐÙ ÓãÛìÝö!"
-#: gui/launcher.cpp:1159
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "ÈÜÐâ ÓãÛìÝïþ..."
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1165
msgid "Record..."
-msgstr ""
+msgstr "·Ðßöá..."
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
@@ -573,148 +675,146 @@ msgstr "·ÝÞÙÔ×ÕÝÐ %d ÝÞÒëå ÓãÛìÝïþ, ßàÐßãèçÐÝÐ %d àÐÝÕÙ ÔÐÔÐÔ×ÕÝëå ÓãÛìÝïþ..."
#: gui/onscreendialog.cpp:101 gui/onscreendialog.cpp:103
msgid "Stop"
-msgstr ""
+msgstr "ÁâÞß"
#: gui/onscreendialog.cpp:106
msgid "Edit record description"
-msgstr ""
+msgstr "ÀíÔÐÓÐÒÐæì ÐßöáÐÝÝÕ ×Ðßöáã"
#: gui/onscreendialog.cpp:108
-#, fuzzy
msgid "Switch to Game"
-msgstr "¿ÕàÐÚÛîçëæì"
+msgstr "¿ÕàÐÚÛîçëææÐ þ ÓãÛìÝî"
#: gui/onscreendialog.cpp:110
-#, fuzzy
msgid "Fast replay"
-msgstr "ÅãâÚö àíÖëÜ"
+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:2298
+#: 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 "³ãÚ. ßàëÛÐÔÐ:"
+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"
@@ -722,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"
@@ -791,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"
@@ -808,175 +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:"
+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 "´×Õ âíÜë:"
+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:1168 gui/fluidsynth-dialog.cpp:138
-msgid "Misc"
-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 "°þâÐ×Ðå.:"
+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."
@@ -985,64 +1093,75 @@ msgstr ""
"ÒëÚÐàëáâÞþÒÐæì Óíâãî âíÜã, ÒÐÜ ÝÕÐÑåÞÔÝÐ áßÐçÐâÚã ßÕàÐÚÛîçëææÐ ÝÐ öÝèãî ÜÞÒã."
#. I18N: You must leave "#" as is, only word 'next' is translatable
-#: gui/predictivedialog.cpp:87
+#: gui/predictivedialog.cpp:86
msgid "# next"
-msgstr ""
+msgstr "# ÝÐáâ"
-#: gui/predictivedialog.cpp:88
+#: gui/predictivedialog.cpp:87
msgid "add"
-msgstr ""
+msgstr "ÔÐÔ"
-#: gui/predictivedialog.cpp:92
-#, fuzzy
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
-msgstr "²ëÔÐÛöæì"
+msgstr "²ëÔÐÛöæì ×ÝÐÚ"
-#: gui/predictivedialog.cpp:96
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
-msgstr ""
+msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:98
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
-msgstr ""
+msgstr "* Pre"
+
+#. I18N: 'Num' means Numbers
+#: gui/predictivedialog.cpp:578
+msgid "* Num"
+msgstr "* »çÑ"
-#: gui/recorderdialog.cpp:64
+#. I18N: 'Abc' means Latin alphabet input
+#: gui/predictivedialog.cpp:581
+msgid "* Abc"
+msgstr "* Abc"
+
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
-msgstr ""
+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 ""
+msgstr "·ÐßöáÐæì"
-#: gui/recorderdialog.cpp:72
-#, fuzzy
+#: gui/recorderdialog.cpp:71
msgid "Playback"
-msgstr "³ãÛïæì"
+msgstr "¿àÐÙÓàÐæì"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
-msgstr ""
+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 ""
+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 ""
+msgstr "½ÐâÐâÚö:"
-#: gui/recorderdialog.cpp:155
-#, fuzzy
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
-msgstr "²ë áÐßàÐþÔë ÖÐÔÐÕæÕ ÒëÔÐÛöæì ÓíâÐ ×ÐåÐÒÐÝÝÕ?"
+msgstr "²ë áÐßàÐþÔë ÖÐÔÐÕæÕ ÒëÔÐÛöæì Óíâë ×Ðßöá?"
+
+#: gui/recorderdialog.cpp:173
+msgid "Unknown Author"
+msgstr "½ÕÒïÔÞÜë ÐþâÐà"
#: gui/saveload-dialog.cpp:167
msgid "List view"
@@ -1104,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:"
@@ -1113,149 +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:661
+#: 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
-msgid "Clear value"
-msgstr "°çëáæöæì ×ÝÐçíÝÝÕ"
-
-#: gui/fluidsynth-dialog.cpp:68
-msgid "Reverb"
-msgstr "ÀíÒÕàÑÕàÐæëï"
-
-#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
-msgid "Active"
-msgstr "°ÚâëþÝÐ"
-
-#: gui/fluidsynth-dialog.cpp:72
-msgid "Room:"
-msgstr "¿ÐÚÞÙ:"
-
-#: gui/fluidsynth-dialog.cpp:79
-msgid "Damp:"
-msgstr "²öÛìÓÞâÝÐáæì:"
-
-#: gui/fluidsynth-dialog.cpp:86
-msgid "Width:"
-msgstr "ÈëàëÝï:"
-
-#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
-msgid "Level:"
-msgstr "Ã×àÞÒÕÝì:"
-
-#: gui/fluidsynth-dialog.cpp:100
-msgid "Chorus"
-msgstr "ÅÞà"
-
-#: gui/fluidsynth-dialog.cpp:104
-msgid "N:"
-msgstr "N:"
-
-#: gui/fluidsynth-dialog.cpp:118
-msgid "Speed:"
-msgstr "ÅãâÚÐáæì:"
-
-#: gui/fluidsynth-dialog.cpp:125
-msgid "Depth:"
-msgstr "³ÛëÑöÝï:"
-
-#: gui/fluidsynth-dialog.cpp:132
-msgid "Type:"
-msgstr "Âëß:"
-
-#: gui/fluidsynth-dialog.cpp:135
-msgid "Sine"
-msgstr "ÁöÝãáÞöÔÐ"
-
-#: gui/fluidsynth-dialog.cpp:136
-msgid "Triangle"
-msgstr "ÂàÞåÚãâÝÐï"
-
-#: gui/fluidsynth-dialog.cpp:140
-msgid "Interpolation:"
-msgstr "¦ÝâíàßÐÛïæëï:"
-
-#: gui/fluidsynth-dialog.cpp:143
-msgid "None (fastest)"
-msgstr "½ïÜÐ (åãâçíÙèÐÕ)"
-
-#: gui/fluidsynth-dialog.cpp:144
-msgid "Linear"
-msgstr "»öÝÕÙÝÐï"
-
-#: gui/fluidsynth-dialog.cpp:145
-msgid "Fourth-order"
-msgstr "ÇÐæÒñàâÐÓÐ ßÐàÐÔÚÐ"
+#: 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/fluidsynth-dialog.cpp:146
-msgid "Seventh-order"
-msgstr "ÁñÜÐÓÐ ßÐàÐÔÚÐ"
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr "(²ë ×ÐþáñÔë ÜÞÖÐæÕ þÚÛîçëæì ïÕ þ ÝÐÛÐÔÐå ÝÐ ×ÐÚÛÐÔæë \"ÀÞ×ÝÐÕ\")"
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset"
-msgstr "ÁÚöÝãæì"
+#: gui/updates-dialog.cpp:92
+msgid "Check for updates automatically"
+msgstr "°þâÐÜÐâëçÝÐ ßàÐÒïàÐæì ÐÑÝÐþÛÕÝÝö"
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset all FluidSynth settings to their default values."
-msgstr "ÁÚöÝãæì ÝÐÛÐÔë FluidSynth ßÐ ×ÜÐþçÐÝÝö."
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr "¿àÐæïÓÝãæì"
-#: gui/fluidsynth-dialog.cpp:217
-msgid ""
-"Do you really want to reset all FluidSynth settings to their default values?"
-msgstr "²ë áÐßàÐþÔë ÖÐÔÐÕæÕ áÚöÝãæì ÝÐÛÐÔë FluidSynth ßÐ ×ÜÐþçÐÝÝö?"
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
+msgid "Clear value"
+msgstr "°çëáæöæì ×ÝÐçíÝÝÕ"
-#: base/main.cpp:228
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "ÀãåÐÒöçÞÚ ÝÕ ßÐÔâàëÜÛöÒÐÕ þ×àÞÒÕÝì ÐÔÛÐÔÚö '%s'"
-#: base/main.cpp:306
+#: base/main.cpp:315
msgid "Menu"
msgstr "¼ÕÝî"
-#: base/main.cpp:309 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:312 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:315
+#: base/main.cpp:324
msgid "Skip line"
msgstr "¿àÐßãáæöæì àÐÔÞÚ"
-#: base/main.cpp:507
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "¿ÐÜëÛÚÐ ×ÐßãáÚã ÓãÛìÝö:"
-#: base/main.cpp:554
+#: base/main.cpp:571
msgid "Could not find any engine capable of running the selected game"
msgstr "½Õ ÜÐÓã ×ÝÐÙáæö àãåÐÒöçÞÚ ÔÛï ×ÐßãáÚã ÐÑàÐÝÐÙ ÓãÛìÝö"
@@ -1323,17 +1381,60 @@ msgstr "¿ÕàÐßëÝÕÝÐ ÚÐàëáâÐçÞÜ"
msgid "Unknown error"
msgstr "½ÕÒïÔÞÜÐï ßÐÜëÛÚÐ"
-#: engines/advancedDetector.cpp:317
+#. I18N: Hercules is graphics card name
+#: common/rendermode.cpp:35
+msgid "Hercules Green"
+msgstr "Hercules ·ïÛñÝë"
+
+#: common/rendermode.cpp:36
+msgid "Hercules Amber"
+msgstr "Hercules ±ãàèâëÝÐÒë"
+
+#: common/rendermode.cpp:42
+msgid "PC-9821 (256 Colors)"
+msgstr "PC-9821 (256 ÚÞÛÕàÐþ)"
+
+#: common/rendermode.cpp:43
+msgid "PC-9801 (16 Colors)"
+msgstr "PC-9801 (16 ÚÞÛÕàÐþ)"
+
+#: common/rendermode.cpp:73
+msgctxt "lowres"
+msgid "Hercules Green"
+msgstr "Hercules ·ïÛñÝë"
+
+#: common/rendermode.cpp:74
+msgctxt "lowres"
+msgid "Hercules Amber"
+msgstr "Hercules ±ãàèâëÝÐÒë"
+
+#: 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' ïèçí ÝÕÒïÔÞÜÐï."
+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 "ÓãÛìÝö, ïÚãî Òë áßàÐÑãÕæÕ ÔÐÔÐæì, ö Ð×ÝÐçæÕ ïÕ ÒÕàáöî, ÜÞÒã ö Ó.Ô."
@@ -1341,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 "·Ð~ß~öáÐæì"
@@ -1370,11 +1471,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "³~Ð~ÛÞþÝÐÕ ÜÕÝî"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:803
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:873
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
-#: engines/toltecs/menu.cpp:281 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 "·ÐåÐÒÐæì ÓãÛìÝî:"
@@ -1383,11 +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:803 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/neverhood/menumodule.cpp:873 engines/pegasus/pegasus.cpp:377
-#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
-#: engines/toltecs/menu.cpp:281 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 "·ÐåÐÒÐæì"
@@ -1411,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 "~°~ÔÜÕÝÐ"
@@ -1425,23 +1535,23 @@ msgstr "~°~ÔÜÕÝÐ"
msgid "~K~eys"
msgstr "~º~ÛÐÒöèë"
-#: engines/engine.cpp:276
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "½Õ ÜÐÓã öÝöæëïÛö×ÐÒÐæì äÐàÜÐâ ÚÞÛÕàã."
-#: engines/engine.cpp:284
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "½Õ ÐâàëÜÐÛÐáï ßÕàÐÚÛîçëæì ÒöÔíÐàíÖëÜ: '"
-#: engines/engine.cpp:293
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "½Õ ÐâàëÜÐÛÐáï ÒëÚÐàëáâÐæì ÚÐàíÚæëî áãÐÔÝÞáöÝ ÑÐÚÞþ."
-#: engines/engine.cpp:298
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "½Õ ÜÐÓã þÖëæì ßÞþÝÐíÚàÐÝÝë àíÖëÜ."
-#: engines/engine.cpp:398
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1455,7 +1565,7 @@ msgstr ""
"ÝÐ ÖÞàáâÚö ÔëáÚ. ¿ÐÔàÐÑï×ÝÐáæö ÜÞÖÝÐ ×ÝÐÙáæö þ\n"
"äÐÙÛÕ README."
-#: engines/engine.cpp:409
+#: 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"
@@ -1470,7 +1580,7 @@ msgstr ""
"×'ïÒöææÐ Üã×ëÚÐ. ¿ÐÔàÐÑï×ÝÐáæö ÜÞÖÝÐ ×ÝÐÙáæö þ\n"
"äÐÙÛÕ README."
-#: engines/engine.cpp:467
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1480,7 +1590,7 @@ msgstr ""
"README ×Ð ÑÐ×ÐÒÐÙ öÝäÐàÜÐæëïÙ, Ð âÐÚáÐÜÐ öÝáâàãÚæëïÜö ßàÐ âÞÕ, ïÚ ÐâàëÜÐæì "
"ÔÐÛÕÙèãî ÔÐßÐÜÞÓã."
-#: engines/engine.cpp:480
+#: 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 "
@@ -1490,10 +1600,14 @@ msgstr ""
"ScummVM æÐÛÚÐÜ. ÏÝÐ, åãâçíÙ ×Ð þáñ, ÝÕ ÑãÔ×Õ ßàÐæÐÒÐæì áâÐÑöÛìÝÐ, ö "
"×ÐåÐÒÐÝÝö ÓãÛìÝïþ ÜÞÓãæì ÝÕ ßàÐæÐÒÐæì ã ÑãÔãçëå ÒÕàáöïå ScummVM."
-#: engines/engine.cpp:483
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Ãáñ ÐÔÝÞ ×Ðßãáæöæì"
+#: audio/adlib.cpp:2290
+msgid "AdLib Emulator"
+msgstr "ÍÜãÛïâÐà AdLib"
+
#: audio/fmopl.cpp:62
msgid "MAME OPL emulator"
msgstr "ÍÜãÛïâÐà MAME OPL"
@@ -1504,7 +1618,7 @@ msgstr "ÍÜãÛïâÐà DOSBox OPL"
#: audio/fmopl.cpp:67
msgid "ALSA Direct FM"
-msgstr ""
+msgstr "¿àÐÜë FM ALSA"
#: audio/mididrv.cpp:209
#, c-format
@@ -1547,42 +1661,186 @@ msgstr ""
"¿ÕàÐÒÐÖÝÐï ÓãÚÐÒÐï ßàëÛÐÔÐ '%s' ÝÕ ÜÞÖÐ Ñëæì áÚÐàëáâÐÝÐ. ³ÛïÔ×öæÕ äÐÙÛ "
"ßàÐâÐÚÞÛã ÔÛï ÑÞÛìè ßÐÔàÐÑï×ÝÐÙ öÝäÐàÜÐæëö."
-#: audio/null.h:44
-msgid "No music"
-msgstr "±Õ× Üã×ëÚö"
-
#: audio/mods/paula.cpp:196
msgid "Amiga Audio Emulator"
msgstr "ÍÜãÛïâÐà ÓãÚã Amiga"
-#: audio/adlib.cpp:2291
-msgid "AdLib Emulator"
-msgstr "ÍÜãÛïâÐà AdLib"
+#: audio/null.h:44
+msgid "No music"
+msgstr "±Õ× Üã×ëÚö"
#: audio/softsynth/appleiigs.cpp:33
msgid "Apple II GS Emulator (NOT IMPLEMENTED)"
msgstr "ÍÜãÛïâÐà Apple II GS (ÐÔáãâÝöçÐÕ)"
-#: audio/softsynth/sid.cpp:1430
-msgid "C64 Audio Emulator"
-msgstr "ÍÜãÛïâÐà ÓãÚã C64"
+#: audio/softsynth/cms.cpp:350
+msgid "Creative Music System Emulator"
+msgstr "ÍÜãÛïâÐà Creative Music System"
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33
+msgid "FM-Towns Audio"
+msgstr "°þÔëñ FM-Towns"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58
+msgid "PC-98 Audio"
+msgstr "°þÔëñ PC-98"
+
+#: 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"
#: audio/softsynth/pcspk.cpp:139
msgid "PC Speaker Emulator"
-msgstr "ÍÜãÛïâÐà PC áßöÚÕàÐ"
+msgstr "ÍÜãÛïâÐà PC-áßöÚÕàÐ"
#: audio/softsynth/pcspk.cpp:158
msgid "IBM PCjr Emulator"
msgstr "ÍÜãÛïâÐà IBM PCjr"
+#: audio/softsynth/sid.cpp:1430
+msgid "C64 Audio Emulator"
+msgstr "ÍÜãÛïâÐà ÓãÚã C64"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Do you really want to return to the Launcher?"
+msgstr "²ë áÐßàÐþÔë ÖÐÔÐÕæÕ ÒïàÝãææÐ þ ÓÐÛÞþÝÐÕ ÜÕÝî?"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Launcher"
+msgstr "³ÐÛÞþÝÐÕ ÜÕÝî"
+
+#: backends/events/default/default-events.cpp:218
+msgid "Do you really want to quit?"
+msgstr "²ë áÐßàÐþÔë ÖÐÔÐÕæÕ ÒëÙáæö?"
+
+#: 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 "²ëåÐÔ"
+
+#: 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 "ÀíÖëÜ 'ÔÞâëÚÐþ' âÐçáÚàëÝÐ - »ÕÒë ÚÛöÚ"
+
+#: 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 "ÀíÖëÜ 'ÔÞâëÚÐþ' âÐçáÚàëÝÐ - ¿àÐÒë ÚÛöÚ"
+
+#: 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 "ÀíÖëÜ 'ÔÞâëÚÐþ' âÐçáÚàëÝÐ - ¿àÐÛñâ (ÑÕ× ÚÛöÚã)"
+
+#: backends/events/gph/gph-events.cpp:409
+msgid "Maximum Volume"
+msgstr "¼ÐÚáöÜÐÛìÝÐï ÓãçÝÐáæì"
+
+#: backends/events/gph/gph-events.cpp:411
+msgid "Increasing Volume"
+msgstr "¿ÐÒÕÛöçíÝÝÕ ÓãçÝÐáæö"
+
+#: backends/events/gph/gph-events.cpp:417
+msgid "Minimal Volume"
+msgstr "¼öÝöÜÐÛìÝÐï ÓãçÝÐáæì"
+
+#: backends/events/gph/gph-events.cpp:419
+msgid "Decreasing Volume"
+msgstr "¿ÐÜïÝèíÝÝÕ ÓãçÝÐáæö"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Enabled"
+msgstr "¿áâàëçÚö þÚÛîçÐÝë"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Disabled"
+msgstr "¿áâàëçÚö ÒëÚÛîçÐÝë"
+
+#: backends/events/openpandora/op-events.cpp:174
+msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
+msgstr "ÀíÖëÜ 'ÔÞâëÚÐþ' âÐçáÚàëÝÐ - ¿àÐÛñâ (ÚÛöÚö ßÐ DPad)"
+
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
+msgid "Do you want to quit ?"
+msgstr "²ë áÐßàÐþÔë ÖÐÔÐÕæÕ ÒëÙáæö?"
+
+#. I18N: Trackpad mode toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:308
+msgid "Trackpad mode is now"
+msgstr "ÀíÖëÜ âàíÚßÐÔÐ ×ÐàÐ×"
+
+#. 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 "ú»"
+
+#: backends/events/webossdl/webossdl-events.cpp:311
+#: backends/events/webossdl/webossdl-events.cpp:338
+msgid "OFF"
+msgstr "²Ëº»"
+
+#: backends/events/webossdl/webossdl-events.cpp:315
+msgid "Swipe two fingers to the right to toggle."
+msgstr "¿àÐÒïÔ×öæÕ ÔÒãÜÐ ßÐÛìæÐÜö ÝÐßàÐÒÐ ÔÛï ßÕàÐÚÛîçíÝÝï."
+
+#. I18N: Auto-drag toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:335
+msgid "Auto-drag mode is now"
+msgstr "ÀíÖëÜ ÐþâÐÔàíÓã ×ÐàÐ×"
+
+#: backends/events/webossdl/webossdl-events.cpp:342
+msgid "Swipe three fingers to the right to toggle."
+msgstr "¿àÐÒïÔ×öæÕ âàëÜÐ ßÐÛìæÐÜö ÝÐßàÐÒÐ ÔÛï ßÕàÐÚÛîçíÝÝï."
+
+#: 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 "±Õ× ßÐÒÕÛöçíÝÝï"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:66
+msgctxt "lowres"
+msgid "Normal (no scaling)"
+msgstr "±Õ× ßÐÒÕÛöçíÝÝï"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
+msgid "Enabled aspect ratio correction"
+msgstr "ºÐàíÚæëï áãÐÔÝÞáöÝ ÑÐÚÞþ ãÚÛîçÐÝÐ"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
+msgid "Disabled aspect ratio correction"
+msgstr "ºÐàíÚæëï áãÐÔÝÞáöÝ ÑÐÚÞþ ÒëÚÛîçÐÝÐ"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
+msgid "Active graphics filter:"
+msgstr "°ÚâëþÝë ÓàÐäöçÝë äöÛìâà:"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+msgid "Windowed mode"
+msgstr "°ÚÞÝÝë àíÖëÜ"
+
#: backends/keymapper/remap-dialog.cpp:48
msgid "Keymap:"
msgstr "ÂÐÑÛöæÐ ÚÛÐÒöè:"
@@ -1612,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 "~·~ÐçëÝöæì"
@@ -1666,7 +1924,7 @@ msgstr "¼ÐèâÐÑ ÓÐÛÞþÝÐÓÐ íÚàÐÝÐ:"
#: backends/platform/ds/arm9/source/dsoptions.cpp:107
msgid "Hardware scale (fast, but low quality)"
-msgstr "ÅÐàÔÒÐàÝÐÕ ÜÐèâÐÑÐÒÐÝÝÕ (åãâÚÐ, ÐÛÕ Ýö×ÚÐÙ ïÚÐáæö)"
+msgstr "°ßÐàÐâÝÐÕ ÜÐèâÐÑÐÒÐÝÝÕ (åãâÚÐ, ÐÛÕ Ýö×ÚÐÙ ïÚÐáæö)"
#: backends/platform/ds/arm9/source/dsoptions.cpp:108
msgid "Software scale (good quality, but slower)"
@@ -1688,18 +1946,26 @@ msgstr "²ëáÞÚÐï ïÚÐáæì ÓãÚã (ÜÐàãÔÝÕÙ) (àíÑãâ)"
msgid "Disable power off"
msgstr "·ÐÑÐàÐÝöæì ÒëÚÛîçíÝÝÕ"
+#: 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 "ÀíÖëÜ Üëèë ÝÐæöáÝãæì-ö-æïÓÝãæì ãÚÛîçÐÝë."
+#: 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 "ÀíÖëÜ Üëèë ÝÐæöáÝãæì-ö-æïÓÝãæì ÒëÚÛîçÐÝë."
+#: 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 "ÀíÖëÜ âÐçßÐÔÐ þÚÛîçÐÝë."
+#: 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 "ÀíÖëÜ âÐçßÐÔÐ ÒëÚÛîçÐÝë."
@@ -1710,9 +1976,9 @@ msgstr "ÀíÖëÜ ßáâàëçÚö"
#: 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
-#: backends/platform/tizen/form.cpp:275
msgid "Left Click"
msgstr "»ÕÒÐï ßáâàëçÚÐ"
@@ -1722,65 +1988,32 @@ msgstr "ÁïàíÔÝïï ßáâàëçÚÐ"
#: backends/platform/maemo/maemo.cpp:220
#: backends/platform/symbian/src/SymbianActions.cpp:43
-#: backends/platform/wince/CEActionsSmartphone.cpp:44
#: backends/platform/tizen/form.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:44
msgid "Right Click"
msgstr "¿àÐÒÐï ßáâàëçÚÐ"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:77
+#: backends/platform/sdl/macosx/appmenu_osx.mm:88
msgid "Hide ScummVM"
msgstr "ÁåÐÒÐæì ScummVM"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:82
+#: backends/platform/sdl/macosx/appmenu_osx.mm:93
msgid "Hide Others"
msgstr "ÁåÐÒÐæì ÐáâÐâÝöï"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:87
+#: backends/platform/sdl/macosx/appmenu_osx.mm:98
msgid "Show All"
msgstr "¿ÐÚÐ×Ðæì ãáñ"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:109
#: backends/platform/sdl/macosx/appmenu_osx.mm:120
+#: backends/platform/sdl/macosx/appmenu_osx.mm:131
msgid "Window"
msgstr "°ÚÝÞ"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:114
+#: backends/platform/sdl/macosx/appmenu_osx.mm:125
msgid "Minimize"
msgstr "·ÓÐàÝãæì"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:46
-msgid "Normal (no scaling)"
-msgstr "±Õ× ßÐÒÕÛöçíÝÝï"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:65
-msgctxt "lowres"
-msgid "Normal (no scaling)"
-msgstr "±Õ× ßÐÒÕÛöçíÝÝï"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
-msgid "Enabled aspect ratio correction"
-msgstr "ºÐàíÚæëï áãÐÔÝÞáöÝ ÑÐÚÞþ ãÚÛîçÐÝÐ"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
-msgid "Disabled aspect ratio correction"
-msgstr "ºÐàíÚæëï áãÐÔÝÞáöÝ ÑÐÚÞþ ÒëÚÛîçÐÝÐ"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
-msgid "Active graphics filter:"
-msgstr "°ÚâëþÝë ÓàÐäöçÝë äöÛìâà:"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
-msgid "Windowed mode"
-msgstr "°ÚÞÝÝë àíÖëÜ"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:118
-msgid "OpenGL"
-msgstr "OpenGL"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:119
-msgid "OpenGL (No filtering)"
-msgstr "OpenGL (ÑÕ× äöÛìâàÐþ)"
-
#: backends/platform/symbian/src/SymbianActions.cpp:38
#: backends/platform/wince/CEActionsSmartphone.cpp:39
msgid "Up"
@@ -1824,14 +2057,6 @@ msgstr "¿àÐßãáæöæì âíÚáâ"
msgid "Fast mode"
msgstr "ÅãâÚö àíÖëÜ"
-#: backends/platform/symbian/src/SymbianActions.cpp:52
-#: backends/platform/wince/CEActionsPocket.cpp:44
-#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: backends/events/default/default-events.cpp:218 engines/scumm/dialogs.cpp:192
-#: engines/scumm/help.cpp:83 engines/scumm/help.cpp:85
-msgid "Quit"
-msgstr "²ëåÐÔ"
-
#: backends/platform/symbian/src/SymbianActions.cpp:53
msgid "Debugger"
msgstr "°ÔÛÐÔçëÚ"
@@ -1848,9 +2073,49 @@ msgstr "²öàâãÐÛìÝÐï ÚÛÐÒöïâãàÐ"
msgid "Key mapper"
msgstr "¿àë×ÝÐçíÝÝÕ ÚÛÐÒöè"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:186
-msgid "Do you want to quit ?"
-msgstr "²ë áÐßàÐþÔë ÖÐÔÐÕæÕ ÒëÙáæö?"
+#: backends/platform/tizen/form.cpp:263
+msgid "Right Click Once"
+msgstr "°ÔÝÐ ßàÐÒÐï ßáâàëçÚÐ"
+
+#: backends/platform/tizen/form.cpp:271
+msgid "Move Only"
+msgstr "ÂÞÛìÚö ßÕàÐÜïáæöæì"
+
+#: backends/platform/tizen/form.cpp:294
+msgid "Escape Key"
+msgstr "ºÛÐÒöèÐ ESC"
+
+#: backends/platform/tizen/form.cpp:299
+msgid "Game Menu"
+msgstr "¼ÕÝî ÓãÛìÝö"
+
+#: backends/platform/tizen/form.cpp:304
+msgid "Show Keypad"
+msgstr "¿ÐÚÐ×Ðæì ÚÛÐÒöïâãàã"
+
+#: backends/platform/tizen/form.cpp:309
+msgid "Control Mouse"
+msgstr "ºöàÐÒÐÝÝÕ Üëèèã"
+
+#: backends/platform/tizen/fs.cpp:259
+msgid "[ Data ]"
+msgstr "[ ´ÐÔ×ÕÝëï ]"
+
+#: backends/platform/tizen/fs.cpp:263
+msgid "[ Resources ]"
+msgstr "[ Àíáãàáë ]"
+
+#: backends/platform/tizen/fs.cpp:267
+msgid "[ SDCard ]"
+msgstr "[ SD-ÚÐàâÐ ]"
+
+#: backends/platform/tizen/fs.cpp:271
+msgid "[ Media ]"
+msgstr "[ ¼ÕÔëï ]"
+
+#: backends/platform/tizen/fs.cpp:275
+msgid "[ Shared ]"
+msgstr "[ ÁÕâÚÐÒÐï âíçÚÐ ]"
#: backends/platform/wii/options.cpp:51
msgid "Video"
@@ -1946,7 +2211,7 @@ msgstr "¿ÐÜëÛÚÐ ßàë ßÐÔÚÛîçíÝÝö DVD"
#: backends/platform/wii/options.cpp:148
msgid "DVD not mounted"
-msgstr "DVD ÝÕ ßÐÔÚÛîçÐÝë"
+msgstr "DVD ßÐÔÚÛîçÐÝë ßÐáßïåÞÒÐ"
#: backends/platform/wii/options.cpp:161
msgid "Network up, share mounted"
@@ -1962,7 +2227,7 @@ msgstr ", ßÐÜëÛÚÐ ßàë ßÐÔÚÛîçíÝÝö âíçÚö"
#: backends/platform/wii/options.cpp:168
msgid ", share not mounted"
-msgstr ", âíçÚÐ ÝÕ ßÐÔÚÛîçÐÝÐ"
+msgstr "ÁÕâÚÐ ßàÐæãÕ, âíçÚÐ ßÐÔÚÛîçÐÝÐ"
#: backends/platform/wii/options.cpp:174
msgid "Network down"
@@ -2097,141 +2362,110 @@ msgstr ""
"½Õ ×ÐÑãÔ×ìæÕáï ßàë×ÝÐçëæì ÚÛÐÒöèã ÔÛï Ô×ÕïÝÝï 'Hide Toolbar', ÚÐÑ ãÑÐçëæì "
"ãÒÕáì öÝÒÕÝâÐà ã ÓãÛìÝö"
-#: backends/events/default/default-events.cpp:196
-msgid "Do you really want to return to the Launcher?"
-msgstr "²ë áÐßàÐþÔë ÖÐÔÐÕæÕ ÒïàÝãææÐ þ ÓÐÛÞþÝÐÕ ÜÕÝî?"
-
-#: backends/events/default/default-events.cpp:196
-msgid "Launcher"
-msgstr "³ÐÛÞþÝÐÕ ÜÕÝî"
-
-#: backends/events/default/default-events.cpp:218
-msgid "Do you really want to quit?"
-msgstr "²ë áÐßàÐþÔë ÖÐÔÐÕæÕ ÒëÙáæö?"
-
-#: 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 "ÀíÖëÜ 'ÔÞâëÚÐþ' âÐçáÚàëÝÐ - »ÕÒë ÚÛöÚ"
-
-#: 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 "ÀíÖëÜ 'ÔÞâëÚÐþ' âÐçáÚàëÝÐ - ¿àÐÒë ÚÛöÚ"
-
-#: 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 "ÀíÖëÜ 'ÔÞâëÚÐþ' âÐçáÚàëÝÐ - ¿àÐÛñâ (ÑÕ× ÚÛöÚã)"
-
-#: backends/events/gph/gph-events.cpp:409
-msgid "Maximum Volume"
-msgstr "¼ÐÚáöÜÐÛìÝÐï ÓãçÝÐáæì"
-
-#: backends/events/gph/gph-events.cpp:411
-msgid "Increasing Volume"
-msgstr "¿ÐÒÕÛöçíÝÝÕ ÓãçÝÐáæö"
-
-#: backends/events/gph/gph-events.cpp:417
-msgid "Minimal Volume"
-msgstr "¼öÝöÜÐÛìÝÐï ÓãçÝÐáæì"
-
-#: backends/events/gph/gph-events.cpp:419
-msgid "Decreasing Volume"
-msgstr "¿ÐÜïÝèíÝÝÕ ÓãçÝÐáæö"
-
-#: backends/events/openpandora/op-events.cpp:174
-msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
-msgstr "ÀíÖëÜ 'ÔÞâëÚÐþ' âÐçáÚàëÝÐ - ¿àÐÛñâ (ÚÛöÚö ßÐ DPad)"
-
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "¿àÐÒïàÐî ÐÑÝÐþÛÕÝÝö..."
-#: backends/platform/tizen/form.cpp:263
-msgid "Right Click Once"
-msgstr "°ÔÝÐ ßàÐÒÐï ßáâàëçÚÐ"
-
-#: backends/platform/tizen/form.cpp:271
-msgid "Move Only"
-msgstr "ÂÞÛìÚö ßÕàÐÜïáæöæì"
-
-#: backends/platform/tizen/form.cpp:294
-msgid "Escape Key"
-msgstr "ºÛÐÒöèÐ ESC"
-
-#: backends/platform/tizen/form.cpp:299
-msgid "Game Menu"
-msgstr "¼ÕÝî ÓãÛìÝö"
-
-#: backends/platform/tizen/form.cpp:304
-msgid "Show Keypad"
-msgstr "¿ÐÚÐ×Ðæì ÚÛÐÒöïâãàã"
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "ÀíÖëÜ ÑÕ× ÚÞÛÕàã"
-#: backends/platform/tizen/form.cpp:309
-msgid "Control Mouse"
-msgstr "ºöàÐÒÐÝÝÕ Üëèèã"
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Enabled"
-msgstr "¿áâàëçÚö þÚÛîçÐÝë"
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Disabled"
-msgstr "¿áâàëçÚö ÒëÚÛîçÐÝë"
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "¿ÐÚÐ×ÒÐæì àÐÔÞÚ ÐÑ'ÕÚâÐþ"
-#: engines/agi/detection.cpp:147 engines/drascula/detection.cpp:302
-#: engines/dreamweb/detection.cpp:47 engines/neverhood/detection.cpp:160
-#: engines/sci/detection.cpp:394 engines/toltecs/detection.cpp:200
-#: engines/zvision/detection_tables.h:51
+#: 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 "²ëÚÐàëáâÞþÒÐæì ÐàëÓöÝÐÛìÝëï íÚàÐÝë ×Ðßöáã/çëâÐÝÝö ÓãÛìÝö"
+msgstr "²ëÚÐàëáâÞþÒÐæì ÐàëÓöÝÐÛìÝëï íÚàÐÝë ×Ðßöáã/çëâÐÝÝï ÓãÛìÝö"
-#: engines/agi/detection.cpp:148 engines/drascula/detection.cpp:303
-#: engines/dreamweb/detection.cpp:48 engines/neverhood/detection.cpp:161
-#: engines/sci/detection.cpp:395 engines/toltecs/detection.cpp:201
+#: 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 ""
-"²ëÚÐàëáâÞþÒÐæì ÐàëÓöÝÐÛìÝëï íÚàÐÝë ×Ðßöáã ö ×ÐåÐÒÐÝÝï ÓãÛìÝö ×ÐÜÕáâ "
+"²ëÚÐàëáâÞþÒÐæì ÐàëÓöÝÐÛìÝëï íÚàÐÝë çëâÐÝÝï ö ×ÐåÐÒÐÝÝï ÓãÛìÝö ×ÐÜÕáâ "
"×àÞÑÛÕÝëå ã ScummVM"
#: engines/agi/detection.cpp:157
-#, fuzzy
msgid "Use an alternative palette"
-msgstr "²ëÚÐàëáâÞþÒÐæì ÐÛìâíàÝÐâëþÝë þáâãß (âÞÛìÚö ÔÛï CD ÒÕàáöö ÓãÛìÝö)"
+msgstr "²ëÚÐàëáâÞþÒÐæì ÐÛìâíàÝÐâëþÝãî ßÐÛöâàã"
#: engines/agi/detection.cpp:158
msgid ""
"Use an alternative palette, common for all Amiga games. This was the old "
"behavior"
msgstr ""
+"²ëÚÐàëáâÞþÒÐæì ÐÛìâíàÝÐâëþÝãî ßÐÛöâàã ÔÛï þáöå ÓãÛìÝïþ Amiga. ³íâÐ ÑëÛö "
+"áâÐàëï ßÐÒÞÔ×öÝë"
#: engines/agi/detection.cpp:167
-#, fuzzy
msgid "Mouse support"
-msgstr "¿ÐÔâàëÜÚÐ ßàÞßãáÚÐþ"
+msgstr "¿ÐÔâàëÜÚÐ Üëèë"
#: engines/agi/detection.cpp:168
msgid ""
"Enables mouse support. Allows to use mouse for movement and in game menus."
msgstr ""
+"ÃÚÛîçÐÕ ßÐÔâàëÜÚã Üëèë. ´Ð×ÒÐÛïÕ ÒëÚÐàëáâÞþÒÐæì Üëè ÔÛï ßÕàÐÜïèçíÝÝï ö þ "
+"ÜÕÝî ÓãÛìÝö."
+
+#: 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/saveload.cpp:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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"
@@ -2242,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"
@@ -2253,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"
@@ -2264,19 +2498,18 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/animation.cpp:557
+#: engines/agos/animation.cpp:558
#, c-format
msgid "Cutscene file '%s' not found!"
msgstr "ÄÐÙÛ ×ÐáâÐþÚö '%s' ÝÕ ×ÝÞÙÔ×ÕÝë!"
#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
-#, fuzzy
msgid "Color Blind Mode"
-msgstr "ÀíÖëÜ ßáâàëçÚö"
+msgstr "ÀíÖëÜ ÑÕ× ÚÞÛÕàã"
#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
-msgstr ""
+msgstr "ÃÚÛîçëæì àíÖëÜ ÔÛï ÛîÔ×ÕÙ áÐ áÛÐÑëÜ ãáßàëÜÐÝÝÕÜ ÚÞÛÕàã"
#: engines/drascula/saveload.cpp:47
msgid ""
@@ -2295,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 "½Õ ÐâàëÜÐÛÐáï ×ÐåÐÒÐæì ÓãÛìÝî þ äÐÙÛ."
@@ -2325,17 +2558,17 @@ 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 "½Õ ÐâàëÜÐÛÐáï ×ÐåÐÒÐæì ÓãÛìÝî"
#: engines/hopkins/detection.cpp:76 engines/hopkins/detection.cpp:86
msgid "Gore Mode"
-msgstr ""
+msgstr "ÀíÖëÜ × ÚàëÒñÙ"
#: engines/hopkins/detection.cpp:77 engines/hopkins/detection.cpp:87
msgid "Enable Gore Mode when available"
-msgstr ""
+msgstr "ÃÚÛîçÐÕ àíÖëÜ × ßÐÚÐ×ÐÜ ÚàëÒö, ÚÐÛö ÔÐáâãßÝÐ"
#. I18N: Studio audience adds an applause and cheering sounds whenever
#. Malcolm makes a joke.
@@ -2454,9 +2687,9 @@ msgstr ""
"·ÔÐÕææÐ, Òë áßàÐÑãÕæÕ ÒëÚÐàëáâÞþÒÐæì ßàëÛÐÔã\n"
"General MIDI, ÐÛÕ ÓíâÐï ÓãÛìÝï ßÐÔâàëÜÛöÒÐÕ âÞÛìÚö\n"
"Roland MT32 MIDI. ¼ë ßÐáßàÐÑãÕÜ ßÐÔÐÑàÐæì General\n"
-"MIDI ßàëÛÐÔë, ßÐÔÞÑÝëï ÔÐ Roland MT32, ÐÛÕ\n"
+"MIDI-ßàëÛÐÔë, ßÐÔÞÑÝëï ÔÐ Roland MT32, ÐÛÕ\n"
"ÜÞÖÐ âÐÚ ÐâàëÜÐææÐ, èâÞ ÝÕÚÐâÞàëï âàíÚö ÑãÔãæì\n"
-"áëÓàÐÝëï ÝïßàÐÒöÛìÝÐ."
+"áëÓàÐÝë ÝïßàÐÒöÛìÝÐ."
#: engines/kyra/saveload_eob.cpp:557
#, c-format
@@ -2468,6 +2701,13 @@ msgid ""
"Do you wish to use this save game file with ScummVM?\n"
"\n"
msgstr ""
+"½öÖíÙ×ÓÐÔÐÝë äÐÙÛ ×ÐåÐÒÐÝÝï × ÐàëÓöÝÐÛìÝÐÙ ÓãÛìÝö Ñëþ ×ÝÞÙÔ×ÕÝë þ ÒÐèÐÙ "
+"ÓãÛìÝïÒÞÙ ÔëàíÚâÞàëö:\n"
+"\n"
+"%s %s\n"
+"\n"
+"Æö ÖÐÔÐÕæÕ ÒëÚÐàëáâÞþÒÐæì ÓíâÐÕ ×ÐåÐÒÐÝÝÕ þ ScummVM?\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:590
#, c-format
@@ -2475,6 +2715,8 @@ msgid ""
"A save game file was found in the specified slot %d. Overwrite?\n"
"\n"
msgstr ""
+"à Ð×ÝÐçÐÝëÜ áÛÞæÕ %d ãÖÞ ñáæì ×ÐåÐÒÐÝÝÕ ÓãÛìÝö. ¿ÕàÐ×ÐßöáÐæì?\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:623
#, c-format
@@ -2486,50 +2728,62 @@ msgid ""
"'import_savefile'.\n"
"\n"
msgstr ""
+"%d ÐàëÓöÝÐÛìÝëå äÐÙÛÐþ ×ÐåÐÒÐÝÝï ÑëÛö ßÐáßïåÞÒÐ öÜßÐàâÐÒÐÝë þ ScummVM.\n"
+"ºÐÛö Òë ßÐÖÐÔÐÕæÕ öÜßÐàâÐÒÐæì ÐàëÓöÝÐÛìÝëï ×ÐåÐÒÐÝÝö, ÒÐÜ âàíÑÐ ÑãÔ×Õ\n"
+"ÐÔÚàëæì ÐÔÛÐÔÐçÝãî ÚÐÝáÞÛì 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"
@@ -2538,15 +2792,23 @@ msgstr ""
"½Õ ÜÐÓã ×ÐåÐÒÐæì ÓãÛìÝî þ ßÐ×öæëî %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:194
+msgid "Load file"
+msgstr "·ÐÓàã×öæì äÐÙÛ"
+
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "·ÐÓàãÖÐî ÓãÛìÝî..."
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:209
+msgid "Save file"
+msgstr "·ÐåÐÒÐæì äÐÙÛ"
+
+#: 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"
@@ -2557,16 +2819,16 @@ msgid ""
msgstr ""
"ScummVM ×ÝÐÙèÞþ ã ÒÐá áâÐàëï ×ÐåÐÒÐÝÝö ÓãÛìÝö Nippon Safes, ïÚöï ÝÕÐÑåÞÔÝÐ "
"ßÕàÐÝÐ×ÒÐæì. ÁâÐàëï ÝÐ×Òë ÑÞÛìè ÝÕ ßÐÔâàëÜÛöÒÐîææÐ, ö âÐÜã Òë ÝÕ ×ÜÞÖÐæÕ "
-"×ÐÓàã×öæì ×ÐåÐÒÐÝÝö, ÚÐÛö ÝÕ ßÕàÐÝÐ×ÐÒÕæÕ öå.\n"
+"×ÐÓàã×öæì ×ÐåÐÒÐÝÝö, ÚÐÛö ÝÕ ßÕàÐÝÐ×ÐÒïæÕ öå.\n"
"\n"
-"½ÐæöáÝöæÕ ¾º, ÚÐÑ ßÕàÐÝÐ×ÒÐæì öå ×ÐàÐ×, ã ÐÔÒÐàÞâÝëÜ ÒëßÐÔÚã ÓíâÐ Ö "
+"½ÐæöáÝöæÕ ¾º, ÚÐÑ ßÕàÐÝÐ×ÒÐæì öå ×ÐàÐ×, ã ÐÔÒÐàÞâÝëÜ ÒëßÐÔÚã ÓíâÐÕ Ö "
"ßÐÒÕÔÐÜÛÕÝÝÕ ×'ïÒöææÐ ßàë ÝÐáâãßÝëÜ ×ÐßãáÚã ÓãÛìÝö.\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"
@@ -2584,7 +2846,7 @@ msgstr "½ïßàÐÒöÛìÝÐÕ öÜï äÐÙÛÐ ×ÐåÐÒÐÝÝï"
#: engines/pegasus/pegasus.cpp:2507
msgid "Up/Zoom In/Move Forward/Open Doors"
-msgstr "ÃÒÕàå/¼ÐèâÐÑ+/½ÐßÕàÐÔ/°ÔçëÝöæì Ô×ÒÕàë"
+msgstr "ÃÒÕàå/¿ÐÒïÛ. ÜÐèâÐÑ/½ÐßÕàÐÔ/°ÔçëÝöæì Ô×ÒÕàë"
#: engines/pegasus/pegasus.cpp:2508
msgid "Down/Zoom Out"
@@ -2620,29 +2882,48 @@ msgstr "°ÛìâíàÝÐâëþÝë þáâãß"
#: engines/queen/detection.cpp:57
msgid "Use an alternative game intro (CD version only)"
-msgstr "²ëÚÐàëáâÞþÒÐæì ÐÛìâíàÝÐâëþÝë þáâãß (âÞÛìÚö ÔÛï CD ÒÕàáöö ÓãÛìÝö)"
+msgstr "²ëÚÐàëáâÞþÒÐæì ÐÛìâíàÝÐâëþÝë þáâãß (âÞÛìÚö ÔÛï CD-ÒÕàáöö ÓãÛìÝö)"
-#: engines/sci/detection.cpp:374
+#: engines/sci/detection.cpp:384
msgid "Skip EGA dithering pass (full color backgrounds)"
-msgstr ""
+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:395
+msgid "Enable high resolution graphics/content"
+msgstr "ÃÚÛîçëæì ÓàÐäöÚã ö ÚÐÝâíÝâ ÒëáÞÚÐÓÐ ÐÔàÞ×ÝÕÝÝï"
+
+#: 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:385
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
msgstr "°ÔÔÐÒÐæì ßÕàÐÒÐÓã ÛöçÑÐÒëÜ ÓãÚÐÒëÜ íäÕÚâÐÜ ×ÐÜÕáâ áöÝâí×ÐÒÐÝëå"
-#: engines/sci/detection.cpp:404
+#: engines/sci/detection.cpp:434
msgid "Use IMF/Yamaha FB-01 for MIDI output"
msgstr "²ëÚÐàëáâÞþÒÐæì IMF/Yamaha FB-01 ÔÛï ÒëÒÐÔã MIDI"
-#: engines/sci/detection.cpp:405
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2650,152 +2931,158 @@ msgstr ""
"²ëÚÐàëáâÞþÒÐæì ÓãÚÐÒãî ÚÐàâã IBM Music Feature æö ÜÞÔãÛì áöÝâí×ã Yamaha "
"FB-01 FM ÔÛï MIDI"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
-msgstr "²ëÚÐàëáâÞþÒÐæì CD ÐþÔëñ"
+msgstr "²ëÚÐàëáâÞþÒÐæì CD-ÐþÔëñ"
-#: engines/sci/detection.cpp:416
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
msgstr ""
"²ëÚÐàëáâÞþÒÐæì ÓãÚÐÒëï ÔÐàÞÖÚö × CD ×ÐÜÕáâ Üã×ëÚö × äÐÙÛÐþ ÓãÛìÝö (ÚÐÛö "
"ÔÐáâãßÝÐ)"
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "²ëÚÐàëáâÞþÒÐæì ÚãàáÞàë Windows"
-#: engines/sci/detection.cpp:427
+#: 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:437
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "²ëÚÐàëáâÞþÒÐæì áàíÑÝëï ÚãàáÞàë"
-#: engines/sci/detection.cpp:438
+#: 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
-#, fuzzy
+#: engines/scumm/dialogs.cpp:179
msgid "Are you sure you want to restart? (Y/N)Y"
-msgstr "²ë þßíþÝÕÝë, èâÞ ÖÐÔÐÕæÕ ßÐçÐæì ö×ÝÞþ? (Y/N)"
+msgstr "²ë þßíþÝÕÝë, èâÞ ÖÐÔÐÕæÕ ßÐçÐæì ö×ÝÞþ? (Y/N)Y"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
-#: engines/scumm/dialogs.cpp:185
-#, fuzzy
+#: engines/scumm/dialogs.cpp:181
msgid "Are you sure you want to quit? (Y/N)Y"
-msgstr "²ë þßíþÝÕÝë, èâÞ ÖÐÔÐÕæÕ ÒëÙáæö? (Y/N)"
+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:600
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "ÂÞÛìÚö ÐÓãçÚÐ"
-#: engines/scumm/dialogs.cpp:601
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "°ÓãçÚÐ ö áãÑâëâàë"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "ÂÞÛìÚö áãÑâëâàë"
-#: engines/scumm/dialogs.cpp:610
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "°ÓãçÚÐ ö âíÚáâ"
-#: engines/scumm/dialogs.cpp:656
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "°ÑïàëæÕ þ×àÞÒÕÝì áÚÛÐÔÐÝÐáæö."
-#: engines/scumm/dialogs.cpp:658
+#: engines/scumm/dialogs.cpp:656
msgid "Refer to your Loom(TM) manual for help."
msgstr "·Ð ÔÐßÐÜÞÓÐÙ ×ÒïàÝöæÕáï ÔÐ öÝáâàãÚæëö Loom(TM)."
-#: engines/scumm/dialogs.cpp:662
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "¿àÐÚâëÚÐÝâ"
-#: engines/scumm/dialogs.cpp:663
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "ÍÚáßÕàâ"
@@ -2859,7 +3146,7 @@ msgstr "³ãçÝÐáæì Üã×ëÚö ßÐÒïÛöçëæì / ßÐÜÕÝèëæì"
#: engines/scumm/help.cpp:89
msgid "Text speed slower / faster"
-msgstr "ÅãâÚÐáæì âíÚáâã åãâçíÙ / ßÐÒÞÛìÝÕÙ"
+msgstr "ÅãâÚÐáæì âíÚáâã ßÐÒÞÛìÝÕÙ / åãâçíÙ"
#: engines/scumm/help.cpp:90
msgid "Simulate left mouse button"
@@ -2915,11 +3202,11 @@ msgstr "¿ÕàÐÚÛîçíÝÝÕ ÚÐàíÚæëö áãÐÔÝÞáöÝ ÑÐÚÞþ"
#: engines/scumm/help.cpp:108
msgid "* Note that using ctrl-f and"
-msgstr "* ²ëÚÐàëáâÐÝÝÕ Ctrl-F ö"
+msgstr "* ²ëÚÐàëáâÐÝÝÕ ctrl-f ö"
#: engines/scumm/help.cpp:109
msgid " ctrl-g are not recommended"
-msgstr " Ctrl-G ÝÕ àíÚÐÜÕÝÔãÕææÐ,"
+msgstr " ctrl-g ÝÕ àíÚÐÜÕÝÔãÕææÐ,"
#: engines/scumm/help.cpp:110
msgid " since they may cause crashes"
@@ -3220,25 +3507,24 @@ msgid "Third kid"
msgstr "Âàíæö ÓÕàÞÙ"
#: engines/scumm/help.cpp:292
-#, fuzzy
msgid "Toggle Inventory/IQ Points display"
-msgstr "ÃÚÛîçëæì ßÐÚÐ× ÔÐÔ×ÕÝëå ã æíÝâàë íÚàÐÝÐ"
+msgstr "¿ÕàÐÚÛîçëæì ßÐÚÐ× öÝÒÕÝâÐàÐ/ÐçÚÞþ IQ"
#: engines/scumm/help.cpp:293
msgid "Toggle Keyboard/Mouse Fighting (*)"
-msgstr ""
+msgstr "¿ÕàÐÚÛîçëæì ÚöàÐÒÐÝÝÕ ÑÐïÜö ÚÛÐÒöïâãàÐÙ/Üëèèã (*)"
#: engines/scumm/help.cpp:295
msgid "* Keyboard Fighting is always on,"
-msgstr ""
+msgstr "* ºöàÐÒÐÝÝÕ ÚÛÐÒöïâãàÐÙ ×ÐþáñÔë þÚÛîçÐÝÐ,"
#: engines/scumm/help.cpp:296
msgid " so despite the in-game message this"
-msgstr ""
+msgstr " âÐÚ èâÞ, ÝïÓÛÕÔ×ïçë ÝÐ ßÐÒÕÔÐÜÛÕÝÝÕ ÓãÛìÝö,"
#: engines/scumm/help.cpp:297
msgid " actually toggles Mouse Fighting Off/On"
-msgstr ""
+msgstr " ÝÐáÐÜàíç ÓíâÐ þÚÛ/ÒëÚÛ ÚöàÐÒÐÝÝÕ Üëèèã"
#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
@@ -3275,7 +3561,7 @@ msgstr "ÃÔÐà ×Ýö×ã"
#: engines/scumm/help.cpp:315
msgid "Sucker punch"
-msgstr ""
+msgstr "ÃÔÐà ××ÐÔã"
#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
@@ -3333,7 +3619,23 @@ msgstr "»ïæÕæì ÝÐßàÐÒÐ"
msgid "Fly to lower right"
msgstr "»ïæÕæì ÝÐßàÐÒÐ-þÝö×"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/input.cpp:578
+msgid "Snap scroll on"
+msgstr "¿àÐÓÞàâÚÐ áÚÞÚÐÜö þÚÛîçÐÝÐ"
+
+#: engines/scumm/input.cpp:580
+msgid "Snap scroll off"
+msgstr "¿àÐÓÞàâÚÐ áÚÞÚÐÜö ÒëÚÛîçÐÝÐ"
+
+#: engines/scumm/input.cpp:593
+msgid "Music volume: "
+msgstr "³ãçÝ. Üã×ëÚö: "
+
+#: engines/scumm/input.cpp:610
+msgid "Subtitle speed: "
+msgstr "ÅãâÚÐáæì âëâàÐþ: "
+
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3342,28 +3644,89 @@ msgstr ""
"ÀíÖëÜ \"àÞÔÝÐÓÐ\" MIDI ßÐâàÐÑãÕ ÐÑÝÐþÛÕÝÝÕ Roland Upgrade ÐÔ\n"
"LucasArts, ÐÛÕ ÝÕ åÐßÐÕ %s. ¿ÕàÐÚÛîçÐîáï ÝÐ AdLib."
-#: engines/scumm/scumm.cpp:2644
-#, fuzzy
+#: 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 ""
-"·ÐàÐ× ßÐÒöÝÝÐ ×ÐßãáæöææÐ ÓãÛìÝï Maniac Mansion. °ÛÕ ScummVM ßÐÚãÛì ÓíâÐÓÐ ÝÕ "
-"þÜÕÕ. ºÐÑ ×ÓãÛïæì, ÝÐæöáÝöæÕ '½ÞÒÐï ÓãÛìÝï' ã áâÐàâÐÒëÜ ÜÕÝî ScummVM, Ð "
-"×ÐâëÜ ÐÑïàëæÕ ÔëàíÚâÞàëî Maniac ã ÔëàíÚâÞàëö × ÓãÛìÝñÙ Tentacle."
+"·ÐàÐ× ßÐÒöÝÝÐ ×ÐßãáæöææÐ ÓãÛìÝï Maniac Mansion. °ÛÕ ÚÐÑ ÓíâÐ ßàÐæÐÒÐÛÐ, "
+"äÐÙÛë ÓãÛìÝö Maniac Mansion ßÐÒöÝÝë Ñëæì áÚÐßöïÒÐÝë þ ÔëàíÚâÞàëî 'Maniac' "
+"ãÝãâàë ÔëàíÚâÞàëö ÓãÛìÝö Tentacle ö áÐÜÐ ÓãÛìÝï ßÐÒöÝÝÐ Ñëæì ÔÐÔÐÔ×ÕÝÐ þ "
+"ScummVM."
#: 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 ""
+"½Õ ÐâàëÜÐÛÐáï ×ÝÐÙáæö ÒëÚÐÝÐÛìÝë äÐÙÛ 'Loom' Macintosh, ÚÐÑ ßàÐçëâÐæì\n"
+"ÔÐÔ×ÕÝëï ßàÐ öÝáâàãÜÕÝâë. ¼ã×ëÚÐ ÑãÔ×Õ ÒëÚÛîçÐÝÐ."
#: 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 ""
+"½Õ ÐâàëÜÐÛÐáï ×ÝÐÙáæö ÒëÚÐÝÐÛìÝë äÐÙÛ 'Monkey Island' Macintosh, ÚÐÑ "
+"ßàÐçëâÐæì\n"
+"ÔÐÔ×ÕÝëï ßàÐ öÝáâàãÜÕÝâë. ¼ã×ëÚÐ ÑãÔ×Õ ÒëÚÛîçÐÝÐ."
+
+#: engines/sherlock/detection.cpp:71
+msgid "Use original savegame dialog"
+msgstr "²ëÚÐàëáâÞþÒÐæì ÐàëÓöÝÐÛìÝëï íÚàÐÝë ×Ðßöáã/çëâÐÝÝï ÓãÛìÝö"
+
+#: engines/sherlock/detection.cpp:72
+msgid ""
+"Files button in-game shows original savegame dialog rather than the ScummVM "
+"menu"
+msgstr ""
+"ºÝÞßÚÐ \"ÄÐÙÛë\" þ ÓãÛìÝö ßÐÚÐ×ÒÐÕ ÐàëÓöÝÐÛìÝë ÔëïÛÞÓ ×ÐåÐÒÐÝÝï, Ð ÝÕ ÜÕÝî "
+"ScummVM"
+
+#: engines/sherlock/detection.cpp:81
+msgid "Pixellated scene transitions"
+msgstr "¿ÕàÐåÞÔë ßÐÜöÖ áæíÝÐÜö × ßöÚáÕÛö×ÐæëïÙ"
+
+#: engines/sherlock/detection.cpp:82
+msgid "When changing scenes, a randomized pixel transition is done"
+msgstr "¿àë ×ÜÕÝÕ áæíÝ ÐÔÑëÒÐÕææÐ ßÕàÐåÞÔ × àÐÝÔÐÜö×ÐÒÐÝëÜö ßöÚáÕÛïÜö"
+
+#: engines/sherlock/detection.cpp:91
+msgid "Don't show hotspots when moving mouse"
+msgstr "½Õ ßÐÚÐ×ÒÐæì åÞâáßÞâë ßàë ÝÐÒïÔ×ÕÝÝö Üëèèã"
+
+#: engines/sherlock/detection.cpp:92
+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"
+msgstr "¿ÐÚÐ×ÒÐæì ßÐàâàíâë ÓÕàÞïþ"
+
+#: engines/sherlock/detection.cpp:102
+msgid "Show portraits for the characters when conversing"
+msgstr "¿ÐÚÐ×ÒÐæì ßÐàâàíâë ÓÕàÞïþ ßÐÔçÐá ÔëïÛÞÓÐþ"
+
+#: engines/sherlock/detection.cpp:111
+msgid "Slide dialogs into view"
+msgstr "´ëïÛÞÓö ×Ðï×ÔÖÐîæì"
+
+#: engines/sherlock/detection.cpp:112
+msgid "Slide UI dialogs into view, rather than simply showing them immediately"
+msgstr "´ëïÛÞÓö ÑãÔãæì ×Ðï×ÔÖÐæì, Ð ÝÕ ßÐÚÐ×ÒÐææÐ öÜÓÝÕÝÝÐ"
+
+#: engines/sherlock/detection.cpp:121
+msgid "Transparent windows"
+msgstr "¿àÐ×àëáâëï ÒÞÚÝë"
+
+#: engines/sherlock/detection.cpp:122
+msgid "Show windows with a partially transparent background"
+msgstr "¿ÐÚÐ×ÒÐæì ÒÞÚÝë × çÐáâÚÞÒÐ ßàÐ×àëáâëÜ äÞÝÐÜ"
#: engines/sky/compact.cpp:130
msgid ""
@@ -3387,7 +3750,7 @@ msgstr "Ãáâãß × ÔëáÚÕâ"
#: engines/sky/detection.cpp:45
msgid "Use the floppy version's intro (CD version only)"
-msgstr "²ëÚÐàëáâÞþÒÐæì ãáâãß × ÓÝãâÚöå ÔëáÚÐþ (âÞÛìÚö ÔÛï CD ÒÕàáöö ÓãÛìÝö)"
+msgstr "²ëÚÐàëáâÞþÒÐæì ãáâãß × ÓÝãâÚöå ÔëáÚÐþ (âÞÛìÚö ÔÛï CD-ÒÕàáöö ÓãÛìÝö)"
#: engines/sword1/animation.cpp:524
#, c-format
@@ -3439,11 +3802,11 @@ msgstr ""
#: engines/sword1/control.cpp:1235
msgid "Keep the old one"
-msgstr "¿ÐÚöÝãæì áâÐàÞÕ"
+msgstr "¿ÐÚöÝãæì áâÐàãî"
#: engines/sword1/control.cpp:1235
msgid "Keep the new one"
-msgstr "·àÐÑöæì ÝÞÒÐÕ"
+msgstr "·àÐÑöæì ÝÞÒãî"
#: engines/sword1/logic.cpp:1633
msgid "This is the end of the Broken Sword 1 Demo"
@@ -3453,7 +3816,7 @@ msgstr "³íâÐ ×ÐÒïàèíÝÝÕ ÔíÜÐ Broken Sword 1"
msgid ""
"PSX cutscenes found but ScummVM has been built without RGB color support"
msgstr ""
-"·ÝÞÙÔ×ÕÝë ×ÐáâÐþÚö þ äÐàÜÐæÕ PSX, ÐÛÕ ScummVM Ñëþ áÐÑàÐÝë ÑÕ× ßÐÔâàëÜÚö RGB "
+"·ÝÞÙÔ×ÕÝë ×ÐáâÐþÚö þ äÐàÜÐæÕ PSX, ÐÛÕ ScummVM Ñëþ áÐÑàÐÝë ÑÕ× ßÐÔâàëÜÚö RGB-"
"ÚÞÛÕàÐþ"
#: engines/sword2/sword2.cpp:79
@@ -3464,30 +3827,40 @@ 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"
msgstr ""
-"ÄÐÙÛ teenagent.dat ×ÖÐâë, ÐÛÕ zlib ÝÕ þÚÛîçÐÝÐ þ Óíâã ßàÐÓàÐÜã. ºÐÛö ÛÐáÚÐ, "
+"ÄÐÙÛ teenagent.dat ×ÖÐâë, ÐÛÕ zlib ÝÕ þÚÛîçÐÝë þ Óíâã ßàÐÓàÐÜã. ºÐÛö ÛÐáÚÐ, "
"àÐáßÐÚãÙæÕ ïÓÞ"
#: engines/wintermute/detection.cpp:58
msgid "Show FPS-counter"
-msgstr ""
+msgstr "¿ÐÚÐ×Ðæì ÛöçëÛìÝöÚ ÚÐÔàÐþ ã áÕÚãÝÔã"
#: engines/wintermute/detection.cpp:59
msgid "Show the current number of frames per second in the upper left corner"
-msgstr ""
+msgstr "¿ÐÚÐ×Ðæì ã ÒÕàåÝöÜ ÛÕÒëÜ ÚãæÕ ÑïÓãçãî ÚÞÛìÚÐáæì ÚÐÔàÐþ ã áÕÚãÝÔã"
#: engines/zvision/detection_tables.h:52
-#, fuzzy
msgid "Use the original save/load screens instead of the ScummVM interface"
msgstr ""
"²ëÚÐàëáâÞþÒÐæì ÐàëÓöÝÐÛìÝëï íÚàÐÝë ×Ðßöáã ö ×ÐåÐÒÐÝÝï ÓãÛìÝö ×ÐÜÕáâ "
@@ -3495,39 +3868,37 @@ msgstr ""
#: engines/zvision/detection_tables.h:61
msgid "Double FPS"
-msgstr ""
+msgstr "¿ÐÔÒÞÙÝë FPS"
#: engines/zvision/detection_tables.h:62
msgid "Increase framerate from 30 to 60 FPS"
-msgstr ""
+msgstr "¿ÐÒïÛöçëæì çÐèçëÝî ÚÐÔàÐþ × 30 ÔÐ 60 ³æ"
#: engines/zvision/detection_tables.h:71
-#, fuzzy
msgid "Enable Venus"
-msgstr "ÃÚÛîçëæì àíÖëÜ ÓÕÛöï"
+msgstr "ÃÚÛîçëæì Venus"
#: engines/zvision/detection_tables.h:72
-#, fuzzy
msgid "Enable the Venus help system"
-msgstr "ÃÚÛîçëæì àíÖëÜ ÓÕÛöï"
+msgstr "ÃÚÛîçëæì áöáâíÜã ÔÐßÐÜÞÓö Venus"
#: engines/zvision/detection_tables.h:81
msgid "Disable animation while turning"
-msgstr ""
+msgstr "²ëÚÛîçëæì ÐÝöÜÐæëî ßÐÔçÐá ßÐÒÐàÞâÐþ"
#: engines/zvision/detection_tables.h:82
msgid "Disable animation while turning in panorama mode"
-msgstr ""
+msgstr "²ëÚÛîçëæì ÐÝöÜÐæëî ßÐÔçÐá ßÐÒÐàÞâÐþ ã àíÖëÜÕ ßÐÝÐàÐÜë"
#: engines/zvision/detection_tables.h:91
msgid "Use high resolution MPEG video"
-msgstr ""
+msgstr "²ëÚÐàëáâÞþÒÐæì ÒöÔíÐ MPEG ÒëáÞÚÐÓÐ ÐÔàÞ×ÝÕÝÝï"
#: engines/zvision/detection_tables.h:92
-#, fuzzy
msgid "Use MPEG video from the DVD version, instead of lower resolution AVI"
msgstr ""
-"²ëÚÐàëáâÞþÒÐæì ÐÛìâíàÝÐâëþÝë ÝÐÑÞà áàíÑÝëå ÚãàáÞàÐþ ×ÐÜÕáâ ×ÒëçÐÙÝëå ×ÐÛÐâëå"
+"²ëÚÐàëáâÞþÒÐæì MPEG-ÒöÔíÐ × DVD-ÒÕàáöö ×ÐÜÕáâ ÒöÔíÐ Ýö×ÚÐÓÐ ÐÔàÞ×ÝÕÝÝï þ "
+"äÐàÜÐæÕ AVI"
#~ msgid "EGA undithering"
#~ msgstr "EGA ÑÕ× àÐáâàã"
@@ -3577,26 +3948,6 @@ msgstr ""
#~ msgid "Active filter mode: Nearest"
#~ msgstr "°ÚâëþÝë àíÖëÜ äöÛìâàÐ: ½ÐÙÑÛö×Úö"
-#~ msgid "Enable Roland GS Mode"
-#~ msgstr "ÃÚÛîçëæì àíÖëÜ Roland GS"
-
-#~ msgid "Hercules Green"
-#~ msgstr "Hercules ·ÕÛñÝëÙ"
-
-#~ msgid "Hercules Amber"
-#~ msgstr "Hercules ÏÝâÐàÝëÙ"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Green"
-#~ msgstr "Hercules ·ÕÛñÝëÙ"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Amber"
-#~ msgstr "Hercules ÏÝâÐàÝëÙ"
-
-#~ msgid "Save game failed!"
-#~ msgstr "½Õ ãÔÐÛÞáì áÞåàÐÝØâì ØÓàã!"
-
#~ msgctxt "lowres"
#~ msgid "Add Game..."
#~ msgstr "´ÞÑ. ØÓàã"
@@ -3610,8 +3961,5 @@ msgstr ""
#~ msgid "Command line argument not processed"
#~ msgstr "¿ÐàÐÜÕâàë ÚÞÜÐÝÔÝÞÙ áâàÞÚØ ÝÕ ÞÑàÐÑÞâÐÝë"
-#~ msgid "FM Towns Emulator"
-#~ msgstr "ÍÜãÛïâÞà FM Towns"
-
#~ msgid "Invalid Path"
#~ msgstr "½ÕÒÕàÝëÙ ßãâì"
diff --git a/po/ca_ES.po b/po/ca_ES.po
index 1a0a756253..9a1ba16a6b 100644
--- a/po/ca_ES.po
+++ b/po/ca_ES.po
@@ -1,5 +1,5 @@
# Catalan translation for ScummVM.
-# Copyright (C) 2007-2015 The ScummVM Team
+# Copyright (C) 2007-2016 The ScummVM Team
# This file is distributed under the same license as the ScummVM package.
# Jordi Vilalta Prat <jvprat@jvprat.com>, 2007-2011.
#
@@ -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: 2015-09-06 15:14+0200\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"
@@ -51,22 +51,23 @@ msgid "Go up"
msgstr "Amunt"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:74 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: 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/fluidsynth-dialog.cpp:152 engines/engine.cpp:483
-#: backends/platform/wii/options.cpp:48
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
-#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:191 engines/sword1/control.cpp:865
+#: 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 "Cancel·la"
#: gui/browser.cpp:76 gui/browser_osx.mm:103 gui/chooser.cpp:47
-#: gui/themebrowser.cpp:56
+#: gui/filebrowser-dialog.cpp:65 gui/themebrowser.cpp:56
msgid "Choose"
msgstr "Escull"
@@ -82,61 +83,180 @@ msgstr "Nom:"
msgid "Notes:"
msgstr ""
-#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:75
+#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74
msgid "Ok"
msgstr ""
-#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
+#: gui/filebrowser-dialog.cpp:49
+msgid "Choose file for loading"
+msgstr ""
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Enter filename for saving"
+msgstr ""
+
+#: gui/filebrowser-dialog.cpp:132
+#, fuzzy
+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: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 "Sí"
+
+#: 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 "No"
+
+#: gui/fluidsynth-dialog.cpp:68
+msgid "Reverb"
+msgstr "Reverberació"
+
+#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
+msgid "Active"
+msgstr "Actiu"
+
+#: gui/fluidsynth-dialog.cpp:72
+msgid "Room:"
+msgstr "Habitació:"
+
+#: gui/fluidsynth-dialog.cpp:79
+msgid "Damp:"
+msgstr "Humitat:"
+
+#: gui/fluidsynth-dialog.cpp:86
+msgid "Width:"
+msgstr "Amplitud:"
+
+#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
+msgid "Level:"
+msgstr "Nivell:"
+
+#: gui/fluidsynth-dialog.cpp:100
+msgid "Chorus"
+msgstr "Cor"
+
+#: gui/fluidsynth-dialog.cpp:104
+msgid "N:"
+msgstr "N:"
+
+#: gui/fluidsynth-dialog.cpp:118
+msgid "Speed:"
+msgstr "Velocitat:"
+
+#: gui/fluidsynth-dialog.cpp:125
+msgid "Depth:"
+msgstr "Profunditat:"
+
+#: gui/fluidsynth-dialog.cpp:132
+msgid "Type:"
+msgstr "Tipus:"
+
+#: gui/fluidsynth-dialog.cpp:135
+msgid "Sine"
+msgstr "Sinus"
+
+#: gui/fluidsynth-dialog.cpp:136
+msgid "Triangle"
+msgstr "Triangle"
+
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
+msgid "Misc"
+msgstr "Misc"
+
+#: gui/fluidsynth-dialog.cpp:140
+msgid "Interpolation:"
+msgstr "Interpolació:"
+
+#: gui/fluidsynth-dialog.cpp:143
+msgid "None (fastest)"
+msgstr "Cap (el més ràpid)"
+
+#: gui/fluidsynth-dialog.cpp:144
+msgid "Linear"
+msgstr "Lineal"
+
+#: gui/fluidsynth-dialog.cpp:145
+msgid "Fourth-order"
+msgstr "Quart ordre"
+
+#: gui/fluidsynth-dialog.cpp:146
+msgid "Seventh-order"
+msgstr "Setè ordre"
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset"
+msgstr "Reset"
+
+#: gui/fluidsynth-dialog.cpp:150
+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: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 "D'acord"
+
+#: gui/fluidsynth-dialog.cpp:217
+msgid ""
+"Do you really want to reset all FluidSynth settings to their default values?"
+msgstr ""
+"Realment voleu retorna tots els ajustos de FluidSynth als seus valors per "
+"defecte?"
+
+#: 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 "Tanca"
-#: gui/gui-manager.cpp:120
+#: gui/gui-manager.cpp:122
msgid "Mouse click"
msgstr "Clic del ratolí"
-#: gui/gui-manager.cpp:124 base/main.cpp:319
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Mostra el teclat"
-#: gui/gui-manager.cpp:128 base/main.cpp:323
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Assigna les tecles"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 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"
-#: gui/KeysDialog.h:36 gui/KeysDialog.cpp:145
-msgid "Choose an action to map"
-msgstr "Sel·leccioneu una acció a assignar"
-
#: gui/KeysDialog.cpp:41
msgid "Map"
msgstr "Assigna"
-#: gui/KeysDialog.cpp:42 gui/launcher.cpp:352 gui/launcher.cpp:1048
-#: gui/launcher.cpp:1052 gui/massadd.cpp:92 gui/options.cpp:1238
-#: gui/saveload-dialog.cpp:932 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:402 engines/engine.cpp:413
-#: 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/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 "D'acord"
-
#: gui/KeysDialog.cpp:49
msgid "Select an action and click 'Map'"
msgstr "Seleccioneu una acció i cliqueu 'Assigna'"
@@ -159,6 +279,10 @@ msgstr "Seleccioneu una acció"
msgid "Press the key to associate"
msgstr "Premeu la tecla a associar"
+#: gui/KeysDialog.cpp:145 gui/KeysDialog.h:36
+msgid "Choose an action to map"
+msgstr "Sel·leccioneu una acció a assignar"
+
#: gui/launcher.cpp:193
msgid "Game"
msgstr "Joc"
@@ -201,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>"
@@ -224,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"
@@ -241,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"
@@ -254,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"
@@ -272,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:95
+#: 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:69
+#: 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:1222
+#: 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/myst.cpp:245 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/myst.cpp:245
-#: engines/mohawk/riven.cpp:718 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:792
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -492,61 +617,41 @@ msgstr ""
"Esteu segur que voleu executar el detector massiu de jocs? Això pot afegir "
"una gran quantitat de jocs."
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Sí"
-
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "No"
-
-#: gui/launcher.cpp:841
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM no ha pogut obrir el directori especificat!"
-#: gui/launcher.cpp:853
+#: 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:867
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Seleccioneu el joc:"
-#: gui/launcher.cpp:941
+#: 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:999
+#: gui/launcher.cpp:1003
#, fuzzy
msgid "Do you want to load saved game?"
msgstr "Voleu carregar o desar el joc?"
-#: gui/launcher.cpp:1048
+#: 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:1052
+#: 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:1159
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Addició Massiva..."
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr ""
@@ -592,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:2298
+#: 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"
@@ -725,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"
@@ -793,193 +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:1168 gui/fluidsynth-dialog.cpp:138
-msgid "Misc"
-msgstr "Misc"
-
-#: 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."
@@ -988,65 +1101,80 @@ msgstr ""
"aquest tema primer haureu de canviar a un altre idioma."
#. I18N: You must leave "#" as is, only word 'next' is translatable
-#: gui/predictivedialog.cpp:87
+#: gui/predictivedialog.cpp:86
msgid "# next"
msgstr ""
-#: gui/predictivedialog.cpp:88
+#: gui/predictivedialog.cpp:87
msgid "add"
msgstr ""
-#: gui/predictivedialog.cpp:92
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
#, fuzzy
msgid "Delete char"
msgstr "Suprimeix"
-#: gui/predictivedialog.cpp:96
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
msgstr ""
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:98
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr ""
-#: gui/recorderdialog.cpp:64
+#. I18N: 'Num' means Numbers
+#: gui/predictivedialog.cpp:578
+msgid "* Num"
+msgstr ""
+
+#. I18N: 'Abc' means Latin alphabet input
+#: gui/predictivedialog.cpp:581
+msgid "* Abc"
+msgstr ""
+
+#: 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:173
+#, fuzzy
+msgid "Unknown Author"
+msgstr "Error desconegut"
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr "Vista de llistat"
@@ -1107,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:"
@@ -1116,154 +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:661
+#: 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
-msgid "Clear value"
-msgstr "Neteja el valor"
-
-#: gui/fluidsynth-dialog.cpp:68
-msgid "Reverb"
-msgstr "Reverberació"
-
-#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
-msgid "Active"
-msgstr "Actiu"
-
-#: gui/fluidsynth-dialog.cpp:72
-msgid "Room:"
-msgstr "Habitació:"
-
-#: gui/fluidsynth-dialog.cpp:79
-msgid "Damp:"
-msgstr "Humitat:"
-
-#: gui/fluidsynth-dialog.cpp:86
-msgid "Width:"
-msgstr "Amplitud:"
-
-#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
-msgid "Level:"
-msgstr "Nivell:"
-
-#: gui/fluidsynth-dialog.cpp:100
-msgid "Chorus"
-msgstr "Cor"
-
-#: gui/fluidsynth-dialog.cpp:104
-msgid "N:"
-msgstr "N:"
-
-#: gui/fluidsynth-dialog.cpp:118
-msgid "Speed:"
-msgstr "Velocitat:"
-
-#: gui/fluidsynth-dialog.cpp:125
-msgid "Depth:"
-msgstr "Profunditat:"
-
-#: gui/fluidsynth-dialog.cpp:132
-msgid "Type:"
-msgstr "Tipus:"
-
-#: gui/fluidsynth-dialog.cpp:135
-msgid "Sine"
-msgstr "Sinus"
-
-#: gui/fluidsynth-dialog.cpp:136
-msgid "Triangle"
-msgstr "Triangle"
-
-#: gui/fluidsynth-dialog.cpp:140
-msgid "Interpolation:"
-msgstr "Interpolació:"
-
-#: gui/fluidsynth-dialog.cpp:143
-msgid "None (fastest)"
-msgstr "Cap (el més ràpid)"
-
-#: gui/fluidsynth-dialog.cpp:144
-msgid "Linear"
-msgstr "Lineal"
-
-#: gui/fluidsynth-dialog.cpp:145
-msgid "Fourth-order"
-msgstr "Quart ordre"
-
-#: gui/fluidsynth-dialog.cpp:146
-msgid "Seventh-order"
-msgstr "Setè ordre"
+#: 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/fluidsynth-dialog.cpp:150
-msgid "Reset"
-msgstr "Reset"
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr ""
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset all FluidSynth settings to their default values."
-msgstr "Retorna tots els ajustos de FluidSynth als seus valors per defecte."
+#: gui/updates-dialog.cpp:92
+#, fuzzy
+msgid "Check for updates automatically"
+msgstr "Comprova les actualitzacions..."
-#: gui/fluidsynth-dialog.cpp:217
-msgid ""
-"Do you really want to reset all FluidSynth settings to their default values?"
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
msgstr ""
-"Realment voleu retorna tots els ajustos de FluidSynth als seus valors per "
-"defecte?"
-#: base/main.cpp:228
+#: 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:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "El motor no suporta el nivell de depuració '%s'"
-#: base/main.cpp:306
+#: base/main.cpp:315
msgid "Menu"
msgstr "Menú"
-#: base/main.cpp:309 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:312 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:315
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Salta la línia"
-#: base/main.cpp:507
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Error al executar el joc:"
-#: base/main.cpp:554
+#: 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"
@@ -1331,17 +1393,61 @@ msgstr "Cancel·lat per l'usuari"
msgid "Unknown error"
msgstr "Error desconegut"
-#: engines/advancedDetector.cpp:317
+#. I18N: Hercules is graphics card name
+#: common/rendermode.cpp:35
+msgid "Hercules Green"
+msgstr ""
+
+#: common/rendermode.cpp:36
+msgid "Hercules Amber"
+msgstr ""
+
+#: common/rendermode.cpp:42
+msgid "PC-9821 (256 Colors)"
+msgstr ""
+
+#: common/rendermode.cpp:43
+msgid "PC-9801 (16 Colors)"
+msgstr ""
+
+#: common/rendermode.cpp:73
+msgctxt "lowres"
+msgid "Hercules Green"
+msgstr ""
+
+#: common/rendermode.cpp:74
+msgctxt "lowres"
+msgid "Hercules Amber"
+msgstr ""
+
+#: 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.:"
@@ -1349,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"
@@ -1378,11 +1484,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "~R~etorna al Llançador"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:803
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:873
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
-#: engines/toltecs/menu.cpp:281 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:"
@@ -1391,11 +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:803 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/neverhood/menumodule.cpp:873 engines/pegasus/pegasus.cpp:377
-#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
-#: engines/toltecs/menu.cpp:281 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"
@@ -1417,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"
@@ -1431,23 +1546,23 @@ msgstr "~C~ancel·la"
msgid "~K~eys"
msgstr "~T~ecles"
-#: engines/engine.cpp:276
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "No s'ha pogut iniciar el format de color."
-#: engines/engine.cpp:284
+#: 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:293
+#: 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:298
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "No s'ha pogut aplicar l'ajust de pantalla completa."
-#: engines/engine.cpp:398
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1461,7 +1576,7 @@ msgstr ""
"els fitxers de dades al disc dur.\n"
"Consulteu el fitxer README per a més detalls."
-#: engines/engine.cpp:409
+#: 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"
@@ -1475,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:467
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1484,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:480
+#: 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 "
@@ -1494,10 +1609,14 @@ 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:483
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Inicia de totes maneres"
+#: audio/adlib.cpp:2290
+msgid "AdLib Emulator"
+msgstr "Emulador d'AdLib"
+
#: audio/fmopl.cpp:62
msgid "MAME OPL emulator"
msgstr "Emulador OPL de MAME"
@@ -1551,31 +1670,36 @@ msgstr ""
"No es pot utilitzar el dispositiu d'àudio preferit '%s'. Vegeu el fitxer de "
"registre per a més informació."
-#: audio/null.h:44
-msgid "No music"
-msgstr "Sense música"
-
#: audio/mods/paula.cpp:196
msgid "Amiga Audio Emulator"
msgstr "Emulador d'àudio Amiga"
-#: audio/adlib.cpp:2291
-msgid "AdLib Emulator"
-msgstr "Emulador d'AdLib"
+#: audio/null.h:44
+msgid "No music"
+msgstr "Sense música"
#: audio/softsynth/appleiigs.cpp:33
msgid "Apple II GS Emulator (NOT IMPLEMENTED)"
msgstr "Emulador d'Apple II GS (NO IMPLEMENTAT)"
-#: audio/softsynth/sid.cpp:1430
-msgid "C64 Audio Emulator"
-msgstr "Emulador d'àudio C64"
+#: audio/softsynth/cms.cpp:350
+msgid "Creative Music System Emulator"
+msgstr ""
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33
+msgid "FM-Towns Audio"
+msgstr ""
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58
+#, fuzzy
+msgid "PC-98 Audio"
+msgstr "Àudio"
+
+#: 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"
@@ -1587,6 +1711,148 @@ msgstr "Emulador Altaveu PC"
msgid "IBM PCjr Emulator"
msgstr "Emulador d'IBM PCjr"
+#: audio/softsynth/sid.cpp:1430
+msgid "C64 Audio Emulator"
+msgstr "Emulador d'àudio C64"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Do you really want to return to the Launcher?"
+msgstr "Realment voleu tornar al Llançador?"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Launcher"
+msgstr "Llançador"
+
+#: backends/events/default/default-events.cpp:218
+msgid "Do you really want to quit?"
+msgstr "Estàs segur de voler sortir?"
+
+#: 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 "Surt"
+
+#: 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 "'Mode Toc' de pantalla tàctil - Clic esquerre"
+
+#: 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 "'Mode Toc' de pantalla tàctil - Clic dret"
+
+#: 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 "'Mode Toc' de pantalla tàctil - Flotant (sense clic)"
+
+#: backends/events/gph/gph-events.cpp:409
+msgid "Maximum Volume"
+msgstr "Volum màxim"
+
+#: backends/events/gph/gph-events.cpp:411
+msgid "Increasing Volume"
+msgstr "Pujant el volum"
+
+#: backends/events/gph/gph-events.cpp:417
+msgid "Minimal Volume"
+msgstr "Volum mínim"
+
+#: backends/events/gph/gph-events.cpp:419
+msgid "Decreasing Volume"
+msgstr "Baixant el volum"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Enabled"
+msgstr "Clicat activat"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Disabled"
+msgstr "Clicat desactivat"
+
+#: backends/events/openpandora/op-events.cpp:174
+msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
+msgstr "'Mode Toc' de pantalla tàctil - Flotant (Clics de DPad)"
+
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
+msgid "Do you want to quit ?"
+msgstr "Vols sortir?"
+
+#. I18N: Trackpad mode toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:308
+#, fuzzy
+msgid "Trackpad mode is now"
+msgstr "Mode Touchpad desactivat."
+
+#. 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 ""
+
+#: backends/events/webossdl/webossdl-events.cpp:311
+#: backends/events/webossdl/webossdl-events.cpp:338
+msgid "OFF"
+msgstr ""
+
+#: backends/events/webossdl/webossdl-events.cpp:315
+msgid "Swipe two fingers to the right to toggle."
+msgstr ""
+
+#. I18N: Auto-drag toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:335
+msgid "Auto-drag mode is now"
+msgstr ""
+
+#: backends/events/webossdl/webossdl-events.cpp:342
+msgid "Swipe three fingers to the right to toggle."
+msgstr ""
+
+#: backends/graphics/opengl/opengl-graphics.cpp:126
+#, fuzzy
+msgid "OpenGL"
+msgstr "Obre"
+
+#: backends/graphics/opengl/opengl-graphics.cpp:127
+msgid "OpenGL (No filtering)"
+msgstr ""
+
+#: 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 "Normal (sense escalar)"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:66
+msgctxt "lowres"
+msgid "Normal (no scaling)"
+msgstr "Normal (no escalat)"
+
+#: 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:2219
+msgid "Disabled aspect ratio correction"
+msgstr "S'ha desactivat la correcció de la relació d'aspecte"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
+msgid "Active graphics filter:"
+msgstr "Filtre de gràfics actiu:"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+msgid "Windowed mode"
+msgstr "Mode de finestra"
+
#: backends/keymapper/remap-dialog.cpp:48
msgid "Keymap:"
msgstr "Assignacions de teclat:"
@@ -1616,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"
@@ -1692,18 +1958,26 @@ msgstr "Alta qualitat d'àudio (més lent) (reiniciar)"
msgid "Disable power off"
msgstr "Desactiva l'apagat automàtic"
+#: 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 "S'ha activat el mode de clic-i-arrossega."
+#: 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 "S'ha desactivat el mode clic-i-arrossega."
+#: 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 "Mode Touchpad activat."
+#: 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 "Mode Touchpad desactivat."
@@ -1714,9 +1988,9 @@ msgstr "Mode clic"
#: 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
-#: backends/platform/tizen/form.cpp:275
msgid "Left Click"
msgstr "Clic esquerre"
@@ -1726,66 +2000,32 @@ msgstr "Clic central"
#: backends/platform/maemo/maemo.cpp:220
#: backends/platform/symbian/src/SymbianActions.cpp:43
-#: backends/platform/wince/CEActionsSmartphone.cpp:44
#: backends/platform/tizen/form.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:44
msgid "Right Click"
msgstr "Clic dret"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:77
+#: backends/platform/sdl/macosx/appmenu_osx.mm:88
msgid "Hide ScummVM"
msgstr "Amaga ScummVM"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:82
+#: backends/platform/sdl/macosx/appmenu_osx.mm:93
msgid "Hide Others"
msgstr "Oculta els altres"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:87
+#: backends/platform/sdl/macosx/appmenu_osx.mm:98
msgid "Show All"
msgstr "Mostra-ho tot"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:109
#: backends/platform/sdl/macosx/appmenu_osx.mm:120
+#: backends/platform/sdl/macosx/appmenu_osx.mm:131
msgid "Window"
msgstr "Finestra"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:114
+#: backends/platform/sdl/macosx/appmenu_osx.mm:125
msgid "Minimize"
msgstr "Minimitza"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:46
-msgid "Normal (no scaling)"
-msgstr "Normal (sense escalar)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:65
-msgctxt "lowres"
-msgid "Normal (no scaling)"
-msgstr "Normal (no escalat)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
-msgid "Enabled aspect ratio correction"
-msgstr "S'ha activat la correcció de la relació d'aspecte"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
-msgid "Disabled aspect ratio correction"
-msgstr "S'ha desactivat la correcció de la relació d'aspecte"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
-msgid "Active graphics filter:"
-msgstr "Filtre de gràfics actiu:"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
-msgid "Windowed mode"
-msgstr "Mode de finestra"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:118
-#, fuzzy
-msgid "OpenGL"
-msgstr "Obre"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:119
-msgid "OpenGL (No filtering)"
-msgstr ""
-
#: backends/platform/symbian/src/SymbianActions.cpp:38
#: backends/platform/wince/CEActionsSmartphone.cpp:39
msgid "Up"
@@ -1829,14 +2069,6 @@ msgstr "Salta el text"
msgid "Fast mode"
msgstr "Mode ràpid"
-#: backends/platform/symbian/src/SymbianActions.cpp:52
-#: backends/platform/wince/CEActionsPocket.cpp:44
-#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: backends/events/default/default-events.cpp:218 engines/scumm/dialogs.cpp:192
-#: engines/scumm/help.cpp:83 engines/scumm/help.cpp:85
-msgid "Quit"
-msgstr "Surt"
-
#: backends/platform/symbian/src/SymbianActions.cpp:53
msgid "Debugger"
msgstr "Depurador"
@@ -1853,9 +2085,50 @@ msgstr "Teclat virtual"
msgid "Key mapper"
msgstr "Assignador de tecles"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:186
-msgid "Do you want to quit ?"
-msgstr "Vols sortir?"
+#: backends/platform/tizen/form.cpp:263
+msgid "Right Click Once"
+msgstr "Un clic dret"
+
+#: backends/platform/tizen/form.cpp:271
+msgid "Move Only"
+msgstr "Només mou"
+
+#: backends/platform/tizen/form.cpp:294
+msgid "Escape Key"
+msgstr "Tecla d'escapada"
+
+#: backends/platform/tizen/form.cpp:299
+msgid "Game Menu"
+msgstr "Menú del joc"
+
+#: backends/platform/tizen/form.cpp:304
+msgid "Show Keypad"
+msgstr "Mostra el teclat numèric"
+
+#: backends/platform/tizen/form.cpp:309
+msgid "Control Mouse"
+msgstr "Controla el ratolí"
+
+#: backends/platform/tizen/fs.cpp:259
+msgid "[ Data ]"
+msgstr ""
+
+#: backends/platform/tizen/fs.cpp:263
+msgid "[ Resources ]"
+msgstr ""
+
+#: backends/platform/tizen/fs.cpp:267
+msgid "[ SDCard ]"
+msgstr ""
+
+#: backends/platform/tizen/fs.cpp:271
+msgid "[ Media ]"
+msgstr ""
+
+#: backends/platform/tizen/fs.cpp:275
+#, fuzzy
+msgid "[ Shared ]"
+msgstr "Compartició:"
#: backends/platform/wii/options.cpp:51
msgid "Video"
@@ -2102,102 +2375,39 @@ msgstr ""
"No us oblideu d'assignar una tecla a l'acció 'Ocultar la barra d'eines' per "
"veure l'inventari complet"
-#: backends/events/default/default-events.cpp:196
-msgid "Do you really want to return to the Launcher?"
-msgstr "Realment voleu tornar al Llançador?"
-
-#: backends/events/default/default-events.cpp:196
-msgid "Launcher"
-msgstr "Llançador"
-
-#: backends/events/default/default-events.cpp:218
-msgid "Do you really want to quit?"
-msgstr "Estàs segur de voler sortir?"
-
-#: 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 "'Mode Toc' de pantalla tàctil - Clic esquerre"
-
-#: 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 "'Mode Toc' de pantalla tàctil - Clic dret"
-
-#: 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 "'Mode Toc' de pantalla tàctil - Flotant (sense clic)"
-
-#: backends/events/gph/gph-events.cpp:409
-msgid "Maximum Volume"
-msgstr "Volum màxim"
-
-#: backends/events/gph/gph-events.cpp:411
-msgid "Increasing Volume"
-msgstr "Pujant el volum"
-
-#: backends/events/gph/gph-events.cpp:417
-msgid "Minimal Volume"
-msgstr "Volum mínim"
-
-#: backends/events/gph/gph-events.cpp:419
-msgid "Decreasing Volume"
-msgstr "Baixant el volum"
-
-#: backends/events/openpandora/op-events.cpp:174
-msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
-msgstr "'Mode Toc' de pantalla tàctil - Flotant (Clics de DPad)"
-
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Comprova les actualitzacions..."
-#: backends/platform/tizen/form.cpp:263
-msgid "Right Click Once"
-msgstr "Un clic dret"
-
-#: backends/platform/tizen/form.cpp:271
-msgid "Move Only"
-msgstr "Només mou"
-
-#: backends/platform/tizen/form.cpp:294
-msgid "Escape Key"
-msgstr "Tecla d'escapada"
-
-#: backends/platform/tizen/form.cpp:299
-msgid "Game Menu"
-msgstr "Menú del joc"
-
-#: backends/platform/tizen/form.cpp:304
-msgid "Show Keypad"
-msgstr "Mostra el teclat numèric"
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "Mode clic"
-#: backends/platform/tizen/form.cpp:309
-msgid "Control Mouse"
-msgstr "Controla el ratolí"
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Enabled"
-msgstr "Clicat activat"
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Disabled"
-msgstr "Clicat desactivat"
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "Mostra les etiquetes dels objectes"
-#: engines/agi/detection.cpp:147 engines/drascula/detection.cpp:302
-#: engines/dreamweb/detection.cpp:47 engines/neverhood/detection.cpp:160
-#: engines/sci/detection.cpp:394 engines/toltecs/detection.cpp:200
-#: engines/zvision/detection_tables.h:51
+#: 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 "Utilitza les pantalles originals de desat/càrrega"
-#: engines/agi/detection.cpp:148 engines/drascula/detection.cpp:303
-#: engines/dreamweb/detection.cpp:48 engines/neverhood/detection.cpp:161
-#: engines/sci/detection.cpp:395 engines/toltecs/detection.cpp:201
+#: 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 ""
"Utilitza les pantalles originals de desat/càrrega, en lloc de les de ScummVM"
@@ -2223,19 +2433,45 @@ msgid ""
"Enables mouse support. Allows to use mouse for movement and in game menus."
msgstr ""
-#: engines/agi/saveload.cpp:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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"
@@ -2246,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"
@@ -2257,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"
@@ -2268,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'!"
@@ -2300,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."
@@ -2330,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"
@@ -2491,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"
@@ -2542,15 +2788,25 @@ msgstr ""
"No s'ha pogut desar a l'espai %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:194
+#, fuzzy
+msgid "Load file"
+msgstr "Carrega partida:"
+
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Carregant la partida..."
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:209
+#, fuzzy
+msgid "Save file"
+msgstr "Desa la partida:"
+
+#: 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"
@@ -2567,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"
@@ -2627,27 +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:395
+#, fuzzy
+msgid "Enable high resolution graphics/content"
+msgstr "Activa la barra gràfica dels punts d'impacte"
+
+#: 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:385
+#: 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:404
+#: 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:405
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2655,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:415
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "Utilitza l'àudio del CD"
-#: engines/sci/detection.cpp:416
+#: 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:426
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Utilitza els cursors de Windows"
-#: engines/sci/detection.cpp:427
+#: 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:437
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Utilitza cursors platejats"
-#: engines/sci/detection.cpp:438
+#: 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:600
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Només veus"
-#: engines/scumm/dialogs.cpp:601
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Veu i subtítols"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Només subtítols"
-#: engines/scumm/dialogs.cpp:610
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Veus i sub."
-#: engines/scumm/dialogs.cpp:656
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Seleccioneu el nivell de competència."
-#: engines/scumm/dialogs.cpp:658
+#: 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:662
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Pràctica"
-#: engines/scumm/dialogs.cpp:663
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Expert"
@@ -3338,7 +3622,26 @@ msgstr "Vola a la dreta"
msgid "Fly to lower right"
msgstr "Vola avall i a la dreta"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/input.cpp:578
+#, fuzzy
+msgid "Snap scroll on"
+msgstr "Desplaçament suau"
+
+#: engines/scumm/input.cpp:580
+msgid "Snap scroll off"
+msgstr ""
+
+#: engines/scumm/input.cpp:593
+#, fuzzy
+msgid "Music volume: "
+msgstr "Volum de música:"
+
+#: engines/scumm/input.cpp:610
+#, fuzzy
+msgid "Subtitle speed: "
+msgstr "Velocitat de subt.:"
+
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3347,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 "
@@ -3370,6 +3673,60 @@ msgid ""
"instruments from. Music will be disabled."
msgstr ""
+#: engines/sherlock/detection.cpp:71
+#, fuzzy
+msgid "Use original savegame dialog"
+msgstr "Utilitza les pantalles originals de desat/càrrega"
+
+#: engines/sherlock/detection.cpp:72
+msgid ""
+"Files button in-game shows original savegame dialog rather than the ScummVM "
+"menu"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:81
+msgid "Pixellated scene transitions"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:82
+msgid "When changing scenes, a randomized pixel transition is done"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:91
+msgid "Don't show hotspots when moving mouse"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:92
+msgid ""
+"Only show hotspot names after you actually click on a hotspot or action "
+"button"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:101
+#, fuzzy
+msgid "Show character portraits"
+msgstr "Commuta el personatge"
+
+#: engines/sherlock/detection.cpp:102
+msgid "Show portraits for the characters when conversing"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:111
+msgid "Slide dialogs into view"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:112
+msgid "Slide UI dialogs into view, rather than simply showing them immediately"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:121
+msgid "Transparent windows"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:122
+msgid "Show windows with a partially transparent background"
+msgstr ""
+
#: engines/sky/compact.cpp:130
msgid ""
"Unable to find \"sky.cpt\" file!\n"
@@ -3473,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"
@@ -3585,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 28c50ed514..ea8ca29b99 100644
--- a/po/cs_CZ.po
+++ b/po/cs_CZ.po
@@ -1,5 +1,5 @@
# Czech translation for ScummVM.
-# Copyright (C) 2001-2015 The ScummVM Team
+# Copyright (C) 2001-2016 The ScummVM Team
# This file is distributed under the same license as the ScummVM package.
# Zbynìk Schwarz <zbynek.schwarz@gmail.com>, 2011-2013.
#
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.7.0git\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2015-09-06 15:14+0200\n"
-"PO-Revision-Date: 2015-07-26 18:51+0200\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"
"Language: Cesky\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
"X-Poedit-SourceCharset: iso-8859-2\n"
-"X-Generator: Poedit 1.8.3\n"
+"X-Generator: Poedit 1.8.7\n"
"X-Poedit-Basepath: ..\n"
#: gui/about.cpp:94
@@ -55,27 +55,27 @@ msgid "Go up"
msgstr "Jít nahoru"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:74 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: 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/fluidsynth-dialog.cpp:152 engines/engine.cpp:483
-#: backends/platform/wii/options.cpp:48
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
-#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:191 engines/sword1/control.cpp:865
+#: 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 "Zru¹it"
#: gui/browser.cpp:76 gui/browser_osx.mm:103 gui/chooser.cpp:47
-#: gui/themebrowser.cpp:56
+#: gui/filebrowser-dialog.cpp:65 gui/themebrowser.cpp:56
msgid "Choose"
msgstr "Zvolit"
#: gui/editrecorddialog.cpp:58
-#, fuzzy
msgid "Author:"
msgstr "Autor:"
@@ -84,65 +84,182 @@ msgid "Name:"
msgstr "Jméno"
#: gui/editrecorddialog.cpp:60
-#, fuzzy
msgid "Notes:"
msgstr "Poznámky:"
-#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:75
+#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74
msgid "Ok"
+msgstr "Ok"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Choose file for loading"
+msgstr "Zvolte soubor pro naètení"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Enter filename for saving"
+msgstr "Zadejte název souboru pro ulo¾ení"
+
+#: gui/filebrowser-dialog.cpp:132
+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: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 "Ano"
+
+#: 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 "Ne"
+
+#: gui/fluidsynth-dialog.cpp:68
+msgid "Reverb"
+msgstr "Dozvuk"
+
+#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
+msgid "Active"
+msgstr "Aktivní"
+
+#: gui/fluidsynth-dialog.cpp:72
+msgid "Room:"
+msgstr "Místnost:"
+
+#: gui/fluidsynth-dialog.cpp:79
+msgid "Damp:"
+msgstr "Tlumení:"
+
+#: gui/fluidsynth-dialog.cpp:86
+msgid "Width:"
+msgstr "©íøka:"
+
+#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
+msgid "Level:"
+msgstr "Úroveò:"
+
+#: gui/fluidsynth-dialog.cpp:100
+msgid "Chorus"
+msgstr "Sbor"
+
+#: gui/fluidsynth-dialog.cpp:104
+msgid "N:"
+msgstr "N:"
+
+#: gui/fluidsynth-dialog.cpp:118
+msgid "Speed:"
+msgstr "Rychlost:"
+
+#: gui/fluidsynth-dialog.cpp:125
+msgid "Depth:"
+msgstr "Hloubka:"
+
+#: gui/fluidsynth-dialog.cpp:132
+msgid "Type:"
+msgstr "Typ:"
+
+#: gui/fluidsynth-dialog.cpp:135
+msgid "Sine"
+msgstr "Sinus"
+
+#: gui/fluidsynth-dialog.cpp:136
+msgid "Triangle"
+msgstr "Trojúhrlník"
+
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
+msgid "Misc"
+msgstr "Rùzné"
+
+#: gui/fluidsynth-dialog.cpp:140
+msgid "Interpolation:"
+msgstr "Interpolace:"
+
+#: gui/fluidsynth-dialog.cpp:143
+msgid "None (fastest)"
+msgstr "®ádná (Nejrychlej¹í)"
+
+#: gui/fluidsynth-dialog.cpp:144
+msgid "Linear"
+msgstr "Lineární"
+
+#: gui/fluidsynth-dialog.cpp:145
+msgid "Fourth-order"
+msgstr "Interpolace ètvrtého øádu"
+
+#: gui/fluidsynth-dialog.cpp:146
+msgid "Seventh-order"
+msgstr "Interpolace sedmého øádu"
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset"
+msgstr "Resetovat"
+
+#: gui/fluidsynth-dialog.cpp:150
+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: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 "OK"
+
+#: gui/fluidsynth-dialog.cpp:217
+msgid ""
+"Do you really want to reset all FluidSynth settings to their default values?"
msgstr ""
+"Opravdu chcete resetovat ve¹kerá nastavení FluidSynth na jejich výchozí "
+"hodnoty?"
-#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
+#: 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 "Zavøít"
-#: gui/gui-manager.cpp:120
+#: gui/gui-manager.cpp:122
msgid "Mouse click"
msgstr "Kliknutí my¹í"
-#: gui/gui-manager.cpp:124 base/main.cpp:319
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Zobrazit klávesnici"
-#: gui/gui-manager.cpp:128 base/main.cpp:323
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Pøemapovat klávesy"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 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"
-#: gui/KeysDialog.h:36 gui/KeysDialog.cpp:145
-msgid "Choose an action to map"
-msgstr "Zvolte èinnost k mapování"
-
#: gui/KeysDialog.cpp:41
msgid "Map"
msgstr "Mapovat"
-#: gui/KeysDialog.cpp:42 gui/launcher.cpp:352 gui/launcher.cpp:1048
-#: gui/launcher.cpp:1052 gui/massadd.cpp:92 gui/options.cpp:1238
-#: gui/saveload-dialog.cpp:932 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:402 engines/engine.cpp:413
-#: 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/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 "OK"
-
#: gui/KeysDialog.cpp:49
msgid "Select an action and click 'Map'"
msgstr "Zvolte èinnost a kliknìte 'Mapovat'"
@@ -165,6 +282,10 @@ msgstr "Prosím vyberte èinnost"
msgid "Press the key to associate"
msgstr "Zmáèknìte klávesu pro pøiøazení"
+#: gui/KeysDialog.cpp:145 gui/KeysDialog.h:36
+msgid "Choose an action to map"
+msgstr "Zvolte èinnost k mapování"
+
#: gui/launcher.cpp:193
msgid "Game"
msgstr "Hra"
@@ -205,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í>"
@@ -228,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"
@@ -245,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"
@@ -258,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"
@@ -276,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:95
+#: 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:69
+#: 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:1222
+#: 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/myst.cpp:245 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/myst.cpp:245
-#: engines/mohawk/riven.cpp:718 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:792
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -493,59 +615,39 @@ msgstr ""
"Opravdu chcete spustit hromadnou detekci her? Toto by mohlo potenciálnì "
"pøidat velkou spoustu her. "
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Ano"
-
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Ne"
-
-#: gui/launcher.cpp:841
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM nemohl tento adresáø otevøít!"
-#: gui/launcher.cpp:853
+#: 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:867
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Vybrat hru:"
-#: gui/launcher.cpp:941
+#: 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:999
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "Chcete naèíst ulo¾enou pozici?"
-#: gui/launcher.cpp:1048
+#: 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:1052
+#: 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:1159
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Hromadné Pøidání..."
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr "Nahrát..."
@@ -574,148 +676,146 @@ msgstr "Objeveno %d nových her, ignorováno %d døíve pøidaných her ..."
#: gui/onscreendialog.cpp:101 gui/onscreendialog.cpp:103
msgid "Stop"
-msgstr ""
+msgstr "Zastavit"
#: gui/onscreendialog.cpp:106
msgid "Edit record description"
-msgstr ""
+msgstr "Upravit popis záznamu"
#: gui/onscreendialog.cpp:108
-#, fuzzy
msgid "Switch to Game"
-msgstr "Pøepnout"
+msgstr "Pøepnout do hry"
#: gui/onscreendialog.cpp:110
-#, fuzzy
msgid "Fast replay"
-msgstr "Rychlý re¾im"
+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:2298
+#: 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"
@@ -723,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"
@@ -790,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"
@@ -807,173 +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:1168 gui/fluidsynth-dialog.cpp:138
-msgid "Misc"
-msgstr "Rùzné"
-
-#: 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."
@@ -982,63 +1090,76 @@ msgstr ""
"tento vzhled pou¾ít, musíte nejdøíve pøepnout na jiný jazyk."
#. I18N: You must leave "#" as is, only word 'next' is translatable
-#: gui/predictivedialog.cpp:87
+#: gui/predictivedialog.cpp:86
msgid "# next"
-msgstr ""
+msgstr "# dal¹í"
-#: gui/predictivedialog.cpp:88
+#: gui/predictivedialog.cpp:87
msgid "add"
-msgstr ""
+msgstr "pøidat"
-#: gui/predictivedialog.cpp:92
-#, fuzzy
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
-msgstr "Smazat"
+msgstr "Smazat znak"
-#: gui/predictivedialog.cpp:96
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
-msgstr ""
+msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:98
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
-msgstr ""
+msgstr "* Prediktivní"
+
+#. I18N: 'Num' means Numbers
+#: gui/predictivedialog.cpp:578
+msgid "* Num"
+msgstr "* Èísla"
-#: gui/recorderdialog.cpp:64
+#. I18N: 'Abc' means Latin alphabet input
+#: gui/predictivedialog.cpp:581
+msgid "* Abc"
+msgstr "* Abc"
+
+#: 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:173
+msgid "Unknown Author"
+msgstr "Neznámý autor"
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr "Seznam"
@@ -1099,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:"
@@ -1108,151 +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:661
+#: 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
-msgid "Clear value"
-msgstr "Vyèistit hodnotu"
-
-#: gui/fluidsynth-dialog.cpp:68
-msgid "Reverb"
-msgstr "Dozvuk"
-
-#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
-msgid "Active"
-msgstr "Aktivní"
-
-#: gui/fluidsynth-dialog.cpp:72
-msgid "Room:"
-msgstr "Místnost:"
-
-#: gui/fluidsynth-dialog.cpp:79
-msgid "Damp:"
-msgstr "Tlumení:"
-
-#: gui/fluidsynth-dialog.cpp:86
-msgid "Width:"
-msgstr "©íøka:"
-
-#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
-msgid "Level:"
-msgstr "Úroveò:"
-
-#: gui/fluidsynth-dialog.cpp:100
-msgid "Chorus"
-msgstr "Sbor"
-
-#: gui/fluidsynth-dialog.cpp:104
-msgid "N:"
-msgstr "N:"
-
-#: gui/fluidsynth-dialog.cpp:118
-msgid "Speed:"
-msgstr "Rychlost:"
-
-#: gui/fluidsynth-dialog.cpp:125
-msgid "Depth:"
-msgstr "Hloubka:"
-
-#: gui/fluidsynth-dialog.cpp:132
-msgid "Type:"
-msgstr "Typ:"
-
-#: gui/fluidsynth-dialog.cpp:135
-msgid "Sine"
-msgstr "Sinus"
-
-#: gui/fluidsynth-dialog.cpp:136
-msgid "Triangle"
-msgstr "Trojúhrlník"
-
-#: gui/fluidsynth-dialog.cpp:140
-msgid "Interpolation:"
-msgstr "Interpolace:"
-
-#: gui/fluidsynth-dialog.cpp:143
-msgid "None (fastest)"
-msgstr "®ádná (Nejrychlej¹í)"
-
-#: gui/fluidsynth-dialog.cpp:144
-msgid "Linear"
-msgstr "Lineární"
-
-#: gui/fluidsynth-dialog.cpp:145
-msgid "Fourth-order"
-msgstr "Interpolace ètvrtého øádu"
-
-#: gui/fluidsynth-dialog.cpp:146
-msgid "Seventh-order"
-msgstr "Interpolace sedmého øádu"
+#: 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/fluidsynth-dialog.cpp:150
-msgid "Reset"
-msgstr "Resetovat"
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr ""
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset all FluidSynth settings to their default values."
-msgstr "Resetovat ve¹kerá nastavení FludSynth n ajejich výchozí hodnoty."
+#: gui/updates-dialog.cpp:92
+#, fuzzy
+msgid "Check for updates automatically"
+msgstr "Zkontrolovat Aktualizace..."
-#: gui/fluidsynth-dialog.cpp:217
-msgid ""
-"Do you really want to reset all FluidSynth settings to their default values?"
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
msgstr ""
-"Opravdu chcete resetovat ve¹kerá nastavení FluidSynth na jejich výchozí "
-"hodnoty?"
-#: base/main.cpp:228
+#: 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:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "Jádro nepodporuje úroveò ladìní '%s'"
-#: base/main.cpp:306
+#: base/main.cpp:315
msgid "Menu"
msgstr "Menu"
-#: base/main.cpp:309 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:312 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:315
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Pøeskoèit øádek"
-#: base/main.cpp:507
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Chyba pøi spu¹tìní hry:"
-#: base/main.cpp:554
+#: 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"
@@ -1320,16 +1375,60 @@ msgstr "Zru¹eno u¾ivatelem"
msgid "Unknown error"
msgstr "Neznámá chyba"
-#: engines/advancedDetector.cpp:317
+#. I18N: Hercules is graphics card name
+#: common/rendermode.cpp:35
+msgid "Hercules Green"
+msgstr "Hercules Zelená"
+
+#: common/rendermode.cpp:36
+msgid "Hercules Amber"
+msgstr "Hercules Jantarová"
+
+#: common/rendermode.cpp:42
+msgid "PC-9821 (256 Colors)"
+msgstr "PC-9821 (256 barev)"
+
+#: common/rendermode.cpp:43
+msgid "PC-9801 (16 Colors)"
+msgstr "PC-9801 (16 barev)"
+
+#: common/rendermode.cpp:73
+msgctxt "lowres"
+msgid "Hercules Green"
+msgstr "Hercules Zelená"
+
+#: common/rendermode.cpp:74
+msgctxt "lowres"
+msgid "Hercules Amber"
+msgstr "Hercules Jantarová"
+
+#: 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.:"
@@ -1337,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"
@@ -1366,11 +1465,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "~N~ávrat do Spou¹tìèe"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:803
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:873
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
-#: engines/toltecs/menu.cpp:281 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:"
@@ -1379,11 +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:803 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/neverhood/menumodule.cpp:873 engines/pegasus/pegasus.cpp:377
-#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
-#: engines/toltecs/menu.cpp:281 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"
@@ -1406,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"
@@ -1420,23 +1528,23 @@ msgstr "~Z~ru¹it"
msgid "~K~eys"
msgstr "~K~lávesy"
-#: engines/engine.cpp:276
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Nelze zavést barevný formát."
-#: engines/engine.cpp:284
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Nelze pøepnout na re¾im obrazu: '"
-#: engines/engine.cpp:293
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "Nelze pou¾ít nastavení pomìru stran."
-#: engines/engine.cpp:298
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Nelze pou¾ít nastavení celé obrazovky."
-#: engines/engine.cpp:398
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1450,7 +1558,7 @@ msgstr ""
"datové soubory na Vá¹ pevný disk.\n"
"Pro podrobnosti si pøeètìte README."
-#: engines/engine.cpp:409
+#: 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"
@@ -1464,7 +1572,7 @@ msgstr ""
"abyste mohli poslouchat hudbu ve høe.\n"
"Pro podrobnosti si pøeètìte README."
-#: engines/engine.cpp:467
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1473,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:480
+#: 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 "
@@ -1483,10 +1591,14 @@ 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:483
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Pøesto spustit"
+#: audio/adlib.cpp:2290
+msgid "AdLib Emulator"
+msgstr "AdLib Emulátor"
+
#: audio/fmopl.cpp:62
msgid "MAME OPL emulator"
msgstr "MAME OPL Emulátor"
@@ -1497,7 +1609,7 @@ msgstr "DOSBox OPL Emulátor"
#: audio/fmopl.cpp:67
msgid "ALSA Direct FM"
-msgstr ""
+msgstr "ALSA Pøímá FM"
#: audio/mididrv.cpp:209
#, c-format
@@ -1540,31 +1652,35 @@ msgstr ""
"Upøednostòované zvukové zaøízení '%s' nelze pou¾ít. Podívejte se na záznam "
"pro více informací."
-#: audio/null.h:44
-msgid "No music"
-msgstr "Bez hudby"
-
#: audio/mods/paula.cpp:196
msgid "Amiga Audio Emulator"
msgstr "Emulátor zvuku Amiga"
-#: audio/adlib.cpp:2291
-msgid "AdLib Emulator"
-msgstr "AdLib Emulátor"
+#: audio/null.h:44
+msgid "No music"
+msgstr "Bez hudby"
#: audio/softsynth/appleiigs.cpp:33
msgid "Apple II GS Emulator (NOT IMPLEMENTED)"
msgstr "Apple II GS Emulátor (NENÍ ZAVEDEN)"
-#: audio/softsynth/sid.cpp:1430
-msgid "C64 Audio Emulator"
-msgstr "Emulátor zvuku C64"
+#: audio/softsynth/cms.cpp:350
+msgid "Creative Music System Emulator"
+msgstr "Emulátor hudebního systému Creative"
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33
+msgid "FM-Towns Audio"
+msgstr "Zvuk FM-Towns"
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58
+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"
@@ -1576,6 +1692,146 @@ msgstr "PC Speaker Emulátor"
msgid "IBM PCjr Emulator"
msgstr "IBM PCjr Emulátor"
+#: audio/softsynth/sid.cpp:1430
+msgid "C64 Audio Emulator"
+msgstr "Emulátor zvuku C64"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Do you really want to return to the Launcher?"
+msgstr "Opravdu se chcete vrátit do Spou¹tìèe?"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Launcher"
+msgstr "Spou¹tìè"
+
+#: backends/events/default/default-events.cpp:218
+msgid "Do you really want to quit?"
+msgstr "Opravdu chcete skonèit?"
+
+#: 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 "Ukonèit"
+
+#: 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 "'Re¾im «uknutí' Dotykové Obrazovky - Levé Kliknutí"
+
+#: 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 "'Re¾im «uknutí' Dotykové Obrazovky - Pravé Kliknutí"
+
+#: 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 "'Re¾im «uknutí' Dotykové Obrazovky - Najetí (Bez Kliknutí)"
+
+#: backends/events/gph/gph-events.cpp:409
+msgid "Maximum Volume"
+msgstr "Maximální Hlasitost"
+
+#: backends/events/gph/gph-events.cpp:411
+msgid "Increasing Volume"
+msgstr "Zvy¹uji Hlasitost"
+
+#: backends/events/gph/gph-events.cpp:417
+msgid "Minimal Volume"
+msgstr "Minimální Hlasitost"
+
+#: backends/events/gph/gph-events.cpp:419
+msgid "Decreasing Volume"
+msgstr "Sni¾uji Hlasitost"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Enabled"
+msgstr "Kliknutí Povoleno"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Disabled"
+msgstr "Kliknutí Zakázáno"
+
+#: backends/events/openpandora/op-events.cpp:174
+msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
+msgstr "'Re¾im «uknutí' Dotykové Obrazovky - Najetí (Dpad kliká)"
+
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
+msgid "Do you want to quit ?"
+msgstr "Chcete ukonèit ?"
+
+#. I18N: Trackpad mode toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:308
+msgid "Trackpad mode is now"
+msgstr "Re¾im trackpadu je nyní"
+
+#. 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 "ZAPNUT"
+
+#: backends/events/webossdl/webossdl-events.cpp:311
+#: backends/events/webossdl/webossdl-events.cpp:338
+msgid "OFF"
+msgstr "VYPNUT"
+
+#: backends/events/webossdl/webossdl-events.cpp:315
+msgid "Swipe two fingers to the right to toggle."
+msgstr "Pro zapnutí pøejeïte dvìma prsty doprava."
+
+#. I18N: Auto-drag toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:335
+msgid "Auto-drag mode is now"
+msgstr "Re¾im automatického ta¾ení je nyní"
+
+#: backends/events/webossdl/webossdl-events.cpp:342
+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:126
+msgid "OpenGL"
+msgstr "OpenGL"
+
+#: backends/graphics/opengl/opengl-graphics.cpp:127
+msgid "OpenGL (No filtering)"
+msgstr "OpenGL (bez filtrování)"
+
+#: 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 "Normální (bez zmìny velikosti)"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:66
+msgctxt "lowres"
+msgid "Normal (no scaling)"
+msgstr "Normální (bez zmìny velikosti)"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
+msgid "Enabled aspect ratio correction"
+msgstr "Povolena korekce pomìru stran"
+
+#: 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:2274
+msgid "Active graphics filter:"
+msgstr "Aktivní grafický filtr:"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+msgid "Windowed mode"
+msgstr "Re¾im do okna"
+
#: backends/keymapper/remap-dialog.cpp:48
msgid "Keymap:"
msgstr "Mapa Kláves:"
@@ -1605,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"
@@ -1681,18 +1937,26 @@ msgstr "Vysoká kvalita zvuku (pomalej¹í) (restart) "
msgid "Disable power off"
msgstr "Zakázat vypnutí"
+#: 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 "Re¾im pøetáhnutí my¹i zapnut."
+#: 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 "Re¾im pøetáhnutí my¹i vypnut."
+#: 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 "Touchpad re¾im zapnut"
+#: 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 "Touchpad re¾im vypnut"
@@ -1703,9 +1967,9 @@ msgstr "Re¾im kliknutí"
#: 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
-#: backends/platform/tizen/form.cpp:275
msgid "Left Click"
msgstr "Levé Kliknutí"
@@ -1715,65 +1979,32 @@ msgstr "Kliknutí prostøedním tlaèítkem"
#: backends/platform/maemo/maemo.cpp:220
#: backends/platform/symbian/src/SymbianActions.cpp:43
-#: backends/platform/wince/CEActionsSmartphone.cpp:44
#: backends/platform/tizen/form.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:44
msgid "Right Click"
msgstr "Pravé kliknutí"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:77
+#: backends/platform/sdl/macosx/appmenu_osx.mm:88
msgid "Hide ScummVM"
msgstr "Skrýt ScummVM"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:82
+#: backends/platform/sdl/macosx/appmenu_osx.mm:93
msgid "Hide Others"
msgstr "Skrýt Ostatní"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:87
+#: backends/platform/sdl/macosx/appmenu_osx.mm:98
msgid "Show All"
msgstr "Zobrazit V¹e"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:109
#: backends/platform/sdl/macosx/appmenu_osx.mm:120
+#: backends/platform/sdl/macosx/appmenu_osx.mm:131
msgid "Window"
msgstr "Okno"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:114
+#: backends/platform/sdl/macosx/appmenu_osx.mm:125
msgid "Minimize"
msgstr "Minimalizovat"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:46
-msgid "Normal (no scaling)"
-msgstr "Normální (bez zmìny velikosti)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:65
-msgctxt "lowres"
-msgid "Normal (no scaling)"
-msgstr "Normální (bez zmìny velikosti)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
-msgid "Enabled aspect ratio correction"
-msgstr "Povolena korekce pomìru stran"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
-msgid "Disabled aspect ratio correction"
-msgstr "Zakázána korekce pomìru stran"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
-msgid "Active graphics filter:"
-msgstr "Aktivní grafický filtr:"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
-msgid "Windowed mode"
-msgstr "Re¾im do okna"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:118
-msgid "OpenGL"
-msgstr "OpenGL"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:119
-msgid "OpenGL (No filtering)"
-msgstr "OpenGL (bez filtrování)"
-
#: backends/platform/symbian/src/SymbianActions.cpp:38
#: backends/platform/wince/CEActionsSmartphone.cpp:39
msgid "Up"
@@ -1817,14 +2048,6 @@ msgstr "Pøeskoèit text"
msgid "Fast mode"
msgstr "Rychlý re¾im"
-#: backends/platform/symbian/src/SymbianActions.cpp:52
-#: backends/platform/wince/CEActionsPocket.cpp:44
-#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: backends/events/default/default-events.cpp:218 engines/scumm/dialogs.cpp:192
-#: engines/scumm/help.cpp:83 engines/scumm/help.cpp:85
-msgid "Quit"
-msgstr "Ukonèit"
-
#: backends/platform/symbian/src/SymbianActions.cpp:53
msgid "Debugger"
msgstr "Ladící program"
@@ -1841,9 +2064,49 @@ msgstr "Virtuální klávesnice"
msgid "Key mapper"
msgstr "Mapovaè kláves"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:186
-msgid "Do you want to quit ?"
-msgstr "Chcete ukonèit ?"
+#: backends/platform/tizen/form.cpp:263
+msgid "Right Click Once"
+msgstr "Pravé kliknutí jednou"
+
+#: backends/platform/tizen/form.cpp:271
+msgid "Move Only"
+msgstr "Pouze Pohyb"
+
+#: backends/platform/tizen/form.cpp:294
+msgid "Escape Key"
+msgstr "Klávesa Escape"
+
+#: backends/platform/tizen/form.cpp:299
+msgid "Game Menu"
+msgstr "Menu Hry"
+
+#: backends/platform/tizen/form.cpp:304
+msgid "Show Keypad"
+msgstr "Zobrazit Klávesnici"
+
+#: backends/platform/tizen/form.cpp:309
+msgid "Control Mouse"
+msgstr "Ovládání My¹i"
+
+#: backends/platform/tizen/fs.cpp:259
+msgid "[ Data ]"
+msgstr "[ Data ]"
+
+#: backends/platform/tizen/fs.cpp:263
+msgid "[ Resources ]"
+msgstr "[ Zdroje ]"
+
+#: backends/platform/tizen/fs.cpp:267
+msgid "[ SDCard ]"
+msgstr "[ SD Karta ]"
+
+#: backends/platform/tizen/fs.cpp:271
+msgid "[ Media ]"
+msgstr "[ Média ]"
+
+#: backends/platform/tizen/fs.cpp:275
+msgid "[ Shared ]"
+msgstr "[ Sdílené ]"
#: backends/platform/wii/options.cpp:51
msgid "Video"
@@ -2092,102 +2355,39 @@ msgstr ""
"Nezapomeòte namapovat klávesu k èinnosti 'Skrýt Panel Nástrojù, abyste "
"vidìli celý inventáø"
-#: backends/events/default/default-events.cpp:196
-msgid "Do you really want to return to the Launcher?"
-msgstr "Opravdu se chcete vrátit do Spou¹tìèe?"
-
-#: backends/events/default/default-events.cpp:196
-msgid "Launcher"
-msgstr "Spou¹tìè"
-
-#: backends/events/default/default-events.cpp:218
-msgid "Do you really want to quit?"
-msgstr "Opravdu chcete skonèit?"
-
-#: 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 "'Re¾im «uknutí' Dotykové Obrazovky - Levé Kliknutí"
-
-#: 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 "'Re¾im «uknutí' Dotykové Obrazovky - Pravé Kliknutí"
-
-#: 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 "'Re¾im «uknutí' Dotykové Obrazovky - Najetí (Bez Kliknutí)"
-
-#: backends/events/gph/gph-events.cpp:409
-msgid "Maximum Volume"
-msgstr "Maximální Hlasitost"
-
-#: backends/events/gph/gph-events.cpp:411
-msgid "Increasing Volume"
-msgstr "Zvy¹uji Hlasitost"
-
-#: backends/events/gph/gph-events.cpp:417
-msgid "Minimal Volume"
-msgstr "Minimální Hlasitost"
-
-#: backends/events/gph/gph-events.cpp:419
-msgid "Decreasing Volume"
-msgstr "Sni¾uji Hlasitost"
-
-#: backends/events/openpandora/op-events.cpp:174
-msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
-msgstr "'Re¾im «uknutí' Dotykové Obrazovky - Najetí (Dpad kliká)"
-
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Zkontrolovat Aktualizace..."
-#: backends/platform/tizen/form.cpp:263
-msgid "Right Click Once"
-msgstr "Pravé kliknutí jednou"
-
-#: backends/platform/tizen/form.cpp:271
-msgid "Move Only"
-msgstr "Pouze Pohyb"
-
-#: backends/platform/tizen/form.cpp:294
-msgid "Escape Key"
-msgstr "Klávesa Escape"
-
-#: backends/platform/tizen/form.cpp:299
-msgid "Game Menu"
-msgstr "Menu Hry"
-
-#: backends/platform/tizen/form.cpp:304
-msgid "Show Keypad"
-msgstr "Zobrazit Klávesnici"
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "Re¾im pro barvoslepé"
-#: backends/platform/tizen/form.cpp:309
-msgid "Control Mouse"
-msgstr "Ovládání My¹i"
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Enabled"
-msgstr "Kliknutí Povoleno"
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Disabled"
-msgstr "Kliknutí Zakázáno"
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "Zobrazit jmenovky objektù"
-#: engines/agi/detection.cpp:147 engines/drascula/detection.cpp:302
-#: engines/dreamweb/detection.cpp:47 engines/neverhood/detection.cpp:160
-#: engines/sci/detection.cpp:394 engines/toltecs/detection.cpp:200
-#: engines/zvision/detection_tables.h:51
+#: 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 "Pou¾ít pùvodní obrazovky naètení/ulo¾ení"
-#: engines/agi/detection.cpp:148 engines/drascula/detection.cpp:303
-#: engines/dreamweb/detection.cpp:48 engines/neverhood/detection.cpp:161
-#: engines/sci/detection.cpp:395 engines/toltecs/detection.cpp:201
+#: 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 "Pou¾ít pùvodní obrazovky naètení/ulo¾ení místo ze ScummVM"
@@ -2214,19 +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:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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"
@@ -2237,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"
@@ -2248,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"
@@ -2259,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'"
@@ -2290,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."
@@ -2320,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."
@@ -2493,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"
@@ -2544,15 +2781,25 @@ msgstr ""
"Nelze ulo¾it hru do pozice %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:194
+#, fuzzy
+msgid "Load file"
+msgstr "Nahrát hru:"
+
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Nahrávání hry..."
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:209
+#, fuzzy
+msgid "Save file"
+msgstr "Ukládání hry selhalo!"
+
+#: 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"
@@ -2568,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"
@@ -2628,28 +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:395
+msgid "Enable high resolution graphics/content"
+msgstr "Povolit grafiku/obsah ve vysokém rozli¹ení"
+
+#: 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:385
+#: 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:404
+#: 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:405
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2657,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:415
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "Pou¾ít zvuky na CD"
-#: engines/sci/detection.cpp:416
+#: 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:426
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Pou¾ít kurzory Windows"
-#: engines/sci/detection.cpp:427
+#: 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:437
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Pou¾ít støíbrné kurzory"
-#: engines/sci/detection.cpp:438
+#: 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:600
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Pouze Øeè"
-#: engines/scumm/dialogs.cpp:601
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Øeè a Titulky"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Pouze Titulky"
-#: engines/scumm/dialogs.cpp:610
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Øeè a Titulky"
-#: engines/scumm/dialogs.cpp:656
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Vyberte úroveò odbornosti."
-#: engines/scumm/dialogs.cpp:658
+#: 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:662
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Cvièení"
-#: engines/scumm/dialogs.cpp:663
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Pokroèilý"
@@ -3332,7 +3605,23 @@ msgstr "Letìt doprava"
msgid "Fly to lower right"
msgstr "Letìt doprava dolù"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/input.cpp:578
+msgid "Snap scroll on"
+msgstr "Pøichycení pøi posunování zapnuto"
+
+#: engines/scumm/input.cpp:580
+msgid "Snap scroll off"
+msgstr "Pøichycení pøi posunování zapnuto"
+
+#: engines/scumm/input.cpp:593
+msgid "Music volume: "
+msgstr "Hlasitost hudby:"
+
+#: engines/scumm/input.cpp:610
+msgid "Subtitle speed: "
+msgstr "Rychlost titulkù:"
+
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3341,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 "
@@ -3367,6 +3656,60 @@ msgstr ""
"Nelze najít spustitelný soubor 'Monkey Island' pro Macintosh z\n"
"jeho¾ mají být naèteny hudební nástroje. Hudba bude zakázána."
+#: engines/sherlock/detection.cpp:71
+#, fuzzy
+msgid "Use original savegame dialog"
+msgstr "Pou¾ít pùvodní obrazovky naètení/ulo¾ení"
+
+#: engines/sherlock/detection.cpp:72
+msgid ""
+"Files button in-game shows original savegame dialog rather than the ScummVM "
+"menu"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:81
+msgid "Pixellated scene transitions"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:82
+msgid "When changing scenes, a randomized pixel transition is done"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:91
+msgid "Don't show hotspots when moving mouse"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:92
+msgid ""
+"Only show hotspot names after you actually click on a hotspot or action "
+"button"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:101
+#, fuzzy
+msgid "Show character portraits"
+msgstr "Zamìnit znaky"
+
+#: engines/sherlock/detection.cpp:102
+msgid "Show portraits for the characters when conversing"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:111
+msgid "Slide dialogs into view"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:112
+msgid "Slide UI dialogs into view, rather than simply showing them immediately"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:121
+msgid "Transparent windows"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:122
+msgid "Show windows with a partially transparent background"
+msgstr ""
+
#: engines/sky/compact.cpp:130
msgid ""
"Unable to find \"sky.cpt\" file!\n"
@@ -3462,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"
@@ -3484,18 +3836,16 @@ msgid "Show the current number of frames per second in the upper left corner"
msgstr "Zobrazit souèasný poèet snímkù za sekundu v horním levém rohu"
#: engines/zvision/detection_tables.h:52
-#, fuzzy
msgid "Use the original save/load screens instead of the ScummVM interface"
-msgstr "Pou¾ít pùvodní obrazovky naètení/ulo¾ení místo ze ScummVM"
+msgstr "Pou¾ít pùvodní obrazovky naètení/ulo¾ení místo rozhraní ScummVM"
#: engines/zvision/detection_tables.h:61
msgid "Double FPS"
msgstr "Dvojité snímky za sekundu"
#: engines/zvision/detection_tables.h:62
-#, fuzzy
msgid "Increase framerate from 30 to 60 FPS"
-msgstr "Zvý¹it herní snímky za sekundu z 30 na 60"
+msgstr "Zvý¹it snímkovou frekvenci z 30 na 60"
#: engines/zvision/detection_tables.h:71
msgid "Enable Venus"
@@ -3510,21 +3860,18 @@ msgid "Disable animation while turning"
msgstr "Zakázat animaci pøi otáèení"
#: engines/zvision/detection_tables.h:82
-#, fuzzy
msgid "Disable animation while turning in panorama mode"
msgstr "Zakázat animaci pøi otáèení v panoramatickém re¾imu"
#: engines/zvision/detection_tables.h:91
-#, fuzzy
msgid "Use high resolution MPEG video"
-msgstr "Pou¾ít videa MPEG ve vysokém rozli¹ení"
+msgstr "Pou¾ít video MPEG ve vysokém rozli¹ení"
#: engines/zvision/detection_tables.h:92
-#, fuzzy
msgid "Use MPEG video from the DVD version, instead of lower resolution AVI"
msgstr ""
-"Pou¾ít videa MPEG ve vysokém rozli¹ení pocházející z DVD verze, namísto "
-"videí AVI v nízkém rozli¹ení."
+"Pou¾ít video MPEG pocházející z DVD verze, namísto videa AVI v nízkém "
+"rozli¹ení."
#~ msgid "EGA undithering"
#~ msgstr "Nerozkládání EGA"
@@ -3586,26 +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"
-
-#~ msgid "Hercules Green"
-#~ msgstr "Hercules Zelená"
-
-#~ msgid "Hercules Amber"
-#~ msgstr "Hercules Jantarová"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Green"
-#~ msgstr "Hercules Zelená"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Amber"
-#~ msgstr "Hercules Jantarová"
-
-#~ msgid "Save game failed!"
-#~ msgstr "Ukládání hry selhalo!"
-
#~ msgctxt "lowres"
#~ msgid "Add Game..."
#~ msgstr "Pøidat Hru..."
diff --git a/po/da_DA.po b/po/da_DK.po
index 8556dd7734..38bbf29ada 100644
--- a/po/da_DA.po
+++ b/po/da_DK.po
@@ -1,5 +1,5 @@
# Dansk translation for ScummVM
-# Copyright (C) 2010-2015 The ScummVM Team
+# Copyright (C) 2010-2016 The ScummVM Team
# This file is distributed under the same license as the ScummVM package.
# Steffen Nyeland <steffen@nyeland.dk>, 2010.
#
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.3.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2015-09-06 15:14+0200\n"
-"PO-Revision-Date: 2014-07-09 17:34+0100\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"
"Language: Dansk\n"
@@ -53,28 +53,29 @@ msgid "Go up"
msgstr "Gå op"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:74 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: 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/fluidsynth-dialog.cpp:152 engines/engine.cpp:483
-#: backends/platform/wii/options.cpp:48
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
-#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:191 engines/sword1/control.cpp:865
+#: 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 "Fortryd"
#: gui/browser.cpp:76 gui/browser_osx.mm:103 gui/chooser.cpp:47
-#: gui/themebrowser.cpp:56
+#: gui/filebrowser-dialog.cpp:65 gui/themebrowser.cpp:56
msgid "Choose"
msgstr "Vælg"
#: gui/editrecorddialog.cpp:58
msgid "Author:"
-msgstr ""
+msgstr "Forfatter:"
#: gui/editrecorddialog.cpp:59 gui/launcher.cpp:204
msgid "Name:"
@@ -82,63 +83,181 @@ msgstr "Navn:"
#: gui/editrecorddialog.cpp:60
msgid "Notes:"
-msgstr ""
+msgstr "Noter:"
-#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:75
+#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74
msgid "Ok"
+msgstr "OK"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Choose file for loading"
+msgstr "Vælg fil til indlæsning"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Enter filename for saving"
+msgstr "Indtast filnavn til at gemme"
+
+#: gui/filebrowser-dialog.cpp:132
+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: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 "Ja"
+
+#: 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 "Nej"
+
+#: gui/fluidsynth-dialog.cpp:68
+msgid "Reverb"
+msgstr "Rumklang"
+
+#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
+msgid "Active"
+msgstr "Aktiv"
+
+#: gui/fluidsynth-dialog.cpp:72
+msgid "Room:"
+msgstr "Rum:"
+
+#: gui/fluidsynth-dialog.cpp:79
+msgid "Damp:"
+msgstr "Dæmp:"
+
+#: gui/fluidsynth-dialog.cpp:86
+msgid "Width:"
+msgstr "Bredde:"
+
+#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
+msgid "Level:"
+msgstr "Styrke:"
+
+#: gui/fluidsynth-dialog.cpp:100
+msgid "Chorus"
+msgstr "Kor"
+
+#: gui/fluidsynth-dialog.cpp:104
+msgid "N:"
+msgstr "N:"
+
+#: gui/fluidsynth-dialog.cpp:118
+msgid "Speed:"
+msgstr "Hastighed:"
+
+#: gui/fluidsynth-dialog.cpp:125
+msgid "Depth:"
+msgstr "Dybde:"
+
+#: gui/fluidsynth-dialog.cpp:132
+msgid "Type:"
+msgstr "Type:"
+
+#: gui/fluidsynth-dialog.cpp:135
+msgid "Sine"
+msgstr "Sinus"
+
+#: gui/fluidsynth-dialog.cpp:136
+msgid "Triangle"
+msgstr "Triangulær"
+
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
+msgid "Misc"
+msgstr "Andet"
+
+#: gui/fluidsynth-dialog.cpp:140
+msgid "Interpolation:"
+msgstr "Interpolation:"
+
+#: gui/fluidsynth-dialog.cpp:143
+msgid "None (fastest)"
+msgstr "Ingen (hurtigst)"
+
+#: gui/fluidsynth-dialog.cpp:144
+msgid "Linear"
+msgstr "Lineær"
+
+#: gui/fluidsynth-dialog.cpp:145
+msgid "Fourth-order"
+msgstr "Fjerde-orden"
+
+#: gui/fluidsynth-dialog.cpp:146
+msgid "Seventh-order"
+msgstr "Syvende-orden"
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset"
+msgstr "Nulstil"
+
+#: gui/fluidsynth-dialog.cpp:150
+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: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 "OK"
+
+#: gui/fluidsynth-dialog.cpp:217
+msgid ""
+"Do you really want to reset all FluidSynth settings to their default values?"
msgstr ""
+"Vil du virkelig nulstille alle FluidSynth indstillinger til deres standard "
+"værdier?"
-#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
+#: 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 "Luk"
-#: gui/gui-manager.cpp:120
+#: gui/gui-manager.cpp:122
msgid "Mouse click"
msgstr "Muse klik"
-#: gui/gui-manager.cpp:124 base/main.cpp:319
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Vis tastatur"
-#: gui/gui-manager.cpp:128 base/main.cpp:323
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Kortlæg taster"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 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"
-#: gui/KeysDialog.h:36 gui/KeysDialog.cpp:145
-msgid "Choose an action to map"
-msgstr "Vælg en handling at kortlægge"
-
#: gui/KeysDialog.cpp:41
msgid "Map"
msgstr "Kortlæg"
-#: gui/KeysDialog.cpp:42 gui/launcher.cpp:352 gui/launcher.cpp:1048
-#: gui/launcher.cpp:1052 gui/massadd.cpp:92 gui/options.cpp:1238
-#: gui/saveload-dialog.cpp:932 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:402 engines/engine.cpp:413
-#: 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/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 "OK"
-
#: gui/KeysDialog.cpp:49
msgid "Select an action and click 'Map'"
msgstr "Vælg en handling og klik 'Kortlæg'"
@@ -161,6 +280,10 @@ msgstr "Vælg venligst en handling"
msgid "Press the key to associate"
msgstr "Tryk tasten for at tilknytte"
+#: gui/KeysDialog.cpp:145 gui/KeysDialog.h:36
+msgid "Choose an action to map"
+msgstr "Vælg en handling at kortlægge"
+
#: gui/launcher.cpp:193
msgid "Game"
msgstr "Spil"
@@ -203,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>"
@@ -226,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"
@@ -243,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"
@@ -256,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"
@@ -274,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:95
+#: 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:69
+#: 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:1222
+#: 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/myst.cpp:245 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/myst.cpp:245
-#: engines/mohawk/riven.cpp:718 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:792
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -491,62 +615,42 @@ msgstr ""
"Vil du virkelig køre fler spils detektoren? Dette kunne potentielt tilføje "
"et stort antal spil."
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Ja"
-
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Nej"
-
-#: gui/launcher.cpp:841
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM kunne ikke åbne det angivne bibliotek!"
-#: gui/launcher.cpp:853
+#: 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:867
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Vælg spillet:"
-#: gui/launcher.cpp:941
+#: 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:999
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "Vil du indlæse gemmer?"
-#: gui/launcher.cpp:1048
+#: 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:1052
+#: 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:1159
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Tilføj flere..."
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1165
msgid "Record..."
-msgstr ""
+msgstr "Optag..."
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
@@ -573,148 +677,146 @@ msgstr "Fundet %d nye spil, ignorer %d tidligere tilføjede spil ..."
#: gui/onscreendialog.cpp:101 gui/onscreendialog.cpp:103
msgid "Stop"
-msgstr ""
+msgstr "Stop"
#: gui/onscreendialog.cpp:106
msgid "Edit record description"
-msgstr ""
+msgstr "Ret optag beskrivelse"
#: gui/onscreendialog.cpp:108
-#, fuzzy
msgid "Switch to Game"
-msgstr "Skift"
+msgstr "Skift til Spil"
#: gui/onscreendialog.cpp:110
-#, fuzzy
msgid "Fast replay"
-msgstr "Hurtig tilstand"
+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:2298
+#: 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"
@@ -722,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"
@@ -787,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"
@@ -804,173 +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:1168 gui/fluidsynth-dialog.cpp:138
-msgid "Misc"
-msgstr "Andet"
-
-#: 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."
@@ -979,64 +1089,75 @@ msgstr ""
"bruge dette tema, skal du skifte til et andet sprog først."
#. I18N: You must leave "#" as is, only word 'next' is translatable
-#: gui/predictivedialog.cpp:87
+#: gui/predictivedialog.cpp:86
msgid "# next"
-msgstr ""
+msgstr "# næste"
-#: gui/predictivedialog.cpp:88
+#: gui/predictivedialog.cpp:87
msgid "add"
-msgstr ""
+msgstr "tilføj"
-#: gui/predictivedialog.cpp:92
-#, fuzzy
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
-msgstr "Slet"
+msgstr "Slet tegn"
-#: gui/predictivedialog.cpp:96
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
-msgstr ""
+msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:98
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
-msgstr ""
+msgstr "* Præ"
+
+#. I18N: 'Num' means Numbers
+#: gui/predictivedialog.cpp:578
+msgid "* Num"
+msgstr "* Num"
-#: gui/recorderdialog.cpp:64
+#. I18N: 'Abc' means Latin alphabet input
+#: gui/predictivedialog.cpp:581
+msgid "* Abc"
+msgstr "* Abc"
+
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
-msgstr ""
+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 ""
+msgstr "Optag"
-#: gui/recorderdialog.cpp:72
-#, fuzzy
+#: gui/recorderdialog.cpp:71
msgid "Playback"
-msgstr "Spil"
+msgstr "Afspil"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
-msgstr ""
+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 ""
+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 ""
+msgstr "Noter: "
-#: gui/recorderdialog.cpp:155
-#, fuzzy
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
-msgstr "Vil du virkelig slette denne gemmer?"
+msgstr "Vil du virkelig slette denne optagelse?"
+
+#: gui/recorderdialog.cpp:173
+msgid "Unknown Author"
+msgstr "Ukendt forfatter"
#: gui/saveload-dialog.cpp:167
msgid "List view"
@@ -1098,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:"
@@ -1107,151 +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:661
+#: 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
-msgid "Clear value"
-msgstr "Slet værdi"
-
-#: gui/fluidsynth-dialog.cpp:68
-msgid "Reverb"
-msgstr "Rumklang"
-
-#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
-msgid "Active"
-msgstr "Aktiv"
-
-#: gui/fluidsynth-dialog.cpp:72
-msgid "Room:"
-msgstr "Rum:"
-
-#: gui/fluidsynth-dialog.cpp:79
-msgid "Damp:"
-msgstr "Dæmp:"
-
-#: gui/fluidsynth-dialog.cpp:86
-msgid "Width:"
-msgstr "Bredde:"
-
-#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
-msgid "Level:"
-msgstr "Styrke:"
-
-#: gui/fluidsynth-dialog.cpp:100
-msgid "Chorus"
-msgstr "Kor"
-
-#: gui/fluidsynth-dialog.cpp:104
-msgid "N:"
-msgstr "N:"
-
-#: gui/fluidsynth-dialog.cpp:118
-msgid "Speed:"
-msgstr "Hastighed:"
-
-#: gui/fluidsynth-dialog.cpp:125
-msgid "Depth:"
-msgstr "Dybde:"
-
-#: gui/fluidsynth-dialog.cpp:132
-msgid "Type:"
-msgstr "Type:"
-
-#: gui/fluidsynth-dialog.cpp:135
-msgid "Sine"
-msgstr "Sinus"
-
-#: gui/fluidsynth-dialog.cpp:136
-msgid "Triangle"
-msgstr "Triangulær"
-
-#: gui/fluidsynth-dialog.cpp:140
-msgid "Interpolation:"
-msgstr "Interpolation:"
-
-#: gui/fluidsynth-dialog.cpp:143
-msgid "None (fastest)"
-msgstr "Ingen (hurtigst)"
-
-#: gui/fluidsynth-dialog.cpp:144
-msgid "Linear"
-msgstr "Lineær"
-
-#: gui/fluidsynth-dialog.cpp:145
-msgid "Fourth-order"
-msgstr "Fjerde-orden"
-
-#: gui/fluidsynth-dialog.cpp:146
-msgid "Seventh-order"
-msgstr "Syvende-orden"
+#: 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/fluidsynth-dialog.cpp:150
-msgid "Reset"
-msgstr "Nulstil"
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr ""
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset all FluidSynth settings to their default values."
-msgstr "Nulstil alle FluidSynth indstillinger til deres standard værdier."
+#: gui/updates-dialog.cpp:92
+#, fuzzy
+msgid "Check for updates automatically"
+msgstr "Søg efter opdateringer..."
-#: gui/fluidsynth-dialog.cpp:217
-msgid ""
-"Do you really want to reset all FluidSynth settings to their default values?"
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
msgstr ""
-"Vil du virkelig nulstille alle FluidSynth indstillinger til deres standard "
-"værdier?"
-#: base/main.cpp:228
+#: 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:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "Motor understøtter ikke fejlfindingsniveau '%s'"
-#: base/main.cpp:306
+#: base/main.cpp:315
msgid "Menu"
msgstr "Menu"
-#: base/main.cpp:309 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:312 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:315
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Spring linje over"
-#: base/main.cpp:507
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Fejl ved kørsel af spil:"
-#: base/main.cpp:554
+#: 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"
@@ -1319,17 +1374,61 @@ msgstr "Bruger annullerede"
msgid "Unknown error"
msgstr "Ukendt fejl"
-#: engines/advancedDetector.cpp:317
+#. I18N: Hercules is graphics card name
+#: common/rendermode.cpp:35
+msgid "Hercules Green"
+msgstr "Hercules grøn"
+
+#: common/rendermode.cpp:36
+msgid "Hercules Amber"
+msgstr "Hercules brun"
+
+#: common/rendermode.cpp:42
+msgid "PC-9821 (256 Colors)"
+msgstr "PC-9821 (256 Farver)"
+
+#: common/rendermode.cpp:43
+msgid "PC-9801 (16 Colors)"
+msgstr "PC-9801 (16 Farver)"
+
+#: common/rendermode.cpp:73
+msgctxt "lowres"
+msgid "Hercules Green"
+msgstr "Hercules grøn"
+
+#: common/rendermode.cpp:74
+msgctxt "lowres"
+msgid "Hercules Amber"
+msgstr "Hercules brun"
+
+#: 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.:"
@@ -1337,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"
@@ -1366,11 +1465,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "~R~etur til oversigt"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:803
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:873
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
-#: engines/toltecs/menu.cpp:281 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:"
@@ -1379,11 +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:803 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/neverhood/menumodule.cpp:873 engines/pegasus/pegasus.cpp:377
-#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
-#: engines/toltecs/menu.cpp:281 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"
@@ -1406,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"
@@ -1420,23 +1528,23 @@ msgstr "~F~ortryd"
msgid "~K~eys"
msgstr "~T~aster"
-#: engines/engine.cpp:276
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Kunne ikke initialisere farveformat."
-#: engines/engine.cpp:284
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Kunne ikke skifte til videotilstand: '"
-#: engines/engine.cpp:293
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "Kunne ikke anvende billedformat korrektion indstilling."
-#: engines/engine.cpp:298
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Kunne ikke anvende fuldskærm indstilling."
-#: engines/engine.cpp:398
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1450,7 +1558,7 @@ msgstr ""
"datafiler til din harddisk i stedet.\n"
"Se README fil for detaljer."
-#: engines/engine.cpp:409
+#: 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"
@@ -1464,7 +1572,7 @@ msgstr ""
"for at lytte til spillets musik.\n"
"Se README fil for detaljer."
-#: engines/engine.cpp:467
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1474,7 +1582,7 @@ msgstr ""
"grundlæggende oplysninger, og for at få instruktioner om, hvordan man får "
"yderligere hjælp."
-#: engines/engine.cpp:480
+#: 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 "
@@ -1484,10 +1592,14 @@ 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:483
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Start alligevel"
+#: audio/adlib.cpp:2290
+msgid "AdLib Emulator"
+msgstr "AdLib emulator"
+
#: audio/fmopl.cpp:62
msgid "MAME OPL emulator"
msgstr "MAME OPL emulator"
@@ -1498,7 +1610,7 @@ msgstr "DOSBox OPL emulator"
#: audio/fmopl.cpp:67
msgid "ALSA Direct FM"
-msgstr ""
+msgstr "ALSA Direct FM"
#: audio/mididrv.cpp:209
#, c-format
@@ -1540,31 +1652,35 @@ msgstr ""
"Den foretrukne lydenhed '%s' kan ikke bruges. Se log filen for mere "
"information."
-#: audio/null.h:44
-msgid "No music"
-msgstr "Ingen musik"
-
#: audio/mods/paula.cpp:196
msgid "Amiga Audio Emulator"
msgstr "Amiga lyd emulator"
-#: audio/adlib.cpp:2291
-msgid "AdLib Emulator"
-msgstr "AdLib emulator"
+#: audio/null.h:44
+msgid "No music"
+msgstr "Ingen musik"
#: audio/softsynth/appleiigs.cpp:33
msgid "Apple II GS Emulator (NOT IMPLEMENTED)"
msgstr "Apple II GS emulator (IKKE IMPLEMENTERET)"
-#: audio/softsynth/sid.cpp:1430
-msgid "C64 Audio Emulator"
-msgstr "C64 lyd emulator"
+#: audio/softsynth/cms.cpp:350
+msgid "Creative Music System Emulator"
+msgstr "Creative Music System Emulator"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33
+msgid "FM-Towns Audio"
+msgstr "FM Towns lyd"
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58
+msgid "PC-98 Audio"
+msgstr "PC-98 lyd"
+
+#: 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"
@@ -1576,6 +1692,146 @@ msgstr "PC Speaker emulator"
msgid "IBM PCjr Emulator"
msgstr "IBM PCjr emulator"
+#: audio/softsynth/sid.cpp:1430
+msgid "C64 Audio Emulator"
+msgstr "C64 lyd emulator"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Do you really want to return to the Launcher?"
+msgstr "Vil du virkelig gå tilbage til oversigten?"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Launcher"
+msgstr "Oversigt"
+
+#: backends/events/default/default-events.cpp:218
+msgid "Do you really want to quit?"
+msgstr "Vil du virkelig afslutte?"
+
+#: 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 "Afslut"
+
+#: 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 "Touchscreen 'Tap Mode' - Venstre Klik"
+
+#: 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 "Touchscreen 'Tap Mode' - Højre Klik"
+
+#: 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 "Touchscreen 'Tap Mode' - Henover (Ingen Klik)"
+
+#: backends/events/gph/gph-events.cpp:409
+msgid "Maximum Volume"
+msgstr "Maximal lydstyrke"
+
+#: backends/events/gph/gph-events.cpp:411
+msgid "Increasing Volume"
+msgstr "Hæver lydstyrke"
+
+#: backends/events/gph/gph-events.cpp:417
+msgid "Minimal Volume"
+msgstr "Minimal lydstyrke"
+
+#: backends/events/gph/gph-events.cpp:419
+msgid "Decreasing Volume"
+msgstr "Sænker lydstyrke"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Enabled"
+msgstr "Klik aktiveret"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Disabled"
+msgstr "Klik deaktiveret"
+
+#: backends/events/openpandora/op-events.cpp:174
+msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
+msgstr "Touchscreen 'Tap Mode' - Henover (DPad Klik)"
+
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
+msgid "Do you want to quit ?"
+msgstr "Vil du afslutte?"
+
+#. I18N: Trackpad mode toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:308
+msgid "Trackpad mode is now"
+msgstr "Pegeplade-tilstand er nu"
+
+#. 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 "TIL"
+
+#: backends/events/webossdl/webossdl-events.cpp:311
+#: backends/events/webossdl/webossdl-events.cpp:338
+msgid "OFF"
+msgstr "FRA"
+
+#: backends/events/webossdl/webossdl-events.cpp:315
+msgid "Swipe two fingers to the right to toggle."
+msgstr "Før to fingre til højre for at skifte."
+
+#. I18N: Auto-drag toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:335
+msgid "Auto-drag mode is now"
+msgstr "Auto-træk tilstand er nu"
+
+#: backends/events/webossdl/webossdl-events.cpp:342
+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:126
+msgid "OpenGL"
+msgstr "OpenGL"
+
+#: backends/graphics/opengl/opengl-graphics.cpp:127
+msgid "OpenGL (No filtering)"
+msgstr "OpenGL (Ingen filtrering)"
+
+#: 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 "Normal (ingen skalering)"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:66
+msgctxt "lowres"
+msgid "Normal (no scaling)"
+msgstr "Normal (ingen skalering)"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
+msgid "Enabled aspect ratio correction"
+msgstr "Aktivér billedformat korrektion"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
+msgid "Disabled aspect ratio correction"
+msgstr "Deaktivér billedformat korrektion"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
+msgid "Active graphics filter:"
+msgstr "Aktive grafik filtre:"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+msgid "Windowed mode"
+msgstr "Vindue tilstand"
+
#: backends/keymapper/remap-dialog.cpp:48
msgid "Keymap:"
msgstr "Tasteoversigt:"
@@ -1605,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"
@@ -1681,18 +1937,26 @@ msgstr "Høj lydkvalitet (langsommere) (genstart)"
msgid "Disable power off"
msgstr "Deaktiver slukning"
+#: 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 "Muse-klik-og-træk tilstand aktiveret."
+#: 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 "Muse-klik-og-træk tilstand deaktiveret."
+#: 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 "Pegeplade tilstand aktiveret."
+#: 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 "Pegeplade tilstand deaktiveret."
@@ -1703,9 +1967,9 @@ msgstr "Klik tilstand"
#: 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
-#: backends/platform/tizen/form.cpp:275
msgid "Left Click"
msgstr "Venstre klik"
@@ -1715,65 +1979,32 @@ msgstr "Miderste klik"
#: backends/platform/maemo/maemo.cpp:220
#: backends/platform/symbian/src/SymbianActions.cpp:43
-#: backends/platform/wince/CEActionsSmartphone.cpp:44
#: backends/platform/tizen/form.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:44
msgid "Right Click"
msgstr "Højre klik"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:77
+#: backends/platform/sdl/macosx/appmenu_osx.mm:88
msgid "Hide ScummVM"
msgstr "Skjul ScummVM"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:82
+#: backends/platform/sdl/macosx/appmenu_osx.mm:93
msgid "Hide Others"
msgstr "Skjul andre"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:87
+#: backends/platform/sdl/macosx/appmenu_osx.mm:98
msgid "Show All"
msgstr "Vis alle"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:109
#: backends/platform/sdl/macosx/appmenu_osx.mm:120
+#: backends/platform/sdl/macosx/appmenu_osx.mm:131
msgid "Window"
msgstr "Vindue"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:114
+#: backends/platform/sdl/macosx/appmenu_osx.mm:125
msgid "Minimize"
msgstr "Minimer"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:46
-msgid "Normal (no scaling)"
-msgstr "Normal (ingen skalering)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:65
-msgctxt "lowres"
-msgid "Normal (no scaling)"
-msgstr "Normal (ingen skalering)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
-msgid "Enabled aspect ratio correction"
-msgstr "Aktivér billedformat korrektion"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
-msgid "Disabled aspect ratio correction"
-msgstr "Deaktivér billedformat korrektion"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
-msgid "Active graphics filter:"
-msgstr "Aktive grafik filtre:"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
-msgid "Windowed mode"
-msgstr "Vindue tilstand"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:118
-msgid "OpenGL"
-msgstr "OpenGL"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:119
-msgid "OpenGL (No filtering)"
-msgstr "OpenGL (Ingen filtrering)"
-
#: backends/platform/symbian/src/SymbianActions.cpp:38
#: backends/platform/wince/CEActionsSmartphone.cpp:39
msgid "Up"
@@ -1817,14 +2048,6 @@ msgstr "Spring tekst over"
msgid "Fast mode"
msgstr "Hurtig tilstand"
-#: backends/platform/symbian/src/SymbianActions.cpp:52
-#: backends/platform/wince/CEActionsPocket.cpp:44
-#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: backends/events/default/default-events.cpp:218 engines/scumm/dialogs.cpp:192
-#: engines/scumm/help.cpp:83 engines/scumm/help.cpp:85
-msgid "Quit"
-msgstr "Afslut"
-
#: backends/platform/symbian/src/SymbianActions.cpp:53
msgid "Debugger"
msgstr "Fejlsøger"
@@ -1841,9 +2064,49 @@ msgstr "Virtuelt tastatur"
msgid "Key mapper"
msgstr "Tastetildeling"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:186
-msgid "Do you want to quit ?"
-msgstr "Vil du afslutte?"
+#: backends/platform/tizen/form.cpp:263
+msgid "Right Click Once"
+msgstr "Enkelt højre klik"
+
+#: backends/platform/tizen/form.cpp:271
+msgid "Move Only"
+msgstr "Flyt kun"
+
+#: backends/platform/tizen/form.cpp:294
+msgid "Escape Key"
+msgstr "Escape tast"
+
+#: backends/platform/tizen/form.cpp:299
+msgid "Game Menu"
+msgstr "Spil menu"
+
+#: backends/platform/tizen/form.cpp:304
+msgid "Show Keypad"
+msgstr "Vis tastatur"
+
+#: backends/platform/tizen/form.cpp:309
+msgid "Control Mouse"
+msgstr "Kontrollér mus"
+
+#: backends/platform/tizen/fs.cpp:259
+msgid "[ Data ]"
+msgstr "[ Data ]"
+
+#: backends/platform/tizen/fs.cpp:263
+msgid "[ Resources ]"
+msgstr "[ Ressourcer ]"
+
+#: backends/platform/tizen/fs.cpp:267
+msgid "[ SDCard ]"
+msgstr "[ SDKort ]"
+
+#: backends/platform/tizen/fs.cpp:271
+msgid "[ Media ]"
+msgstr "[ Medie ]"
+
+#: backends/platform/tizen/fs.cpp:275
+msgid "[ Shared ]"
+msgstr "[ Delt ]"
#: backends/platform/wii/options.cpp:51
msgid "Video"
@@ -2091,139 +2354,105 @@ msgstr ""
"Glem ikke at tildele en tast til 'Skjul værktøjslinje' handling for at se "
"hele oversigten"
-#: backends/events/default/default-events.cpp:196
-msgid "Do you really want to return to the Launcher?"
-msgstr "Vil du virkelig gå tilbage til oversigten?"
-
-#: backends/events/default/default-events.cpp:196
-msgid "Launcher"
-msgstr "Oversigt"
-
-#: backends/events/default/default-events.cpp:218
-msgid "Do you really want to quit?"
-msgstr "Vil du virkelig afslutte?"
-
-#: 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 "Touchscreen 'Tap Mode' - Venstre Klik"
-
-#: 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 "Touchscreen 'Tap Mode' - Højre Klik"
-
-#: 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 "Touchscreen 'Tap Mode' - Henover (Ingen Klik)"
-
-#: backends/events/gph/gph-events.cpp:409
-msgid "Maximum Volume"
-msgstr "Maximal lydstyrke"
-
-#: backends/events/gph/gph-events.cpp:411
-msgid "Increasing Volume"
-msgstr "Hæver lydstyrke"
-
-#: backends/events/gph/gph-events.cpp:417
-msgid "Minimal Volume"
-msgstr "Minimal lydstyrke"
-
-#: backends/events/gph/gph-events.cpp:419
-msgid "Decreasing Volume"
-msgstr "Sænker lydstyrke"
-
-#: backends/events/openpandora/op-events.cpp:174
-msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
-msgstr "Touchscreen 'Tap Mode' - Henover (DPad Klik)"
-
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Søg efter opdateringer..."
-#: backends/platform/tizen/form.cpp:263
-msgid "Right Click Once"
-msgstr "Enkelt højre klik"
-
-#: backends/platform/tizen/form.cpp:271
-msgid "Move Only"
-msgstr "Flyt kun"
-
-#: backends/platform/tizen/form.cpp:294
-msgid "Escape Key"
-msgstr "Escape tast"
-
-#: backends/platform/tizen/form.cpp:299
-msgid "Game Menu"
-msgstr "Spil menu"
-
-#: backends/platform/tizen/form.cpp:304
-msgid "Show Keypad"
-msgstr "Vis tastatur"
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "Farveblind-tilstand"
-#: backends/platform/tizen/form.cpp:309
-msgid "Control Mouse"
-msgstr "Kontrollér mus"
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Enabled"
-msgstr "Klik aktiveret"
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Disabled"
-msgstr "Klik deaktiveret"
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "Vis labels på genstande"
-#: engines/agi/detection.cpp:147 engines/drascula/detection.cpp:302
-#: engines/dreamweb/detection.cpp:47 engines/neverhood/detection.cpp:160
-#: engines/sci/detection.cpp:394 engines/toltecs/detection.cpp:200
-#: engines/zvision/detection_tables.h:51
+#: 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 "Brug original gem/indlæs skærme"
-#: engines/agi/detection.cpp:148 engines/drascula/detection.cpp:303
-#: engines/dreamweb/detection.cpp:48 engines/neverhood/detection.cpp:161
-#: engines/sci/detection.cpp:395 engines/toltecs/detection.cpp:201
+#: 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 "Brug de originale gem/indlæs skærme, istedet for dem fra ScummVM"
#: engines/agi/detection.cpp:157
-#, fuzzy
msgid "Use an alternative palette"
-msgstr "Brug en alternativ spil intro (kun CD version)"
+msgstr "Brug en alternativ palette"
#: engines/agi/detection.cpp:158
msgid ""
"Use an alternative palette, common for all Amiga games. This was the old "
"behavior"
msgstr ""
+"Brug en alternativ palet, fælles for alle Amiga spil. Dette var den gamle "
+"adfærd"
#: engines/agi/detection.cpp:167
-#, fuzzy
msgid "Mouse support"
-msgstr "Spring over støtte"
+msgstr "Understøt mus"
#: engines/agi/detection.cpp:168
msgid ""
"Enables mouse support. Allows to use mouse for movement and in game menus."
msgstr ""
+"Aktivér muse support. Gør det muligt at bruge musen til bevægelse og i spil "
+"menuer."
-#: engines/agi/saveload.cpp:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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"
@@ -2234,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"
@@ -2245,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"
@@ -2256,19 +2485,18 @@ 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!"
#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
-#, fuzzy
msgid "Color Blind Mode"
-msgstr "Klik tilstand"
+msgstr "Farveblind-tilstand"
#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
-msgstr ""
+msgstr "Aktivér Farveblind tilstand som standard"
#: engines/drascula/saveload.cpp:47
msgid ""
@@ -2288,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."
@@ -2318,17 +2546,17 @@ 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"
#: engines/hopkins/detection.cpp:76 engines/hopkins/detection.cpp:86
msgid "Gore Mode"
-msgstr ""
+msgstr "Splatter-tilstand"
#: engines/hopkins/detection.cpp:77 engines/hopkins/detection.cpp:87
msgid "Enable Gore Mode when available"
-msgstr ""
+msgstr "Aktiver Splatter-tilstand når mulig"
#. I18N: Studio audience adds an applause and cheering sounds whenever
#. Malcolm makes a joke.
@@ -2460,6 +2688,12 @@ msgid ""
"Do you wish to use this save game file with ScummVM?\n"
"\n"
msgstr ""
+"Følgende originale savegame fil er blevet fundet i din spil sti:\n"
+"\n"
+"%s %s\n"
+"\n"
+"Ønsker du at bruge denne savegame fil med ScummVM?\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:590
#, c-format
@@ -2467,6 +2701,8 @@ msgid ""
"A save game file was found in the specified slot %d. Overwrite?\n"
"\n"
msgstr ""
+"En savegame fil blev fundet på den angivne plads %d. Overskriv?\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:623
#, c-format
@@ -2478,52 +2714,68 @@ msgid ""
"'import_savefile'.\n"
"\n"
msgstr ""
+"%d originale savegame filer, er med succes er blevet importeret i\n"
+"ScummVM. Hvis du manuelt vil importere original savegame filer senere, vil "
+"du være\n"
+"nødt til at åbne ScummVM debug konsol og bruge 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~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"
@@ -2532,15 +2784,23 @@ msgstr ""
"Kan ikke gemme spil på plads %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:194
+msgid "Load file"
+msgstr "Indlæs fil"
+
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Indlæser spil..."
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:209
+msgid "Save file"
+msgstr "Gem fil"
+
+#: 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"
@@ -2556,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"
@@ -2616,27 +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 ""
+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:395
+msgid "Enable high resolution graphics/content"
+msgstr "Aktivér høj opløsnings grafik/indhold"
+
+#: 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:385
+#: 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:404
+#: 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:405
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2644,148 +2923,155 @@ msgstr ""
"Bruge et IBM Musik Feature-kort eller et Yamaha FB-01 FM synth modul til "
"MIDI-udgang"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "Brug CD lyd"
-#: engines/sci/detection.cpp:416
+#: 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:426
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Brug Windows markør"
-#: engines/sci/detection.cpp:427
+#: 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:437
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Brug sølv markør"
-#: engines/sci/detection.cpp:438
+#: 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
-#, fuzzy
+#: 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) "
+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
-#, fuzzy
+#: 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) "
+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:600
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Kun tale"
-#: engines/scumm/dialogs.cpp:601
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Tale og Undertekster"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Kun undertekster"
-#: engines/scumm/dialogs.cpp:610
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Tale & Tekst"
-#: engines/scumm/dialogs.cpp:656
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Vælg et Færdighedsniveau."
-#: engines/scumm/dialogs.cpp:658
+#: 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:662
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Træning"
-#: engines/scumm/dialogs.cpp:663
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Ekspert"
@@ -3210,25 +3496,24 @@ msgid "Third kid"
msgstr "Tredie barn"
#: engines/scumm/help.cpp:292
-#, fuzzy
msgid "Toggle Inventory/IQ Points display"
-msgstr "Skift Center Data Display"
+msgstr "Skift Inventory/IQ Points display "
#: engines/scumm/help.cpp:293
msgid "Toggle Keyboard/Mouse Fighting (*)"
-msgstr ""
+msgstr "Skift Tastatur/Muse Kamp (*)"
#: engines/scumm/help.cpp:295
msgid "* Keyboard Fighting is always on,"
-msgstr ""
+msgstr "* Tastatur Kamp er altid slået til,"
#: engines/scumm/help.cpp:296
msgid " so despite the in-game message this"
-msgstr ""
+msgstr " så på trods af in-game beskeden, denne"
#: engines/scumm/help.cpp:297
msgid " actually toggles Mouse Fighting Off/On"
-msgstr ""
+msgstr " skifter faktisk Muse Kamp Fra/Til"
#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
@@ -3265,7 +3550,7 @@ msgstr "Slå lavt"
#: engines/scumm/help.cpp:315
msgid "Sucker punch"
-msgstr ""
+msgstr "Mavepuster"
#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
@@ -3323,7 +3608,23 @@ msgstr "Flyv til højre"
msgid "Fly to lower right"
msgstr "Flyv nederst til højre"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/input.cpp:578
+msgid "Snap scroll on"
+msgstr "Jævn bevægelse til"
+
+#: engines/scumm/input.cpp:580
+msgid "Snap scroll off"
+msgstr "Jævn bevægelse fra"
+
+#: engines/scumm/input.cpp:593
+msgid "Music volume: "
+msgstr "Musik lydstyrke: "
+
+#: engines/scumm/input.cpp:610
+msgid "Subtitle speed: "
+msgstr "Tekst hastighed: "
+
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3332,28 +3633,87 @@ msgstr ""
"Indbygget MIDI understøttelse kræver Roland opgradering fra LucasArts,\n"
"men %s mangler. Bruger AdLib i stedet."
-#: engines/scumm/scumm.cpp:2644
-#, fuzzy
+#: 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 ""
-"Normalt ville Maniac Mansion begynde nu. Men ScummVM kan ikke gøre det "
-"endnu. For at spille det, gå til 'Tilføj spil' i ScummVM start-menuen og "
-"vælg 'Maniac' mappen inde i Tentacle spillets mappe."
+"Normalt ville Maniac Mansion starte nu. Men for at det skal fungere, skal "
+"spil filerne til Maniac Mansion skal være i \"Maniac\" mappen inde i "
+"Tentacle spil biblioteket, og spillet skal tilføjes til ScummVM."
#: 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 ""
+"Kunne ikke finde den 'Loom' Macintosh eksekverbare fil, til\n"
+"at læse instrumenterne fra. Musik bliver deaktiveret."
#: 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 ""
+"Kunne ikke finde den 'Monkey Island' Macintosh eksekverbare fil, til\n"
+"at læse instrumenterne fra. Musik bliver deaktiveret."
+
+#: engines/sherlock/detection.cpp:71
+msgid "Use original savegame dialog"
+msgstr "Brug original gem/indlæs dialog"
+
+#: engines/sherlock/detection.cpp:72
+msgid ""
+"Files button in-game shows original savegame dialog rather than the ScummVM "
+"menu"
+msgstr ""
+"Knappen Files i spillet viser original gem/indlæs dialog snarere end ScummVM "
+"menuen"
+
+#: engines/sherlock/detection.cpp:81
+msgid "Pixellated scene transitions"
+msgstr "Pixelleret scene overgange"
+
+#: engines/sherlock/detection.cpp:82
+msgid "When changing scenes, a randomized pixel transition is done"
+msgstr "Ved sceneskift, bruges en tilfældig pixelleret overgang"
+
+#: engines/sherlock/detection.cpp:91
+msgid "Don't show hotspots when moving mouse"
+msgstr "Vis ikke hotspots, når du flytter musen"
+
+#: engines/sherlock/detection.cpp:92
+msgid ""
+"Only show hotspot names after you actually click on a hotspot or action "
+"button"
+msgstr ""
+"Vis kun hotspot navne efter du rent faktisk klikker på et hotspot eller en "
+"handlingsknap"
+
+#: engines/sherlock/detection.cpp:101
+msgid "Show character portraits"
+msgstr "Vis person portrætter"
+
+#: engines/sherlock/detection.cpp:102
+msgid "Show portraits for the characters when conversing"
+msgstr "Vis portrætter for personer når de taler"
+
+#: engines/sherlock/detection.cpp:111
+msgid "Slide dialogs into view"
+msgstr "Skub dialoger til syne"
+
+#: engines/sherlock/detection.cpp:112
+msgid "Slide UI dialogs into view, rather than simply showing them immediately"
+msgstr "Skub dialoger til syne, i stedet for blot at vise dem straks"
+
+#: engines/sherlock/detection.cpp:121
+msgid "Transparent windows"
+msgstr "Gennemsigtige vinduer"
+
+#: engines/sherlock/detection.cpp:122
+msgid "Show windows with a partially transparent background"
+msgstr "Vis vinduer med delvis gennemsigtig baggrund"
#: engines/sky/compact.cpp:130
msgid ""
@@ -3453,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"
@@ -3468,52 +3837,49 @@ msgstr ""
#: engines/wintermute/detection.cpp:58
msgid "Show FPS-counter"
-msgstr ""
+msgstr "Vis FPS-tæller"
#: engines/wintermute/detection.cpp:59
msgid "Show the current number of frames per second in the upper left corner"
-msgstr ""
+msgstr "Vis det nuværende antal billeder per sekund i øverste venstre hjørne"
#: engines/zvision/detection_tables.h:52
-#, fuzzy
msgid "Use the original save/load screens instead of the ScummVM interface"
-msgstr "Brug de originale gem/indlæs skærme, istedet for dem fra ScummVM"
+msgstr ""
+"Brug de originale gem/indlæs skærme, i stedet for dem fra ScummVM "
+"brugerfladen"
#: engines/zvision/detection_tables.h:61
msgid "Double FPS"
-msgstr ""
+msgstr "Dobbelt FPS"
#: engines/zvision/detection_tables.h:62
msgid "Increase framerate from 30 to 60 FPS"
-msgstr ""
+msgstr "Øger billedhastighed fra 30 til 60 FPS"
#: engines/zvision/detection_tables.h:71
-#, fuzzy
msgid "Enable Venus"
-msgstr "Aktivér helium tilstand"
+msgstr "Aktivér Venus"
#: engines/zvision/detection_tables.h:72
-#, fuzzy
msgid "Enable the Venus help system"
-msgstr "Aktivér helium tilstand"
+msgstr "Aktivér Venus hjælpe systemmet"
#: engines/zvision/detection_tables.h:81
msgid "Disable animation while turning"
-msgstr ""
+msgstr "Deaktiver animation, mens du drejer"
#: engines/zvision/detection_tables.h:82
msgid "Disable animation while turning in panorama mode"
-msgstr ""
+msgstr "Deaktiver animation mens du drejer i panorama-tilstand"
#: engines/zvision/detection_tables.h:91
msgid "Use high resolution MPEG video"
-msgstr ""
+msgstr "Brug høj opløsning MPEG-video"
#: engines/zvision/detection_tables.h:92
-#, fuzzy
msgid "Use MPEG video from the DVD version, instead of lower resolution AVI"
-msgstr ""
-"Brug det alternative sæt af sølv markører, i stedet for de normale gyldne"
+msgstr "Brug MPEG-video fra DVD-versionen, i stedet for lavere opløsning AVI"
#~ msgid "EGA undithering"
#~ msgstr "EGA farveforøgelse"
@@ -3559,27 +3925,6 @@ msgstr ""
#~ msgid "Active filter mode: Nearest"
#~ msgstr "Aktiv filter tilstand: Nærmest"
-#~ msgid "Enable Roland GS Mode"
-#~ msgstr "Aktivér Roland GS tilstand"
-
-#~ msgid "Hercules Green"
-#~ msgstr "Hercules grøn"
-
-#~ msgid "Hercules Amber"
-#~ msgstr "Hercules brun"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Green"
-#~ msgstr "Hercules grøn"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Amber"
-#~ msgstr "Hercules brun"
-
-#, fuzzy
-#~ msgid "Save game failed!"
-#~ msgstr "Gemmer:"
-
#~ msgctxt "lowres"
#~ msgid "Add Game..."
#~ msgstr "Tilføj spil..."
@@ -3590,8 +3935,5 @@ msgstr ""
#~ msgid "Discovered %d new games."
#~ msgstr "Fundet %d nye spil."
-#~ msgid "FM Towns Emulator"
-#~ msgstr "FM Towns emulator"
-
#~ msgid "Invalid Path"
#~ msgstr "Ugyldig sti"
diff --git a/po/de_DE.po b/po/de_DE.po
index 56d363b597..227204e395 100644
--- a/po/de_DE.po
+++ b/po/de_DE.po
@@ -1,23 +1,22 @@
# German translation for ScummVM.
-# Copyright (C) 2010-2015 The ScummVM Team
+# 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>, 2015.
+# 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: 2015-09-06 15:14+0200\n"
-"PO-Revision-Date: 2015-07-04 12:06+0200\n"
-"Last-Translator: Lothar Serra Mari <scummvm@rootfather.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.2\n"
#: gui/about.cpp:94
#, c-format
@@ -55,27 +54,27 @@ msgid "Go up"
msgstr "Pfad hoch"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:74 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: 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/fluidsynth-dialog.cpp:152 engines/engine.cpp:483
-#: backends/platform/wii/options.cpp:48
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
-#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:191 engines/sword1/control.cpp:865
+#: 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 "Abbrechen"
#: gui/browser.cpp:76 gui/browser_osx.mm:103 gui/chooser.cpp:47
-#: gui/themebrowser.cpp:56
+#: gui/filebrowser-dialog.cpp:65 gui/themebrowser.cpp:56
msgid "Choose"
msgstr "Auswählen"
#: gui/editrecorddialog.cpp:58
-#, fuzzy
msgid "Author:"
msgstr "Autor:"
@@ -84,65 +83,182 @@ msgid "Name:"
msgstr "Name:"
#: gui/editrecorddialog.cpp:60
-#, fuzzy
msgid "Notes:"
msgstr "Notizen:"
-#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:75
+#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74
msgid "Ok"
+msgstr "OK"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Choose file for loading"
+msgstr "Zu ladende Datei auswählen"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Enter filename for saving"
+msgstr "Dateiname zum Speichern eingeben"
+
+#: gui/filebrowser-dialog.cpp:132
+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: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 "Ja"
+
+#: 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 "Nein"
+
+#: gui/fluidsynth-dialog.cpp:68
+msgid "Reverb"
+msgstr "Hall"
+
+#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
+msgid "Active"
+msgstr "Aktiv"
+
+#: gui/fluidsynth-dialog.cpp:72
+msgid "Room:"
+msgstr "Raum:"
+
+#: gui/fluidsynth-dialog.cpp:79
+msgid "Damp:"
+msgstr "Dämpfung:"
+
+#: gui/fluidsynth-dialog.cpp:86
+msgid "Width:"
+msgstr "Radius:"
+
+#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
+msgid "Level:"
+msgstr "Intensität:"
+
+#: gui/fluidsynth-dialog.cpp:100
+msgid "Chorus"
+msgstr "Chor"
+
+#: gui/fluidsynth-dialog.cpp:104
+msgid "N:"
+msgstr "Stimmen:"
+
+#: gui/fluidsynth-dialog.cpp:118
+msgid "Speed:"
+msgstr "Rate:"
+
+#: gui/fluidsynth-dialog.cpp:125
+msgid "Depth:"
+msgstr "Trennzeit:"
+
+#: gui/fluidsynth-dialog.cpp:132
+msgid "Type:"
+msgstr "Typ:"
+
+#: gui/fluidsynth-dialog.cpp:135
+msgid "Sine"
+msgstr "Sinus"
+
+#: gui/fluidsynth-dialog.cpp:136
+msgid "Triangle"
+msgstr "Dreieck"
+
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
+msgid "Misc"
+msgstr "Sonstiges"
+
+#: gui/fluidsynth-dialog.cpp:140
+msgid "Interpolation:"
+msgstr "Interpolation:"
+
+#: gui/fluidsynth-dialog.cpp:143
+msgid "None (fastest)"
+msgstr "Keine (am schnellsten)"
+
+#: gui/fluidsynth-dialog.cpp:144
+msgid "Linear"
+msgstr "Linear"
+
+#: gui/fluidsynth-dialog.cpp:145
+msgid "Fourth-order"
+msgstr "Vierstufig"
+
+#: gui/fluidsynth-dialog.cpp:146
+msgid "Seventh-order"
+msgstr "Siebenstufig"
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset"
+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: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 "OK"
+
+#: gui/fluidsynth-dialog.cpp:217
+msgid ""
+"Do you really want to reset all FluidSynth settings to their default values?"
msgstr ""
+"Möchten Sie wirklich alle FluidSynth-Einstellungen auf ihre Standard-Werte "
+"zurücksetzen?"
-#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
+#: 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 "Schließen"
-#: gui/gui-manager.cpp:120
+#: gui/gui-manager.cpp:122
msgid "Mouse click"
msgstr "Mausklick"
-#: gui/gui-manager.cpp:124 base/main.cpp:319
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Tastatur anzeigen"
-#: gui/gui-manager.cpp:128 base/main.cpp:323
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Tasten neu zuweisen"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 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"
-#: gui/KeysDialog.h:36 gui/KeysDialog.cpp:145
-msgid "Choose an action to map"
-msgstr "Eine Aktion zum Zuweisen auswählen"
-
#: gui/KeysDialog.cpp:41
msgid "Map"
msgstr "Zuweisen"
-#: gui/KeysDialog.cpp:42 gui/launcher.cpp:352 gui/launcher.cpp:1048
-#: gui/launcher.cpp:1052 gui/massadd.cpp:92 gui/options.cpp:1238
-#: gui/saveload-dialog.cpp:932 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:402 engines/engine.cpp:413
-#: 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/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 "OK"
-
#: gui/KeysDialog.cpp:49
msgid "Select an action and click 'Map'"
msgstr "Aktion auswählen und \"Zuweisen\" klicken"
@@ -165,6 +281,10 @@ msgstr "Bitte eine Aktion auswählen"
msgid "Press the key to associate"
msgstr "Taste drücken, um sie zuzuweisen"
+#: gui/KeysDialog.cpp:145 gui/KeysDialog.h:36
+msgid "Choose an action to map"
+msgstr "Eine Aktion zum Zuweisen auswählen"
+
#: gui/launcher.cpp:193
msgid "Game"
msgstr "Spiel"
@@ -207,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>"
@@ -230,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"
@@ -247,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"
@@ -260,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."
@@ -278,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:95
+#: 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:69
+#: 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:1222
+#: 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/myst.cpp:245 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/myst.cpp:245
-#: engines/mohawk/riven.cpp:718 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:792
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -497,60 +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:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Ja"
-
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Nein"
-
-#: gui/launcher.cpp:841
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM konnte das gewählte Verzeichnis nicht öffnen!"
-#: gui/launcher.cpp:853
+#: 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:867
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Spiel auswählen:"
-#: gui/launcher.cpp:941
+#: 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:999
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "Möchten Sie einen Spielstand laden?"
-#: gui/launcher.cpp:1048
+#: 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:1052
+#: 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:1159
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Durchsuchen"
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr "Aufzeichnen"
@@ -579,151 +680,149 @@ msgstr "%d neue Spiele gefunden, %d bereits hinzugefügte Spiele ignoriert..."
#: gui/onscreendialog.cpp:101 gui/onscreendialog.cpp:103
msgid "Stop"
-msgstr ""
+msgstr "Anhalten"
#: gui/onscreendialog.cpp:106
msgid "Edit record description"
-msgstr ""
+msgstr "Aufnahme-Beschreibung ändern"
#: gui/onscreendialog.cpp:108
-#, fuzzy
msgid "Switch to Game"
msgstr "Wechsle"
#: gui/onscreendialog.cpp:110
-#, fuzzy
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:2298
+#: 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"
@@ -731,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"
@@ -800,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"
@@ -817,178 +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 stumm"
+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:1168 gui/fluidsynth-dialog.cpp:138
-msgid "Misc"
-msgstr "Sonstiges"
-
-#: 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."
@@ -998,63 +1105,76 @@ msgstr ""
"wechseln."
#. I18N: You must leave "#" as is, only word 'next' is translatable
-#: gui/predictivedialog.cpp:87
+#: gui/predictivedialog.cpp:86
msgid "# next"
-msgstr ""
+msgstr "# nächste"
-#: gui/predictivedialog.cpp:88
+#: gui/predictivedialog.cpp:87
msgid "add"
-msgstr ""
+msgstr "hinzufügen"
-#: gui/predictivedialog.cpp:92
-#, fuzzy
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
msgstr "Löschen"
-#: gui/predictivedialog.cpp:96
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
-msgstr ""
+msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:98
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
-msgstr ""
+msgstr "* Vorschau"
+
+#. I18N: 'Num' means Numbers
+#: gui/predictivedialog.cpp:578
+msgid "* Num"
+msgstr "* Zahlen"
+
+#. I18N: 'Abc' means Latin alphabet input
+#: gui/predictivedialog.cpp:581
+msgid "* Abc"
+msgstr "* ABC"
-#: gui/recorderdialog.cpp:64
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
-msgstr "Spiel aufzeichnen oder wiedergeben"
+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:173
+msgid "Unknown Author"
+msgstr "Unbekannter Autor"
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr "Listenansicht"
@@ -1115,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:"
@@ -1124,151 +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:661
+#: 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
-msgid "Clear value"
-msgstr "Wert löschen"
-
-#: gui/fluidsynth-dialog.cpp:68
-msgid "Reverb"
-msgstr "Hall"
-
-#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
-msgid "Active"
-msgstr "Aktiv"
-
-#: gui/fluidsynth-dialog.cpp:72
-msgid "Room:"
-msgstr "Raum:"
-
-#: gui/fluidsynth-dialog.cpp:79
-msgid "Damp:"
-msgstr "Dämpfung:"
-
-#: gui/fluidsynth-dialog.cpp:86
-msgid "Width:"
-msgstr "Radius:"
-
-#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
-msgid "Level:"
-msgstr "Intensität:"
-
-#: gui/fluidsynth-dialog.cpp:100
-msgid "Chorus"
-msgstr "Chor"
-
-#: gui/fluidsynth-dialog.cpp:104
-msgid "N:"
-msgstr "Stimmen:"
-
-#: gui/fluidsynth-dialog.cpp:118
-msgid "Speed:"
-msgstr "Rate:"
-
-#: gui/fluidsynth-dialog.cpp:125
-msgid "Depth:"
-msgstr "Trennzeit:"
-
-#: gui/fluidsynth-dialog.cpp:132
-msgid "Type:"
-msgstr "Typ:"
-
-#: gui/fluidsynth-dialog.cpp:135
-msgid "Sine"
-msgstr "Sinus"
-
-#: gui/fluidsynth-dialog.cpp:136
-msgid "Triangle"
-msgstr "Dreieck"
-
-#: gui/fluidsynth-dialog.cpp:140
-msgid "Interpolation:"
-msgstr "Interpolation:"
-
-#: gui/fluidsynth-dialog.cpp:143
-msgid "None (fastest)"
-msgstr "Keine (am schnellsten)"
-
-#: gui/fluidsynth-dialog.cpp:144
-msgid "Linear"
-msgstr "Linear"
-
-#: gui/fluidsynth-dialog.cpp:145
-msgid "Fourth-order"
-msgstr "Vierstufig"
+#: 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/fluidsynth-dialog.cpp:146
-msgid "Seventh-order"
-msgstr "Siebenstufig"
+#: 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/fluidsynth-dialog.cpp:150
-msgid "Reset"
-msgstr "Rücksetzen"
+#: gui/updates-dialog.cpp:92
+msgid "Check for updates automatically"
+msgstr "Automatisch nach Aktualisierungen suchen"
-#: 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/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr "Fortfahren"
-#: gui/fluidsynth-dialog.cpp:217
-msgid ""
-"Do you really want to reset all FluidSynth settings to their default values?"
-msgstr ""
-"Möchten Sie wirklich alle FluidSynth-Einstellungen auf ihre Standard-Werte "
-"zurücksetzen?"
+#: 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:228
+#: 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:306
+#: base/main.cpp:315
msgid "Menu"
msgstr "Menü"
-#: base/main.cpp:309 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:312 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:315
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Zeile überspringen"
-#: base/main.cpp:507
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Fehler beim Ausführen des Spiels:"
-#: base/main.cpp:554
+#: 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."
@@ -1336,18 +1395,61 @@ msgstr "Abbruch durch Benutzer"
msgid "Unknown error"
msgstr "Unbekannter Fehler"
-#: engines/advancedDetector.cpp:317
+#. I18N: Hercules is graphics card name
+#: common/rendermode.cpp:35
+msgid "Hercules Green"
+msgstr "Hercules Grün"
+
+#: common/rendermode.cpp:36
+msgid "Hercules Amber"
+msgstr "Hercules Bernstein"
+
+#: common/rendermode.cpp:42
+msgid "PC-9821 (256 Colors)"
+msgstr "PC-9821 (256 Farben)"
+
+#: common/rendermode.cpp:43
+msgid "PC-9801 (16 Colors)"
+msgstr "PC-9801 (16 Farben)"
+
+#: common/rendermode.cpp:73
+msgctxt "lowres"
+msgid "Hercules Green"
+msgstr "Hercules Grün"
+
+#: common/rendermode.cpp:74
+msgctxt "lowres"
+msgid "Hercules Amber"
+msgstr "Hercules Bernst."
+
+#: 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/"
@@ -1357,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"
@@ -1386,11 +1488,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "Zur Spiele~l~iste"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:803
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:873
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
-#: engines/toltecs/menu.cpp:281 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:"
@@ -1399,11 +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:803 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/neverhood/menumodule.cpp:873 engines/pegasus/pegasus.cpp:377
-#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
-#: engines/toltecs/menu.cpp:281 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"
@@ -1425,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"
@@ -1439,23 +1550,23 @@ msgstr "~A~bbrechen"
msgid "~K~eys"
msgstr "~T~asten"
-#: engines/engine.cpp:276
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Konnte Farbenformat nicht initialisieren."
-#: engines/engine.cpp:284
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Konnte nicht zu Grafikmodus wechseln: \""
-#: engines/engine.cpp:293
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "Konnte Einstellung für Seitenverhältniskorrektur nicht anwenden."
-#: engines/engine.cpp:298
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Konnte Einstellung für Vollbildmodus nicht anwenden."
-#: engines/engine.cpp:398
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1471,7 +1582,7 @@ msgstr ""
"Lesen Sie die Liesmich-Datei für\n"
"weitere Informationen."
-#: engines/engine.cpp:409
+#: 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"
@@ -1486,7 +1597,7 @@ msgstr ""
"Spiel hören zu können. Lesen Sie die\n"
"Liesmich-Datei für weitere Informationen."
-#: engines/engine.cpp:467
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1495,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:480
+#: 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 "
@@ -1506,10 +1617,14 @@ msgstr ""
"und jegliche Spielstände, die Sie erstellen, könnten in zukünftigen "
"Versionen von ScummVM nicht mehr funktionieren."
-#: engines/engine.cpp:483
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Trotzdem starten"
+#: audio/adlib.cpp:2290
+msgid "AdLib Emulator"
+msgstr "AdLib-Emulator"
+
#: audio/fmopl.cpp:62
msgid "MAME OPL emulator"
msgstr "MAME-OPL-Emulator"
@@ -1520,7 +1635,7 @@ msgstr "DOSBox-OPL-Emulator"
#: audio/fmopl.cpp:67
msgid "ALSA Direct FM"
-msgstr ""
+msgstr "ALSA Direct FM"
#: audio/mididrv.cpp:209
#, c-format
@@ -1563,31 +1678,35 @@ msgstr ""
"Das bevorzugte Audiogerät \"%s\" kann nicht verwendet werden. Schauen Sie "
"für weitere Informationen in der Log-Datei nach."
-#: audio/null.h:44
-msgid "No music"
-msgstr "Keine Musik"
-
#: audio/mods/paula.cpp:196
msgid "Amiga Audio Emulator"
msgstr "Amiga-Audio-Emulator"
-#: audio/adlib.cpp:2291
-msgid "AdLib Emulator"
-msgstr "AdLib-Emulator"
+#: audio/null.h:44
+msgid "No music"
+msgstr "Keine Musik"
#: audio/softsynth/appleiigs.cpp:33
msgid "Apple II GS Emulator (NOT IMPLEMENTED)"
msgstr "Apple-II-GS-Emulator (NICHT INTEGRIERT)"
-#: audio/softsynth/sid.cpp:1430
-msgid "C64 Audio Emulator"
-msgstr "C64-Audio-Emulator"
+#: audio/softsynth/cms.cpp:350
+msgid "Creative Music System Emulator"
+msgstr "Creative-Music-System-Emulator"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33
+msgid "FM-Towns Audio"
+msgstr "FM-Towns-Audio"
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58
+msgid "PC-98 Audio"
+msgstr "PC-98-Audio"
+
+#: 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"
@@ -1599,6 +1718,146 @@ msgstr "PC-Lautsprecher-Emulator"
msgid "IBM PCjr Emulator"
msgstr "IBM-PCjr-Emulator"
+#: audio/softsynth/sid.cpp:1430
+msgid "C64 Audio Emulator"
+msgstr "C64-Audio-Emulator"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Do you really want to return to the Launcher?"
+msgstr "Möchten Sie wirklich zur Spieleliste zurückkehren?"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Launcher"
+msgstr "Spieleliste"
+
+#: backends/events/default/default-events.cpp:218
+msgid "Do you really want to quit?"
+msgstr "Möchten Sie wirklich beenden?"
+
+#: 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 "Beenden"
+
+#: 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 "Berührungsbildschirm-Tipp-Modus - Linksklick"
+
+#: 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 "Berührungsbildschirm-Tipp-Modus - Rechtsklick"
+
+#: 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 "Berührungsbildschirm-Tipp-Modus - schweben (kein Klick)"
+
+#: backends/events/gph/gph-events.cpp:409
+msgid "Maximum Volume"
+msgstr "Höchste Lautstärke"
+
+#: backends/events/gph/gph-events.cpp:411
+msgid "Increasing Volume"
+msgstr "Lautstärke höher"
+
+#: backends/events/gph/gph-events.cpp:417
+msgid "Minimal Volume"
+msgstr "Niedrigste Lautstärke"
+
+#: backends/events/gph/gph-events.cpp:419
+msgid "Decreasing Volume"
+msgstr "Lautstärke niedriger"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Enabled"
+msgstr "Klicken aktiviert"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Disabled"
+msgstr "Klicken deaktiviert"
+
+#: backends/events/openpandora/op-events.cpp:174
+msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
+msgstr "Berührungsbildschirm-Tipp-Modus - schweben (DPad-Klicks)"
+
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
+msgid "Do you want to quit ?"
+msgstr "Möchten Sie beenden?"
+
+#. I18N: Trackpad mode toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:308
+msgid "Trackpad mode is now"
+msgstr "Trackpad-Modus ist jetzt "
+
+#. 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 "AN"
+
+#: backends/events/webossdl/webossdl-events.cpp:311
+#: backends/events/webossdl/webossdl-events.cpp:338
+msgid "OFF"
+msgstr "AUS"
+
+#: backends/events/webossdl/webossdl-events.cpp:315
+msgid "Swipe two fingers to the right to toggle."
+msgstr "Zum Umschalten mit zwei Fingern nach rechts wischen."
+
+#. I18N: Auto-drag toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:335
+msgid "Auto-drag mode is now"
+msgstr "Automatisches Ziehen ist jetzt "
+
+#: backends/events/webossdl/webossdl-events.cpp:342
+msgid "Swipe three fingers to the right to toggle."
+msgstr "Zum Umschalten mit drei Fingern nach rechts wischen."
+
+#: backends/graphics/opengl/opengl-graphics.cpp:126
+msgid "OpenGL"
+msgstr "OpenGL"
+
+#: backends/graphics/opengl/opengl-graphics.cpp:127
+msgid "OpenGL (No filtering)"
+msgstr "OpenGL (ohne Filter)"
+
+#: 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 "Normal (keine Skalierung)"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:66
+msgctxt "lowres"
+msgid "Normal (no scaling)"
+msgstr "Normal ohn.Skalieren"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
+msgid "Enabled aspect ratio correction"
+msgstr "Seitenverhältniskorrektur an"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
+msgid "Disabled aspect ratio correction"
+msgstr "Seitenverhältniskorrektur aus"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
+msgid "Active graphics filter:"
+msgstr "Aktiver Grafikfilter:"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+msgid "Windowed mode"
+msgstr "Fenstermodus"
+
#: backends/keymapper/remap-dialog.cpp:48
msgid "Keymap:"
msgstr "Tasten-Layout:"
@@ -1628,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"
@@ -1704,18 +1963,26 @@ msgstr "Hohe Audioqualität (lansamer) (erfordert Neustart)"
msgid "Disable power off"
msgstr "Stromsparmodus abschalten"
+#: 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 "Maus-klick-und-zieh-Modus aktiviert."
+#: 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 "Maus-klick-und-zieh-Modus ausgeschaltet."
+#: 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 "Touchpad-Modus aktiviert."
+#: 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 "Touchpad-Modus ausgeschaltet."
@@ -1726,9 +1993,9 @@ msgstr "Klickmodus"
#: 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
-#: backends/platform/tizen/form.cpp:275
msgid "Left Click"
msgstr "Linksklick"
@@ -1738,65 +2005,32 @@ msgstr "Mittelklick"
#: backends/platform/maemo/maemo.cpp:220
#: backends/platform/symbian/src/SymbianActions.cpp:43
-#: backends/platform/wince/CEActionsSmartphone.cpp:44
#: backends/platform/tizen/form.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:44
msgid "Right Click"
msgstr "Rechtsklick"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:77
+#: backends/platform/sdl/macosx/appmenu_osx.mm:88
msgid "Hide ScummVM"
msgstr "ScummVM ausblenden"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:82
+#: backends/platform/sdl/macosx/appmenu_osx.mm:93
msgid "Hide Others"
msgstr "Andere ausblenden"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:87
+#: backends/platform/sdl/macosx/appmenu_osx.mm:98
msgid "Show All"
msgstr "Alle einblenden"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:109
#: backends/platform/sdl/macosx/appmenu_osx.mm:120
+#: backends/platform/sdl/macosx/appmenu_osx.mm:131
msgid "Window"
msgstr "Fenster"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:114
+#: backends/platform/sdl/macosx/appmenu_osx.mm:125
msgid "Minimize"
msgstr "Minimieren"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:46
-msgid "Normal (no scaling)"
-msgstr "Normal (keine Skalierung)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:65
-msgctxt "lowres"
-msgid "Normal (no scaling)"
-msgstr "Normal ohn.Skalieren"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
-msgid "Enabled aspect ratio correction"
-msgstr "Seitenverhältniskorrektur an"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
-msgid "Disabled aspect ratio correction"
-msgstr "Seitenverhältniskorrektur aus"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
-msgid "Active graphics filter:"
-msgstr "Aktiver Grafikfilter:"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
-msgid "Windowed mode"
-msgstr "Fenstermodus"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:118
-msgid "OpenGL"
-msgstr "OpenGL"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:119
-msgid "OpenGL (No filtering)"
-msgstr "OpenGL (ohne Filter)"
-
#: backends/platform/symbian/src/SymbianActions.cpp:38
#: backends/platform/wince/CEActionsSmartphone.cpp:39
msgid "Up"
@@ -1840,14 +2074,6 @@ msgstr "Text überspringen"
msgid "Fast mode"
msgstr "Schneller Modus"
-#: backends/platform/symbian/src/SymbianActions.cpp:52
-#: backends/platform/wince/CEActionsPocket.cpp:44
-#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: backends/events/default/default-events.cpp:218 engines/scumm/dialogs.cpp:192
-#: engines/scumm/help.cpp:83 engines/scumm/help.cpp:85
-msgid "Quit"
-msgstr "Beenden"
-
#: backends/platform/symbian/src/SymbianActions.cpp:53
msgid "Debugger"
msgstr "Debugger"
@@ -1864,9 +2090,49 @@ msgstr "Virtuelle Tastatur"
msgid "Key mapper"
msgstr "Tasten zuordnen"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:186
-msgid "Do you want to quit ?"
-msgstr "Möchten Sie beenden?"
+#: backends/platform/tizen/form.cpp:263
+msgid "Right Click Once"
+msgstr "Einmal Rechtsklick"
+
+#: backends/platform/tizen/form.cpp:271
+msgid "Move Only"
+msgstr "Nur bewegen"
+
+#: backends/platform/tizen/form.cpp:294
+msgid "Escape Key"
+msgstr "Escape-Taste"
+
+#: backends/platform/tizen/form.cpp:299
+msgid "Game Menu"
+msgstr "Spielmenü"
+
+#: backends/platform/tizen/form.cpp:304
+msgid "Show Keypad"
+msgstr "Ziffernblock zeigen"
+
+#: backends/platform/tizen/form.cpp:309
+msgid "Control Mouse"
+msgstr "Maus steuern"
+
+#: backends/platform/tizen/fs.cpp:259
+msgid "[ Data ]"
+msgstr "[ Daten ]"
+
+#: backends/platform/tizen/fs.cpp:263
+msgid "[ Resources ]"
+msgstr "[ Ressourcen ]"
+
+#: backends/platform/tizen/fs.cpp:267
+msgid "[ SDCard ]"
+msgstr "[ SD-Karte ]"
+
+#: backends/platform/tizen/fs.cpp:271
+msgid "[ Media ]"
+msgstr "[ Datenträger ]"
+
+#: backends/platform/tizen/fs.cpp:275
+msgid "[ Shared ]"
+msgstr "[ Öffentlich ]"
#: backends/platform/wii/options.cpp:51
msgid "Video"
@@ -1982,7 +2248,7 @@ msgstr ", öffentliches Verzeichnis nicht eingebunden"
#: backends/platform/wii/options.cpp:174
msgid "Network down"
-msgstr "Netzwerk ist aus."
+msgstr "Netzwerk ist nicht verfügbar."
#: backends/platform/wii/options.cpp:178
msgid "Initializing network"
@@ -2115,102 +2381,37 @@ msgstr ""
"Vergessen Sie nicht, der Aktion \"Werkzeugleiste verbergen\" eine Taste "
"zuzuweisen, um das ganze Inventar sehen zu können."
-#: backends/events/default/default-events.cpp:196
-msgid "Do you really want to return to the Launcher?"
-msgstr "Möchten Sie wirklich zur Spieleliste zurückkehren?"
-
-#: backends/events/default/default-events.cpp:196
-msgid "Launcher"
-msgstr "Spieleliste"
-
-#: backends/events/default/default-events.cpp:218
-msgid "Do you really want to quit?"
-msgstr "Möchten Sie wirklich beenden?"
-
-#: 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 "Berührungsbildschirm-Tipp-Modus - Linksklick"
-
-#: 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 "Berührungsbildschirm-Tipp-Modus - Rechtsklick"
-
-#: 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 "Berührungsbildschirm-Tipp-Modus - schweben (kein Klick)"
-
-#: backends/events/gph/gph-events.cpp:409
-msgid "Maximum Volume"
-msgstr "Höchste Lautstärke"
-
-#: backends/events/gph/gph-events.cpp:411
-msgid "Increasing Volume"
-msgstr "Lautstärke höher"
-
-#: backends/events/gph/gph-events.cpp:417
-msgid "Minimal Volume"
-msgstr "Niedrigste Lautstärke"
-
-#: backends/events/gph/gph-events.cpp:419
-msgid "Decreasing Volume"
-msgstr "Lautstärke niedriger"
-
-#: backends/events/openpandora/op-events.cpp:174
-msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
-msgstr "Berührungsbildschirm-Tipp-Modus - schweben (DPad-Klicks)"
-
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Suche nach Aktualisierungen..."
-#: backends/platform/tizen/form.cpp:263
-msgid "Right Click Once"
-msgstr "Einmal Rechtsklick"
-
-#: backends/platform/tizen/form.cpp:271
-msgid "Move Only"
-msgstr "Nur bewegen"
-
-#: backends/platform/tizen/form.cpp:294
-msgid "Escape Key"
-msgstr "Escape-Taste"
-
-#: backends/platform/tizen/form.cpp:299
-msgid "Game Menu"
-msgstr "Spielmenü"
-
-#: backends/platform/tizen/form.cpp:304
-msgid "Show Keypad"
-msgstr "Ziffernblock zeigen"
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+msgid "Color mode"
+msgstr "Farbmodus einschalten"
-#: backends/platform/tizen/form.cpp:309
-msgid "Control Mouse"
-msgstr "Maus steuern"
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr "Farbgrafik verwenden"
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Enabled"
-msgstr "Klicken aktiviert"
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr "Abtastzeilen/Scanlines"
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Disabled"
-msgstr "Klicken deaktiviert"
+#: engines/adl/detection.cpp:64
+msgid "Show scanlines"
+msgstr "Abtastzeilen (Scanlines) anzeigen"
-#: engines/agi/detection.cpp:147 engines/drascula/detection.cpp:302
-#: engines/dreamweb/detection.cpp:47 engines/neverhood/detection.cpp:160
-#: engines/sci/detection.cpp:394 engines/toltecs/detection.cpp:200
-#: engines/zvision/detection_tables.h:51
+#: 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 "Originale Spielstand-Menüs"
-#: engines/agi/detection.cpp:148 engines/drascula/detection.cpp:303
-#: engines/dreamweb/detection.cpp:48 engines/neverhood/detection.cpp:161
-#: engines/sci/detection.cpp:395 engines/toltecs/detection.cpp:201
+#: 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 ""
"Verwendet die originalen Menüs zum Speichern und Laden statt der von ScummVM."
@@ -2238,19 +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:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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"
@@ -2261,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"
@@ -2272,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"
@@ -2283,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!"
@@ -2314,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."
@@ -2344,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."
@@ -2523,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"
@@ -2577,15 +2818,23 @@ msgstr ""
"Kann Spiel nicht speichern auf Speicherplatz %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:194
+msgid "Load file"
+msgstr "Datei laden"
+
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Spiel wird geladen..."
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:209
+msgid "Save file"
+msgstr "Datei speichern"
+
+#: 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"
@@ -2602,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"
@@ -2662,29 +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"
+
+#: engines/sci/detection.cpp:395
+msgid "Enable high resolution graphics/content"
+msgstr "Aktiviere hochauflösende Grafik/Inhalte"
+
+#: 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:385
+#: 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:404
+#: 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:405
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2692,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:415
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "CD-Ton verwenden"
-#: engines/sci/detection.cpp:416
+#: 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:426
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Windows-Mauszeiger verwenden"
-#: engines/sci/detection.cpp:427
+#: 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:437
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Silberne Mauszeiger verwenden"
-#: engines/sci/detection.cpp:438
+#: 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:600
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Nur Sprache"
-#: engines/scumm/dialogs.cpp:601
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Sprachausgabe und Untertitel"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Nur Untertitel"
-#: engines/scumm/dialogs.cpp:610
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Sprache & Text"
-#: engines/scumm/dialogs.cpp:656
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Wähle einen Schwierigkeitsgrad."
-#: engines/scumm/dialogs.cpp:658
+#: 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:662
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Anfänger"
-#: engines/scumm/dialogs.cpp:663
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Experte"
@@ -2946,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"
@@ -3371,7 +3644,23 @@ msgstr "Nach rechts fliegen"
msgid "Fly to lower right"
msgstr "Nach unten rechts fliegen"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/input.cpp:578
+msgid "Snap scroll on"
+msgstr "Blättern einschalten"
+
+#: engines/scumm/input.cpp:580
+msgid "Snap scroll off"
+msgstr "Blättern ausschalten"
+
+#: engines/scumm/input.cpp:593
+msgid "Music volume: "
+msgstr "Musiklautstärke:"
+
+#: engines/scumm/input.cpp:610
+msgid "Subtitle speed: "
+msgstr "Untertitel-Tempo:"
+
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3381,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 "
@@ -3408,6 +3697,63 @@ msgstr ""
"Macintosh-Programmdatei für Instrumente in \"Monkey Island\" nicht\n"
"gefunden. Musik wird abgeschaltet."
+#: engines/sherlock/detection.cpp:71
+msgid "Use original savegame dialog"
+msgstr "Originale Spielstand-Menüs verwenden"
+
+#: engines/sherlock/detection.cpp:72
+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."
+
+#: engines/sherlock/detection.cpp:81
+msgid "Pixellated scene transitions"
+msgstr "Verpixelte Szenenübergänge"
+
+#: engines/sherlock/detection.cpp:82
+msgid "When changing scenes, a randomized pixel transition is done"
+msgstr "Bei Szenenwechseln wird ein zufälliger Pixelübergang verwendet."
+
+#: engines/sherlock/detection.cpp:91
+msgid "Don't show hotspots when moving mouse"
+msgstr "Bei Mausbewegung keine Klickpunkte anzeigen"
+
+#: engines/sherlock/detection.cpp:92
+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."
+
+#: engines/sherlock/detection.cpp:101
+msgid "Show character portraits"
+msgstr "Figurenportraits zeigen"
+
+#: engines/sherlock/detection.cpp:102
+msgid "Show portraits for the characters when conversing"
+msgstr "Zeigt Portraits der Figuren bei Gesprächen."
+
+#: engines/sherlock/detection.cpp:111
+msgid "Slide dialogs into view"
+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."
+
+#: engines/sherlock/detection.cpp:121
+msgid "Transparent windows"
+msgstr "Transparente Fenster"
+
+#: engines/sherlock/detection.cpp:122
+msgid "Show windows with a partially transparent background"
+msgstr "Zeigt Fenster mit teilweise transparentem Hintergrund"
+
#: engines/sky/compact.cpp:130
msgid ""
"Unable to find \"sky.cpt\" file!\n"
@@ -3512,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"
@@ -3538,7 +3895,6 @@ msgstr ""
"Zeige die aktuelle Anzahl von Bildern pro Sekunde in der oberen linken Ecke"
#: engines/zvision/detection_tables.h:52
-#, fuzzy
msgid "Use the original save/load screens instead of the ScummVM interface"
msgstr ""
"Verwendet die originalen Menüs zum Speichern und Laden statt der von ScummVM."
@@ -3548,7 +3904,6 @@ msgid "Double FPS"
msgstr "FPS verdoppeln"
#: engines/zvision/detection_tables.h:62
-#, fuzzy
msgid "Increase framerate from 30 to 60 FPS"
msgstr "Bilder pro Sekunde im Spiel von 30 auf 60 erhöhen"
@@ -3565,17 +3920,14 @@ msgid "Disable animation while turning"
msgstr "Animation während Drehen ausschalten"
#: engines/zvision/detection_tables.h:82
-#, fuzzy
msgid "Disable animation while turning in panorama mode"
msgstr "Animation während Drehen im Panorama-Modus ausschalten"
#: engines/zvision/detection_tables.h:91
-#, fuzzy
msgid "Use high resolution MPEG video"
msgstr "Nutze hochauflösende MPEG-Filme"
#: engines/zvision/detection_tables.h:92
-#, fuzzy
msgid "Use MPEG video from the DVD version, instead of lower resolution AVI"
msgstr ""
"Verwende hochauflösende MPEG-Filme der DVD-Version anstelle der AVI-Filme"
@@ -3628,12 +3980,6 @@ msgstr ""
#~ msgid "Active filter mode: Nearest"
#~ msgstr "Aktiver Filtermodus: nächste Nachbarn"
-#~ msgid "Enable Roland GS Mode"
-#~ msgstr "Roland-GS-Modus"
-
-#~ msgid "Save game failed!"
-#~ msgstr "Konnte Spielstand nicht speichern!"
-
#~ 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 3398957b22..33e4783d32 100644
--- a/po/es_ES.po
+++ b/po/es_ES.po
@@ -1,5 +1,5 @@
# Spanish translation for ScummVM.
-# Copyright (C) 2010-2015 The ScummVM Team
+# Copyright (C) 2010-2016 The ScummVM Team
# This file is distributed under the same license as the ScummVM package.
# Tomás Maidagan, 2011.
#
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.4.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2015-09-06 15:14+0200\n"
-"PO-Revision-Date: 2014-07-06 20:39+0100\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"
"Language: Espanol\n"
@@ -52,28 +52,29 @@ msgid "Go up"
msgstr "Arriba"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:74 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: 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/fluidsynth-dialog.cpp:152 engines/engine.cpp:483
-#: backends/platform/wii/options.cpp:48
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
-#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:191 engines/sword1/control.cpp:865
+#: 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 "Cancelar"
#: gui/browser.cpp:76 gui/browser_osx.mm:103 gui/chooser.cpp:47
-#: gui/themebrowser.cpp:56
+#: gui/filebrowser-dialog.cpp:65 gui/themebrowser.cpp:56
msgid "Choose"
msgstr "Aceptar"
#: gui/editrecorddialog.cpp:58
msgid "Author:"
-msgstr ""
+msgstr "Autor:"
#: gui/editrecorddialog.cpp:59 gui/launcher.cpp:204
msgid "Name:"
@@ -81,63 +82,181 @@ msgstr "Nombre:"
#: gui/editrecorddialog.cpp:60
msgid "Notes:"
-msgstr ""
+msgstr "Notas:"
-#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:75
+#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74
msgid "Ok"
+msgstr "Aceptar"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Choose file for loading"
+msgstr "Elegir el archivo para cargar"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Enter filename for saving"
+msgstr "Escribir el nombre del archivo"
+
+#: gui/filebrowser-dialog.cpp:132
+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: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 "Sí"
+
+#: 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 "No"
+
+#: gui/fluidsynth-dialog.cpp:68
+msgid "Reverb"
+msgstr "Reverberación"
+
+#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
+msgid "Active"
+msgstr "Activa"
+
+#: gui/fluidsynth-dialog.cpp:72
+msgid "Room:"
+msgstr "Sala:"
+
+#: gui/fluidsynth-dialog.cpp:79
+msgid "Damp:"
+msgstr "Atenuación:"
+
+#: gui/fluidsynth-dialog.cpp:86
+msgid "Width:"
+msgstr "Amplitud"
+
+#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
+msgid "Level:"
+msgstr "Nivel:"
+
+#: gui/fluidsynth-dialog.cpp:100
+msgid "Chorus"
+msgstr "Coro"
+
+#: gui/fluidsynth-dialog.cpp:104
+msgid "N:"
+msgstr "N:"
+
+#: gui/fluidsynth-dialog.cpp:118
+msgid "Speed:"
+msgstr "Velocidad:"
+
+#: gui/fluidsynth-dialog.cpp:125
+msgid "Depth:"
+msgstr "Profundidad:"
+
+#: gui/fluidsynth-dialog.cpp:132
+msgid "Type:"
+msgstr "Tipo"
+
+#: gui/fluidsynth-dialog.cpp:135
+msgid "Sine"
+msgstr "Seno"
+
+#: gui/fluidsynth-dialog.cpp:136
+msgid "Triangle"
+msgstr "Triángulo"
+
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
+msgid "Misc"
+msgstr "Otras"
+
+#: gui/fluidsynth-dialog.cpp:140
+msgid "Interpolation:"
+msgstr "Interpolación:"
+
+#: gui/fluidsynth-dialog.cpp:143
+msgid "None (fastest)"
+msgstr "Ninguna (la más rápida)"
+
+#: gui/fluidsynth-dialog.cpp:144
+msgid "Linear"
+msgstr "Lineal"
+
+#: gui/fluidsynth-dialog.cpp:145
+msgid "Fourth-order"
+msgstr "Cuarto grado"
+
+#: gui/fluidsynth-dialog.cpp:146
+msgid "Seventh-order"
+msgstr "Séptimo grado"
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset"
+msgstr "Reiniciar"
+
+#: gui/fluidsynth-dialog.cpp:150
+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: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 "Aceptar"
+
+#: gui/fluidsynth-dialog.cpp:217
+msgid ""
+"Do you really want to reset all FluidSynth settings to their default values?"
msgstr ""
+"¿Seguro que quieres volver a los valores por defecto de las opciones de "
+"FluidSynth?"
-#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
+#: 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 "Cerrar"
-#: gui/gui-manager.cpp:120
+#: gui/gui-manager.cpp:122
msgid "Mouse click"
msgstr "Clic de ratón"
-#: gui/gui-manager.cpp:124 base/main.cpp:319
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Mostrar el teclado"
-#: gui/gui-manager.cpp:128 base/main.cpp:323
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Asignar teclas"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 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"
-#: gui/KeysDialog.h:36 gui/KeysDialog.cpp:145
-msgid "Choose an action to map"
-msgstr "Elige una acción para asociarla"
-
#: gui/KeysDialog.cpp:41
msgid "Map"
msgstr "Asignar"
-#: gui/KeysDialog.cpp:42 gui/launcher.cpp:352 gui/launcher.cpp:1048
-#: gui/launcher.cpp:1052 gui/massadd.cpp:92 gui/options.cpp:1238
-#: gui/saveload-dialog.cpp:932 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:402 engines/engine.cpp:413
-#: 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/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 "Aceptar"
-
#: gui/KeysDialog.cpp:49
msgid "Select an action and click 'Map'"
msgstr "Selecciona una acción y pulsa 'Asignar'"
@@ -160,6 +279,10 @@ msgstr "Por favor, selecciona una acción"
msgid "Press the key to associate"
msgstr "Pulsa una tecla para asignarla"
+#: gui/KeysDialog.cpp:145 gui/KeysDialog.h:36
+msgid "Choose an action to map"
+msgstr "Elige una acción para asociarla"
+
#: gui/launcher.cpp:193
msgid "Game"
msgstr "Juego"
@@ -202,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>"
@@ -225,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."
@@ -242,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"
@@ -255,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"
@@ -273,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:95
+#: 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:69
+#: 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:1222
+#: 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/myst.cpp:245 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/myst.cpp:245
-#: engines/mohawk/riven.cpp:718 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:792
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -490,62 +614,42 @@ msgstr ""
"¿Seguro que quieres ejecutar la detección masiva? Puede que se añada un gran "
"número de juegos."
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Sí"
-
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "No"
-
-#: gui/launcher.cpp:841
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "¡ScummVM no ha podido abrir el directorio!"
-#: gui/launcher.cpp:853
+#: 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:867
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Elige el juego:"
-#: gui/launcher.cpp:941
+#: 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:999
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "¿Quieres cargar la partida guardada?"
-#: gui/launcher.cpp:1048
+#: 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:1052
+#: 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:1159
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Añadir varios..."
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1165
msgid "Record..."
-msgstr ""
+msgstr "Grabar..."
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
@@ -572,151 +676,149 @@ msgstr "%d juegos nuevos encontrados. %d juegos ignorados (ya añadidos)..."
#: gui/onscreendialog.cpp:101 gui/onscreendialog.cpp:103
msgid "Stop"
-msgstr ""
+msgstr "Detener"
#: gui/onscreendialog.cpp:106
msgid "Edit record description"
-msgstr ""
+msgstr "Editar la descripción de la grabación"
#: gui/onscreendialog.cpp:108
-#, fuzzy
msgid "Switch to Game"
-msgstr "Cambiar"
+msgstr "Volver al juego"
#: gui/onscreendialog.cpp:110
-#, fuzzy
msgid "Fast replay"
-msgstr "Modo rápido"
+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 expansión compatibles con algunos juegos"
+msgstr "Modos especiales de difuminado compatibles con algunos juegos"
-#: gui/options.cpp:758
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2298
+#: 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"
@@ -724,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"
@@ -793,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"
@@ -810,174 +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:1168 gui/fluidsynth-dialog.cpp:138
-msgid "Misc"
-msgstr "Otras"
-
-#: 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."
@@ -986,64 +1096,75 @@ msgstr ""
"este tema debes cambiar a otro idioma primero."
#. I18N: You must leave "#" as is, only word 'next' is translatable
-#: gui/predictivedialog.cpp:87
+#: gui/predictivedialog.cpp:86
msgid "# next"
-msgstr ""
+msgstr "# siguiente"
-#: gui/predictivedialog.cpp:88
+#: gui/predictivedialog.cpp:87
msgid "add"
-msgstr ""
+msgstr "añadir"
-#: gui/predictivedialog.cpp:92
-#, fuzzy
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
-msgstr "Borrar"
+msgstr "Borrar personaje"
-#: gui/predictivedialog.cpp:96
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
-msgstr ""
+msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:98
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
-msgstr ""
+msgstr "* Pre"
+
+#. I18N: 'Num' means Numbers
+#: gui/predictivedialog.cpp:578
+msgid "* Num"
+msgstr "* Num"
-#: gui/recorderdialog.cpp:64
+#. I18N: 'Abc' means Latin alphabet input
+#: gui/predictivedialog.cpp:581
+msgid "* Abc"
+msgstr "* Abc"
+
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
-msgstr ""
+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 ""
+msgstr "Grabar"
-#: gui/recorderdialog.cpp:72
-#, fuzzy
+#: gui/recorderdialog.cpp:71
msgid "Playback"
-msgstr "Jugar"
+msgstr "Reproducción"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
-msgstr ""
+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 ""
+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 ""
+msgstr "Notas:"
-#: gui/recorderdialog.cpp:155
-#, fuzzy
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
-msgstr "¿Seguro que quieres borrar esta partida?"
+msgstr "¿Seguro que quieres borrar esta grabación?"
+
+#: gui/recorderdialog.cpp:173
+msgid "Unknown Author"
+msgstr "Autor desconocido"
#: gui/saveload-dialog.cpp:167
msgid "List view"
@@ -1105,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:"
@@ -1114,151 +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:661
+#: 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
-msgid "Clear value"
-msgstr "Eliminar valor"
-
-#: gui/fluidsynth-dialog.cpp:68
-msgid "Reverb"
-msgstr "Reverberación"
-
-#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
-msgid "Active"
-msgstr "Activa"
-
-#: gui/fluidsynth-dialog.cpp:72
-msgid "Room:"
-msgstr "Sala:"
-
-#: gui/fluidsynth-dialog.cpp:79
-msgid "Damp:"
-msgstr "Atenuación:"
-
-#: gui/fluidsynth-dialog.cpp:86
-msgid "Width:"
-msgstr "Amplitud"
-
-#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
-msgid "Level:"
-msgstr "Nivel:"
-
-#: gui/fluidsynth-dialog.cpp:100
-msgid "Chorus"
-msgstr "Coro"
-
-#: gui/fluidsynth-dialog.cpp:104
-msgid "N:"
-msgstr "N:"
-
-#: gui/fluidsynth-dialog.cpp:118
-msgid "Speed:"
-msgstr "Velocidad:"
-
-#: gui/fluidsynth-dialog.cpp:125
-msgid "Depth:"
-msgstr "Profundidad:"
-
-#: gui/fluidsynth-dialog.cpp:132
-msgid "Type:"
-msgstr "Tipo"
-
-#: gui/fluidsynth-dialog.cpp:135
-msgid "Sine"
-msgstr "Seno"
-
-#: gui/fluidsynth-dialog.cpp:136
-msgid "Triangle"
-msgstr "Triángulo"
-
-#: gui/fluidsynth-dialog.cpp:140
-msgid "Interpolation:"
-msgstr "Interpolación:"
-
-#: gui/fluidsynth-dialog.cpp:143
-msgid "None (fastest)"
-msgstr "Ninguna (la más rápida)"
-
-#: gui/fluidsynth-dialog.cpp:144
-msgid "Linear"
-msgstr "Lineal"
-
-#: gui/fluidsynth-dialog.cpp:145
-msgid "Fourth-order"
-msgstr "Cuarto grado"
-
-#: gui/fluidsynth-dialog.cpp:146
-msgid "Seventh-order"
-msgstr "Séptimo grado"
+#: 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/fluidsynth-dialog.cpp:150
-msgid "Reset"
-msgstr "Reiniciar"
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr ""
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset all FluidSynth settings to their default values."
-msgstr "Volver a los valores por defecto de las opciones de FluidSynth"
+#: gui/updates-dialog.cpp:92
+#, fuzzy
+msgid "Check for updates automatically"
+msgstr "Buscar actualizaciones..."
-#: gui/fluidsynth-dialog.cpp:217
-msgid ""
-"Do you really want to reset all FluidSynth settings to their default values?"
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
msgstr ""
-"¿Seguro que quieres volver a los valores por defecto de las opciones de "
-"FluidSynth?"
-#: base/main.cpp:228
+#: 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: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:306
+#: base/main.cpp:315
msgid "Menu"
msgstr "Menú"
-#: base/main.cpp:309 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:312 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:315
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Saltar frase"
-#: base/main.cpp:507
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Error al ejecutar el juego:"
-#: base/main.cpp:554
+#: 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"
@@ -1326,16 +1381,60 @@ msgstr "Cancel·lat per l'usuari"
msgid "Unknown error"
msgstr "Error desconocido"
-#: engines/advancedDetector.cpp:317
+#. I18N: Hercules is graphics card name
+#: common/rendermode.cpp:35
+msgid "Hercules Green"
+msgstr "Hercules verde"
+
+#: common/rendermode.cpp:36
+msgid "Hercules Amber"
+msgstr "Hercules ámbar"
+
+#: common/rendermode.cpp:42
+msgid "PC-9821 (256 Colors)"
+msgstr "PC-9821 (256 colores)"
+
+#: common/rendermode.cpp:43
+msgid "PC-9801 (16 Colors)"
+msgstr "PC-9801 (16 colores)"
+
+#: common/rendermode.cpp:73
+msgctxt "lowres"
+msgid "Hercules Green"
+msgstr "Hercules verde"
+
+#: common/rendermode.cpp:74
+msgctxt "lowres"
+msgid "Hercules Amber"
+msgstr "Hercules ámbar"
+
+#: 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.:"
@@ -1343,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"
@@ -1372,11 +1471,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "~V~olver al lanzador"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:803
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:873
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
-#: engines/toltecs/menu.cpp:281 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"
@@ -1385,11 +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:803 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/neverhood/menumodule.cpp:873 engines/pegasus/pegasus.cpp:377
-#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
-#: engines/toltecs/menu.cpp:281 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"
@@ -1413,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"
@@ -1427,23 +1535,23 @@ msgstr "~C~ancelar"
msgid "~K~eys"
msgstr "~T~eclas"
-#: engines/engine.cpp:276
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "No se ha podido iniciar el formato de color."
-#: engines/engine.cpp:284
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "No se ha podido cambiar al modo de video: '"
-#: engines/engine.cpp:293
+#: 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:298
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "No se ha podido aplicar el ajuste de pantalla completa."
-#: engines/engine.cpp:398
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1457,7 +1565,7 @@ msgstr ""
"copiar los archivos del juego al disco duro.\n"
"Consulta el archivo README para más detalles."
-#: engines/engine.cpp:409
+#: 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"
@@ -1471,7 +1579,7 @@ msgstr ""
"poder escuchar la música del juego.\n"
"Consulta el archivo README para más detalles."
-#: engines/engine.cpp:467
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1481,7 +1589,7 @@ msgstr ""
"README para encontrar información básica e instrucciones sobre cómo obtener "
"más ayuda."
-#: engines/engine.cpp:480
+#: 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 "
@@ -1491,10 +1599,14 @@ 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:483
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Jugar aun así"
+#: audio/adlib.cpp:2290
+msgid "AdLib Emulator"
+msgstr "Emulador de AdLib"
+
#: audio/fmopl.cpp:62
msgid "MAME OPL emulator"
msgstr "Emulador OPL de MAME"
@@ -1505,7 +1617,7 @@ msgstr "Emulador OPL de DOSBox"
#: audio/fmopl.cpp:67
msgid "ALSA Direct FM"
-msgstr ""
+msgstr "ALSA Direct FM"
#: audio/mididrv.cpp:209
#, c-format
@@ -1548,31 +1660,35 @@ msgstr ""
"El dispositivo de sonido preferido, '%s', no se puede utilizar. Consulta el "
"registro para más información."
-#: audio/null.h:44
-msgid "No music"
-msgstr "Sin música"
-
#: audio/mods/paula.cpp:196
msgid "Amiga Audio Emulator"
msgstr "Emulador de Amiga Audio"
-#: audio/adlib.cpp:2291
-msgid "AdLib Emulator"
-msgstr "Emulador de AdLib"
+#: audio/null.h:44
+msgid "No music"
+msgstr "Sin música"
#: audio/softsynth/appleiigs.cpp:33
msgid "Apple II GS Emulator (NOT IMPLEMENTED)"
msgstr "Emulador de Apple II GS (NO IMPLEMENTADO)"
-#: audio/softsynth/sid.cpp:1430
-msgid "C64 Audio Emulator"
-msgstr "Emulador de C64 Audio"
+#: audio/softsynth/cms.cpp:350
+msgid "Creative Music System Emulator"
+msgstr "Emulador de Creative Music System"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33
+msgid "FM-Towns Audio"
+msgstr "FM-Towns Audio"
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58
+msgid "PC-98 Audio"
+msgstr "PC-98 Audio"
+
+#: 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"
@@ -1584,6 +1700,146 @@ msgstr "Emulador del altavoz de PC"
msgid "IBM PCjr Emulator"
msgstr "Emulador de IBM PCjr"
+#: audio/softsynth/sid.cpp:1430
+msgid "C64 Audio Emulator"
+msgstr "Emulador de C64 Audio"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Do you really want to return to the Launcher?"
+msgstr "¿Seguro que quieres volver al lanzador?"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Launcher"
+msgstr "Lanzador"
+
+#: backends/events/default/default-events.cpp:218
+msgid "Do you really want to quit?"
+msgstr "¿Seguro que quieres salir?"
+
+#: 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 "Salir"
+
+#: 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 "'Modo toque' de pantalla táctil - Clic izquierdo"
+
+#: 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 "'Modo toque' de pantalla táctil - Clic derecho"
+
+#: 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 "'Modo toque' de pantalla táctil - Flotante (sin clic)"
+
+#: backends/events/gph/gph-events.cpp:409
+msgid "Maximum Volume"
+msgstr "Volumen máximo"
+
+#: backends/events/gph/gph-events.cpp:411
+msgid "Increasing Volume"
+msgstr "Aumentando el volumen"
+
+#: backends/events/gph/gph-events.cpp:417
+msgid "Minimal Volume"
+msgstr "Volumen mínimo"
+
+#: backends/events/gph/gph-events.cpp:419
+msgid "Decreasing Volume"
+msgstr "Bajando el volumen"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Enabled"
+msgstr "Clic activado"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Disabled"
+msgstr "Clic desactivado"
+
+#: backends/events/openpandora/op-events.cpp:174
+msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
+msgstr "'Modo toque' de pantalla táctil - Flotante (clic de cruceta)"
+
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
+msgid "Do you want to quit ?"
+msgstr "¿Quieres salir?"
+
+#. I18N: Trackpad mode toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:308
+msgid "Trackpad mode is now"
+msgstr "El modo trackpad está"
+
+#. 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 "activado"
+
+#: backends/events/webossdl/webossdl-events.cpp:311
+#: backends/events/webossdl/webossdl-events.cpp:338
+msgid "OFF"
+msgstr "desactivado"
+
+#: backends/events/webossdl/webossdl-events.cpp:315
+msgid "Swipe two fingers to the right to toggle."
+msgstr "Desliza dos dedos hacia la derecha para cambiar de modo."
+
+#. I18N: Auto-drag toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:335
+msgid "Auto-drag mode is now"
+msgstr "El modo de arrastre automático está"
+
+#: backends/events/webossdl/webossdl-events.cpp:342
+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:126
+msgid "OpenGL"
+msgstr "OpenGL"
+
+#: backends/graphics/opengl/opengl-graphics.cpp:127
+msgid "OpenGL (No filtering)"
+msgstr "OpenGL (sin filtros)"
+
+#: 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 "Normal (sin reescalado)"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:66
+msgctxt "lowres"
+msgid "Normal (no scaling)"
+msgstr "Normal"
+
+#: 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:2219
+msgid "Disabled aspect ratio correction"
+msgstr "Desactivar la corrección de aspecto"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
+msgid "Active graphics filter:"
+msgstr "Filtro de gráficos activo:"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+msgid "Windowed mode"
+msgstr "Modo ventana"
+
#: backends/keymapper/remap-dialog.cpp:48
msgid "Keymap:"
msgstr "Asignación de teclas:"
@@ -1613,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~"
@@ -1689,18 +1945,26 @@ msgstr "Sonido de alta calidad (más lento) (reinicio)"
msgid "Disable power off"
msgstr "Desactivar apagado"
+#: 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 "Modo clic-de-ratón-y-arrastrar activado."
+#: 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 "Modo clic-de-ratón-y-arrastrar desactivado."
+#: 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 "Modo Touchpad activado."
+#: 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 "Modo Touchpad desactivado."
@@ -1711,9 +1975,9 @@ msgstr "Modo clic"
#: 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
-#: backends/platform/tizen/form.cpp:275
msgid "Left Click"
msgstr "Clic izquierdo"
@@ -1723,65 +1987,32 @@ msgstr "Clic central"
#: backends/platform/maemo/maemo.cpp:220
#: backends/platform/symbian/src/SymbianActions.cpp:43
-#: backends/platform/wince/CEActionsSmartphone.cpp:44
#: backends/platform/tizen/form.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:44
msgid "Right Click"
msgstr "Clic derecho"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:77
+#: backends/platform/sdl/macosx/appmenu_osx.mm:88
msgid "Hide ScummVM"
msgstr "Ocultar ScummVM"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:82
+#: backends/platform/sdl/macosx/appmenu_osx.mm:93
msgid "Hide Others"
msgstr "Ocultar otros"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:87
+#: backends/platform/sdl/macosx/appmenu_osx.mm:98
msgid "Show All"
msgstr "Mostrar todo"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:109
#: backends/platform/sdl/macosx/appmenu_osx.mm:120
+#: backends/platform/sdl/macosx/appmenu_osx.mm:131
msgid "Window"
msgstr "Ventana"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:114
+#: backends/platform/sdl/macosx/appmenu_osx.mm:125
msgid "Minimize"
msgstr "Minimizar"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:46
-msgid "Normal (no scaling)"
-msgstr "Normal (sin reescalado)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:65
-msgctxt "lowres"
-msgid "Normal (no scaling)"
-msgstr "Normal"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
-msgid "Enabled aspect ratio correction"
-msgstr "Activar la corrección de aspecto"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
-msgid "Disabled aspect ratio correction"
-msgstr "Desactivar la corrección de aspecto"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
-msgid "Active graphics filter:"
-msgstr "Filtro de gráficos activo:"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
-msgid "Windowed mode"
-msgstr "Modo ventana"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:118
-msgid "OpenGL"
-msgstr "OpenGL"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:119
-msgid "OpenGL (No filtering)"
-msgstr "OpenGL (sin filtros)"
-
#: backends/platform/symbian/src/SymbianActions.cpp:38
#: backends/platform/wince/CEActionsSmartphone.cpp:39
msgid "Up"
@@ -1825,14 +2056,6 @@ msgstr "Saltar texto"
msgid "Fast mode"
msgstr "Modo rápido"
-#: backends/platform/symbian/src/SymbianActions.cpp:52
-#: backends/platform/wince/CEActionsPocket.cpp:44
-#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: backends/events/default/default-events.cpp:218 engines/scumm/dialogs.cpp:192
-#: engines/scumm/help.cpp:83 engines/scumm/help.cpp:85
-msgid "Quit"
-msgstr "Salir"
-
#: backends/platform/symbian/src/SymbianActions.cpp:53
msgid "Debugger"
msgstr "Debugger"
@@ -1849,9 +2072,49 @@ msgstr "Teclado virtual"
msgid "Key mapper"
msgstr "Asignación de teclas"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:186
-msgid "Do you want to quit ?"
-msgstr "¿Quieres salir?"
+#: backends/platform/tizen/form.cpp:263
+msgid "Right Click Once"
+msgstr "Un clic derecho"
+
+#: backends/platform/tizen/form.cpp:271
+msgid "Move Only"
+msgstr "Solo mover"
+
+#: backends/platform/tizen/form.cpp:294
+msgid "Escape Key"
+msgstr "Tecla Escape"
+
+#: backends/platform/tizen/form.cpp:299
+msgid "Game Menu"
+msgstr "Menú del juego"
+
+#: backends/platform/tizen/form.cpp:304
+msgid "Show Keypad"
+msgstr "Mostrar el teclado numérico"
+
+#: backends/platform/tizen/form.cpp:309
+msgid "Control Mouse"
+msgstr "Control del ratón"
+
+#: backends/platform/tizen/fs.cpp:259
+msgid "[ Data ]"
+msgstr "[ Datos ]"
+
+#: backends/platform/tizen/fs.cpp:263
+msgid "[ Resources ]"
+msgstr "[ Recursos ]"
+
+#: backends/platform/tizen/fs.cpp:267
+msgid "[ SDCard ]"
+msgstr "[ Tarjeta SD ]"
+
+#: backends/platform/tizen/fs.cpp:271
+msgid "[ Media ]"
+msgstr "[ Media ]"
+
+#: backends/platform/tizen/fs.cpp:275
+msgid "[ Shared ]"
+msgstr "[ Compartido ]"
#: backends/platform/wii/options.cpp:51
msgid "Video"
@@ -2099,141 +2362,106 @@ msgstr ""
"No olvides asignar una tecla a la acción 'Ocultar barra de tareas' para ver "
"todo el inventario"
-#: backends/events/default/default-events.cpp:196
-msgid "Do you really want to return to the Launcher?"
-msgstr "¿Seguro que quieres volver al lanzador?"
-
-#: backends/events/default/default-events.cpp:196
-msgid "Launcher"
-msgstr "Lanzador"
-
-#: backends/events/default/default-events.cpp:218
-msgid "Do you really want to quit?"
-msgstr "¿Seguro que quieres salir?"
-
-#: 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 "'Modo toque' de pantalla táctil - Clic izquierdo"
-
-#: 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 "'Modo toque' de pantalla táctil - Clic derecho"
-
-#: 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 "'Modo toque' de pantalla táctil - Flotante (sin clic)"
-
-#: backends/events/gph/gph-events.cpp:409
-msgid "Maximum Volume"
-msgstr "Volumen máximo"
-
-#: backends/events/gph/gph-events.cpp:411
-msgid "Increasing Volume"
-msgstr "Aumentando el volumen"
-
-#: backends/events/gph/gph-events.cpp:417
-msgid "Minimal Volume"
-msgstr "Volumen mínimo"
-
-#: backends/events/gph/gph-events.cpp:419
-msgid "Decreasing Volume"
-msgstr "Bajando el volumen"
-
-#: backends/events/openpandora/op-events.cpp:174
-msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
-msgstr "'Modo toque' de pantalla táctil - Flotante (clic de cruceta)"
-
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Buscar actualizaciones..."
-#: backends/platform/tizen/form.cpp:263
-msgid "Right Click Once"
-msgstr "Un clic derecho"
-
-#: backends/platform/tizen/form.cpp:271
-msgid "Move Only"
-msgstr "Solo mover"
-
-#: backends/platform/tizen/form.cpp:294
-msgid "Escape Key"
-msgstr "Tecla Escape"
-
-#: backends/platform/tizen/form.cpp:299
-msgid "Game Menu"
-msgstr "Menú del juego"
-
-#: backends/platform/tizen/form.cpp:304
-msgid "Show Keypad"
-msgstr "Mostrar el teclado numérico"
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "Modo para daltónicos"
-#: backends/platform/tizen/form.cpp:309
-msgid "Control Mouse"
-msgstr "Control del ratón"
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Enabled"
-msgstr "Clic activado"
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Disabled"
-msgstr "Clic desactivado"
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "Mostrar etiquetas de objetos"
-#: engines/agi/detection.cpp:147 engines/drascula/detection.cpp:302
-#: engines/dreamweb/detection.cpp:47 engines/neverhood/detection.cpp:160
-#: engines/sci/detection.cpp:394 engines/toltecs/detection.cpp:200
-#: engines/zvision/detection_tables.h:51
+#: 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 "Usar pantallas de guardar/cargar originales"
-#: engines/agi/detection.cpp:148 engines/drascula/detection.cpp:303
-#: engines/dreamweb/detection.cpp:48 engines/neverhood/detection.cpp:161
-#: engines/sci/detection.cpp:395 engines/toltecs/detection.cpp:201
+#: 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 ""
"Utilizar las pantallas de guardar/cargar originales, en vez de las de ScummVM"
#: engines/agi/detection.cpp:157
-#, fuzzy
msgid "Use an alternative palette"
-msgstr ""
-"Usa una introducción alternativa para el juego (solo para la versión CD)"
+msgstr "Usar paleta alternativa"
#: engines/agi/detection.cpp:158
msgid ""
"Use an alternative palette, common for all Amiga games. This was the old "
"behavior"
msgstr ""
+"Usar una paleta alternativa, común para todos los juegos de Amiga. Esta es "
+"la opción que se usaba antes."
#: engines/agi/detection.cpp:167
-#, fuzzy
msgid "Mouse support"
-msgstr "Permitir omisiones"
+msgstr "Compatibilidad de ratón"
#: engines/agi/detection.cpp:168
msgid ""
"Enables mouse support. Allows to use mouse for movement and in game menus."
msgstr ""
+"Activa el ratón. Permite usar el ratón para moverse en el juego y en los "
+"menús."
+
+#: 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:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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"
@@ -2244,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"
@@ -2255,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"
@@ -2266,19 +2494,18 @@ 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'"
#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
-#, fuzzy
msgid "Color Blind Mode"
-msgstr "Modo clic"
+msgstr "Modo para daltónicos"
#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
-msgstr ""
+msgstr "Activar por defecto el modo para daltónicos"
#: engines/drascula/saveload.cpp:47
msgid ""
@@ -2298,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."
@@ -2328,17 +2555,17 @@ 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"
#: engines/hopkins/detection.cpp:76 engines/hopkins/detection.cpp:86
msgid "Gore Mode"
-msgstr ""
+msgstr "Modo sangriento"
#: engines/hopkins/detection.cpp:77 engines/hopkins/detection.cpp:87
msgid "Enable Gore Mode when available"
-msgstr ""
+msgstr "Activar el modo sangriento si está disponible"
#. I18N: Studio audience adds an applause and cheering sounds whenever
#. Malcolm makes a joke.
@@ -2470,6 +2697,12 @@ msgid ""
"Do you wish to use this save game file with ScummVM?\n"
"\n"
msgstr ""
+"Se ha encontrado esta partida guardada en el directorio del juego:\n"
+"\n"
+"%s %s\n"
+"\n"
+"Do you wish to use this save game file with ScummVM?\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:590
#, c-format
@@ -2477,6 +2710,8 @@ msgid ""
"A save game file was found in the specified slot %d. Overwrite?\n"
"\n"
msgstr ""
+"Ya hay una partida guardada en la ranura %d. ¿Quieres sobrescribirla?\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:623
#, c-format
@@ -2488,51 +2723,66 @@ msgid ""
"'import_savefile'.\n"
"\n"
msgstr ""
+"Se han importado %d partidas guardadas originales.\n"
+"Si más adelante quieres importar manualmente más partidas guardadas\n"
+"originales, tendrás que abrir la consola de ScummVM y usar el comando "
+"'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"
@@ -2541,15 +2791,23 @@ msgstr ""
"No se puede guardar en la ranura %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:194
+msgid "Load file"
+msgstr "Cargar partida"
+
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Cargando partida..."
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:209
+msgid "Save file"
+msgstr "Guardar partida"
+
+#: 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"
@@ -2566,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"
@@ -2627,27 +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 ""
+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:395
+msgid "Enable high resolution graphics/content"
+msgstr "Activar gráficos/contenido de alta resolución"
+
+#: 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:385
+#: 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:404
+#: 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:405
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2655,149 +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:415
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "Usar CD audio"
-#: engines/sci/detection.cpp:416
+#: 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:426
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Usar cursores de Windows"
-#: engines/sci/detection.cpp:427
+#: 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:437
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Usar cursores plateados"
-#: engines/sci/detection.cpp:438
+#: 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
-#, fuzzy
+#: 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
-#, fuzzy
+#: 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:600
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Solo voces"
-#: engines/scumm/dialogs.cpp:601
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Voces y subtítulos"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Solo subtítulos"
-#: engines/scumm/dialogs.cpp:610
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Voces y sub."
-#: engines/scumm/dialogs.cpp:656
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Selecciona un nivel de dificultad."
-#: engines/scumm/dialogs.cpp:658
+#: 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:662
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Práctica"
-#: engines/scumm/dialogs.cpp:663
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Experto"
@@ -3222,25 +3506,24 @@ msgid "Third kid"
msgstr "Tercer chaval"
#: engines/scumm/help.cpp:292
-#, fuzzy
msgid "Toggle Inventory/IQ Points display"
-msgstr "Activar/Desactivar pantalla de datos"
+msgstr "Alternar entre el inventario y la pantalla de puntuación"
#: engines/scumm/help.cpp:293
msgid "Toggle Keyboard/Mouse Fighting (*)"
-msgstr ""
+msgstr "Alternar entre modo de lucha con teclado o con ratón (*)"
#: engines/scumm/help.cpp:295
msgid "* Keyboard Fighting is always on,"
-msgstr ""
+msgstr "* El modo de lucha con teclado siempre está activo,"
#: engines/scumm/help.cpp:296
msgid " so despite the in-game message this"
-msgstr ""
+msgstr " así que, independientemente de lo que diga el juego,"
#: engines/scumm/help.cpp:297
msgid " actually toggles Mouse Fighting Off/On"
-msgstr ""
+msgstr " esta opción activa/desactiva el modo de lucha con ratón"
#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
@@ -3277,7 +3560,7 @@ msgstr "Puñetazo bajo"
#: engines/scumm/help.cpp:315
msgid "Sucker punch"
-msgstr ""
+msgstr "Puñetazo a traición"
#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
@@ -3335,7 +3618,23 @@ msgstr "Volar a la derecha"
msgid "Fly to lower right"
msgstr "Volar abajo y a la derecha"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/input.cpp:578
+msgid "Snap scroll on"
+msgstr "Desplazamiento mediante toques"
+
+#: engines/scumm/input.cpp:580
+msgid "Snap scroll off"
+msgstr "Desplazamiento normal"
+
+#: engines/scumm/input.cpp:593
+msgid "Music volume: "
+msgstr "Volumen de la música:"
+
+#: engines/scumm/input.cpp:610
+msgid "Subtitle speed: "
+msgstr "Vel. de subtítulos:"
+
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3344,28 +3643,89 @@ 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
-#, fuzzy
+#: 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 ""
-"Maniac Mansion debería arrancar en este momento, pero ScummVM aún no lo "
-"permite. Para jugar, ve a 'Añadir juego' en el menú de inicio de ScummVM y "
-"selecciona el directorio 'Maniac', dentro del directorio de DOTT."
+"Maniac Mansion debería arrancar en este momento, pero para que esto sea "
+"posible debes mover los archivos de Maniac Mansion al directorio 'Maniac', "
+"dentro del directorio de DOTT, y añadir el juego a ScummVM."
#: 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 ""
+"No se ha podido encontrar el ejecutable de Macintosh de 'Loom'\n"
+"para reproducir los instrumentos. Se ha desactivado la música."
#: 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 ""
+"No se ha podido encontrar el ejecutable de Macintosh de 'Monkey Island'\n"
+"para reproducir los instrumentos. Se ha desactivado la música."
+
+#: engines/sherlock/detection.cpp:71
+msgid "Use original savegame dialog"
+msgstr "Usar menús originales al guardar/cargar"
+
+#: engines/sherlock/detection.cpp:72
+msgid ""
+"Files button in-game shows original savegame dialog rather than the ScummVM "
+"menu"
+msgstr ""
+"Se usan los menús originales para guardar y cargar partida en vez de los "
+"menús de ScummVM"
+
+#: engines/sherlock/detection.cpp:81
+msgid "Pixellated scene transitions"
+msgstr "Transiciones pixeladas"
+
+#: engines/sherlock/detection.cpp:82
+msgid "When changing scenes, a randomized pixel transition is done"
+msgstr "Al cambiar de escena, se utiliza una transición aleatoria de píxeles"
+
+#: engines/sherlock/detection.cpp:91
+msgid "Don't show hotspots when moving mouse"
+msgstr "No mostrar los puntos interactivos al mover el ratón"
+
+#: engines/sherlock/detection.cpp:92
+msgid ""
+"Only show hotspot names after you actually click on a hotspot or action "
+"button"
+msgstr ""
+"El nombre de los puntos interactivos solo aparece al hacer clic en uno de "
+"ellos o en un botón de acción."
+
+#: engines/sherlock/detection.cpp:101
+msgid "Show character portraits"
+msgstr "Mostrar retratos"
+
+#: engines/sherlock/detection.cpp:102
+msgid "Show portraits for the characters when conversing"
+msgstr "Mostrar retratos de los personajes durante las conversaciones"
+
+#: engines/sherlock/detection.cpp:111
+msgid "Slide dialogs into view"
+msgstr "Utilizar una transición al mostrar los diálogos"
+
+#: engines/sherlock/detection.cpp:112
+msgid "Slide UI dialogs into view, rather than simply showing them immediately"
+msgstr ""
+"Los diálogos se muestran con una transición, en vez de aparecer "
+"inmediatamente"
+
+#: engines/sherlock/detection.cpp:121
+msgid "Transparent windows"
+msgstr "Ventanas transparentes"
+
+#: engines/sherlock/detection.cpp:122
+msgid "Show windows with a partially transparent background"
+msgstr "Mostrar las ventanas con un fondo parcialmente transparente"
#: engines/sky/compact.cpp:130
msgid ""
@@ -3469,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"
@@ -3486,53 +3855,50 @@ msgstr ""
#: engines/wintermute/detection.cpp:58
msgid "Show FPS-counter"
-msgstr ""
+msgstr "Mostrar contador de FPS"
#: engines/wintermute/detection.cpp:59
msgid "Show the current number of frames per second in the upper left corner"
msgstr ""
+"El número de fotogramas por segundo aparece en la esquina superior izquierda"
#: engines/zvision/detection_tables.h:52
-#, fuzzy
msgid "Use the original save/load screens instead of the ScummVM interface"
msgstr ""
-"Utilizar las pantallas de guardar/cargar originales, en vez de las de ScummVM"
+"Utilizar los menús originales para guardar/cargar, en vez de los de ScummVM"
#: engines/zvision/detection_tables.h:61
msgid "Double FPS"
-msgstr ""
+msgstr "Duplicar FPS"
#: engines/zvision/detection_tables.h:62
msgid "Increase framerate from 30 to 60 FPS"
-msgstr ""
+msgstr "Aumenta el número de fotogramas por segundo de 30 a 60"
#: engines/zvision/detection_tables.h:71
-#, fuzzy
msgid "Enable Venus"
-msgstr "Activar el modo helio"
+msgstr "Activar Venus"
#: engines/zvision/detection_tables.h:72
-#, fuzzy
msgid "Enable the Venus help system"
-msgstr "Activar el modo helio"
+msgstr "Activar el modo de ayuda Venus"
#: engines/zvision/detection_tables.h:81
msgid "Disable animation while turning"
-msgstr ""
+msgstr "Desactivar animación al girar"
#: engines/zvision/detection_tables.h:82
msgid "Disable animation while turning in panorama mode"
-msgstr ""
+msgstr "Desactivar la animación al girar en el modo panorama"
#: engines/zvision/detection_tables.h:91
msgid "Use high resolution MPEG video"
-msgstr ""
+msgstr "Usar vídeos MPEG de alta resolución"
#: engines/zvision/detection_tables.h:92
-#, fuzzy
msgid "Use MPEG video from the DVD version, instead of lower resolution AVI"
msgstr ""
-"Usar los cursores plateados alternativos, en vez de los dorados normales"
+"Usar los vídeos MPEG de la versión DVD, en vez de los AVI de baja resolución"
#~ msgid "EGA undithering"
#~ msgstr "Difuminado EGA"
@@ -3579,23 +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"
-
-#~ msgid "Hercules Green"
-#~ msgstr "Hercules verde"
-
-#~ msgid "Hercules Amber"
-#~ msgstr "Hercules ámbar"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Green"
-#~ msgstr "Hercules verde"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Amber"
-#~ msgstr "Hercules ámbar"
-
-#~ msgid "Save game failed!"
-#~ msgstr "No se ha podido guardar la partida."
diff --git a/po/eu.po b/po/eu.po
index 913338606e..e0100ed169 100644
--- a/po/eu.po
+++ b/po/eu.po
@@ -1,5 +1,5 @@
# Basque translation for ScummVM.
-# Copyright (C) 2012-2015 The ScummVM Team
+# Copyright (C) 2012-2016 The ScummVM Team
# This file is distributed under the same license as the ScummVM package.
# Mikel Iturbe Urretxa <mikel@hamahiru.org>, 2012.
#
@@ -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: 2015-09-06 15:14+0200\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"
@@ -30,13 +30,12 @@ msgid "Available engines:"
msgstr "Motore erabilgarriak:"
#: gui/browser.cpp:68 gui/browser_osx.mm:104
-#, fuzzy
msgid "Show hidden files"
-msgstr "Kontsola erakutsi / ezkutatu"
+msgstr "Erakutsi fitxategi ezkutuak"
#: gui/browser.cpp:68
msgid "Show files marked with the hidden attribute"
-msgstr ""
+msgstr "Erakutsi ezkutu modura markaturiko fitxategiak"
#: gui/browser.cpp:72
msgid "Go up"
@@ -52,28 +51,29 @@ msgid "Go up"
msgstr "Joan gora"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:74 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: 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/fluidsynth-dialog.cpp:152 engines/engine.cpp:483
-#: backends/platform/wii/options.cpp:48
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
-#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:191 engines/sword1/control.cpp:865
+#: 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 "Utzi"
#: gui/browser.cpp:76 gui/browser_osx.mm:103 gui/chooser.cpp:47
-#: gui/themebrowser.cpp:56
+#: gui/filebrowser-dialog.cpp:65 gui/themebrowser.cpp:56
msgid "Choose"
msgstr "Aukeratu"
#: gui/editrecorddialog.cpp:58
msgid "Author:"
-msgstr ""
+msgstr "Egilea:"
#: gui/editrecorddialog.cpp:59 gui/launcher.cpp:204
msgid "Name:"
@@ -81,63 +81,179 @@ msgstr "Izena:"
#: gui/editrecorddialog.cpp:60
msgid "Notes:"
-msgstr ""
+msgstr "Oharrak:"
-#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:75
+#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74
msgid "Ok"
-msgstr ""
+msgstr "Ados"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Choose file for loading"
+msgstr "Aukeratu kargatzeko fitxategia"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Enter filename for saving"
+msgstr "Sartu gordetzeko fitxategi-izena"
+
+#: gui/filebrowser-dialog.cpp:132
+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: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 "Bai"
+
+#: 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 "Ez"
-#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
+#: gui/fluidsynth-dialog.cpp:68
+msgid "Reverb"
+msgstr "Erreberberazioa"
+
+#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
+msgid "Active"
+msgstr "Aktiboa"
+
+#: gui/fluidsynth-dialog.cpp:72
+msgid "Room:"
+msgstr "Gela:"
+
+#: gui/fluidsynth-dialog.cpp:79
+msgid "Damp:"
+msgstr "Moteltzea:"
+
+#: gui/fluidsynth-dialog.cpp:86
+msgid "Width:"
+msgstr "Zabalera:"
+
+#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
+msgid "Level:"
+msgstr "Maila:"
+
+#: gui/fluidsynth-dialog.cpp:100
+msgid "Chorus"
+msgstr "Koroa"
+
+#: gui/fluidsynth-dialog.cpp:104
+msgid "N:"
+msgstr "N:"
+
+#: gui/fluidsynth-dialog.cpp:118
+msgid "Speed:"
+msgstr "Abiadura:"
+
+#: gui/fluidsynth-dialog.cpp:125
+msgid "Depth:"
+msgstr "Sakonera:"
+
+#: gui/fluidsynth-dialog.cpp:132
+msgid "Type:"
+msgstr "Mota:"
+
+#: gui/fluidsynth-dialog.cpp:135
+msgid "Sine"
+msgstr "Sinua"
+
+#: gui/fluidsynth-dialog.cpp:136
+msgid "Triangle"
+msgstr "Triangelua"
+
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
+msgid "Misc"
+msgstr "Beste"
+
+#: gui/fluidsynth-dialog.cpp:140
+msgid "Interpolation:"
+msgstr "Interpolazioa:"
+
+#: gui/fluidsynth-dialog.cpp:143
+msgid "None (fastest)"
+msgstr "Bat ere ez (azkarrena)"
+
+#: gui/fluidsynth-dialog.cpp:144
+msgid "Linear"
+msgstr "Lineala"
+
+#: gui/fluidsynth-dialog.cpp:145
+msgid "Fourth-order"
+msgstr "Laugarren ordena"
+
+#: gui/fluidsynth-dialog.cpp:146
+msgid "Seventh-order"
+msgstr "Zazpigarren ordena"
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset"
+msgstr "Berrezarri"
+
+#: gui/fluidsynth-dialog.cpp:150
+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: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 "Ados"
+
+#: gui/fluidsynth-dialog.cpp:217
+msgid ""
+"Do you really want to reset all FluidSynth settings to their default values?"
+msgstr "FluidSynth-en ezarpen guztiak berrezarri balio lehenetsietara?"
+
+#: 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 "Itxi"
-#: gui/gui-manager.cpp:120
+#: gui/gui-manager.cpp:122
msgid "Mouse click"
msgstr "Sagu-klika"
-#: gui/gui-manager.cpp:124 base/main.cpp:319
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
-msgstr "Teklatua erakutsi"
+msgstr "Erakutsi teklatua"
-#: gui/gui-manager.cpp:128 base/main.cpp:323
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
-msgstr "Teklak esleitu"
+msgstr "Esleitu teklak"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 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"
-#: gui/KeysDialog.h:36 gui/KeysDialog.cpp:145
-msgid "Choose an action to map"
-msgstr "Aukeratu esleituko den ekintza"
-
#: gui/KeysDialog.cpp:41
msgid "Map"
msgstr "Esleitu"
-#: gui/KeysDialog.cpp:42 gui/launcher.cpp:352 gui/launcher.cpp:1048
-#: gui/launcher.cpp:1052 gui/massadd.cpp:92 gui/options.cpp:1238
-#: gui/saveload-dialog.cpp:932 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:402 engines/engine.cpp:413
-#: 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/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 "Ados"
-
#: gui/KeysDialog.cpp:49
msgid "Select an action and click 'Map'"
msgstr "Aukeratu ekintza eta sakatu \"Esleitu\""
@@ -160,6 +276,10 @@ msgstr "Mesedez, aukeratu ekintza bat"
msgid "Press the key to associate"
msgstr "Sakatu esleituko den tekla"
+#: gui/KeysDialog.cpp:145 gui/KeysDialog.h:36
+msgid "Choose an action to map"
+msgstr "Aukeratu esleituko den ekintza"
+
#: gui/launcher.cpp:193
msgid "Game"
msgstr "Jokoa"
@@ -201,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>"
@@ -221,15 +341,14 @@ msgid "Platform:"
msgstr "Plataforma:"
#: gui/launcher.cpp:237
-#, fuzzy
msgid "Engine"
-msgstr "Aztertu"
+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"
@@ -242,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"
@@ -255,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"
@@ -273,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:95
+#: 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:69
+#: 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:1222
+#: 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/myst.cpp:245 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/myst.cpp:245
-#: engines/mohawk/riven.cpp:718 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:792
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -490,64 +610,43 @@ msgstr ""
"Joko detektatzaile masiboa exekutatu nahi al duzu? Honek joko kantitate "
"handia gehitu dezake."
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Bai"
-
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Ez"
-
-#: gui/launcher.cpp:841
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM-k ezin izan du zehazturiko direktorioa ireki!"
-#: gui/launcher.cpp:853
+#: 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:867
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Jokoa aukeratu:"
-#: gui/launcher.cpp:941
+#: 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:999
-#, fuzzy
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
-msgstr "Jokoa kargatu edo gorde nahi duzu?"
+msgstr "Gordetako jokoa kargatu?"
-#: gui/launcher.cpp:1048
+#: 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:1052
+#: 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:1159
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
-msgstr "Hainbat gehitu..."
+msgstr "Gehitu hainbat..."
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1165
msgid "Record..."
-msgstr ""
+msgstr "Grabatu..."
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
@@ -576,148 +675,146 @@ msgstr ""
#: gui/onscreendialog.cpp:101 gui/onscreendialog.cpp:103
msgid "Stop"
-msgstr ""
+msgstr "Gelditu"
#: gui/onscreendialog.cpp:106
msgid "Edit record description"
-msgstr ""
+msgstr "Editatu grabazioaren desribapena"
#: gui/onscreendialog.cpp:108
-#, fuzzy
msgid "Switch to Game"
-msgstr "Aldatu"
+msgstr "Aldatu jokora"
#: gui/onscreendialog.cpp:110
-#, fuzzy
msgid "Fast replay"
-msgstr "Modu bizkorra"
+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:2298
+#: 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"
@@ -725,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 ""
-
-#: 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"
@@ -794,190 +887,203 @@ 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
-#, fuzzy
+#: gui/options.cpp:891
msgid "Roland GS Device (enable MT-32 mappings)"
-msgstr "Benetako Roland MT-32 (GM emulazio gabe)"
+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"
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:1168 gui/fluidsynth-dialog.cpp:138
-msgid "Misc"
-msgstr "Beste"
-
-#: 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."
@@ -986,72 +1092,83 @@ msgstr ""
"nahi baduzu, aurretik beste hizkuntza batera pasa behar duzu."
#. I18N: You must leave "#" as is, only word 'next' is translatable
-#: gui/predictivedialog.cpp:87
+#: gui/predictivedialog.cpp:86
msgid "# next"
-msgstr ""
+msgstr "# hurrengoa"
-#: gui/predictivedialog.cpp:88
+#: gui/predictivedialog.cpp:87
msgid "add"
-msgstr ""
+msgstr "gehitu"
-#: gui/predictivedialog.cpp:92
-#, fuzzy
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
-msgstr "Ezabatu"
+msgstr "Ezabatu karakterea"
-#: gui/predictivedialog.cpp:96
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
-msgstr ""
+msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:98
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
-msgstr ""
+msgstr "* Pre"
+
+#. I18N: 'Num' means Numbers
+#: gui/predictivedialog.cpp:578
+msgid "* Num"
+msgstr "* Zenb"
-#: gui/recorderdialog.cpp:64
+#. I18N: 'Abc' means Latin alphabet input
+#: gui/predictivedialog.cpp:581
+msgid "* Abc"
+msgstr "* Abc"
+
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
-msgstr ""
+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 ""
+msgstr "Grabatu"
-#: gui/recorderdialog.cpp:72
-#, fuzzy
+#: gui/recorderdialog.cpp:71
msgid "Playback"
-msgstr "Jolastu"
+msgstr "Erreproduzitu"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
-msgstr ""
+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 ""
+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 ""
+msgstr "Oharrak: "
-#: gui/recorderdialog.cpp:155
-#, fuzzy
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
-msgstr "Ezabatu partida gorde hau?"
+msgstr "Ezabatu grabazio hau?"
+
+#: gui/recorderdialog.cpp:173
+msgid "Unknown Author"
+msgstr "Egile ezezaguna"
#: gui/saveload-dialog.cpp:167
msgid "List view"
-msgstr ""
+msgstr "Zerrenda ikuspegia"
#: gui/saveload-dialog.cpp:168
msgid "Grid view"
-msgstr ""
+msgstr "Sareta ikuspegia "
#: gui/saveload-dialog.cpp:211 gui/saveload-dialog.cpp:360
msgid "No date saved"
@@ -1075,198 +1192,124 @@ msgstr "Data:"
#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:890
msgid "Time: "
-msgstr "Ordua"
+msgstr "Ordua: "
#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:898
msgid "Playtime: "
-msgstr "Denbora:"
+msgstr "Denbora: "
#: gui/saveload-dialog.cpp:408 gui/saveload-dialog.cpp:496
msgid "Untitled savestate"
-msgstr "Titulurik gabeko partida"
+msgstr "Titulurik gabeko joko gordea"
#: gui/saveload-dialog.cpp:548
msgid "Next"
-msgstr ""
+msgstr "Aurr."
#: gui/saveload-dialog.cpp:551
msgid "Prev"
-msgstr ""
+msgstr "Hurr."
#: gui/saveload-dialog.cpp:748
-#, fuzzy
msgid "New Save"
msgstr "Gorde"
#: gui/saveload-dialog.cpp:748
-#, fuzzy
msgid "Create a new save game"
-msgstr "Ezin izan da jokoa gorde"
+msgstr "Sortu joko gorde berria"
#: gui/saveload-dialog.cpp:877
-#, fuzzy
msgid "Name: "
-msgstr "Izena:"
+msgstr "Izena: "
-#: gui/saveload-dialog.cpp:949
+#: gui/saveload-dialog.cpp:951
#, c-format
msgid "Enter a description for slot %d:"
-msgstr ""
+msgstr "Sartu deskribapena %d zirrikiturako: "
#: gui/themebrowser.cpp:45
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
-#, fuzzy
+#: gui/ThemeEngine.cpp:416
msgid "Standard Renderer"
-msgstr "Estandarra (16bpp)"
+msgstr "Errendatzaile estandarra"
-#: gui/ThemeEngine.cpp:348 engines/scumm/dialogs.cpp:661
+#: gui/ThemeEngine.cpp:416 engines/scumm/dialogs.cpp:659
msgid "Standard"
msgstr "Estandarra"
-#: gui/ThemeEngine.cpp:350
-#, fuzzy
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased Renderer"
-msgstr "Lausotua (16bpp)"
+msgstr "Errendatzaile lausotua"
-#: gui/ThemeEngine.cpp:350
-#, fuzzy
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased"
-msgstr "Lausotua (16bpp)"
-
-#: gui/widget.cpp:323 gui/widget.cpp:325 gui/widget.cpp:331 gui/widget.cpp:333
-msgid "Clear value"
-msgstr "Balioa kendu:"
-
-#: gui/fluidsynth-dialog.cpp:68
-#, fuzzy
-msgid "Reverb"
-msgstr "Inoiz ez"
+msgstr "Lausotua"
-#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
-#, fuzzy
-msgid "Active"
-msgstr "(Aktiboa)"
-
-#: gui/fluidsynth-dialog.cpp:72
-msgid "Room:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:79
-msgid "Damp:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:86
-msgid "Width:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
-msgid "Level:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:100
-msgid "Chorus"
+#: 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/fluidsynth-dialog.cpp:104
-msgid "N:"
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
msgstr ""
-#: gui/fluidsynth-dialog.cpp:118
+#: gui/updates-dialog.cpp:92
#, fuzzy
-msgid "Speed:"
-msgstr "Ahotsa"
-
-#: gui/fluidsynth-dialog.cpp:125
-msgid "Depth:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:132
-msgid "Type:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:135
-msgid "Sine"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:136
-msgid "Triangle"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:140
-msgid "Interpolation:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:143
-msgid "None (fastest)"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:144
-msgid "Linear"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:145
-msgid "Fourth-order"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:146
-msgid "Seventh-order"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset"
-msgstr ""
+msgid "Check for updates automatically"
+msgstr "Eguneraketak bilatzen..."
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset all FluidSynth settings to their default values."
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
msgstr ""
-#: gui/fluidsynth-dialog.cpp:217
-#, fuzzy
-msgid ""
-"Do you really want to reset all FluidSynth settings to their default values?"
-msgstr "Ziur zaude abiarazlera itzuli nahi duzula?"
+#: 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:228
+#: 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:306
+#: base/main.cpp:315
msgid "Menu"
msgstr "Menua"
-#: base/main.cpp:309 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:312 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:315
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Lerroa saltatu"
-#: base/main.cpp:507
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Jokoa exekutatzean errorea:"
-#: base/main.cpp:554
+#: 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"
@@ -1334,16 +1377,60 @@ msgstr "Erabiltzaileak utzia"
msgid "Unknown error"
msgstr "Errore ezezaguna"
-#: engines/advancedDetector.cpp:317
+#. I18N: Hercules is graphics card name
+#: common/rendermode.cpp:35
+msgid "Hercules Green"
+msgstr "Herkules berdea"
+
+#: common/rendermode.cpp:36
+msgid "Hercules Amber"
+msgstr "Herkules anbar-kolorekoa"
+
+#: common/rendermode.cpp:42
+msgid "PC-9821 (256 Colors)"
+msgstr "PC-9821 (256 Kolore)"
+
+#: common/rendermode.cpp:43
+msgid "PC-9801 (16 Colors)"
+msgstr "PC-9801 (16 kolore)"
+
+#: common/rendermode.cpp:73
+msgctxt "lowres"
+msgid "Hercules Green"
+msgstr "Herkules berdea"
+
+#: common/rendermode.cpp:74
+msgctxt "lowres"
+msgid "Hercules Amber"
+msgstr "Herkules anbar-kolorekoa"
+
+#: 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:"
@@ -1351,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"
@@ -1380,11 +1467,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "It~z~uli abiarazlera"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:803
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:873
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
-#: engines/toltecs/menu.cpp:281 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:"
@@ -1393,11 +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:803 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/neverhood/menumodule.cpp:873 engines/pegasus/pegasus.cpp:377
-#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
-#: engines/toltecs/menu.cpp:281 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"
@@ -1419,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"
@@ -1433,23 +1529,23 @@ msgstr "~U~tzi"
msgid "~K~eys"
msgstr "~T~eklak"
-#: engines/engine.cpp:276
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Kolore formatua ezin izan da hasieratu."
-#: engines/engine.cpp:284
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Ezin izan da aldatu bideo modura : '"
-#: engines/engine.cpp:293
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "Ezin izan da formatu-ratio ezarpena aplikatu."
-#: engines/engine.cpp:298
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Ezin izan da pantaila-osoa ezarpena aplikatu."
-#: engines/engine.cpp:398
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1463,7 +1559,7 @@ msgstr ""
"fitxategiak disko gogorrera kopiatzea.\n"
"Jo README fitxategira xehetasunetarako."
-#: engines/engine.cpp:409
+#: 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"
@@ -1477,7 +1573,7 @@ msgstr ""
"izateko. Jo README fitxategira\n"
"xehetasunetarako."
-#: engines/engine.cpp:467
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1486,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:480
+#: 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 "
@@ -1496,10 +1592,14 @@ msgstr ""
"Hori dela eta, ezegonkorra izan daiteke eta gerta daiteke gordeta izan "
"ditzakezun partidan ez ibiltzea ScummVM-ren etorkizuneko bertsioetan."
-#: engines/engine.cpp:483
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Jolastu berdin-berdin"
+#: audio/adlib.cpp:2290
+msgid "AdLib Emulator"
+msgstr "AdLib emuladorea"
+
#: audio/fmopl.cpp:62
msgid "MAME OPL emulator"
msgstr "MAME OPL emuladorea"
@@ -1510,7 +1610,7 @@ msgstr "DOSBox OPL emuladorea"
#: audio/fmopl.cpp:67
msgid "ALSA Direct FM"
-msgstr ""
+msgstr "ALSA FM zuzena"
#: audio/mididrv.cpp:209
#, c-format
@@ -1553,31 +1653,35 @@ msgstr ""
"'%s' gogoko soinu gailua ezin da erabili. Ikusi log fitxategia informazio "
"gehiagorako."
-#: audio/null.h:44
-msgid "No music"
-msgstr "Musikarik ez"
-
#: audio/mods/paula.cpp:196
msgid "Amiga Audio Emulator"
msgstr "Amiga Audio emuladorea"
-#: audio/adlib.cpp:2291
-msgid "AdLib Emulator"
-msgstr "AdLib emuladorea"
+#: audio/null.h:44
+msgid "No music"
+msgstr "Musikarik ez"
#: audio/softsynth/appleiigs.cpp:33
msgid "Apple II GS Emulator (NOT IMPLEMENTED)"
msgstr "Apple II GS emuladorea (INPLEMENTATU GABE)"
-#: audio/softsynth/sid.cpp:1430
-msgid "C64 Audio Emulator"
-msgstr "C64 Audio emuladorea"
+#: audio/softsynth/cms.cpp:350
+msgid "Creative Music System Emulator"
+msgstr "Creative musika sistema emuladorea"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33
+msgid "FM-Towns Audio"
+msgstr "FM-Towns soinua"
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58
+msgid "PC-98 Audio"
+msgstr "PC-98 Soinua"
+
+#: 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"
@@ -1589,6 +1693,146 @@ msgstr "PC bozgoragailuaren emuladorea"
msgid "IBM PCjr Emulator"
msgstr "IBM PCjr emuladorea"
+#: audio/softsynth/sid.cpp:1430
+msgid "C64 Audio Emulator"
+msgstr "C64 Audio emuladorea"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Do you really want to return to the Launcher?"
+msgstr "Ziur zaude abiarazlera itzuli nahi duzula?"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Launcher"
+msgstr "Abiarazlea"
+
+#: backends/events/default/default-events.cpp:218
+msgid "Do you really want to quit?"
+msgstr "Benetan irten?"
+
+#: 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 "Irten"
+
+#: 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 "Ukimen-pantailako 'kolpetxo modua' - Ezker klika"
+
+#: 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 "Ukimen-pantailako 'kolpetxo modua' - Eskuin klika"
+
+#: 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 "Ukimen-pantailako 'kolpetxo modua' - Flotatu (klikik ez)"
+
+#: backends/events/gph/gph-events.cpp:409
+msgid "Maximum Volume"
+msgstr "Bolumen maximoa"
+
+#: backends/events/gph/gph-events.cpp:411
+msgid "Increasing Volume"
+msgstr "Bolumena igotzen"
+
+#: backends/events/gph/gph-events.cpp:417
+msgid "Minimal Volume"
+msgstr "Bolumen minimoa"
+
+#: backends/events/gph/gph-events.cpp:419
+msgid "Decreasing Volume"
+msgstr "Bolumena jaisten"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Enabled"
+msgstr "Klikatzea gaituta"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Disabled"
+msgstr "Klikatzea desgaituta"
+
+#: backends/events/openpandora/op-events.cpp:174
+msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
+msgstr "Ukimen-pantailako 'kolpetxo modua' - Flotatu (DPad klikak)"
+
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
+msgid "Do you want to quit ?"
+msgstr "Benetan irten?"
+
+#. I18N: Trackpad mode toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:308
+msgid "Trackpad mode is now"
+msgstr "Trackpad modua orain:"
+
+#. 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 "ON"
+
+#: backends/events/webossdl/webossdl-events.cpp:311
+#: backends/events/webossdl/webossdl-events.cpp:338
+msgid "OFF"
+msgstr "OFF"
+
+#: backends/events/webossdl/webossdl-events.cpp:315
+msgid "Swipe two fingers to the right to toggle."
+msgstr "Pasatu bi atzamara eskuinean gaitu/desgaitzeko."
+
+#. I18N: Auto-drag toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:335
+msgid "Auto-drag mode is now"
+msgstr "Auto-arrastatzea orain:"
+
+#: backends/events/webossdl/webossdl-events.cpp:342
+msgid "Swipe three fingers to the right to toggle."
+msgstr "Pasatu hiru atzamar eskuinean gaitu/desgaitzeko."
+
+#: backends/graphics/opengl/opengl-graphics.cpp:126
+msgid "OpenGL"
+msgstr "OpenGL"
+
+#: backends/graphics/opengl/opengl-graphics.cpp:127
+msgid "OpenGL (No filtering)"
+msgstr "OpenGL (Iragazi gabe)"
+
+#: 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 "Normala (eskalatu gabe)"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:66
+msgctxt "lowres"
+msgid "Normal (no scaling)"
+msgstr "Normala"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
+msgid "Enabled aspect ratio correction"
+msgstr "Formatu-ratio zuzenketa gaituta"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
+msgid "Disabled aspect ratio correction"
+msgstr "Formatu-ratio zuzenketa desgaituta"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
+msgid "Active graphics filter:"
+msgstr "Filtro grafiko aktiboa:"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+msgid "Windowed mode"
+msgstr "Leiho modua"
+
#: backends/keymapper/remap-dialog.cpp:48
msgid "Keymap:"
msgstr "Teklen esleipena:"
@@ -1618,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"
@@ -1694,18 +1938,26 @@ msgstr "Kalitate altuko soinua (geldoagoa) (berrabiarazi)"
msgid "Disable power off"
msgstr "Itzaltzea desgaitu"
+#: 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 "Saguko klik-eta-arrastratu modua gaituta."
+#: 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 "Saguko klik-eta-arrastratu modua desgaituta."
+#: 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 "Touchpad modua gaituta."
+#: 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 "Touchpad modua desgaituta."
@@ -1716,9 +1968,9 @@ msgstr "Klikatzeko modua"
#: 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
-#: backends/platform/tizen/form.cpp:275
msgid "Left Click"
msgstr "Ezker-klika"
@@ -1728,66 +1980,32 @@ msgstr "Erdiko klika"
#: backends/platform/maemo/maemo.cpp:220
#: backends/platform/symbian/src/SymbianActions.cpp:43
-#: backends/platform/wince/CEActionsSmartphone.cpp:44
#: backends/platform/tizen/form.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:44
msgid "Right Click"
msgstr "Eskuin-klika"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:77
+#: backends/platform/sdl/macosx/appmenu_osx.mm:88
msgid "Hide ScummVM"
msgstr "ScummVM ezkutatu"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:82
+#: backends/platform/sdl/macosx/appmenu_osx.mm:93
msgid "Hide Others"
msgstr "Besteak ezkutatu"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:87
+#: backends/platform/sdl/macosx/appmenu_osx.mm:98
msgid "Show All"
msgstr "Denak erakutsi"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:109
#: backends/platform/sdl/macosx/appmenu_osx.mm:120
+#: backends/platform/sdl/macosx/appmenu_osx.mm:131
msgid "Window"
msgstr "Leihoa"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:114
+#: backends/platform/sdl/macosx/appmenu_osx.mm:125
msgid "Minimize"
msgstr "Minimizatu"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:46
-msgid "Normal (no scaling)"
-msgstr "Normala (eskalatu gabe)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:65
-msgctxt "lowres"
-msgid "Normal (no scaling)"
-msgstr "Normala"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
-msgid "Enabled aspect ratio correction"
-msgstr "Formatu-ratio zuzenketa gaituta"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
-msgid "Disabled aspect ratio correction"
-msgstr "Formatu-ratio zuzenketa desgaituta"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
-msgid "Active graphics filter:"
-msgstr "Filtro grafiko aktiboa:"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
-msgid "Windowed mode"
-msgstr "Leiho modua"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:118
-#, fuzzy
-msgid "OpenGL"
-msgstr "Ireki"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:119
-msgid "OpenGL (No filtering)"
-msgstr ""
-
#: backends/platform/symbian/src/SymbianActions.cpp:38
#: backends/platform/wince/CEActionsSmartphone.cpp:39
msgid "Up"
@@ -1831,14 +2049,6 @@ msgstr "Testua saltatu"
msgid "Fast mode"
msgstr "Modu bizkorra"
-#: backends/platform/symbian/src/SymbianActions.cpp:52
-#: backends/platform/wince/CEActionsPocket.cpp:44
-#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: backends/events/default/default-events.cpp:218 engines/scumm/dialogs.cpp:192
-#: engines/scumm/help.cpp:83 engines/scumm/help.cpp:85
-msgid "Quit"
-msgstr "Irten"
-
#: backends/platform/symbian/src/SymbianActions.cpp:53
msgid "Debugger"
msgstr "Araztailea"
@@ -1855,9 +2065,49 @@ msgstr "Teklatu birtuala"
msgid "Key mapper"
msgstr "Teklen esleipena"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:186
-msgid "Do you want to quit ?"
-msgstr "Irten nahi al duzu?"
+#: backends/platform/tizen/form.cpp:263
+msgid "Right Click Once"
+msgstr "Eskuin-klika behin"
+
+#: backends/platform/tizen/form.cpp:271
+msgid "Move Only"
+msgstr "Mugitu bakarrik"
+
+#: backends/platform/tizen/form.cpp:294
+msgid "Escape Key"
+msgstr "Ihes tekla"
+
+#: backends/platform/tizen/form.cpp:299
+msgid "Game Menu"
+msgstr "Jokoaren menua"
+
+#: backends/platform/tizen/form.cpp:304
+msgid "Show Keypad"
+msgstr "Teklatu numerikoa erakutsi"
+
+#: backends/platform/tizen/form.cpp:309
+msgid "Control Mouse"
+msgstr "Saguaren kontrola"
+
+#: backends/platform/tizen/fs.cpp:259
+msgid "[ Data ]"
+msgstr "[ Datuak ]"
+
+#: backends/platform/tizen/fs.cpp:263
+msgid "[ Resources ]"
+msgstr "[ Baliabideak ]"
+
+#: backends/platform/tizen/fs.cpp:267
+msgid "[ SDCard ]"
+msgstr "[ SD Txartela ]"
+
+#: backends/platform/tizen/fs.cpp:271
+msgid "[ Media ]"
+msgstr "[ Multimedia ]"
+
+#: backends/platform/tizen/fs.cpp:275
+msgid "[ Shared ]"
+msgstr "[ Konpartitua ]"
#: backends/platform/wii/options.cpp:51
msgid "Video"
@@ -2105,138 +2355,106 @@ msgstr ""
"Ez ahaztu 'tresna-barra ezkutatu' ekintza tekla bati esleitzea inbentario "
"osoa ikusteko"
-#: backends/events/default/default-events.cpp:196
-msgid "Do you really want to return to the Launcher?"
-msgstr "Ziur zaude abiarazlera itzuli nahi duzula?"
-
-#: backends/events/default/default-events.cpp:196
-msgid "Launcher"
-msgstr "Abiarazlea"
-
-#: backends/events/default/default-events.cpp:218
-msgid "Do you really want to quit?"
-msgstr "Benetan irten?"
-
-#: 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 "Ukimen-pantailako 'kolpetxo modua' - Ezker klika"
-
-#: 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 "Ukimen-pantailako 'kolpetxo modua' - Eskuin klika"
-
-#: 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 "Ukimen-pantailako 'kolpetxo modua' - Flotatu (klikik ez)"
-
-#: backends/events/gph/gph-events.cpp:409
-msgid "Maximum Volume"
-msgstr "Bolumen maximoa"
-
-#: backends/events/gph/gph-events.cpp:411
-msgid "Increasing Volume"
-msgstr "Bolumena igotzen"
-
-#: backends/events/gph/gph-events.cpp:417
-msgid "Minimal Volume"
-msgstr "Bolumen minimoa"
-
-#: backends/events/gph/gph-events.cpp:419
-msgid "Decreasing Volume"
-msgstr "Bolumena jaisten"
-
-#: backends/events/openpandora/op-events.cpp:174
-#, fuzzy
-msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
-msgstr "Ukimen-pantailako 'kolpetxo modua' - Flotatu (klikik ez)"
-
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Eguneraketak bilatzen..."
-#: backends/platform/tizen/form.cpp:263
-msgid "Right Click Once"
-msgstr "Eskuin-klika behin"
-
-#: backends/platform/tizen/form.cpp:271
-msgid "Move Only"
-msgstr "Mugitu bakarrik"
-
-#: backends/platform/tizen/form.cpp:294
-msgid "Escape Key"
-msgstr "Ihes tekla"
-
-#: backends/platform/tizen/form.cpp:299
-msgid "Game Menu"
-msgstr "Jokoaren menua"
-
-#: backends/platform/tizen/form.cpp:304
-msgid "Show Keypad"
-msgstr "Teklatu numerikoa erakutsi"
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "Daltonikoentzako modua"
-#: backends/platform/tizen/form.cpp:309
-msgid "Control Mouse"
-msgstr "Saguaren kontrola"
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Enabled"
-msgstr "Klikatzea gaituta"
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Disabled"
-msgstr "Klikatzea desgaituta"
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "Erakutsi objektuen etiketak"
-#: engines/agi/detection.cpp:147 engines/drascula/detection.cpp:302
-#: engines/dreamweb/detection.cpp:47 engines/neverhood/detection.cpp:160
-#: engines/sci/detection.cpp:394 engines/toltecs/detection.cpp:200
-#: engines/zvision/detection_tables.h:51
+#: 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 ""
+msgstr "Erabili jatorrizko gorde/kargatu pantailak"
-#: engines/agi/detection.cpp:148 engines/drascula/detection.cpp:303
-#: engines/dreamweb/detection.cpp:48 engines/neverhood/detection.cpp:161
-#: engines/sci/detection.cpp:395 engines/toltecs/detection.cpp:201
+#: 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 ""
+"Erabili jatorrizko gorde/kargatu pantailak, ScummVM-renak erabilibeharrean"
#: engines/agi/detection.cpp:157
msgid "Use an alternative palette"
-msgstr ""
+msgstr "Erabili paleta alternatiboa"
#: engines/agi/detection.cpp:158
msgid ""
"Use an alternative palette, common for all Amiga games. This was the old "
"behavior"
msgstr ""
+"Erabili kolore-paleta alternatiboa, Amiga joko guztientzako komuna. Hau zen "
+"konportamendu zaharra"
#: engines/agi/detection.cpp:167
msgid "Mouse support"
-msgstr ""
+msgstr "Saguaren euskarria"
#: engines/agi/detection.cpp:168
msgid ""
"Enables mouse support. Allows to use mouse for movement and in game menus."
msgstr ""
+"Saguaren euskarria giatzen du. Sagua mugitzeko eta jokoko menuetan "
+"erabiltzea ahalbidetzen du"
-#: engines/agi/saveload.cpp:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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"
@@ -2247,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"
@@ -2258,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"
@@ -2269,22 +2487,20 @@ 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!"
#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
-#, fuzzy
msgid "Color Blind Mode"
-msgstr "Klikatzeko modua"
+msgstr "Daltonikoentzako modua"
#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
-msgstr ""
+msgstr "Gaitu daltonikoentzako modua lehenetsi modura"
#: engines/drascula/saveload.cpp:47
-#, fuzzy
msgid ""
"ScummVM found that you have old savefiles for Drascula that should be "
"converted.\n"
@@ -2294,29 +2510,28 @@ msgid ""
"Press OK to convert them now, otherwise you will be asked again the next "
"time you start the game.\n"
msgstr ""
-"ScummVM-k aurkitu du konbertitu beharko liratekeen Broken Sword 1-eko "
-"partida gorde zaharrak dituzula.\n"
+"ScummVM-k aurkitu du konbertitu beharko liratekeen Drascula-ko partida gorde "
+"zaharrak dituzula.\n"
"Partida gordeen formatu zaharra ez da bateragarria jada, eta beraz ezingo "
"dituzu zure partidak kargatu ez badituzu formatu berrira pasatzen.\n"
"\n"
"Sakatu Ados orain konbertitzeko, bestela berriz galdetuko dizut jokoa berriz "
"martxan jartzen duzunean.\n"
-#: engines/dreamweb/detection.cpp:57
-#, fuzzy
+#: engines/dreamweb/detection.cpp:58
msgid "Use bright palette mode"
-msgstr "Goiko eskuineko objektua"
+msgstr "Erabili paleta argia"
-#: engines/dreamweb/detection.cpp:58
+#: engines/dreamweb/detection.cpp:59
msgid "Display graphics using the game's bright palette"
-msgstr ""
+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."
@@ -2326,85 +2541,82 @@ msgid "Failed to delete file."
msgstr "Ezin izan da fitxategia ezabatu"
#: engines/groovie/detection.cpp:312
-#, fuzzy
msgid "Fast movie speed"
-msgstr "Modu bizkorra"
+msgstr "Bideo abiadura azkarra"
#: engines/groovie/detection.cpp:313
msgid "Play movies at an increased speed"
-msgstr ""
+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"
#: engines/hopkins/detection.cpp:76 engines/hopkins/detection.cpp:86
msgid "Gore Mode"
-msgstr ""
+msgstr "Gore modua"
#: engines/hopkins/detection.cpp:77 engines/hopkins/detection.cpp:87
msgid "Enable Gore Mode when available"
-msgstr ""
+msgstr "Gaitu Gore modua eskuragarri dagoenean"
#. I18N: Studio audience adds an applause and cheering sounds whenever
#. Malcolm makes a joke.
#: engines/kyra/detection.cpp:62
msgid "Studio audience"
-msgstr ""
+msgstr "Estudio ingurunea"
#: engines/kyra/detection.cpp:63
msgid "Enable studio audience"
-msgstr ""
+msgstr "Gaitu estudio ingurunea"
#. I18N: This option allows the user to skip text and cutscenes.
#: engines/kyra/detection.cpp:73
msgid "Skip support"
-msgstr ""
+msgstr "Jauzi egin"
#: engines/kyra/detection.cpp:74
msgid "Allow text and cutscenes to be skipped"
-msgstr ""
+msgstr "Utzi testua eta bideoak saltatzen"
#. I18N: Helium mode makes people sound like they've inhaled Helium.
#: engines/kyra/detection.cpp:84
msgid "Helium mode"
-msgstr ""
+msgstr "Helio modua"
#: engines/kyra/detection.cpp:85
-#, fuzzy
msgid "Enable helium mode"
-msgstr "Roland GS modua gaitu"
+msgstr "Gaitu helio modua"
#. I18N: When enabled, this option makes scrolling smoother when
#. changing from one screen to another.
#: engines/kyra/detection.cpp:99
msgid "Smooth scrolling"
-msgstr ""
+msgstr "Korritze leuna"
#: engines/kyra/detection.cpp:100
msgid "Enable smooth scrolling when walking"
-msgstr ""
+msgstr "Gaitu korritze leuna oinez ibiltzean"
#. 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
-#, fuzzy
msgid "Floating cursors"
-msgstr "Kurtsore normala"
+msgstr "Kurtsore flotatzaileak"
#: engines/kyra/detection.cpp:113
msgid "Enable floating cursors"
-msgstr ""
+msgstr "Gaitu kurtsore flotatzaileak"
#. I18N: HP stands for Hit Points
#: engines/kyra/detection.cpp:127
msgid "HP bar graphs"
-msgstr ""
+msgstr "HP barrak"
#: engines/kyra/detection.cpp:128
msgid "Enable hit point bar graphs"
-msgstr ""
+msgstr "Gaitu bizitza barrak"
#: engines/kyra/lol.cpp:478
msgid "Attack 1"
@@ -2444,7 +2656,7 @@ msgstr "Eskuinera biratu"
#: engines/kyra/lol.cpp:487
msgid "Rest"
-msgstr "Kargatu"
+msgstr "Atsedena"
#: engines/kyra/lol.cpp:488
msgid "Options"
@@ -2455,7 +2667,6 @@ msgid "Choose Spell"
msgstr "Sorginkeria aukeratu"
#: engines/kyra/sound_midi.cpp:477
-#, fuzzy
msgid ""
"You appear to be using a General MIDI device,\n"
"but your game only supports Roland MT32 MIDI.\n"
@@ -2479,6 +2690,12 @@ msgid ""
"Do you wish to use this save game file with ScummVM?\n"
"\n"
msgstr ""
+"Hurrengo jatorrizko gordetako fitxategia aurkitu da bidean:\n"
+"\n"
+"%s %s\n"
+"\n"
+"Gordetako jokoaren fitxategia ScummVM-rekin erabili?\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:590
#, c-format
@@ -2486,6 +2703,9 @@ msgid ""
"A save game file was found in the specified slot %d. Overwrite?\n"
"\n"
msgstr ""
+"Joko gorde baten fitxategia aurkitu da zehaztutako %d zirrikituan."
+"Gainidatzi?\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:623
#, c-format
@@ -2497,50 +2717,65 @@ msgid ""
"'import_savefile'.\n"
"\n"
msgstr ""
+"Jatorrizko %d gordetako joko fitxategi ondo inportatu dira \n"
+"ScummVM-era. Geroago eskuz jatorrizko joko gordeak inportatu\n"
+"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 ""
+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 ""
+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 ""
+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"
@@ -2549,15 +2784,23 @@ msgstr ""
"Ezin da partida gorde %i zirrikituan\n"
"\n"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:194
+msgid "Load file"
+msgstr "Kargatu fitxategia:"
+
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Jokoa kargatzen..."
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:209
+msgid "Save file"
+msgstr "Gorde fitxategia"
+
+#: 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"
@@ -2574,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"
@@ -2592,218 +2835,246 @@ msgstr ""
#: engines/pegasus/pegasus.cpp:714
msgid "Invalid save file name"
-msgstr ""
+msgstr "Gordetako jokoko fitxategi-izen baliogabea"
#: engines/pegasus/pegasus.cpp:2507
msgid "Up/Zoom In/Move Forward/Open Doors"
-msgstr ""
+msgstr "Gora/Zoom-a hurbildu/Mugitu aurrera/Ireki ateak"
#: engines/pegasus/pegasus.cpp:2508
-#, fuzzy
msgid "Down/Zoom Out"
-msgstr "Zoom-a hurbildu"
+msgstr "Behera/Zoom-a urrundu"
#: engines/pegasus/pegasus.cpp:2511
msgid "Display/Hide Inventory Tray"
-msgstr ""
+msgstr "Erakutsi/Ezkutatu inbentorioaren erretilua"
#: engines/pegasus/pegasus.cpp:2512
msgid "Display/Hide Biochip Tray"
-msgstr ""
+msgstr "Erakutsi/Ezkutatu Biochip erretilua"
#: engines/pegasus/pegasus.cpp:2513
msgid "Action/Select"
-msgstr ""
+msgstr "Ekintza/Aukeratu"
#: engines/pegasus/pegasus.cpp:2514
msgid "Toggle Center Data Display"
-msgstr ""
+msgstr "Erakutsi/Ezkutatu Datu Zentroa"
#: engines/pegasus/pegasus.cpp:2515
msgid "Display/Hide Info Screen"
-msgstr ""
+msgstr "Erakutsi/Ezkutatu informazio pantaila"
#: engines/pegasus/pegasus.cpp:2516
msgid "Display/Hide Pause Menu"
-msgstr ""
+msgstr "Erakutsi/Ezkutatu pausa menua"
#: engines/queen/detection.cpp:56
msgid "Alternative intro"
-msgstr ""
+msgstr "Sarrera alternatiboa"
#: engines/queen/detection.cpp:57
msgid "Use an alternative game intro (CD version only)"
-msgstr ""
+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 ""
+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:395
+msgid "Enable high resolution graphics/content"
+msgstr "Gaitu erresoluzio altuko grafikoak/edukiak"
+
+#: 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 "Soinu efektu berezien bolumena"
+msgstr "Lehenetsi soinu efektu digitalak"
-#: engines/sci/detection.cpp:385
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
-msgstr ""
+msgstr "Lehenetsi soinu efektu digitalak sintetizatuen ordez"
-#: engines/sci/detection.cpp:404
+#: engines/sci/detection.cpp:434
msgid "Use IMF/Yamaha FB-01 for MIDI output"
-msgstr ""
+msgstr "Erabili IMF/Yamaha FB-01 MIDI irteerarako"
-#: engines/sci/detection.cpp:405
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
msgstr ""
+"Erabili IBM Music Feature txartela edo Yamaha FB-01 FM "
+"sintetizatzailemodulua MIDI irteerarako"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
-msgstr ""
+msgstr "Erabili audio CDa"
-#: engines/sci/detection.cpp:416
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
-msgstr ""
+msgstr "Erabili CD-ko audioa jokokoa beharrean, eskurarri badago"
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
-msgstr ""
+msgstr "Erabili Windows-eko kurtsoreak"
-#: engines/sci/detection.cpp:427
+#: 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:437
-#, fuzzy
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
-msgstr "Kurtsore normala"
+msgstr "Erabili zilarrezko kurtsoreak"
-#: engines/sci/detection.cpp:438
+#: 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/detection.cpp:1340
+#, fuzzy
+msgid "Show Object Line"
+msgstr "Erakutsi objektuen etiketak"
-#: engines/scumm/dialogs.cpp:176
+#: 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
-#, fuzzy
+#: engines/scumm/dialogs.cpp:179
msgid "Are you sure you want to restart? (Y/N)Y"
-msgstr "Ziur zaude berrabiarazi nahi duzula (B/E)B"
+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
-#, fuzzy
+#: engines/scumm/dialogs.cpp:181
msgid "Are you sure you want to quit? (Y/N)Y"
-msgstr "Ziur zaude irten nahi duzula? (B/E)B"
+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:600
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Ahotsak bakarrik"
-#: engines/scumm/dialogs.cpp:601
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Ahotsak eta azpitituluak"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Azpitituluak bakarrik"
-#: engines/scumm/dialogs.cpp:610
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Ahotsak & azpit."
-#: engines/scumm/dialogs.cpp:656
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Zailtasuna aukeratu."
-#: engines/scumm/dialogs.cpp:658
+#: 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:662
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Entrenamendua"
-#: engines/scumm/dialogs.cpp:663
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Aditua"
@@ -2855,7 +3126,7 @@ msgstr "Alt"
#: engines/scumm/help.cpp:81
msgid "Save game state 1-10"
-msgstr "1-10 partida gorde"
+msgstr "Gorde 1-10 jokoa"
#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:90
msgid "Enter"
@@ -3229,23 +3500,23 @@ msgstr "Hirugarren gaztea"
#: engines/scumm/help.cpp:292
msgid "Toggle Inventory/IQ Points display"
-msgstr ""
+msgstr "Txandakatu Inbentarioa/IQ puntuak"
#: engines/scumm/help.cpp:293
msgid "Toggle Keyboard/Mouse Fighting (*)"
-msgstr ""
+msgstr "Txandakatu teklatu/sagu bidezko borroka (*)"
#: engines/scumm/help.cpp:295
msgid "* Keyboard Fighting is always on,"
-msgstr ""
+msgstr "* Teklatu bidezko borroka beti dago gaituta"
#: engines/scumm/help.cpp:296
msgid " so despite the in-game message this"
-msgstr ""
+msgstr " beraz, nahiz eta honelako mezuak erakutsi"
#: engines/scumm/help.cpp:297
msgid " actually toggles Mouse Fighting Off/On"
-msgstr ""
+msgstr " benetan sagu bidezko borroka gaitu/desgaitzen du"
#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
@@ -3282,7 +3553,7 @@ msgstr "Ukabilkada baxua"
#: engines/scumm/help.cpp:315
msgid "Sucker punch"
-msgstr ""
+msgstr "Ukabilkada inuzentea"
#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
@@ -3340,7 +3611,23 @@ msgstr "Eskuinera hegan egin"
msgid "Fly to lower right"
msgstr "Behera eta eskuinera hegan egin"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/input.cpp:578
+msgid "Snap scroll on"
+msgstr "Heldutako korritze barra gaituta"
+
+#: engines/scumm/input.cpp:580
+msgid "Snap scroll off"
+msgstr "Heldutako korritze barra desgaituta"
+
+#: engines/scumm/input.cpp:593
+msgid "Music volume: "
+msgstr "Musika: "
+
+#: engines/scumm/input.cpp:610
+msgid "Subtitle speed: "
+msgstr "Azpitit. abiadura:"
+
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3349,28 +3636,88 @@ msgstr ""
"MIDI euskarri natiboak LucasArts-en Roland eguneraketa behar du,\n"
"baina %s ez dago eskuragarri. AdLib erabiliko da."
-#: engines/scumm/scumm.cpp:2644
-#, fuzzy
+#: 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 ""
-"Maniac Mansion orain hasi beharko litzateke, baina ScummVM-k ez du "
-"baimentzen oraindik. Jolasteko , joan 'Jokoa gehitu' hasierako menura eta "
-"aukeratu 'Maniac' direktorioa Tentacle-ren joko-direktorioaren barruan."
+"Maniac Mansion orain hasi beharko litzateke, baina horretarako, jokoko "
+"fitxategiak 'Maniac' direktorio barruan egon behar dira, Tentacle jokoko "
+"direktorioan, eta jokoa ScummVM-ra gehitu behar da."
#: 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 ""
+"Ezin izan da 'Loom' Macintosh exekutagarria aurkitu instrumentuak\n"
+"bertatik irakurtzeko. Musika desgaituta egongo da."
#: 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 ""
+"Ezin izan da 'Monkey Island' Macintosh exekutagarria aurkitu instrumentuak\n"
+"bertatik irakurtzeko. Musika desgaituta egongo da."
+
+#: engines/sherlock/detection.cpp:71
+msgid "Use original savegame dialog"
+msgstr "Erabili jatorrizko jokoa gordetzeko elkarrizketak"
+
+#: engines/sherlock/detection.cpp:72
+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"
+
+#: engines/sherlock/detection.cpp:81
+msgid "Pixellated scene transitions"
+msgstr "Eszena trantsizio pixelatuak"
+
+#: engines/sherlock/detection.cpp:82
+msgid "When changing scenes, a randomized pixel transition is done"
+msgstr "Eszenak aldatzean, ausazko pixel trantsizioa egiten da"
+
+#: engines/sherlock/detection.cpp:91
+msgid "Don't show hotspots when moving mouse"
+msgstr "Ez erakutsi puntu interesgarriak sagua mugitzean"
+
+#: engines/sherlock/detection.cpp:92
+msgid ""
+"Only show hotspot names after you actually click on a hotspot or action "
+"button"
+msgstr ""
+"Erakutsi puntu interesgarrien izenak haien gainean edota ekintza botoiaren "
+"gainean klik egin eta gero bakarrik "
+
+#: engines/sherlock/detection.cpp:101
+msgid "Show character portraits"
+msgstr "Erakutsi pertsonaien erretratuak"
+
+#: engines/sherlock/detection.cpp:102
+msgid "Show portraits for the characters when conversing"
+msgstr "Erakutsi pertsonaien erretratuak elkarrizketetan"
+
+#: engines/sherlock/detection.cpp:111
+msgid "Slide dialogs into view"
+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"
+
+#: engines/sherlock/detection.cpp:121
+msgid "Transparent windows"
+msgstr "Leiho gardenak"
+
+#: engines/sherlock/detection.cpp:122
+msgid "Show windows with a partially transparent background"
+msgstr "Erakutsi leihoak partzialki gardena den fondoarekin"
#: engines/sky/compact.cpp:130
msgid ""
@@ -3390,16 +3737,16 @@ msgstr ""
#: engines/sky/detection.cpp:44
msgid "Floppy intro"
-msgstr ""
+msgstr "Floppy introa"
#: engines/sky/detection.cpp:45
msgid "Use the floppy version's intro (CD version only)"
-msgstr ""
+msgstr "Erabili floppy bertsioko sarrera (CD bertsioa soilik)"
#: engines/sword1/animation.cpp:524
#, c-format
msgid "PSX stream cutscene '%s' cannot be played in paletted mode"
-msgstr ""
+msgstr "'%s' PSX eszena ezin da erreproduzitu paletatutako moduan"
#: engines/sword1/animation.cpp:545 engines/sword2/animation.cpp:445
msgid "DXA cutscenes found but ScummVM has been built without zlib"
@@ -3407,11 +3754,10 @@ msgstr ""
"DXA bideoak aurkitu dira, baina ScummVM zlib euskarri gabe konpilatu da"
#: engines/sword1/animation.cpp:561 engines/sword2/animation.cpp:461
-#, fuzzy
msgid ""
"MPEG-2 cutscenes found but ScummVM has been built without MPEG-2 support"
msgstr ""
-"DXA bideoak aurkitu dira, baina ScummVM zlib euskarri gabe konpilatu da"
+"MPEG-2 bideoak aurkitu dira, baina ScummVM MPEG-2 euskarri gabe konpilatu da"
#: engines/sword1/animation.cpp:568 engines/sword2/animation.cpp:470
#, c-format
@@ -3466,68 +3812,78 @@ msgstr ""
#: engines/sword2/sword2.cpp:79
msgid "Show object labels"
-msgstr ""
+msgstr "Erakutsi objektuen etiketak"
#: engines/sword2/sword2.cpp:80
msgid "Show labels for objects on mouse hover"
+msgstr "Erakutsi objektuen etiketak sagua pasatzean"
+
+#: engines/sword25/detection.cpp:46
+msgid "Use English speech"
msgstr ""
-#: engines/teenagent/resources.cpp:95
+#: engines/sword25/detection.cpp:47
msgid ""
-"You're missing the 'teenagent.dat' file. Get it from the ScummVM website"
+"Use English speech instead of German for every language other than German"
msgstr ""
-#: engines/teenagent/resources.cpp:116
+#: 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:117
msgid ""
"The teenagent.dat file is compressed and zlib hasn't been included in this "
"executable. Please decompress it"
msgstr ""
+"teenagent. dat fitxategia konprimituta dago eta zlib ez dago txertatuta "
+"exekutagarri honetan. Deskonprimitu"
#: engines/wintermute/detection.cpp:58
msgid "Show FPS-counter"
-msgstr ""
+msgstr "Erakutsi FPS kontatzailea"
#: engines/wintermute/detection.cpp:59
msgid "Show the current number of frames per second in the upper left corner"
-msgstr ""
+msgstr "Erakutsi momentuko FPS (frames per second) goiko ezkerreko ertzean"
#: engines/zvision/detection_tables.h:52
msgid "Use the original save/load screens instead of the ScummVM interface"
msgstr ""
+"Erabili jatorrizko gorde/kargatu pantailak ScummVM interfazearenak beharrean"
#: engines/zvision/detection_tables.h:61
msgid "Double FPS"
-msgstr ""
+msgstr "Bikoiztu FPSa"
#: engines/zvision/detection_tables.h:62
msgid "Increase framerate from 30 to 60 FPS"
-msgstr ""
+msgstr "Areagotu framerate-a 30etik 60 FPSra"
#: engines/zvision/detection_tables.h:71
-#, fuzzy
msgid "Enable Venus"
-msgstr "Roland GS modua gaitu"
+msgstr "Gaitu Venus"
#: engines/zvision/detection_tables.h:72
-#, fuzzy
msgid "Enable the Venus help system"
-msgstr "Roland GS modua gaitu"
+msgstr "Gaitu Venus laguntza sistema"
#: engines/zvision/detection_tables.h:81
msgid "Disable animation while turning"
-msgstr ""
+msgstr "Desgaitu animazioak biratzean"
#: engines/zvision/detection_tables.h:82
msgid "Disable animation while turning in panorama mode"
-msgstr ""
+msgstr "Desgaitu animazioak panorama moduan biratzean"
#: engines/zvision/detection_tables.h:91
msgid "Use high resolution MPEG video"
-msgstr ""
+msgstr "Erabili bereizmen altuko MPEG bideoa"
#: engines/zvision/detection_tables.h:92
msgid "Use MPEG video from the DVD version, instead of lower resolution AVI"
-msgstr ""
+msgstr "Erabili DVD bertsioko MPEG bideoa, bereizmen baxuagoko AVI-a beharrean"
#~ msgid "EGA undithering"
#~ msgstr "EGA lausotzea"
@@ -3577,23 +3933,3 @@ msgstr ""
#~ msgid "Active filter mode: Nearest"
#~ msgstr "Filtro aktibo modua: hurbilena"
-
-#~ msgid "Enable Roland GS Mode"
-#~ msgstr "Roland GS modua gaitu"
-
-#~ msgid "Hercules Green"
-#~ msgstr "Herkules berdea"
-
-#~ msgid "Hercules Amber"
-#~ msgstr "Herkules anbar-kolorekoa"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Green"
-#~ msgstr "Herkules berdea"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Amber"
-#~ msgstr "Herkules anbar-kolorekoa"
-
-#~ msgid "Save game failed!"
-#~ msgstr "Partida gordeak huts egin du!"
diff --git a/po/fi_FI.po b/po/fi_FI.po
index 7851775712..e073d23af6 100644
--- a/po/fi_FI.po
+++ b/po/fi_FI.po
@@ -1,5 +1,5 @@
# Finnish translation for ScummVM.
-# Copyright (c) 2012-2015 The ScummVM Team
+# Copyright (c) 2012-2016 The ScummVM Team
# This file is distributed under the same license as the ScummVM package.
# Toni Saarela <saarela@gmail.com>, 2012.
#
@@ -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: 2015-09-06 15:14+0200\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"
@@ -53,22 +53,23 @@ msgid "Go up"
msgstr "Siirry ylös"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:74 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: 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/fluidsynth-dialog.cpp:152 engines/engine.cpp:483
-#: backends/platform/wii/options.cpp:48
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
-#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:191 engines/sword1/control.cpp:865
+#: 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 "Peruuta"
#: gui/browser.cpp:76 gui/browser_osx.mm:103 gui/chooser.cpp:47
-#: gui/themebrowser.cpp:56
+#: gui/filebrowser-dialog.cpp:65 gui/themebrowser.cpp:56
msgid "Choose"
msgstr "Valitse"
@@ -84,61 +85,182 @@ msgstr "Nimi:"
msgid "Notes:"
msgstr ""
-#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:75
+#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74
msgid "Ok"
msgstr ""
-#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
+#: gui/filebrowser-dialog.cpp:49
+msgid "Choose file for loading"
+msgstr ""
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Enter filename for saving"
+msgstr ""
+
+#: gui/filebrowser-dialog.cpp:132
+#, fuzzy
+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: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 "Kyllä"
+
+#: 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 "Ei"
+
+#: gui/fluidsynth-dialog.cpp:68
+#, fuzzy
+msgid "Reverb"
+msgstr "Ei koskaan"
+
+#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
+#, fuzzy
+msgid "Active"
+msgstr " (Aktiivinen)"
+
+#: gui/fluidsynth-dialog.cpp:72
+msgid "Room:"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:79
+msgid "Damp:"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:86
+msgid "Width:"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
+msgid "Level:"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:100
+msgid "Chorus"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:104
+msgid "N:"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:118
+#, fuzzy
+msgid "Speed:"
+msgstr "Puhe"
+
+#: gui/fluidsynth-dialog.cpp:125
+msgid "Depth:"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:132
+msgid "Type:"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:135
+msgid "Sine"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:136
+msgid "Triangle"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
+msgid "Misc"
+msgstr "Muut"
+
+#: gui/fluidsynth-dialog.cpp:140
+msgid "Interpolation:"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:143
+msgid "None (fastest)"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:144
+msgid "Linear"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:145
+msgid "Fourth-order"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:146
+msgid "Seventh-order"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset all FluidSynth settings to their default values."
+msgstr ""
+
+#: 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 "Tallenna"
+
+#: gui/fluidsynth-dialog.cpp:217
+#, fuzzy
+msgid ""
+"Do you really want to reset all FluidSynth settings to their default values?"
+msgstr "Haluatko varmasti palata pelivalitsimeen?"
+
+#: 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 "Sulje"
-#: gui/gui-manager.cpp:120
+#: gui/gui-manager.cpp:122
msgid "Mouse click"
msgstr "Hiiren klikkaus"
-#: gui/gui-manager.cpp:124 base/main.cpp:319
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Näytä näppäimistö"
-#: gui/gui-manager.cpp:128 base/main.cpp:323
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Määritä näppäimet uudelleen"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 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"
-#: gui/KeysDialog.h:36 gui/KeysDialog.cpp:145
-msgid "Choose an action to map"
-msgstr "Valitse toiminto"
-
#: gui/KeysDialog.cpp:41
msgid "Map"
msgstr "Näppäinkartta"
-#: gui/KeysDialog.cpp:42 gui/launcher.cpp:352 gui/launcher.cpp:1048
-#: gui/launcher.cpp:1052 gui/massadd.cpp:92 gui/options.cpp:1238
-#: gui/saveload-dialog.cpp:932 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:402 engines/engine.cpp:413
-#: 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/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 "Tallenna"
-
#: gui/KeysDialog.cpp:49
msgid "Select an action and click 'Map'"
msgstr "Valitse toiminto ja klikkaa 'Map'"
@@ -161,6 +283,10 @@ msgstr "Valitse toiminto"
msgid "Press the key to associate"
msgstr "Paina haluamaasi nappia"
+#: gui/KeysDialog.cpp:145 gui/KeysDialog.h:36
+msgid "Choose an action to map"
+msgstr "Valitse toiminto"
+
#: gui/launcher.cpp:193
msgid "Game"
msgstr "Peli"
@@ -203,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>"
@@ -226,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"
@@ -243,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"
@@ -256,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"
@@ -274,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:95
+#: 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:69
+#: 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:1222
+#: 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/myst.cpp:245 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/myst.cpp:245
-#: engines/mohawk/riven.cpp:718 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:792
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -491,60 +618,40 @@ msgstr ""
"Haluatko varmasti lisätä pelejä alihakemistoineen? Tämä voi lisätä suuren "
"määrän pelejä."
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Kyllä"
-
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Ei"
-
-#: gui/launcher.cpp:841
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM ei voi avata kyseistä hakemistoa!"
-#: gui/launcher.cpp:853
+#: 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:867
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Valitse peli:"
-#: gui/launcher.cpp:941
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "Haluatko varmasti poistaa pelin asetuksineen listalta?"
-#: gui/launcher.cpp:999
+#: gui/launcher.cpp:1003
#, fuzzy
msgid "Do you want to load saved game?"
msgstr "Haluatko tallentaa vai ladata pelin?"
-#: gui/launcher.cpp:1048
+#: 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:1052
+#: 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:1159
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Lisää monta..."
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr ""
@@ -593,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:2298
+#: 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"
@@ -728,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"
@@ -794,191 +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:1168 gui/fluidsynth-dialog.cpp:138
-msgid "Misc"
-msgstr "Muut"
-
-#: 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."
@@ -987,65 +1102,80 @@ msgstr ""
"ja yritä sitten uudelleen."
#. I18N: You must leave "#" as is, only word 'next' is translatable
-#: gui/predictivedialog.cpp:87
+#: gui/predictivedialog.cpp:86
msgid "# next"
msgstr ""
-#: gui/predictivedialog.cpp:88
+#: gui/predictivedialog.cpp:87
msgid "add"
msgstr ""
-#: gui/predictivedialog.cpp:92
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
#, fuzzy
msgid "Delete char"
msgstr "Poista"
-#: gui/predictivedialog.cpp:96
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
msgstr ""
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:98
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr ""
-#: gui/recorderdialog.cpp:64
+#. I18N: 'Num' means Numbers
+#: gui/predictivedialog.cpp:578
+msgid "* Num"
+msgstr ""
+
+#. I18N: 'Abc' means Latin alphabet input
+#: gui/predictivedialog.cpp:581
+msgid "* Abc"
+msgstr ""
+
+#: 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:173
+#, fuzzy
+msgid "Unknown Author"
+msgstr "Tuntematon virhe"
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr "Listanäkymä"
@@ -1106,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:"
@@ -1115,156 +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:661
+#: 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
-msgid "Clear value"
-msgstr "Tyhjennä arvo"
-
-#: gui/fluidsynth-dialog.cpp:68
-#, fuzzy
-msgid "Reverb"
-msgstr "Ei koskaan"
-
-#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
-#, fuzzy
-msgid "Active"
-msgstr " (Aktiivinen)"
-
-#: gui/fluidsynth-dialog.cpp:72
-msgid "Room:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:79
-msgid "Damp:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:86
-msgid "Width:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
-msgid "Level:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:100
-msgid "Chorus"
+#: 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/fluidsynth-dialog.cpp:104
-msgid "N:"
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
msgstr ""
-#: gui/fluidsynth-dialog.cpp:118
+#: gui/updates-dialog.cpp:92
#, fuzzy
-msgid "Speed:"
-msgstr "Puhe"
-
-#: gui/fluidsynth-dialog.cpp:125
-msgid "Depth:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:132
-msgid "Type:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:135
-msgid "Sine"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:136
-msgid "Triangle"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:140
-msgid "Interpolation:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:143
-msgid "None (fastest)"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:144
-msgid "Linear"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:145
-msgid "Fourth-order"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:146
-msgid "Seventh-order"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset"
-msgstr ""
+msgid "Check for updates automatically"
+msgstr "Tarkista päivitykset..."
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset all FluidSynth settings to their default values."
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
msgstr ""
-#: gui/fluidsynth-dialog.cpp:217
-#, fuzzy
-msgid ""
-"Do you really want to reset all FluidSynth settings to their default values?"
-msgstr "Haluatko varmasti palata pelivalitsimeen?"
+#: 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:228
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "Pelimoottori ei tue debug tasoa '%s'"
-#: base/main.cpp:306
+#: base/main.cpp:315
msgid "Menu"
msgstr "Valikko"
-#: base/main.cpp:309 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:312 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:315
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Ohita rivi"
-#: base/main.cpp:507
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Virhe ajettaessa peliä:"
-#: base/main.cpp:554
+#: 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"
@@ -1332,17 +1394,61 @@ msgstr "Käyttäjä peruutti"
msgid "Unknown error"
msgstr "Tuntematon virhe"
-#: engines/advancedDetector.cpp:317
+#. I18N: Hercules is graphics card name
+#: common/rendermode.cpp:35
+msgid "Hercules Green"
+msgstr ""
+
+#: common/rendermode.cpp:36
+msgid "Hercules Amber"
+msgstr ""
+
+#: common/rendermode.cpp:42
+msgid "PC-9821 (256 Colors)"
+msgstr ""
+
+#: common/rendermode.cpp:43
+msgid "PC-9801 (16 Colors)"
+msgstr ""
+
+#: common/rendermode.cpp:73
+msgctxt "lowres"
+msgid "Hercules Green"
+msgstr ""
+
+#: common/rendermode.cpp:74
+msgctxt "lowres"
+msgid "Hercules Amber"
+msgstr ""
+
+#: 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."
@@ -1351,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"
@@ -1380,11 +1486,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "Palaa p~e~livalitsimeen"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:803
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:873
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
-#: engines/toltecs/menu.cpp:281 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:"
@@ -1393,11 +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:803 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/neverhood/menumodule.cpp:873 engines/pegasus/pegasus.cpp:377
-#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
-#: engines/toltecs/menu.cpp:281 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"
@@ -1419,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"
@@ -1433,23 +1548,23 @@ msgstr "~P~eruuta"
msgid "~K~eys"
msgstr "~N~äppäimet"
-#: engines/engine.cpp:276
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Väriformaattia ei voitu alustaa"
-#: engines/engine.cpp:284
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Videotilan vaihto ei onnistunut:'"
-#: engines/engine.cpp:293
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "Kuvasuhdeasetusta ei voitu asettaa."
-#: engines/engine.cpp:298
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Kokoruututila-asetusta ei voi asettaa."
-#: engines/engine.cpp:398
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1462,7 +1577,7 @@ msgstr ""
"pelin tiedostot kovalevyllesi. Avaa LUEMINUT\n"
"tiedosto ohjeita varten."
-#: engines/engine.cpp:409
+#: 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"
@@ -1475,7 +1590,7 @@ msgstr ""
"ohjelmistoa käyttäen, jotta musiikit\n"
"kuuluvat. Lue ohjeet LUEMINUT tiedostosta."
-#: engines/engine.cpp:467
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1484,7 +1599,7 @@ msgstr ""
"Pelitilan lataus epäonnistui (%s)! Avaa LUEMINUT tiedosto saadaksesi "
"lisätietoa."
-#: engines/engine.cpp:480
+#: 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 "
@@ -1494,10 +1609,14 @@ msgstr ""
"epävakaa, eivätkä pelitallennukset välttämättä toimi tulevissa ScummVM:n "
"versioissa."
-#: engines/engine.cpp:483
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Pelaa silti"
+#: audio/adlib.cpp:2290
+msgid "AdLib Emulator"
+msgstr "AdLib emulaattori"
+
#: audio/fmopl.cpp:62
msgid "MAME OPL emulator"
msgstr "MAME OPL emulaattori"
@@ -1551,31 +1670,36 @@ msgstr ""
"Ensisijaista äänilaitetta '%s' ei voida käyttää. Avaa lokitiedosto "
"saadaksesi lisätietoja."
-#: audio/null.h:44
-msgid "No music"
-msgstr "Ei musiikkia"
-
#: audio/mods/paula.cpp:196
msgid "Amiga Audio Emulator"
msgstr "Amiga Audio emulaattori"
-#: audio/adlib.cpp:2291
-msgid "AdLib Emulator"
-msgstr "AdLib emulaattori"
+#: audio/null.h:44
+msgid "No music"
+msgstr "Ei musiikkia"
#: audio/softsynth/appleiigs.cpp:33
msgid "Apple II GS Emulator (NOT IMPLEMENTED)"
msgstr "Apple II GS emulaattori (EI TOTEUTETTU)"
-#: audio/softsynth/sid.cpp:1430
-msgid "C64 Audio Emulator"
-msgstr "C64 Audio emulaattori"
+#: audio/softsynth/cms.cpp:350
+msgid "Creative Music System Emulator"
+msgstr ""
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33
+msgid "FM-Towns Audio"
+msgstr ""
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58
+#, fuzzy
+msgid "PC-98 Audio"
+msgstr "Ääni"
+
+#: 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"
@@ -1587,6 +1711,149 @@ msgstr "PC kaiuttimen emulaattori"
msgid "IBM PCjr Emulator"
msgstr "IBM PCjr emulaattori"
+#: audio/softsynth/sid.cpp:1430
+msgid "C64 Audio Emulator"
+msgstr "C64 Audio emulaattori"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Do you really want to return to the Launcher?"
+msgstr "Haluatko varmasti palata pelivalitsimeen?"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Launcher"
+msgstr "Pelivalitsin"
+
+#: backends/events/default/default-events.cpp:218
+msgid "Do you really want to quit?"
+msgstr "Haluatko varmasti lopettaa?"
+
+#: 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 "Lopeta"
+
+#: 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 "Kosketusnäytön 'Tap moodi' - vasen klikkaus"
+
+#: 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 "Kosketusnäytön 'Tap moodi' - oikea klikkaus"
+
+#: 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 "Kosketusnäytön 'Tap moodi' - ei klikkausta"
+
+#: backends/events/gph/gph-events.cpp:409
+msgid "Maximum Volume"
+msgstr "Maksimi äänenvoimakkuus"
+
+#: backends/events/gph/gph-events.cpp:411
+msgid "Increasing Volume"
+msgstr "Nostetaan äänenvoimakkuutta"
+
+#: backends/events/gph/gph-events.cpp:417
+msgid "Minimal Volume"
+msgstr "Minimi äänenvoimakkuus"
+
+#: backends/events/gph/gph-events.cpp:419
+msgid "Decreasing Volume"
+msgstr "Lasketaan äänenvoimakkuutta"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Enabled"
+msgstr "Klikkaus päällä"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Disabled"
+msgstr "Klikkaus pois päältä"
+
+#: backends/events/openpandora/op-events.cpp:174
+#, fuzzy
+msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
+msgstr "Kosketusnäytön 'Tap moodi' - ei klikkausta"
+
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
+msgid "Do you want to quit ?"
+msgstr "Haluatko lopettaa?"
+
+#. I18N: Trackpad mode toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:308
+#, fuzzy
+msgid "Trackpad mode is now"
+msgstr "Touchpad tila pois päältä"
+
+#. 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 ""
+
+#: backends/events/webossdl/webossdl-events.cpp:311
+#: backends/events/webossdl/webossdl-events.cpp:338
+msgid "OFF"
+msgstr ""
+
+#: backends/events/webossdl/webossdl-events.cpp:315
+msgid "Swipe two fingers to the right to toggle."
+msgstr ""
+
+#. I18N: Auto-drag toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:335
+msgid "Auto-drag mode is now"
+msgstr ""
+
+#: backends/events/webossdl/webossdl-events.cpp:342
+msgid "Swipe three fingers to the right to toggle."
+msgstr ""
+
+#: backends/graphics/opengl/opengl-graphics.cpp:126
+#, fuzzy
+msgid "OpenGL"
+msgstr "Avaa"
+
+#: backends/graphics/opengl/opengl-graphics.cpp:127
+msgid "OpenGL (No filtering)"
+msgstr ""
+
+#: 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 "Normaali (ei skaalausta)"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:66
+msgctxt "lowres"
+msgid "Normal (no scaling)"
+msgstr "Normaali (ei skaalausta)"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
+msgid "Enabled aspect ratio correction"
+msgstr "Kuvasuhteen korjaus päällä"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
+msgid "Disabled aspect ratio correction"
+msgstr "Kuvasuhteen korjaus pois päältä"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
+msgid "Active graphics filter:"
+msgstr "Valittu grafiikkafiltteri:"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+msgid "Windowed mode"
+msgstr "Ikkunoitu tila"
+
#: backends/keymapper/remap-dialog.cpp:48
msgid "Keymap:"
msgstr "Näppäinkartta:"
@@ -1616,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"
@@ -1694,18 +1961,26 @@ msgstr "Korkealuokkainen ääni (hidas) (buuttaus)"
msgid "Disable power off"
msgstr ""
+#: 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 "Hiiren vedä-ja-pudota tila käytössä."
+#: 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 "Hiiren vedä-ja-pudota tila pois käytöstä."
+#: 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 "Touchad tila päällä"
+#: 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 "Touchpad tila pois päältä"
@@ -1716,9 +1991,9 @@ msgstr "Klikkaus moodi"
#: 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
-#: backends/platform/tizen/form.cpp:275
msgid "Left Click"
msgstr "Vasen klikkaus"
@@ -1728,66 +2003,32 @@ msgstr "Keskiklikkaus"
#: backends/platform/maemo/maemo.cpp:220
#: backends/platform/symbian/src/SymbianActions.cpp:43
-#: backends/platform/wince/CEActionsSmartphone.cpp:44
#: backends/platform/tizen/form.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:44
msgid "Right Click"
msgstr "Oikea klikkaus"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:77
+#: backends/platform/sdl/macosx/appmenu_osx.mm:88
msgid "Hide ScummVM"
msgstr "Piilota ScummVM"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:82
+#: backends/platform/sdl/macosx/appmenu_osx.mm:93
msgid "Hide Others"
msgstr "Piilota muut"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:87
+#: backends/platform/sdl/macosx/appmenu_osx.mm:98
msgid "Show All"
msgstr "Näytä kaikki"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:109
#: backends/platform/sdl/macosx/appmenu_osx.mm:120
+#: backends/platform/sdl/macosx/appmenu_osx.mm:131
msgid "Window"
msgstr "Ikkuna"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:114
+#: backends/platform/sdl/macosx/appmenu_osx.mm:125
msgid "Minimize"
msgstr "Minimoi"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:46
-msgid "Normal (no scaling)"
-msgstr "Normaali (ei skaalausta)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:65
-msgctxt "lowres"
-msgid "Normal (no scaling)"
-msgstr "Normaali (ei skaalausta)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
-msgid "Enabled aspect ratio correction"
-msgstr "Kuvasuhteen korjaus päällä"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
-msgid "Disabled aspect ratio correction"
-msgstr "Kuvasuhteen korjaus pois päältä"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
-msgid "Active graphics filter:"
-msgstr "Valittu grafiikkafiltteri:"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
-msgid "Windowed mode"
-msgstr "Ikkunoitu tila"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:118
-#, fuzzy
-msgid "OpenGL"
-msgstr "Avaa"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:119
-msgid "OpenGL (No filtering)"
-msgstr ""
-
#: backends/platform/symbian/src/SymbianActions.cpp:38
#: backends/platform/wince/CEActionsSmartphone.cpp:39
msgid "Up"
@@ -1831,14 +2072,6 @@ msgstr "Ohita teksti"
msgid "Fast mode"
msgstr "Nopea moodi"
-#: backends/platform/symbian/src/SymbianActions.cpp:52
-#: backends/platform/wince/CEActionsPocket.cpp:44
-#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: backends/events/default/default-events.cpp:218 engines/scumm/dialogs.cpp:192
-#: engines/scumm/help.cpp:83 engines/scumm/help.cpp:85
-msgid "Quit"
-msgstr "Lopeta"
-
#: backends/platform/symbian/src/SymbianActions.cpp:53
msgid "Debugger"
msgstr "Debuggeri"
@@ -1855,9 +2088,50 @@ msgstr "Virtuaalinen näppäimistö"
msgid "Key mapper"
msgstr "Näppäinmäärittelijä"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:186
-msgid "Do you want to quit ?"
-msgstr "Haluatko lopettaa?"
+#: backends/platform/tizen/form.cpp:263
+msgid "Right Click Once"
+msgstr "Klikkaa oikealla kerran"
+
+#: backends/platform/tizen/form.cpp:271
+msgid "Move Only"
+msgstr ""
+
+#: backends/platform/tizen/form.cpp:294
+msgid "Escape Key"
+msgstr "Esc näppäin"
+
+#: backends/platform/tizen/form.cpp:299
+msgid "Game Menu"
+msgstr "Pelivalikko"
+
+#: backends/platform/tizen/form.cpp:304
+msgid "Show Keypad"
+msgstr "Näytä keypad"
+
+#: backends/platform/tizen/form.cpp:309
+msgid "Control Mouse"
+msgstr "Ohjaa hiirtä"
+
+#: backends/platform/tizen/fs.cpp:259
+msgid "[ Data ]"
+msgstr ""
+
+#: backends/platform/tizen/fs.cpp:263
+msgid "[ Resources ]"
+msgstr ""
+
+#: backends/platform/tizen/fs.cpp:267
+msgid "[ SDCard ]"
+msgstr ""
+
+#: backends/platform/tizen/fs.cpp:271
+msgid "[ Media ]"
+msgstr ""
+
+#: backends/platform/tizen/fs.cpp:275
+#, fuzzy
+msgid "[ Shared ]"
+msgstr "Jako:"
#: backends/platform/wii/options.cpp:51
msgid "Video"
@@ -2106,103 +2380,39 @@ msgstr ""
"Muista määritellä näppäin työkalupalkin piilottamiselle, jotta voit nähdä "
"koko tavaraluettelon"
-#: backends/events/default/default-events.cpp:196
-msgid "Do you really want to return to the Launcher?"
-msgstr "Haluatko varmasti palata pelivalitsimeen?"
-
-#: backends/events/default/default-events.cpp:196
-msgid "Launcher"
-msgstr "Pelivalitsin"
-
-#: backends/events/default/default-events.cpp:218
-msgid "Do you really want to quit?"
-msgstr "Haluatko varmasti lopettaa?"
-
-#: 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 "Kosketusnäytön 'Tap moodi' - vasen klikkaus"
-
-#: 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 "Kosketusnäytön 'Tap moodi' - oikea klikkaus"
-
-#: 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 "Kosketusnäytön 'Tap moodi' - ei klikkausta"
-
-#: backends/events/gph/gph-events.cpp:409
-msgid "Maximum Volume"
-msgstr "Maksimi äänenvoimakkuus"
-
-#: backends/events/gph/gph-events.cpp:411
-msgid "Increasing Volume"
-msgstr "Nostetaan äänenvoimakkuutta"
-
-#: backends/events/gph/gph-events.cpp:417
-msgid "Minimal Volume"
-msgstr "Minimi äänenvoimakkuus"
-
-#: backends/events/gph/gph-events.cpp:419
-msgid "Decreasing Volume"
-msgstr "Lasketaan äänenvoimakkuutta"
-
-#: backends/events/openpandora/op-events.cpp:174
-#, fuzzy
-msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
-msgstr "Kosketusnäytön 'Tap moodi' - ei klikkausta"
-
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Tarkista päivitykset..."
-#: backends/platform/tizen/form.cpp:263
-msgid "Right Click Once"
-msgstr "Klikkaa oikealla kerran"
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "Klikkaus moodi"
-#: backends/platform/tizen/form.cpp:271
-msgid "Move Only"
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
msgstr ""
-#: backends/platform/tizen/form.cpp:294
-msgid "Escape Key"
-msgstr "Esc näppäin"
-
-#: backends/platform/tizen/form.cpp:299
-msgid "Game Menu"
-msgstr "Pelivalikko"
-
-#: backends/platform/tizen/form.cpp:304
-msgid "Show Keypad"
-msgstr "Näytä keypad"
-
-#: backends/platform/tizen/form.cpp:309
-msgid "Control Mouse"
-msgstr "Ohjaa hiirtä"
-
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Enabled"
-msgstr "Klikkaus päällä"
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Disabled"
-msgstr "Klikkaus pois päältä"
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "Näytä esineiden tiedot"
-#: engines/agi/detection.cpp:147 engines/drascula/detection.cpp:302
-#: engines/dreamweb/detection.cpp:47 engines/neverhood/detection.cpp:160
-#: engines/sci/detection.cpp:394 engines/toltecs/detection.cpp:200
-#: engines/zvision/detection_tables.h:51
+#: 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 "Käytä alkuperäisiä tallenna/lataa valikkoja"
-#: engines/agi/detection.cpp:148 engines/drascula/detection.cpp:303
-#: engines/dreamweb/detection.cpp:48 engines/neverhood/detection.cpp:161
-#: engines/sci/detection.cpp:395 engines/toltecs/detection.cpp:201
+#: 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 "Käytä alkuperäisiä tallenna/lataa valikkoja, ScummVM valikoiden sijaan"
@@ -2227,19 +2437,45 @@ msgid ""
"Enables mouse support. Allows to use mouse for movement and in game menus."
msgstr ""
-#: engines/agi/saveload.cpp:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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"
@@ -2250,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"
@@ -2261,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"
@@ -2272,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!"
@@ -2303,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."
@@ -2334,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."
@@ -2493,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"
@@ -2544,15 +2790,25 @@ msgstr ""
"Pelin tallennus kohtaan ei onnistunut kohtaan %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:194
+#, fuzzy
+msgid "Load file"
+msgstr "Lataa peli:"
+
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Ladataan peliä..."
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:209
+#, fuzzy
+msgid "Save file"
+msgstr "Tallenna peli:"
+
+#: 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"
@@ -2568,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"
@@ -2628,176 +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:395
+#, fuzzy
+msgid "Enable high resolution graphics/content"
+msgstr "Käytä kestopisteissä värillisiä grafiikkapalkkeja numeroiden sijaan"
+
+#: 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:385
+#: 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:404
+#: 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:405
+#: 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:415
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "Käytä CD:n ääntä"
-#: engines/sci/detection.cpp:416
+#: 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:426
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Käytä Windowsin kursoreita"
-#: engines/sci/detection.cpp:427
+#: 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:437
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Käytä hopeisia kursoreita"
-#: engines/sci/detection.cpp:438
+#: 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:600
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Vain puhe"
-#: engines/scumm/dialogs.cpp:601
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Puhe ja Tekstitys"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Vain tekstitys"
-#: engines/scumm/dialogs.cpp:610
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Puhe & teksti"
-#: engines/scumm/dialogs.cpp:656
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Valitse taitotasosi."
-#: engines/scumm/dialogs.cpp:658
+#: 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:662
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Harjoitus"
-#: engines/scumm/dialogs.cpp:663
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Ekspertti"
@@ -3334,7 +3618,26 @@ msgstr "Lennä oikealle"
msgid "Fly to lower right"
msgstr "Lennä alas oikealle"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/input.cpp:578
+#, fuzzy
+msgid "Snap scroll on"
+msgstr "Pehmeä vieritys"
+
+#: engines/scumm/input.cpp:580
+msgid "Snap scroll off"
+msgstr ""
+
+#: engines/scumm/input.cpp:593
+#, fuzzy
+msgid "Music volume: "
+msgstr "Musiikki:"
+
+#: engines/scumm/input.cpp:610
+#, fuzzy
+msgid "Subtitle speed: "
+msgstr "Tekstin nopeus:"
+
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3343,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 "
@@ -3366,6 +3669,60 @@ msgid ""
"instruments from. Music will be disabled."
msgstr ""
+#: engines/sherlock/detection.cpp:71
+#, fuzzy
+msgid "Use original savegame dialog"
+msgstr "Käytä alkuperäisiä tallenna/lataa valikkoja"
+
+#: engines/sherlock/detection.cpp:72
+msgid ""
+"Files button in-game shows original savegame dialog rather than the ScummVM "
+"menu"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:81
+msgid "Pixellated scene transitions"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:82
+msgid "When changing scenes, a randomized pixel transition is done"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:91
+msgid "Don't show hotspots when moving mouse"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:92
+msgid ""
+"Only show hotspot names after you actually click on a hotspot or action "
+"button"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:101
+#, fuzzy
+msgid "Show character portraits"
+msgstr "Vaihda hahmoa"
+
+#: engines/sherlock/detection.cpp:102
+msgid "Show portraits for the characters when conversing"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:111
+msgid "Slide dialogs into view"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:112
+msgid "Slide UI dialogs into view, rather than simply showing them immediately"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:121
+msgid "Transparent windows"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:122
+msgid "Show windows with a partially transparent background"
+msgstr ""
+
#: engines/sky/compact.cpp:130
msgid ""
"Unable to find \"sky.cpt\" file!\n"
@@ -3462,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"
@@ -3569,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 64247a45bf..a6f3a1f35f 100644
--- a/po/fr_FR.po
+++ b/po/fr_FR.po
@@ -1,14 +1,14 @@
# French translation for ScummVM.
-# Copyright (C) 2010-2015 The ScummVM Team
+# Copyright (C) 2010-2016 The ScummVM Team
# This file is distributed under the same license as the ScummVM package.
# Thierry Crozat <criezy@scummvm.org>, 2011.
#
msgid ""
msgstr ""
-"Project-Id-Version: ScummVM 1.3.0svn\n"
+"Project-Id-Version: ScummVM 1.8.0git\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2015-09-06 15:14+0200\n"
-"PO-Revision-Date: 2014-07-05 13:49-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"
"Language: Francais\n"
@@ -16,7 +16,7 @@ msgstr ""
"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.6.6\n"
+"X-Generator: Poedit 1.8.6\n"
#: gui/about.cpp:94
#, c-format
@@ -25,11 +25,11 @@ msgstr "(compilé sur %s)"
#: gui/about.cpp:101
msgid "Features compiled in:"
-msgstr "Options incluses:"
+msgstr "Options incluses :"
#: gui/about.cpp:110
msgid "Available engines:"
-msgstr "Moteurs disponibles:"
+msgstr "Moteurs disponibles :"
#: gui/browser.cpp:68 gui/browser_osx.mm:104
msgid "Show hidden files"
@@ -53,92 +53,210 @@ msgid "Go up"
msgstr "Remonter"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:74 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: 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/fluidsynth-dialog.cpp:152 engines/engine.cpp:483
-#: backends/platform/wii/options.cpp:48
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
-#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:191 engines/sword1/control.cpp:865
+#: 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 "Annuler"
#: gui/browser.cpp:76 gui/browser_osx.mm:103 gui/chooser.cpp:47
-#: gui/themebrowser.cpp:56
+#: gui/filebrowser-dialog.cpp:65 gui/themebrowser.cpp:56
msgid "Choose"
msgstr "Choisir"
#: gui/editrecorddialog.cpp:58
msgid "Author:"
-msgstr ""
+msgstr "Auteur :"
#: gui/editrecorddialog.cpp:59 gui/launcher.cpp:204
msgid "Name:"
-msgstr "Nom:"
+msgstr "Nom :"
#: gui/editrecorddialog.cpp:60
msgid "Notes:"
-msgstr ""
+msgstr "Notes :"
-#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:75
+#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74
msgid "Ok"
+msgstr "Ok"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Choose file for loading"
+msgstr "Choisir le fichier à charger"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Enter filename for saving"
+msgstr "Choisir le nom de fichier pour la sauvegarde"
+
+#: gui/filebrowser-dialog.cpp:132
+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: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 "Oui"
+
+#: 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 "Non"
+
+#: gui/fluidsynth-dialog.cpp:68
+msgid "Reverb"
+msgstr "Réverb"
+
+#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
+msgid "Active"
+msgstr "Actif"
+
+#: gui/fluidsynth-dialog.cpp:72
+msgid "Room:"
+msgstr "Pièce :"
+
+#: gui/fluidsynth-dialog.cpp:79
+msgid "Damp:"
+msgstr "Atténuation :"
+
+#: gui/fluidsynth-dialog.cpp:86
+msgid "Width:"
+msgstr "Largeur :"
+
+#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
+msgid "Level:"
+msgstr "Niveau :"
+
+#: gui/fluidsynth-dialog.cpp:100
+msgid "Chorus"
+msgstr "Chorus"
+
+#: gui/fluidsynth-dialog.cpp:104
+msgid "N:"
+msgstr "N :"
+
+#: gui/fluidsynth-dialog.cpp:118
+msgid "Speed:"
+msgstr "Vitesse :"
+
+#: gui/fluidsynth-dialog.cpp:125
+msgid "Depth:"
+msgstr "Profondeur :"
+
+#: gui/fluidsynth-dialog.cpp:132
+msgid "Type:"
+msgstr "Type :"
+
+#: gui/fluidsynth-dialog.cpp:135
+msgid "Sine"
+msgstr "Sinus"
+
+#: gui/fluidsynth-dialog.cpp:136
+msgid "Triangle"
+msgstr "Triangle"
+
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
+msgid "Misc"
+msgstr "Divers"
+
+#: gui/fluidsynth-dialog.cpp:140
+msgid "Interpolation:"
+msgstr "Interpolation :"
+
+#: gui/fluidsynth-dialog.cpp:143
+msgid "None (fastest)"
+msgstr "Aucune (plus rapide)"
+
+#: gui/fluidsynth-dialog.cpp:144
+msgid "Linear"
+msgstr "Linéaire"
+
+#: gui/fluidsynth-dialog.cpp:145
+msgid "Fourth-order"
+msgstr "Quatrième degré"
+
+#: gui/fluidsynth-dialog.cpp:146
+msgid "Seventh-order"
+msgstr "Septième degré"
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset"
+msgstr "Réinitialiser"
+
+#: gui/fluidsynth-dialog.cpp:150
+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: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 "OK"
+
+#: gui/fluidsynth-dialog.cpp:217
+msgid ""
+"Do you really want to reset all FluidSynth settings to their default values?"
msgstr ""
+"Voulez-vous vraiment remettre tous les réglages à leurs valeurs par défaut ?"
-#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
+#: 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 "Fermer"
-#: gui/gui-manager.cpp:120
+#: gui/gui-manager.cpp:122
msgid "Mouse click"
msgstr "Clic de souris"
-#: gui/gui-manager.cpp:124 base/main.cpp:319
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Afficher le clavier"
-#: gui/gui-manager.cpp:128 base/main.cpp:323
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Changer l'affectation des touches"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 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"
-#: gui/KeysDialog.h:36 gui/KeysDialog.cpp:145
-msgid "Choose an action to map"
-msgstr "Sélectionnez une action à affecter"
-
#: gui/KeysDialog.cpp:41
msgid "Map"
msgstr "Affecter"
-#: gui/KeysDialog.cpp:42 gui/launcher.cpp:352 gui/launcher.cpp:1048
-#: gui/launcher.cpp:1052 gui/massadd.cpp:92 gui/options.cpp:1238
-#: gui/saveload-dialog.cpp:932 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:402 engines/engine.cpp:413
-#: 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/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 "OK"
-
#: gui/KeysDialog.cpp:49
msgid "Select an action and click 'Map'"
msgstr "Selectionez une action et cliquez 'Affecter'"
@@ -151,7 +269,7 @@ msgstr "Touche associée: %s"
#: gui/KeysDialog.cpp:82 gui/KeysDialog.cpp:104 gui/KeysDialog.cpp:143
#, c-format
msgid "Associated key : none"
-msgstr "Touche associée: aucune"
+msgstr "Touche associée : aucune"
#: gui/KeysDialog.cpp:90
msgid "Please select an action"
@@ -161,13 +279,17 @@ msgstr "Selectionnez une action"
msgid "Press the key to associate"
msgstr "Appuyez sur la touche à associer"
+#: gui/KeysDialog.cpp:145 gui/KeysDialog.h:36
+msgid "Choose an action to map"
+msgstr "Sélectionnez une action à affecter"
+
#: gui/launcher.cpp:193
msgid "Game"
msgstr "Jeu"
#: gui/launcher.cpp:197
msgid "ID:"
-msgstr "ID:"
+msgstr "ID :"
#: gui/launcher.cpp:197 gui/launcher.cpp:199 gui/launcher.cpp:200
msgid ""
@@ -180,7 +302,7 @@ msgstr ""
#: gui/launcher.cpp:199
msgctxt "lowres"
msgid "ID:"
-msgstr "ID:"
+msgstr "ID :"
#: gui/launcher.cpp:204 gui/launcher.cpp:206 gui/launcher.cpp:207
msgid "Full title of the game"
@@ -189,11 +311,11 @@ msgstr "Nom complet du jeu"
#: gui/launcher.cpp:206
msgctxt "lowres"
msgid "Name:"
-msgstr "Nom:"
+msgstr "Nom :"
#: gui/launcher.cpp:210
msgid "Language:"
-msgstr "Langue:"
+msgstr "Langue :"
#: gui/launcher.cpp:210 gui/launcher.cpp:211
msgid ""
@@ -203,15 +325,15 @@ 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>"
#: gui/launcher.cpp:222
msgid "Platform:"
-msgstr "Plateforme:"
+msgstr "Système :"
#: gui/launcher.cpp:222 gui/launcher.cpp:224 gui/launcher.cpp:225
msgid "Platform the game was originally designed for"
@@ -220,17 +342,17 @@ msgstr "Plateforme pour laquelle votre jeu a été conçu"
#: gui/launcher.cpp:224
msgctxt "lowres"
msgid "Platform:"
-msgstr "Système:"
+msgstr "Système :"
#: gui/launcher.cpp:237
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"
@@ -243,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"
@@ -256,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"
@@ -274,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:"
+msgstr "Chemin du Jeu :"
-#: gui/launcher.cpp:325
+#: gui/launcher.cpp:327
msgctxt "lowres"
msgid "Game Path:"
-msgstr "Chemin du Jeu:"
+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:"
+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:"
+msgstr "Extra :"
-#: gui/launcher.cpp:339 gui/options.cpp:1132
+#: gui/launcher.cpp:341 gui/options.cpp:1138
msgid "Save Path:"
-msgstr "Sauvegardes:"
+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
+msgstr "Sauvegardes :"
+
+#: 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:95
+#: 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:69
+#: 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:1222
+#: gui/launcher.cpp:663 gui/launcher.cpp:1226
msgid "Search:"
-msgstr "Filtre:"
+msgstr "Filtre :"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
-#: engines/mohawk/myst.cpp:245 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:"
+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/myst.cpp:245
-#: engines/mohawk/riven.cpp:718 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:792
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -492,62 +615,42 @@ msgstr ""
"Voulez-vous vraiment lancer la détection automatique des jeux ? Cela peut "
"potentiellement ajouter un grand nombre de jeux."
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Oui"
-
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Non"
-
-#: gui/launcher.cpp:841
+#: 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:853
+#: 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:867
+#: gui/launcher.cpp:871
msgid "Pick the game:"
-msgstr "Choisissez le jeu:"
+msgstr "Choisissez le jeu :"
-#: gui/launcher.cpp:941
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "Voulez-vous vraiment supprimer ce jeu ?"
-#: gui/launcher.cpp:999
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "Voulez-vous charger le jeu ?"
-#: gui/launcher.cpp:1048
+#: 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:1052
+#: 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:1159
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Ajout Massif..."
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1165
msgid "Record..."
-msgstr ""
+msgstr "Enregistrer..."
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
@@ -555,7 +658,7 @@ msgstr "... en cours ..."
#: gui/massadd.cpp:259
msgid "Scan complete!"
-msgstr "Examen terminé!"
+msgstr "Examen terminé !"
#: gui/massadd.cpp:262
#, c-format
@@ -575,150 +678,148 @@ msgstr ""
#: gui/onscreendialog.cpp:101 gui/onscreendialog.cpp:103
msgid "Stop"
-msgstr ""
+msgstr "Arrêter"
#: gui/onscreendialog.cpp:106
msgid "Edit record description"
-msgstr ""
+msgstr "Changer la description de l'enregistrement"
#: gui/onscreendialog.cpp:108
-#, fuzzy
msgid "Switch to Game"
-msgstr "Commuter"
+msgstr "Retourner au jeu"
#: gui/onscreendialog.cpp:110
-#, fuzzy
msgid "Fast replay"
-msgstr "Mode rapide"
+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:"
+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:"
+msgstr "Mode graphique :"
-#: gui/options.cpp:746
+#: gui/options.cpp:752
msgid "Render mode:"
-msgstr "Mode de rendu:"
+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:2298
+#: 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é:"
+msgstr "Sortie Préféré :"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Music Device:"
-msgstr "Sortie Audio:"
+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é:"
+msgstr "Sortie Préféré :"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Music Device:"
-msgstr "Sortie Audio:"
+msgstr "Sortie Audio :"
-#: gui/options.cpp:798
+#: gui/options.cpp:804
msgid "AdLib emulator:"
-msgstr "Émulateur AdLib:"
+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:"
+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"
@@ -726,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:"
+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:"
+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:"
+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:"
+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:"
+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"
@@ -795,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"
@@ -812,178 +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:"
+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:"
+msgstr "Vitesse des ST :"
-#: gui/options.cpp:935
+#: gui/options.cpp:937
msgctxt "lowres"
msgid "Text and Speech:"
-msgstr "Dialogue:"
+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:"
+msgstr "Vitesse des ST :"
-#: gui/options.cpp:959
+#: gui/options.cpp:961
msgid "Music volume:"
-msgstr "Volume Musique:"
+msgstr "Volume Musique :"
-#: gui/options.cpp:961
+#: gui/options.cpp:963
msgctxt "lowres"
msgid "Music volume:"
-msgstr "Musique:"
+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:"
+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:"
+msgstr "Bruitage :"
-#: gui/options.cpp:981
+#: gui/options.cpp:983
msgid "Speech volume:"
-msgstr "Volume Dialogues:"
+msgstr "Volume Dialogues :"
-#: gui/options.cpp:983
+#: gui/options.cpp:985
msgctxt "lowres"
msgid "Speech volume:"
-msgstr "Dialogues:"
+msgstr "Dialogues :"
+
+#: gui/options.cpp:1115
+msgid "FluidSynth Settings"
+msgstr "Paramètres FluidSynth"
-#: gui/options.cpp:1140
+#: gui/options.cpp:1146
msgid "Theme Path:"
-msgstr "Thèmes:"
+msgstr "Thèmes :"
-#: gui/options.cpp:1142
+#: gui/options.cpp:1148
msgctxt "lowres"
msgid "Theme Path:"
-msgstr "Thèmes:"
+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:"
+msgstr "Plugins :"
-#: gui/options.cpp:1159
+#: gui/options.cpp:1165
msgctxt "lowres"
msgid "Plugins Path:"
-msgstr "Plugins:"
+msgstr "Plugins :"
-#: gui/options.cpp:1168 gui/fluidsynth-dialog.cpp:138
-msgid "Misc"
-msgstr "Divers"
-
-#: 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:"
+msgstr "Thème :"
-#: gui/options.cpp:1176
+#: gui/options.cpp:1182
msgid "GUI Renderer:"
-msgstr "Interface:"
+msgstr "Interface :"
-#: gui/options.cpp:1188
+#: gui/options.cpp:1194
msgid "Autosave:"
-msgstr "Sauvegarde auto:"
+msgstr "Sauvegarde auto :"
-#: gui/options.cpp:1190
+#: gui/options.cpp:1196
msgctxt "lowres"
msgid "Autosave:"
-msgstr "Sauvegarde:"
+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:"
+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."
@@ -992,64 +1101,75 @@ msgstr ""
"vous voulez l'utiliser vous devez d'abord changer de langue."
#. I18N: You must leave "#" as is, only word 'next' is translatable
-#: gui/predictivedialog.cpp:87
+#: gui/predictivedialog.cpp:86
msgid "# next"
-msgstr ""
+msgstr "# suivant"
-#: gui/predictivedialog.cpp:88
+#: gui/predictivedialog.cpp:87
msgid "add"
-msgstr ""
+msgstr "ajouter"
-#: gui/predictivedialog.cpp:92
-#, fuzzy
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
-msgstr "Supprimer"
+msgstr "Supprimer le caractère"
-#: gui/predictivedialog.cpp:96
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
-msgstr ""
+msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:98
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
-msgstr ""
+msgstr "* Pré"
+
+#. I18N: 'Num' means Numbers
+#: gui/predictivedialog.cpp:578
+msgid "* Num"
+msgstr "* 123"
+
+#. I18N: 'Abc' means Latin alphabet input
+#: gui/predictivedialog.cpp:581
+msgid "* Abc"
+msgstr "* Abc"
-#: gui/recorderdialog.cpp:64
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
-msgstr ""
+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 ""
+msgstr "Enregistrer"
-#: gui/recorderdialog.cpp:72
-#, fuzzy
+#: gui/recorderdialog.cpp:71
msgid "Playback"
-msgstr "Jouer"
+msgstr "Lecture"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
-msgstr ""
+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 ""
+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 ""
+msgstr "Notes : "
-#: gui/recorderdialog.cpp:155
-#, fuzzy
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
-msgstr "Voulez-vous vraiment supprimer cette sauvegarde ?"
+msgstr "Voulez-vous vraiment supprimer cet enregistrement ?"
+
+#: gui/recorderdialog.cpp:173
+msgid "Unknown Author"
+msgstr "Auteur inconnu"
#: gui/saveload-dialog.cpp:167
msgid "List view"
@@ -1077,15 +1197,15 @@ msgstr "Voulez-vous vraiment supprimer cette sauvegarde ?"
#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:884
msgid "Date: "
-msgstr "Date: "
+msgstr "Date : "
#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:890
msgid "Time: "
-msgstr "Heure: "
+msgstr "Heure : "
#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:898
msgid "Playtime: "
-msgstr "Durée de jeu: "
+msgstr "Durée de jeu : "
#: gui/saveload-dialog.cpp:408 gui/saveload-dialog.cpp:496
msgid "Untitled savestate"
@@ -1111,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:"
@@ -1120,150 +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:661
+#: 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
-msgid "Clear value"
-msgstr "Effacer la valeur"
-
-#: gui/fluidsynth-dialog.cpp:68
-msgid "Reverb"
-msgstr "Réverb"
-
-#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
-msgid "Active"
-msgstr "Actif"
-
-#: gui/fluidsynth-dialog.cpp:72
-msgid "Room:"
-msgstr "Pièce:"
-
-#: gui/fluidsynth-dialog.cpp:79
-msgid "Damp:"
-msgstr "Atténuation:"
-
-#: gui/fluidsynth-dialog.cpp:86
-msgid "Width:"
-msgstr "Largeur:"
-
-#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
-msgid "Level:"
-msgstr "Niveau:"
-
-#: gui/fluidsynth-dialog.cpp:100
-msgid "Chorus"
-msgstr "Chorus"
-
-#: gui/fluidsynth-dialog.cpp:104
-msgid "N:"
-msgstr "N:"
-
-#: gui/fluidsynth-dialog.cpp:118
-msgid "Speed:"
-msgstr "Vitesse:"
-
-#: gui/fluidsynth-dialog.cpp:125
-msgid "Depth:"
-msgstr "Profondeur:"
-
-#: gui/fluidsynth-dialog.cpp:132
-msgid "Type:"
-msgstr "Type:"
-
-#: gui/fluidsynth-dialog.cpp:135
-msgid "Sine"
-msgstr "Sinus"
-
-#: gui/fluidsynth-dialog.cpp:136
-msgid "Triangle"
-msgstr "Triangle"
-
-#: gui/fluidsynth-dialog.cpp:140
-msgid "Interpolation:"
-msgstr "Interpolation:"
-
-#: gui/fluidsynth-dialog.cpp:143
-msgid "None (fastest)"
-msgstr "Aucune (plus rapide)"
+#: 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/fluidsynth-dialog.cpp:144
-msgid "Linear"
-msgstr "Linéaire"
+#: 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/fluidsynth-dialog.cpp:145
-msgid "Fourth-order"
-msgstr "Quatrième degré"
+#: gui/updates-dialog.cpp:92
+msgid "Check for updates automatically"
+msgstr "Vérifier les mises à jour automatiquement"
-#: gui/fluidsynth-dialog.cpp:146
-msgid "Seventh-order"
-msgstr "Septième degré"
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr "Appliquer"
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset"
-msgstr "Réinitialiser"
-
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset all FluidSynth settings to their default values."
-msgstr "Remet tous les réglages à leurs valeurs par défaut."
-
-#: gui/fluidsynth-dialog.cpp:217
-msgid ""
-"Do you really want to reset all FluidSynth settings to their default values?"
-msgstr ""
-"Voulez-vous vraiment remettre tous les réglages à leurs valeurs par défaut ?"
+#: 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:228
+#: 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:306
+#: base/main.cpp:315
msgid "Menu"
msgstr "Menu"
-#: base/main.cpp:309 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:312 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:315
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Passer la phrase"
-#: base/main.cpp:507
+#: base/main.cpp:524
msgid "Error running game:"
-msgstr "Erreur lors de l'éxécution du jeu:"
+msgstr "Erreur lors de l'éxécution du jeu : "
-#: base/main.cpp:554
+#: 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é"
@@ -1297,7 +1357,7 @@ msgstr "Chemin inexistant"
#: common/error.cpp:54
msgid "Path not a directory"
-msgstr "Chemin n'est pas un répertoire"
+msgstr "Le chemin n'est pas un répertoire"
#: common/error.cpp:56
msgid "Path not a file"
@@ -1309,11 +1369,11 @@ msgstr "Impossible de créer le fichier"
#: common/error.cpp:61
msgid "Reading data failed"
-msgstr "Echec de la lecture"
+msgstr "Échec de la lecture"
#: common/error.cpp:63
msgid "Writing data failed"
-msgstr "Echec de l'écriture des données"
+msgstr "Échec de l'écriture des données"
#: common/error.cpp:66
msgid "Could not find suitable engine plugin"
@@ -1331,18 +1391,61 @@ msgstr "Annuler par l'utilisateur"
msgid "Unknown error"
msgstr "Erreur inconnue"
-#: engines/advancedDetector.cpp:317
+#. I18N: Hercules is graphics card name
+#: common/rendermode.cpp:35
+msgid "Hercules Green"
+msgstr "Hercules Vert"
+
+#: common/rendermode.cpp:36
+msgid "Hercules Amber"
+msgstr "Hercules Ambre"
+
+#: common/rendermode.cpp:42
+msgid "PC-9821 (256 Colors)"
+msgstr "PC-9821 (256 couleurs)"
+
+#: common/rendermode.cpp:43
+msgid "PC-9801 (16 Colors)"
+msgstr "PC-9801 (16 couleurs)"
+
+#: common/rendermode.cpp:73
+msgctxt "lowres"
+msgid "Hercules Green"
+msgstr "Hercules Vert"
+
+#: common/rendermode.cpp:74
+msgctxt "lowres"
+msgid "Hercules Amber"
+msgstr "Hercules Ambre"
+
+#: 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..."
@@ -1350,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"
@@ -1379,24 +1482,33 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "Retour au ~L~anceur"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:803
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:873
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
-#: engines/toltecs/menu.cpp:281 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:"
+msgstr "Sauvegarde :"
#: 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:803 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/neverhood/menumodule.cpp:873 engines/pegasus/pegasus.cpp:377
-#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
-#: engines/toltecs/menu.cpp:281 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"
@@ -1419,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"
@@ -1433,23 +1545,23 @@ msgstr "~A~nnuler"
msgid "~K~eys"
msgstr "~T~ouches"
-#: engines/engine.cpp:276
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Impossible d'initialiser le format des couleurs."
-#: engines/engine.cpp:284
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Impossible de changer le mode vidéo à: '"
-#: engines/engine.cpp:293
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "Impossible d'appliquer la correction du rapport d'aspect."
-#: engines/engine.cpp:298
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Impossible d'appliquer l'option plein écran."
-#: engines/engine.cpp:398
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1463,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:409
+#: 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"
@@ -1477,29 +1589,33 @@ msgstr ""
"logiciel approprié.\n"
"Lisez le fichier README pour plus de détails."
-#: engines/engine.cpp:467
+#: 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 ""
-"Echec du chargement (%s)! . Lisez le fichier README pour les informations de "
+"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:480
+#: 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 ""
-"Attention:le jeu que vous vous apprêtez à jouer n'est pas encore "
+"Attention : le jeu que vous vous apprêtez à jouer n'est pas encore "
"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:483
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Jouer quand même"
+#: audio/adlib.cpp:2290
+msgid "AdLib Emulator"
+msgstr "Émulateur AdLib"
+
#: audio/fmopl.cpp:62
msgid "MAME OPL emulator"
msgstr "Émulateur MAME OPL"
@@ -1510,7 +1626,7 @@ msgstr "Émulateur DOSBox OPL"
#: audio/fmopl.cpp:67
msgid "ALSA Direct FM"
-msgstr ""
+msgstr "ALSA direct-FM"
#: audio/mididrv.cpp:209
#, c-format
@@ -1532,8 +1648,8 @@ msgid ""
"The selected audio device '%s' cannot be used. See log file for more "
"information."
msgstr ""
-"The selected audio device '%s' ne peut pas être utilisé. Voir le fichier de "
-"log pour plus de détails."
+"Le périphérique audio sélectionné '%s' ne peut pas être utilisé. Voir le "
+"fichier de log pour plus de détails."
#: audio/mididrv.cpp:257
#, c-format
@@ -1553,31 +1669,35 @@ msgstr ""
"Le périphérique audio préféré '%s' ne peut pas être utilisé. Voir le fichier "
"de log pour plus de détails."
-#: audio/null.h:44
-msgid "No music"
-msgstr "Pas de musique"
-
#: audio/mods/paula.cpp:196
msgid "Amiga Audio Emulator"
msgstr "Émulateur Amiga Audio"
-#: audio/adlib.cpp:2291
-msgid "AdLib Emulator"
-msgstr "Émulateur AdLib"
+#: audio/null.h:44
+msgid "No music"
+msgstr "Pas de musique"
#: audio/softsynth/appleiigs.cpp:33
msgid "Apple II GS Emulator (NOT IMPLEMENTED)"
msgstr "Émulateur Apple II GS (PAS IMPLÉMENTÉ)"
-#: audio/softsynth/sid.cpp:1430
-msgid "C64 Audio Emulator"
-msgstr "Émulateur C64 Audio"
+#: audio/softsynth/cms.cpp:350
+msgid "Creative Music System Emulator"
+msgstr "Émulateur Creative Music System"
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33
+msgid "FM-Towns Audio"
+msgstr "Audio FM Towns"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58
+msgid "PC-98 Audio"
+msgstr "Audio PC-98"
+
+#: 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"
@@ -1589,6 +1709,146 @@ msgstr "Émulateur Haut Parleur PC"
msgid "IBM PCjr Emulator"
msgstr "Émulateur IBM PCjr"
+#: audio/softsynth/sid.cpp:1430
+msgid "C64 Audio Emulator"
+msgstr "Émulateur C64 Audio"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Do you really want to return to the Launcher?"
+msgstr "Voulez-vous vraiment retourner au Lanceur ?"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Launcher"
+msgstr "Lanceur"
+
+#: backends/events/default/default-events.cpp:218
+msgid "Do you really want to quit?"
+msgstr "Voulez-vous vraiment quitter ?"
+
+#: 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 "Quitter"
+
+#: 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 "Touchscreen 'Tap Mode' - Clic Gauche"
+
+#: 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 "Touchscreen 'Tap Mode' - Clic Droit"
+
+#: 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 "Touchscreen 'Tap Mode' - Déplacer sans cliquer"
+
+#: backends/events/gph/gph-events.cpp:409
+msgid "Maximum Volume"
+msgstr "Volume Maximum"
+
+#: backends/events/gph/gph-events.cpp:411
+msgid "Increasing Volume"
+msgstr "Augmentation Volume"
+
+#: backends/events/gph/gph-events.cpp:417
+msgid "Minimal Volume"
+msgstr "Volume Minimum"
+
+#: backends/events/gph/gph-events.cpp:419
+msgid "Decreasing Volume"
+msgstr "Diminution Volume"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Enabled"
+msgstr "Clic Activé"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Disabled"
+msgstr "Clic Désactivé"
+
+#: backends/events/openpandora/op-events.cpp:174
+msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
+msgstr "Touchscreen 'Tap Mode' - Déplacer sans cliquer"
+
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
+msgid "Do you want to quit ?"
+msgstr "Voulez-vous quitter ?"
+
+#. I18N: Trackpad mode toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:308
+msgid "Trackpad mode is now"
+msgstr "Le mode touchpad est maintenant"
+
+#. 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 "activé"
+
+#: backends/events/webossdl/webossdl-events.cpp:311
+#: backends/events/webossdl/webossdl-events.cpp:338
+msgid "OFF"
+msgstr "désactivé"
+
+#: backends/events/webossdl/webossdl-events.cpp:315
+msgid "Swipe two fingers to the right to toggle."
+msgstr "Glissez deux doigts vers la droite pour changer de mode."
+
+#. I18N: Auto-drag toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:335
+msgid "Auto-drag mode is now"
+msgstr "Le mode glisser-auto est maintenant"
+
+#: backends/events/webossdl/webossdl-events.cpp:342
+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:126
+msgid "OpenGL"
+msgstr "OpenGL"
+
+#: backends/graphics/opengl/opengl-graphics.cpp:127
+msgid "OpenGL (No filtering)"
+msgstr "OpenGL (sans filtre)"
+
+#: 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 "Normal (échelle d'origine)"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:66
+msgctxt "lowres"
+msgid "Normal (no scaling)"
+msgstr "Normal"
+
+#: 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:2219
+msgid "Disabled aspect ratio correction"
+msgstr "Désactiver la correction du rapport d'aspect"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
+msgid "Active graphics filter:"
+msgstr "Mode graphique actif:"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+msgid "Windowed mode"
+msgstr "Mode Fenêtre"
+
#: backends/keymapper/remap-dialog.cpp:48
msgid "Keymap:"
msgstr "Affectation des touches:"
@@ -1618,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"
@@ -1684,7 +1944,7 @@ msgstr "Sans changement d'échelle (vous devez faire défiler l'écran)"
#: backends/platform/ds/arm9/source/dsoptions.cpp:111
msgid "Brightness:"
-msgstr "Luminosité:"
+msgstr "Luminosité :"
#: backends/platform/ds/arm9/source/dsoptions.cpp:121
msgid "High quality audio (slower) (reboot)"
@@ -1694,18 +1954,26 @@ msgstr "Audio haute qualité (plus lent) (redémarrer)"
msgid "Disable power off"
msgstr "Désactivé l'extinction"
+#: 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 "Mode souris-cliquer-et-déplacer activé"
+#: 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 "Mode souris-cliquer-et-déplacer désactivé"
+#: 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 "Mode touchpad activé"
+#: 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 "Mode touchpad désactivé"
@@ -1716,9 +1984,9 @@ msgstr "Mode Clic"
#: 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
-#: backends/platform/tizen/form.cpp:275
msgid "Left Click"
msgstr "Clic Gauche"
@@ -1728,65 +1996,32 @@ msgstr "Clic Milieu"
#: backends/platform/maemo/maemo.cpp:220
#: backends/platform/symbian/src/SymbianActions.cpp:43
-#: backends/platform/wince/CEActionsSmartphone.cpp:44
#: backends/platform/tizen/form.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:44
msgid "Right Click"
msgstr "Clic Droit"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:77
+#: backends/platform/sdl/macosx/appmenu_osx.mm:88
msgid "Hide ScummVM"
msgstr "Masquer ScummVM"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:82
+#: backends/platform/sdl/macosx/appmenu_osx.mm:93
msgid "Hide Others"
msgstr "Masquer les autres"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:87
+#: backends/platform/sdl/macosx/appmenu_osx.mm:98
msgid "Show All"
msgstr "Tout afficher"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:109
#: backends/platform/sdl/macosx/appmenu_osx.mm:120
+#: backends/platform/sdl/macosx/appmenu_osx.mm:131
msgid "Window"
msgstr "Fenêtre"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:114
+#: backends/platform/sdl/macosx/appmenu_osx.mm:125
msgid "Minimize"
msgstr "Placer dans le Dock"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:46
-msgid "Normal (no scaling)"
-msgstr "Normal (échelle d'origine)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:65
-msgctxt "lowres"
-msgid "Normal (no scaling)"
-msgstr "Normal"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
-msgid "Enabled aspect ratio correction"
-msgstr "Activer la correction du rapport d'aspect"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
-msgid "Disabled aspect ratio correction"
-msgstr "Désactiver la correction du rapport d'aspect"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
-msgid "Active graphics filter:"
-msgstr "Mode graphique actif:"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
-msgid "Windowed mode"
-msgstr "Mode Fenêtre"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:118
-msgid "OpenGL"
-msgstr "OpenGL"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:119
-msgid "OpenGL (No filtering)"
-msgstr "OpenGL (sans filtre)"
-
#: backends/platform/symbian/src/SymbianActions.cpp:38
#: backends/platform/wince/CEActionsSmartphone.cpp:39
msgid "Up"
@@ -1830,14 +2065,6 @@ msgstr "Sauter le texte"
msgid "Fast mode"
msgstr "Mode rapide"
-#: backends/platform/symbian/src/SymbianActions.cpp:52
-#: backends/platform/wince/CEActionsPocket.cpp:44
-#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: backends/events/default/default-events.cpp:218 engines/scumm/dialogs.cpp:192
-#: engines/scumm/help.cpp:83 engines/scumm/help.cpp:85
-msgid "Quit"
-msgstr "Quitter"
-
#: backends/platform/symbian/src/SymbianActions.cpp:53
msgid "Debugger"
msgstr "Debugger"
@@ -1854,9 +2081,49 @@ msgstr "Clavier virtuel"
msgid "Key mapper"
msgstr "Affectation des touches"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:186
-msgid "Do you want to quit ?"
-msgstr "Voulez-vous quitter ?"
+#: backends/platform/tizen/form.cpp:263
+msgid "Right Click Once"
+msgstr "Simple Clic Droit"
+
+#: backends/platform/tizen/form.cpp:271
+msgid "Move Only"
+msgstr "Déplacer Uniquement"
+
+#: backends/platform/tizen/form.cpp:294
+msgid "Escape Key"
+msgstr "Touche d'échappement"
+
+#: backends/platform/tizen/form.cpp:299
+msgid "Game Menu"
+msgstr "Menu du Jeu"
+
+#: backends/platform/tizen/form.cpp:304
+msgid "Show Keypad"
+msgstr "Afficher le clavier"
+
+#: backends/platform/tizen/form.cpp:309
+msgid "Control Mouse"
+msgstr "Contrôles la Souris"
+
+#: backends/platform/tizen/fs.cpp:259
+msgid "[ Data ]"
+msgstr "[ Données ]"
+
+#: backends/platform/tizen/fs.cpp:263
+msgid "[ Resources ]"
+msgstr "[ Ressources ]"
+
+#: backends/platform/tizen/fs.cpp:267
+msgid "[ SDCard ]"
+msgstr "[ Carte SD ]"
+
+#: backends/platform/tizen/fs.cpp:271
+msgid "[ Media ]"
+msgstr "[ Média ]"
+
+#: backends/platform/tizen/fs.cpp:275
+msgid "[ Shared ]"
+msgstr "[ Partagé ]"
#: backends/platform/wii/options.cpp:51
msgid "Video"
@@ -1896,7 +2163,7 @@ msgstr "DVD"
#: backends/platform/wii/options.cpp:89 backends/platform/wii/options.cpp:101
msgid "Status:"
-msgstr "Status:"
+msgstr "État :"
#: backends/platform/wii/options.cpp:90 backends/platform/wii/options.cpp:102
msgid "Unknown"
@@ -1920,15 +2187,15 @@ msgstr "Serveur:"
#: backends/platform/wii/options.cpp:110
msgid "Share:"
-msgstr "Disque partagé:"
+msgstr "Disque partagé :"
#: backends/platform/wii/options.cpp:114
msgid "Username:"
-msgstr "Nom d'utilisateur:"
+msgstr "Nom d'utilisateur :"
#: backends/platform/wii/options.cpp:118
msgid "Password:"
-msgstr "Mot de passe:"
+msgstr "Mot de passe :"
#: backends/platform/wii/options.cpp:121
msgid "Init network"
@@ -2105,186 +2372,151 @@ msgstr ""
"Noubliez pas d'affecter une touche à l'action 'Cacher Bar d'Outils' pour "
"pouvoir voir entièrement l'inventaire"
-#: backends/events/default/default-events.cpp:196
-msgid "Do you really want to return to the Launcher?"
-msgstr "Voulez-vous vraiment retourner au Lanceur ?"
-
-#: backends/events/default/default-events.cpp:196
-msgid "Launcher"
-msgstr "Lanceur"
-
-#: backends/events/default/default-events.cpp:218
-msgid "Do you really want to quit?"
-msgstr "Voulez-vous vraiment quitter ?"
-
-#: 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 "Touchscreen 'Tap Mode' - Clic Gauche"
-
-#: 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 "Touchscreen 'Tap Mode' - Clic Droit"
-
-#: 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 "Touchscreen 'Tap Mode' - Déplacer sans cliquer"
-
-#: backends/events/gph/gph-events.cpp:409
-msgid "Maximum Volume"
-msgstr "Volume Maximum"
-
-#: backends/events/gph/gph-events.cpp:411
-msgid "Increasing Volume"
-msgstr "Augmentation Volume"
-
-#: backends/events/gph/gph-events.cpp:417
-msgid "Minimal Volume"
-msgstr "Volume Minimum"
-
-#: backends/events/gph/gph-events.cpp:419
-msgid "Decreasing Volume"
-msgstr "Diminution Volume"
-
-#: backends/events/openpandora/op-events.cpp:174
-msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
-msgstr "Touchscreen 'Tap Mode' - Déplacer sans cliquer"
-
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Recherche des mises à jour..."
-#: backends/platform/tizen/form.cpp:263
-msgid "Right Click Once"
-msgstr "Simple Clic Droit"
-
-#: backends/platform/tizen/form.cpp:271
-msgid "Move Only"
-msgstr "Déplacer Uniquement"
-
-#: backends/platform/tizen/form.cpp:294
-msgid "Escape Key"
-msgstr "Touche d'échappement"
-
-#: backends/platform/tizen/form.cpp:299
-msgid "Game Menu"
-msgstr "Menu du Jeu"
-
-#: backends/platform/tizen/form.cpp:304
-msgid "Show Keypad"
-msgstr "Afficher le clavier"
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+msgid "Color mode"
+msgstr "Mode Couleurs"
-#: backends/platform/tizen/form.cpp:309
-msgid "Control Mouse"
-msgstr "Contrôles la Souris"
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr "Utiliser les graphiques en couleurs"
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Enabled"
-msgstr "Clic Activé"
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr "Tracé par ligne"
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Disabled"
-msgstr "Clic Désactivé"
+#: engines/adl/detection.cpp:64
+msgid "Show scanlines"
+msgstr "Afficher le tracé par ligne"
-#: engines/agi/detection.cpp:147 engines/drascula/detection.cpp:302
-#: engines/dreamweb/detection.cpp:47 engines/neverhood/detection.cpp:160
-#: engines/sci/detection.cpp:394 engines/toltecs/detection.cpp:200
-#: engines/zvision/detection_tables.h:51
+#: 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 "Dialogues sauvegarde/chargement d'origine"
-#: engines/agi/detection.cpp:148 engines/drascula/detection.cpp:303
-#: engines/dreamweb/detection.cpp:48 engines/neverhood/detection.cpp:161
-#: engines/sci/detection.cpp:395 engines/toltecs/detection.cpp:201
+#: 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 ""
"Utiliser les dialogues sauvegarde/chargement d'origine plutôt que ceux de "
"ScummVM"
#: engines/agi/detection.cpp:157
-#, fuzzy
msgid "Use an alternative palette"
-msgstr "Utiliser une intro alternative (version CD uniquement)"
+msgstr "Utiliser une palette alternative"
#: engines/agi/detection.cpp:158
msgid ""
"Use an alternative palette, common for all Amiga games. This was the old "
"behavior"
msgstr ""
+"Utiliser une palette de remplacement commune à tous les jeux Amiga. C'est "
+"l'ancien comportement."
#: engines/agi/detection.cpp:167
-#, fuzzy
msgid "Mouse support"
-msgstr "Support des interruptions"
+msgstr "Support de la souris"
#: engines/agi/detection.cpp:168
msgid ""
"Enables mouse support. Allows to use mouse for movement and in game menus."
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:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
-msgid "Restore game:"
-msgstr "Charger le jeu:"
+#: engines/agi/detection.cpp:177
+msgid "Use Hercules hires font"
+msgstr "Utiliser les polices Hercules haute résolution"
-#: engines/agi/saveload.cpp:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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: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"
"\n"
"%s"
msgstr ""
-"Échec du chargement de l'état du jeu depuis le fichier:\n"
+"Échec du chargement de l'état du jeu depuis le fichier :\n"
"\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"
"\n"
"%s"
msgstr ""
-"Échec de l'enregistrement de l'état du jeu dans le fichier:\n"
+"Échec de l'enregistrement de l'état du jeu dans le fichier :\n"
"\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"
"\n"
"%s"
msgstr ""
-"État du jeu enregistré avec succès dans le fichier:\n"
+"État du jeu enregistré avec succès dans le fichier :\n"
"\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é!"
+msgstr "Fichier de séquence '%s' non trouvé !"
#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
-#, fuzzy
msgid "Color Blind Mode"
-msgstr "Mode Clic"
+msgstr "Mode Daltonien"
#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
-msgstr ""
+msgstr "Activer le mode Daltonien par défaut"
#: engines/drascula/saveload.cpp:47
msgid ""
@@ -2304,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."
@@ -2334,17 +2566,17 @@ 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."
#: engines/hopkins/detection.cpp:76 engines/hopkins/detection.cpp:86
msgid "Gore Mode"
-msgstr ""
+msgstr "Mode Sanglant"
#: engines/hopkins/detection.cpp:77 engines/hopkins/detection.cpp:87
msgid "Enable Gore Mode when available"
-msgstr ""
+msgstr "Activer le Mode Sanglant quand il est disponible"
#. I18N: Studio audience adds an applause and cheering sounds whenever
#. Malcolm makes a joke.
@@ -2460,8 +2692,8 @@ msgid ""
"General MIDI ones. It is still possible that\n"
"some tracks sound incorrect."
msgstr ""
-"Il semble que vous utilisiez un périphérique General MIDI,\n"
-"mais ce jeu ne support que le MIDI Roland MT32. Nous essayons\n"
+"Il semble que vous utilisez un périphérique General MIDI,\n"
+"mais ce jeu ne supporte que le MIDI Roland MT32. Nous essayons\n"
"d'associer les instruments Roland MT32 aux instruments General\n"
"MIDI. Cependant il est possible que quelques pistes ne soient\n"
" pas jouées correctement."
@@ -2476,6 +2708,13 @@ msgid ""
"Do you wish to use this save game file with ScummVM?\n"
"\n"
msgstr ""
+"Le fichier de sauvegarde original suivant a été trouvé dans le répertoire du "
+"jeu :\n"
+"\n"
+"%s %s\n"
+"\n"
+"Voulez-vous utiliser cette sauvegarde avec ScummVM ?\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:590
#, c-format
@@ -2483,6 +2722,8 @@ msgid ""
"A save game file was found in the specified slot %d. Overwrite?\n"
"\n"
msgstr ""
+"Une sauvegarde existe déjà dans l'emplacement %d. Écraser ?\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:623
#, c-format
@@ -2494,53 +2735,66 @@ msgid ""
"'import_savefile'.\n"
"\n"
msgstr ""
+"%d sauvegardes originales ont été importées avec succès. Si vous voulez\n"
+"importer d'autre sauvegardes originales plus tard, vous devrez ouvrir la\n"
+"console de debug de ScummVM et utiliser la commande 'import_savefile'.\n"
+"\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"
@@ -2549,15 +2803,23 @@ msgstr ""
"Erreur lors de la sauvegarde dans l'emplacement %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:194
+msgid "Load file"
+msgstr "Charger une partie"
+
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Chargement en cours..."
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:209
+msgid "Save file"
+msgstr "Sauver une partie"
+
+#: 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"
@@ -2574,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"
@@ -2632,27 +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 ""
+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:395
+msgid "Enable high resolution graphics/content"
+msgstr "Utiliser les graphiques haute résolution"
+
+#: 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 sonors digitals"
+msgstr "Préférer les effets sonores digitaux"
-#: engines/sci/detection.cpp:385
+#: 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:404
+#: 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:405
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2660,157 +2941,163 @@ msgstr ""
"Utiliser une carte IBM Music Feature ou un module Yamaha FB-01 FM pour la "
"sortie MIDI"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "Utiliser la musique du CD"
-#: engines/sci/detection.cpp:416
+#: 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:426
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Utiliser les curseurs Windows"
-#: engines/sci/detection.cpp:427
+#: 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:437
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Utiliser les curseurs argentés"
-#: engines/sci/detection.cpp:438
+#: 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
-#, fuzzy
+#: 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
-#, fuzzy
+#: 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:600
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Voix"
-#: engines/scumm/dialogs.cpp:601
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Voix et Sous-titres"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Sous-titres"
-#: engines/scumm/dialogs.cpp:610
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Voix & ST"
-#: engines/scumm/dialogs.cpp:656
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Sélectionnez un niveau de compétence."
-#: engines/scumm/dialogs.cpp:658
+#: 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:662
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Essai"
-#: engines/scumm/dialogs.cpp:663
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Expert"
#: engines/scumm/help.cpp:74
msgid "Common keyboard commands:"
-msgstr "Commandes clavier communes:"
+msgstr "Commandes clavier communes :"
#: engines/scumm/help.cpp:75
msgid "Save / Load dialog"
@@ -2834,7 +3121,7 @@ msgstr "Espace"
#: engines/scumm/help.cpp:79
msgid "Pause game"
-msgstr "Mettre en pause:"
+msgstr "Mettre en pause"
#: engines/scumm/help.cpp:80 engines/scumm/help.cpp:85
#: engines/scumm/help.cpp:96 engines/scumm/help.cpp:97
@@ -2846,7 +3133,7 @@ msgstr "Ctrl"
#: engines/scumm/help.cpp:80
msgid "Load game state 1-10"
-msgstr "Charger sauvegarde 1-10:"
+msgstr "Charger sauvegarde 1-10"
#: engines/scumm/help.cpp:81 engines/scumm/help.cpp:85
#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:101
@@ -2856,7 +3143,7 @@ msgstr "Alt"
#: engines/scumm/help.cpp:81
msgid "Save game state 1-10"
-msgstr "Écrire sauvegarde 1-10:"
+msgstr "Écrire sauvegarde 1-10"
#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:90
msgid "Enter"
@@ -2884,7 +3171,7 @@ msgstr "Simuler bouton droit de la souris"
#: engines/scumm/help.cpp:94
msgid "Special keyboard commands:"
-msgstr "Commandes clavier spéciales:"
+msgstr "Commandes clavier spéciales :"
#: engines/scumm/help.cpp:95
msgid "Show / Hide console"
@@ -2896,7 +3183,7 @@ msgstr "Ouvrir le débugger"
#: engines/scumm/help.cpp:97
msgid "Show memory consumption"
-msgstr "Afficher la consomation de mémoire"
+msgstr "Afficher la consommation de mémoire"
#: engines/scumm/help.cpp:98
msgid "Run in fast mode (*)"
@@ -2940,11 +3227,11 @@ msgstr " ou comportement incorrect du jeu."
#: engines/scumm/help.cpp:115
msgid "Spinning drafts on the keyboard:"
-msgstr "Filage au clavier:"
+msgstr "Filage au clavier :"
#: engines/scumm/help.cpp:117
msgid "Main game controls:"
-msgstr "Controles principaux du jeu:"
+msgstr "Contrôles principaux du jeu :"
#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
#: engines/scumm/help.cpp:162
@@ -3229,25 +3516,24 @@ msgid "Third kid"
msgstr "Troisième enfant"
#: engines/scumm/help.cpp:292
-#, fuzzy
msgid "Toggle Inventory/IQ Points display"
-msgstr "Basculer l'Affichage Central"
+msgstr "Basculer entre Inventaire/Points QI"
#: engines/scumm/help.cpp:293
msgid "Toggle Keyboard/Mouse Fighting (*)"
-msgstr ""
+msgstr "Basculer entre Clavier et Souris pour les combats (*)"
#: engines/scumm/help.cpp:295
msgid "* Keyboard Fighting is always on,"
-msgstr ""
+msgstr "* Le clavier peut toujours être utilisé pour les combats,"
#: engines/scumm/help.cpp:296
msgid " so despite the in-game message this"
-msgstr ""
+msgstr " donc malgré le message dans le jeu cela simplement"
#: engines/scumm/help.cpp:297
msgid " actually toggles Mouse Fighting Off/On"
-msgstr ""
+msgstr " active/désactive le combat à la souris"
#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
@@ -3284,7 +3570,7 @@ msgstr "Frapper bas"
#: engines/scumm/help.cpp:315
msgid "Sucker punch"
-msgstr ""
+msgstr "Sucker punch"
#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
@@ -3342,7 +3628,23 @@ msgstr "Voler vers la droite"
msgid "Fly to lower right"
msgstr "Voler vers la bas à droite"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/input.cpp:578
+msgid "Snap scroll on"
+msgstr "Défilement par à-coups"
+
+#: engines/scumm/input.cpp:580
+msgid "Snap scroll off"
+msgstr "Défilement régulier"
+
+#: engines/scumm/input.cpp:593
+msgid "Music volume: "
+msgstr "Volume Musique :"
+
+#: engines/scumm/input.cpp:610
+msgid "Subtitle speed: "
+msgstr "Vitesse des ST :"
+
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3351,29 +3653,92 @@ 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
-#, fuzzy
+#: 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 ""
-"Normalement, Maniac Mansion devrait démarrer maintenant. Cependant ScummVM "
-"ne supporte pas encore cette fonctionalité. Pour jouer à Maniac Mansion, "
-"choisissez 'Ajouter...' dans le Lanceur de ScummVM et sélectionnez le "
-"répertoire 'Maniac Mansion' dans le répertoire du jeu Day Of The Tentacle."
+"Normalement, Maniac Mansion devrait démarrer maintenant. Mais pour que cela "
+"marche il faut que les fichiers du jeu Maniac Mansion soient dans e "
+"répertoire 'Maniac' à l'intérieur du répertoire du jeu Day of the Tentacle, "
+"et le jeu doit être ajouter à ScummVM."
#: 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 ""
+"L'exécutable Macintosh de 'Loom' n'a pas été trouvé pour\n"
+"y lire les instruments. La musique sera désactivée."
#: 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 ""
+"L'exécutable Macintosh de 'Monkey Island' n'a pas été trouvé pour\n"
+"y lire les instruments. La musique sera désactivée."
+
+#: engines/sherlock/detection.cpp:71
+msgid "Use original savegame dialog"
+msgstr "Utiliser le dialogue de sauvegarde d'origine"
+
+#: engines/sherlock/detection.cpp:72
+msgid ""
+"Files button in-game shows original savegame dialog rather than the ScummVM "
+"menu"
+msgstr ""
+"Le bouton Fichiers du jeu ouvre le dialogue de sauvegarde d'origine au lieu "
+"d'ouvrir celui de ScummVM"
+
+#: engines/sherlock/detection.cpp:81
+msgid "Pixellated scene transitions"
+msgstr "Transitions de scènes pixélisées"
+
+#: engines/sherlock/detection.cpp:82
+msgid "When changing scenes, a randomized pixel transition is done"
+msgstr ""
+"Lors du changement de scène une transition avec des pixels aléatoires est "
+"utilisée"
+
+#: engines/sherlock/detection.cpp:91
+msgid "Don't show hotspots when moving mouse"
+msgstr "Ne pas afficher les zones actives lors du déplacement de la souris"
+
+#: engines/sherlock/detection.cpp:92
+msgid ""
+"Only show hotspot names after you actually click on a hotspot or action "
+"button"
+msgstr ""
+"Afficher le nom des zones actives uniquement après avoir cliqué sur la zone "
+"ou le bouton d'action"
+
+#: engines/sherlock/detection.cpp:101
+msgid "Show character portraits"
+msgstr "Afficher le portrait des personnages"
+
+#: engines/sherlock/detection.cpp:102
+msgid "Show portraits for the characters when conversing"
+msgstr "Afficher le portrait des personnages lors des conversations"
+
+#: engines/sherlock/detection.cpp:111
+msgid "Slide dialogs into view"
+msgstr "Utiliser une transition pour les dialogues"
+
+#: engines/sherlock/detection.cpp:112
+msgid "Slide UI dialogs into view, rather than simply showing them immediately"
+msgstr ""
+"Utiliser une transition pour faire apparaître les dialogues au lieu de les "
+"afficher immédiatement"
+
+#: engines/sherlock/detection.cpp:121
+msgid "Transparent windows"
+msgstr "Fenêtres transparentes"
+
+#: engines/sherlock/detection.cpp:122
+msgid "Show windows with a partially transparent background"
+msgstr "Afficher les fenêtres avec un fond partiellement transparent"
#: engines/sky/compact.cpp:130
msgid ""
@@ -3477,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"
@@ -3494,14 +3870,14 @@ msgstr ""
#: engines/wintermute/detection.cpp:58
msgid "Show FPS-counter"
-msgstr ""
+msgstr "Afficher le compteur FPS"
#: engines/wintermute/detection.cpp:59
msgid "Show the current number of frames per second in the upper left corner"
msgstr ""
+"Affiche le nombre d'images par seconde (FPS) dans le coin en haut à gauche"
#: engines/zvision/detection_tables.h:52
-#, fuzzy
msgid "Use the original save/load screens instead of the ScummVM interface"
msgstr ""
"Utiliser les dialogues sauvegarde/chargement d'origine plutôt que ceux de "
@@ -3509,38 +3885,37 @@ msgstr ""
#: engines/zvision/detection_tables.h:61
msgid "Double FPS"
-msgstr ""
+msgstr "Doubler les FPS"
#: engines/zvision/detection_tables.h:62
msgid "Increase framerate from 30 to 60 FPS"
-msgstr ""
+msgstr "Augmente de 30 à 60 le nombre d'images par seconde"
#: engines/zvision/detection_tables.h:71
-#, fuzzy
msgid "Enable Venus"
-msgstr "Activer le mode helium"
+msgstr "Activer Venus"
#: engines/zvision/detection_tables.h:72
-#, fuzzy
msgid "Enable the Venus help system"
-msgstr "Activer le mode helium"
+msgstr "Active le système d'aide Venus"
#: engines/zvision/detection_tables.h:81
msgid "Disable animation while turning"
-msgstr ""
+msgstr "Désactiver les animations en tournant"
#: engines/zvision/detection_tables.h:82
msgid "Disable animation while turning in panorama mode"
-msgstr ""
+msgstr "Désactiver les animations en tournant dans le mode panorama"
#: engines/zvision/detection_tables.h:91
msgid "Use high resolution MPEG video"
-msgstr ""
+msgstr "Utiliser les vidéos MPEG haute résolution"
#: engines/zvision/detection_tables.h:92
-#, fuzzy
msgid "Use MPEG video from the DVD version, instead of lower resolution AVI"
-msgstr "Utiliser les curseurs argentés au lieu des curseurs normaux dorés"
+msgstr ""
+"Utiliser les vidéos MPEG du DVD à la place des vidéos AVI de plus basse "
+"résolution"
#~ msgid "EGA undithering"
#~ msgstr "Détramage EGA"
@@ -3588,26 +3963,6 @@ msgstr "Utiliser les curseurs argentés au lieu des curseurs normaux dorés"
#~ msgid "Active filter mode: Nearest"
#~ msgstr "Filtre actif: Plus proche"
-#~ msgid "Enable Roland GS Mode"
-#~ msgstr "Activer le mode Roland GS"
-
-#~ msgid "Hercules Green"
-#~ msgstr "Hercules Vert"
-
-#~ msgid "Hercules Amber"
-#~ msgstr "Hercules Ambre"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Green"
-#~ msgstr "Hercules Vert"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Amber"
-#~ msgstr "Hercules Ambre"
-
-#~ msgid "Save game failed!"
-#~ msgstr "Échec de la sauvegarde!"
-
#~ msgctxt "lowres"
#~ msgid "Add Game..."
#~ msgstr "Ajouter..."
@@ -3621,8 +3976,5 @@ msgstr "Utiliser les curseurs argentés au lieu des curseurs normaux dorés"
#~ msgid "Command line argument not processed"
#~ msgstr "Argument de ligne de commande non traité"
-#~ msgid "FM Towns Emulator"
-#~ msgstr "Émulateur FM Towns"
-
#~ msgid "Invalid Path"
#~ msgstr "Chemin Invalide"
diff --git a/po/gl_ES.po b/po/gl_ES.po
index cec2582c0a..c4a4dfb198 100644
--- a/po/gl_ES.po
+++ b/po/gl_ES.po
@@ -1,21 +1,21 @@
# Galician translation for ScummVM.
-# Copyright (C) 2010-2015 The ScummVM Team
+# Copyright (C) 2010-2016 The ScummVM Team
# This file is distributed under the same license as the ScummVM package.
# Santiago G. Sanz <s.sanz@uvigo.es>, 2013.
#
msgid ""
msgstr ""
-"Project-Id-Version: ScummVM 1.6.0git\n"
+"Project-Id-Version: ScummVM 1.8.0git\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2015-09-06 15:14+0200\n"
-"PO-Revision-Date: 2014-07-02 09:51+0100\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"
"Language: Galego\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=iso-8859-1\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Generator: Poedit 1.6.5\n"
+"X-Generator: Poedit 1.8.6\n"
#: gui/about.cpp:94
#, c-format
@@ -52,28 +52,29 @@ msgid "Go up"
msgstr "Arriba"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:74 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: 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/fluidsynth-dialog.cpp:152 engines/engine.cpp:483
-#: backends/platform/wii/options.cpp:48
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
-#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:191 engines/sword1/control.cpp:865
+#: 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 "Cancelar"
#: gui/browser.cpp:76 gui/browser_osx.mm:103 gui/chooser.cpp:47
-#: gui/themebrowser.cpp:56
+#: gui/filebrowser-dialog.cpp:65 gui/themebrowser.cpp:56
msgid "Choose"
msgstr "Elixir"
#: gui/editrecorddialog.cpp:58
msgid "Author:"
-msgstr ""
+msgstr "Autor:"
#: gui/editrecorddialog.cpp:59 gui/launcher.cpp:204
msgid "Name:"
@@ -81,63 +82,182 @@ msgstr "Nome:"
#: gui/editrecorddialog.cpp:60
msgid "Notes:"
-msgstr ""
+msgstr "Notas:"
-#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:75
+#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74
msgid "Ok"
+msgstr "Aceptar"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Choose file for loading"
+msgstr "Escoller ficheiro para cargar"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Enter filename for saving"
+msgstr "Introducir nome de ficheiro para gardar"
+
+#: gui/filebrowser-dialog.cpp:132
+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: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 "Si"
+
+#: 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 "Non"
+
+#: gui/fluidsynth-dialog.cpp:68
+msgid "Reverb"
+msgstr "Reverberación"
+
+#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
+msgid "Active"
+msgstr "Activa"
+
+#: gui/fluidsynth-dialog.cpp:72
+msgid "Room:"
+msgstr "Sala:"
+
+#: gui/fluidsynth-dialog.cpp:79
+msgid "Damp:"
+msgstr "Humidade:"
+
+#: gui/fluidsynth-dialog.cpp:86
+msgid "Width:"
+msgstr "Largo:"
+
+#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
+msgid "Level:"
+msgstr "Nivel:"
+
+#: gui/fluidsynth-dialog.cpp:100
+msgid "Chorus"
+msgstr "Refrán"
+
+#: gui/fluidsynth-dialog.cpp:104
+msgid "N:"
+msgstr "N:"
+
+#: gui/fluidsynth-dialog.cpp:118
+msgid "Speed:"
+msgstr "Velocidade:"
+
+#: gui/fluidsynth-dialog.cpp:125
+msgid "Depth:"
+msgstr "Profundidade:"
+
+#: gui/fluidsynth-dialog.cpp:132
+msgid "Type:"
+msgstr "Tipo:"
+
+#: gui/fluidsynth-dialog.cpp:135
+msgid "Sine"
+msgstr "Seno"
+
+#: gui/fluidsynth-dialog.cpp:136
+msgid "Triangle"
+msgstr "Triángulo"
+
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
+msgid "Misc"
+msgstr "Misc."
+
+#: gui/fluidsynth-dialog.cpp:140
+msgid "Interpolation:"
+msgstr "Interpolación:"
+
+#: gui/fluidsynth-dialog.cpp:143
+msgid "None (fastest)"
+msgstr "Ningunha (máis rápido)"
+
+#: gui/fluidsynth-dialog.cpp:144
+msgid "Linear"
+msgstr "Lineal"
+
+#: gui/fluidsynth-dialog.cpp:145
+msgid "Fourth-order"
+msgstr "Cuarta orde"
+
+#: gui/fluidsynth-dialog.cpp:146
+msgid "Seventh-order"
+msgstr "Séptima orde"
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset"
+msgstr "Restablecer"
+
+#: gui/fluidsynth-dialog.cpp:150
+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: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 "Aceptar"
-#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
+#: gui/fluidsynth-dialog.cpp:217
+msgid ""
+"Do you really want to reset all FluidSynth settings to their default values?"
+msgstr ""
+"Seguro que queres restablecer a configuración de FluidSynth aos seus valores "
+"predefinidos?"
+
+#: 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 "Pechar"
-#: gui/gui-manager.cpp:120
+#: gui/gui-manager.cpp:122
msgid "Mouse click"
msgstr "Premer co rato"
-#: gui/gui-manager.cpp:124 base/main.cpp:319
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Mostrar teclado"
-#: gui/gui-manager.cpp:128 base/main.cpp:323
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Asignar teclas"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 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"
-#: gui/KeysDialog.h:36 gui/KeysDialog.cpp:145
-msgid "Choose an action to map"
-msgstr "Elixe unha acción para asignala"
-
#: gui/KeysDialog.cpp:41
msgid "Map"
msgstr "Asignar"
-#: gui/KeysDialog.cpp:42 gui/launcher.cpp:352 gui/launcher.cpp:1048
-#: gui/launcher.cpp:1052 gui/massadd.cpp:92 gui/options.cpp:1238
-#: gui/saveload-dialog.cpp:932 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:402 engines/engine.cpp:413
-#: 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/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 "Aceptar"
-
#: gui/KeysDialog.cpp:49
msgid "Select an action and click 'Map'"
msgstr "Selecciona unha acción e preme en Asignar"
@@ -160,6 +280,10 @@ msgstr "Selecciona unha acción"
msgid "Press the key to associate"
msgstr "Preme a tecla para asociala"
+#: gui/KeysDialog.cpp:145 gui/KeysDialog.h:36
+msgid "Choose an action to map"
+msgstr "Elixe unha acción para asignala"
+
#: gui/launcher.cpp:193
msgid "Game"
msgstr "Xogo"
@@ -200,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>"
@@ -223,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"
@@ -240,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"
@@ -253,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"
@@ -271,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:95
+#: 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:69
+#: 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:1222
+#: 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/myst.cpp:245 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/myst.cpp:245
-#: engines/mohawk/riven.cpp:718 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:792
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -488,65 +613,45 @@ msgstr ""
"Queres executar o detector de xogos en masa? É posible que se engada un gran "
"número de xogos."
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Si"
-
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Non"
-
-#: gui/launcher.cpp:841
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM non foi quen de abrir o directorio!"
-#: gui/launcher.cpp:853
+#: 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:867
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Elixe o xogo:"
-#: gui/launcher.cpp:941
+#: 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:999
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "Queres cargar a partida gardada?"
-#: gui/launcher.cpp:1048
+#: 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:1052
+#: 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:1159
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Engadir en masa..."
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1165
msgid "Record..."
-msgstr ""
+msgstr "Gravar..."
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
-msgstr "...progreso..."
+msgstr "... progreso..."
#: gui/massadd.cpp:259
msgid "Scan complete!"
@@ -569,148 +674,146 @@ msgstr "%d xogos novos atopados; %d xogos xa engadidos ignorados..."
#: gui/onscreendialog.cpp:101 gui/onscreendialog.cpp:103
msgid "Stop"
-msgstr ""
+msgstr "Deter"
#: gui/onscreendialog.cpp:106
msgid "Edit record description"
-msgstr ""
+msgstr "Editar descrición de gravación"
#: gui/onscreendialog.cpp:108
-#, fuzzy
msgid "Switch to Game"
-msgstr "Cambiar"
+msgstr "Cambiar ao xogo"
#: gui/onscreendialog.cpp:110
-#, fuzzy
msgid "Fast replay"
-msgstr "Modo rápido"
+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:2298
+#: 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"
@@ -718,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"
@@ -803,174 +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:1168 gui/fluidsynth-dialog.cpp:138
-msgid "Misc"
-msgstr "Misc."
-
-#: 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."
@@ -979,64 +1090,75 @@ msgstr ""
"deberás cambiar antes o idioma da interfaz."
#. I18N: You must leave "#" as is, only word 'next' is translatable
-#: gui/predictivedialog.cpp:87
+#: gui/predictivedialog.cpp:86
msgid "# next"
-msgstr ""
+msgstr "# seguinte"
-#: gui/predictivedialog.cpp:88
+#: gui/predictivedialog.cpp:87
msgid "add"
-msgstr ""
+msgstr "engadir"
-#: gui/predictivedialog.cpp:92
-#, fuzzy
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
-msgstr "Eliminar"
+msgstr "Eliminar carácter"
-#: gui/predictivedialog.cpp:96
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
-msgstr ""
+msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:98
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
-msgstr ""
+msgstr "* Pre"
+
+#. I18N: 'Num' means Numbers
+#: gui/predictivedialog.cpp:578
+msgid "* Num"
+msgstr "* Núm"
+
+#. I18N: 'Abc' means Latin alphabet input
+#: gui/predictivedialog.cpp:581
+msgid "* Abc"
+msgstr "* Abc"
-#: gui/recorderdialog.cpp:64
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
-msgstr ""
+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 ""
+msgstr "Gravar"
-#: gui/recorderdialog.cpp:72
-#, fuzzy
+#: gui/recorderdialog.cpp:71
msgid "Playback"
-msgstr "Xogar"
+msgstr "Reproducir"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
-msgstr ""
+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 ""
+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 ""
+msgstr "Notas:"
-#: gui/recorderdialog.cpp:155
-#, fuzzy
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
-msgstr "Seguro que queres eliminar esta partida?"
+msgstr "Seguro que queres eliminar esta gravación?"
+
+#: gui/recorderdialog.cpp:173
+msgid "Unknown Author"
+msgstr "Autor descoñecido"
#: gui/saveload-dialog.cpp:167
msgid "List view"
@@ -1098,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:"
@@ -1107,152 +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:661
+#: 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
-msgid "Clear value"
-msgstr "Limpar valor"
-
-#: gui/fluidsynth-dialog.cpp:68
-msgid "Reverb"
-msgstr "Reverberación"
-
-#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
-msgid "Active"
-msgstr "Activa"
-
-#: gui/fluidsynth-dialog.cpp:72
-msgid "Room:"
-msgstr "Sala:"
-
-#: gui/fluidsynth-dialog.cpp:79
-msgid "Damp:"
-msgstr "Humidade:"
-
-#: gui/fluidsynth-dialog.cpp:86
-msgid "Width:"
-msgstr "Largo:"
-
-#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
-msgid "Level:"
-msgstr "Nivel:"
-
-#: gui/fluidsynth-dialog.cpp:100
-msgid "Chorus"
-msgstr "Refrán"
-
-#: gui/fluidsynth-dialog.cpp:104
-msgid "N:"
-msgstr "N:"
-
-#: gui/fluidsynth-dialog.cpp:118
-msgid "Speed:"
-msgstr "Velocidade:"
-
-#: gui/fluidsynth-dialog.cpp:125
-msgid "Depth:"
-msgstr "Profundidade:"
-
-#: gui/fluidsynth-dialog.cpp:132
-msgid "Type:"
-msgstr "Tipo:"
-
-#: gui/fluidsynth-dialog.cpp:135
-msgid "Sine"
-msgstr "Seno"
-
-#: gui/fluidsynth-dialog.cpp:136
-msgid "Triangle"
-msgstr "Triángulo"
-
-#: gui/fluidsynth-dialog.cpp:140
-msgid "Interpolation:"
-msgstr "Interpolación:"
-
-#: gui/fluidsynth-dialog.cpp:143
-msgid "None (fastest)"
-msgstr "Ningunha (máis rápido)"
-
-#: gui/fluidsynth-dialog.cpp:144
-msgid "Linear"
-msgstr "Lineal"
-
-#: gui/fluidsynth-dialog.cpp:145
-msgid "Fourth-order"
-msgstr "Cuarta orde"
+#: 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/fluidsynth-dialog.cpp:146
-msgid "Seventh-order"
-msgstr "Séptima orde"
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr ""
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset"
-msgstr "Restablecer"
+#: gui/updates-dialog.cpp:92
+#, fuzzy
+msgid "Check for updates automatically"
+msgstr "Buscar actualizacións..."
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset all FluidSynth settings to their default values."
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
msgstr ""
-"Restablece a configuración de FluidSynth aos seus valores predefinidos."
-#: gui/fluidsynth-dialog.cpp:217
-msgid ""
-"Do you really want to reset all FluidSynth settings to their default values?"
-msgstr ""
-"Seguro que queres restablecer a configuración de FluidSynth aos seus valores "
-"predefinidos?"
+#: 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:228
+#: 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:306
+#: base/main.cpp:315
msgid "Menu"
msgstr "Menú"
-#: base/main.cpp:309 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:312 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:315
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Omitir liña"
-#: base/main.cpp:507
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Erro de execución do xogo:"
-#: base/main.cpp:554
+#: 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"
@@ -1320,16 +1375,60 @@ msgstr "Usuario cancelado"
msgid "Unknown error"
msgstr "Erro descoñecido"
-#: engines/advancedDetector.cpp:317
+#. I18N: Hercules is graphics card name
+#: common/rendermode.cpp:35
+msgid "Hercules Green"
+msgstr "Hercules verde"
+
+#: common/rendermode.cpp:36
+msgid "Hercules Amber"
+msgstr "Hercules ámbar"
+
+#: common/rendermode.cpp:42
+msgid "PC-9821 (256 Colors)"
+msgstr "PC-9821 (256 cores)"
+
+#: common/rendermode.cpp:43
+msgid "PC-9801 (16 Colors)"
+msgstr "PC-9801 (16 cores)"
+
+#: common/rendermode.cpp:73
+msgctxt "lowres"
+msgid "Hercules Green"
+msgstr "Hercules verde"
+
+#: common/rendermode.cpp:74
+msgctxt "lowres"
+msgid "Hercules Amber"
+msgstr "Hercules ámbar"
+
+#: 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.:"
@@ -1337,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"
@@ -1366,11 +1465,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "~V~olver ao Iniciador"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:803
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:873
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
-#: engines/toltecs/menu.cpp:281 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:"
@@ -1379,11 +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:803 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/neverhood/menumodule.cpp:873 engines/pegasus/pegasus.cpp:377
-#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
-#: engines/toltecs/menu.cpp:281 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"
@@ -1406,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"
@@ -1420,23 +1528,23 @@ msgstr "~C~ancelar"
msgid "~K~eys"
msgstr "~T~eclas"
-#: engines/engine.cpp:276
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Non se puido iniciar o formato de cor."
-#: engines/engine.cpp:284
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Non se puido cambiar ao modo de vídeo: '"
-#: engines/engine.cpp:293
+#: 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:298
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Non se puido aplicar a configuración de pantalla completa."
-#: engines/engine.cpp:398
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1450,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:409
+#: 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"
@@ -1464,7 +1572,7 @@ msgstr ""
"do xogo. Consulta o ficheiro README\n"
"para obter máis información."
-#: engines/engine.cpp:467
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1473,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:480
+#: 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 "
@@ -1483,10 +1591,14 @@ msgstr ""
"Por iso, talvez sexa inestable e os ficheiros de gardado talvez non "
"funcionen en futuras versións de ScummVM."
-#: engines/engine.cpp:483
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Iniciar de todos os xeitos"
+#: audio/adlib.cpp:2290
+msgid "AdLib Emulator"
+msgstr "Emulador de AdLib"
+
#: audio/fmopl.cpp:62
msgid "MAME OPL emulator"
msgstr "Emulador de OPL de MAME"
@@ -1497,7 +1609,7 @@ msgstr "Emulador de OPL de DOSBox"
#: audio/fmopl.cpp:67
msgid "ALSA Direct FM"
-msgstr ""
+msgstr "ALSA Direct FM"
#: audio/mididrv.cpp:209
#, c-format
@@ -1540,31 +1652,35 @@ msgstr ""
"Non se pode empregar o dispositivo de son preferido (%s). Consulta o "
"rexistro para obter máis información."
-#: audio/null.h:44
-msgid "No music"
-msgstr "Sen música"
-
#: audio/mods/paula.cpp:196
msgid "Amiga Audio Emulator"
msgstr "Emulador de Amiga Audio"
-#: audio/adlib.cpp:2291
-msgid "AdLib Emulator"
-msgstr "Emulador de AdLib"
+#: audio/null.h:44
+msgid "No music"
+msgstr "Sen música"
#: audio/softsynth/appleiigs.cpp:33
msgid "Apple II GS Emulator (NOT IMPLEMENTED)"
msgstr "Emulador de Apple II GS (non implementado)"
-#: audio/softsynth/sid.cpp:1430
-msgid "C64 Audio Emulator"
-msgstr "Emulador de C64 Audio"
+#: audio/softsynth/cms.cpp:350
+msgid "Creative Music System Emulator"
+msgstr "Emulador de Creative Music System"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33
+msgid "FM-Towns Audio"
+msgstr "FM-Towns Audio"
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58
+msgid "PC-98 Audio"
+msgstr "PC-98 Audio"
+
+#: 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"
@@ -1576,6 +1692,146 @@ msgstr "Emulador de altofalante de PC"
msgid "IBM PCjr Emulator"
msgstr "Emulador de IBM PCjr"
+#: audio/softsynth/sid.cpp:1430
+msgid "C64 Audio Emulator"
+msgstr "Emulador de C64 Audio"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Do you really want to return to the Launcher?"
+msgstr "Seguro que queres volver ao Iniciador?"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Launcher"
+msgstr "Iniciador"
+
+#: backends/events/default/default-events.cpp:218
+msgid "Do you really want to quit?"
+msgstr "Seguro que queres saír?"
+
+#: 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 "Saír"
+
+#: 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 "Modo Pantalla táctil: premer botón primario"
+
+#: 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 "Modo Pantalla táctil: premer botón secundario"
+
+#: 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 "Modo Pantalla táctil: apuntar co rato (sen premer)"
+
+#: backends/events/gph/gph-events.cpp:409
+msgid "Maximum Volume"
+msgstr "Volume máximo"
+
+#: backends/events/gph/gph-events.cpp:411
+msgid "Increasing Volume"
+msgstr "Subindo volume"
+
+#: backends/events/gph/gph-events.cpp:417
+msgid "Minimal Volume"
+msgstr "Volume mínimo"
+
+#: backends/events/gph/gph-events.cpp:419
+msgid "Decreasing Volume"
+msgstr "Baixando volume"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Enabled"
+msgstr "Premer activado"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Disabled"
+msgstr "Premer desactivado"
+
+#: backends/events/openpandora/op-events.cpp:174
+msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
+msgstr "Modo Pantalla táctil: apuntar co rato (premer na cruceta)"
+
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
+msgid "Do you want to quit ?"
+msgstr "Queres saír?"
+
+#. I18N: Trackpad mode toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:308
+msgid "Trackpad mode is now"
+msgstr "O modo Panel táctil está"
+
+#. 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 "ACTIVADO"
+
+#: backends/events/webossdl/webossdl-events.cpp:311
+#: backends/events/webossdl/webossdl-events.cpp:338
+msgid "OFF"
+msgstr "DESACTIVADO"
+
+#: backends/events/webossdl/webossdl-events.cpp:315
+msgid "Swipe two fingers to the right to toggle."
+msgstr "Arrastra dous dedos á dereita para cambiar o estado."
+
+#. I18N: Auto-drag toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:335
+msgid "Auto-drag mode is now"
+msgstr "O modo Autoarrastrar está"
+
+#: backends/events/webossdl/webossdl-events.cpp:342
+msgid "Swipe three fingers to the right to toggle."
+msgstr "Arrastra tres dedos á dereita para cambiar o estado."
+
+#: backends/graphics/opengl/opengl-graphics.cpp:126
+msgid "OpenGL"
+msgstr "OpenGL"
+
+#: backends/graphics/opengl/opengl-graphics.cpp:127
+msgid "OpenGL (No filtering)"
+msgstr "OpenGL (Sen filtraxe)"
+
+#: 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 "Normal (sen escala)"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:66
+msgctxt "lowres"
+msgid "Normal (no scaling)"
+msgstr "Normal (sen escala)"
+
+#: 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:2219
+msgid "Disabled aspect ratio correction"
+msgstr "Corrección de proporción desactivada"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
+msgid "Active graphics filter:"
+msgstr "Filtro de gráficos activo:"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+msgid "Windowed mode"
+msgstr "Modo en ventá"
+
#: backends/keymapper/remap-dialog.cpp:48
msgid "Keymap:"
msgstr "Asignación de teclas:"
@@ -1605,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"
@@ -1681,31 +1937,39 @@ msgstr "Son de alta calidade (máis lento) (reiniciar)"
msgid "Disable power off"
msgstr "Desactivar apagado"
+#: 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 "Modo premer e arrastrar activado."
+msgstr "Modo Premer e arrastrar activado."
+#: 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 "Modo premer e arrastrar desactivado."
+msgstr "Modo Premer e arrastrar desactivado."
+#: 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 "Modo panel táctil activado."
+msgstr "Modo Panel táctil activado."
+#: 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 "Modo panel táctil desactivado."
+msgstr "Modo Panel táctil desactivado."
#: backends/platform/maemo/maemo.cpp:208
msgid "Click Mode"
-msgstr "Modo rato"
+msgstr "Modo Rato"
#: 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
-#: backends/platform/tizen/form.cpp:275
msgid "Left Click"
msgstr "Botón primario"
@@ -1715,65 +1979,32 @@ msgstr "Botón central"
#: backends/platform/maemo/maemo.cpp:220
#: backends/platform/symbian/src/SymbianActions.cpp:43
-#: backends/platform/wince/CEActionsSmartphone.cpp:44
#: backends/platform/tizen/form.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:44
msgid "Right Click"
msgstr "Botón secundario"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:77
+#: backends/platform/sdl/macosx/appmenu_osx.mm:88
msgid "Hide ScummVM"
msgstr "Ocultar ScummVM"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:82
+#: backends/platform/sdl/macosx/appmenu_osx.mm:93
msgid "Hide Others"
msgstr "Ocultar outros"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:87
+#: backends/platform/sdl/macosx/appmenu_osx.mm:98
msgid "Show All"
msgstr "Mostrar todo"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:109
#: backends/platform/sdl/macosx/appmenu_osx.mm:120
+#: backends/platform/sdl/macosx/appmenu_osx.mm:131
msgid "Window"
msgstr "Ventá"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:114
+#: backends/platform/sdl/macosx/appmenu_osx.mm:125
msgid "Minimize"
msgstr "Minimizar"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:46
-msgid "Normal (no scaling)"
-msgstr "Normal (sen escala)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:65
-msgctxt "lowres"
-msgid "Normal (no scaling)"
-msgstr "Normal (sen escala)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
-msgid "Enabled aspect ratio correction"
-msgstr "Corrección de proporción activada"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
-msgid "Disabled aspect ratio correction"
-msgstr "Corrección de proporción desactivada"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
-msgid "Active graphics filter:"
-msgstr "Filtro de gráficos activo:"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
-msgid "Windowed mode"
-msgstr "Modo en ventá"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:118
-msgid "OpenGL"
-msgstr "OpenGL"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:119
-msgid "OpenGL (No filtering)"
-msgstr "OpenGL (Sen filtraxe)"
-
#: backends/platform/symbian/src/SymbianActions.cpp:38
#: backends/platform/wince/CEActionsSmartphone.cpp:39
msgid "Up"
@@ -1815,15 +2046,7 @@ msgstr "Omitir texto"
#: backends/platform/symbian/src/SymbianActions.cpp:51
msgid "Fast mode"
-msgstr "Modo rápido"
-
-#: backends/platform/symbian/src/SymbianActions.cpp:52
-#: backends/platform/wince/CEActionsPocket.cpp:44
-#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: backends/events/default/default-events.cpp:218 engines/scumm/dialogs.cpp:192
-#: engines/scumm/help.cpp:83 engines/scumm/help.cpp:85
-msgid "Quit"
-msgstr "Saír"
+msgstr "Modo Rápido"
#: backends/platform/symbian/src/SymbianActions.cpp:53
msgid "Debugger"
@@ -1841,9 +2064,49 @@ msgstr "Teclado virtual"
msgid "Key mapper"
msgstr "Asignador de teclas"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:186
-msgid "Do you want to quit ?"
-msgstr "Queres saír?"
+#: backends/platform/tizen/form.cpp:263
+msgid "Right Click Once"
+msgstr "Botón secundario unha vez"
+
+#: backends/platform/tizen/form.cpp:271
+msgid "Move Only"
+msgstr "Mover unicamente"
+
+#: backends/platform/tizen/form.cpp:294
+msgid "Escape Key"
+msgstr "ESC"
+
+#: backends/platform/tizen/form.cpp:299
+msgid "Game Menu"
+msgstr "Menú do xogo"
+
+#: backends/platform/tizen/form.cpp:304
+msgid "Show Keypad"
+msgstr "Mostrar teclado numérico"
+
+#: backends/platform/tizen/form.cpp:309
+msgid "Control Mouse"
+msgstr "Rato"
+
+#: backends/platform/tizen/fs.cpp:259
+msgid "[ Data ]"
+msgstr "[ Datos ]"
+
+#: backends/platform/tizen/fs.cpp:263
+msgid "[ Resources ]"
+msgstr "[ Recursos ]"
+
+#: backends/platform/tizen/fs.cpp:267
+msgid "[ SDCard ]"
+msgstr "[ Tarxeta SD ]"
+
+#: backends/platform/tizen/fs.cpp:271
+msgid "[ Media ]"
+msgstr "[ Medios ]"
+
+#: backends/platform/tizen/fs.cpp:275
+msgid "[ Shared ]"
+msgstr "[ Compartido ]"
#: backends/platform/wii/options.cpp:51
msgid "Video"
@@ -2090,140 +2353,106 @@ msgstr ""
"Non esquezas asignar unha tecla á acción Ocultar barra de ferramentas para "
"ver o inventario completo"
-#: backends/events/default/default-events.cpp:196
-msgid "Do you really want to return to the Launcher?"
-msgstr "Seguro que queres volver ao Iniciador?"
-
-#: backends/events/default/default-events.cpp:196
-msgid "Launcher"
-msgstr "Iniciador"
-
-#: backends/events/default/default-events.cpp:218
-msgid "Do you really want to quit?"
-msgstr "Seguro que queres saír?"
-
-#: 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 "Modo pantalla táctil: premer botón primario"
-
-#: 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 "Modo pantalla táctil: premer botón secundario"
-
-#: 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 "Modo pantalla táctil: apuntar co rato (sen premer)"
-
-#: backends/events/gph/gph-events.cpp:409
-msgid "Maximum Volume"
-msgstr "Volume máximo"
-
-#: backends/events/gph/gph-events.cpp:411
-msgid "Increasing Volume"
-msgstr "Subindo volume"
-
-#: backends/events/gph/gph-events.cpp:417
-msgid "Minimal Volume"
-msgstr "Volume mínimo"
-
-#: backends/events/gph/gph-events.cpp:419
-msgid "Decreasing Volume"
-msgstr "Baixando volume"
-
-#: backends/events/openpandora/op-events.cpp:174
-msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
-msgstr "Modo pantalla táctil: apuntar co rato (premer na cruceta)"
-
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Buscar actualizacións..."
-#: backends/platform/tizen/form.cpp:263
-msgid "Right Click Once"
-msgstr "Botón secundario unha vez"
-
-#: backends/platform/tizen/form.cpp:271
-msgid "Move Only"
-msgstr "Mover unicamente"
-
-#: backends/platform/tizen/form.cpp:294
-msgid "Escape Key"
-msgstr "ESC"
-
-#: backends/platform/tizen/form.cpp:299
-msgid "Game Menu"
-msgstr "Menú do xogo"
-
-#: backends/platform/tizen/form.cpp:304
-msgid "Show Keypad"
-msgstr "Mostrar teclado numérico"
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "Modo accesible para daltonismo"
-#: backends/platform/tizen/form.cpp:309
-msgid "Control Mouse"
-msgstr "Rato"
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Enabled"
-msgstr "Premer activado"
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Disabled"
-msgstr "Premer desactivado"
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "Mostrar etiquetas"
-#: engines/agi/detection.cpp:147 engines/drascula/detection.cpp:302
-#: engines/dreamweb/detection.cpp:47 engines/neverhood/detection.cpp:160
-#: engines/sci/detection.cpp:394 engines/toltecs/detection.cpp:200
-#: engines/zvision/detection_tables.h:51
+#: 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 "Empregar pantallas orixinais de gardado e carga"
-#: engines/agi/detection.cpp:148 engines/drascula/detection.cpp:303
-#: engines/dreamweb/detection.cpp:48 engines/neverhood/detection.cpp:161
-#: engines/sci/detection.cpp:395 engines/toltecs/detection.cpp:201
+#: 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 ""
"Empregar as pantallas orixinais de gardado e carga, no canto das de ScummVM"
#: engines/agi/detection.cpp:157
-#, fuzzy
msgid "Use an alternative palette"
-msgstr "Empregar unha introdución alternativa para o xogo (só versión en CD)"
+msgstr "Empregar unha paleta alternativa"
#: engines/agi/detection.cpp:158
msgid ""
"Use an alternative palette, common for all Amiga games. This was the old "
"behavior"
msgstr ""
+"Empregar unha paleta alternativa, común para todos os xogos de Amiga (uso "
+"antigo)"
#: engines/agi/detection.cpp:167
-#, fuzzy
msgid "Mouse support"
-msgstr "Omisións"
+msgstr "Compatibilidade co rato"
#: engines/agi/detection.cpp:168
msgid ""
"Enables mouse support. Allows to use mouse for movement and in game menus."
msgstr ""
+"Activa a compatibilidade co rato. Permite o uso do rato para o movemento e "
+"os menús do xogo."
+
+#: engines/agi/detection.cpp:177
+#, fuzzy
+msgid "Use Hercules hires font"
+msgstr "Hercules verde"
-#: engines/agi/saveload.cpp:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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"
@@ -2234,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"
@@ -2245,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"
@@ -2256,19 +2485,18 @@ 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!"
#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
-#, fuzzy
msgid "Color Blind Mode"
-msgstr "Modo rato"
+msgstr "Modo accesible para daltonismo"
#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
-msgstr ""
+msgstr "Activa o modo accesible para daltonismo de xeito predeterminado."
#: engines/drascula/saveload.cpp:47
msgid ""
@@ -2288,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 de paleta intensa"
+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."
@@ -2318,17 +2546,17 @@ 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"
#: engines/hopkins/detection.cpp:76 engines/hopkins/detection.cpp:86
msgid "Gore Mode"
-msgstr ""
+msgstr "Modo Gore"
#: engines/hopkins/detection.cpp:77 engines/hopkins/detection.cpp:87
msgid "Enable Gore Mode when available"
-msgstr ""
+msgstr "Activa o modo Gore, de ser o caso."
#. I18N: Studio audience adds an applause and cheering sounds whenever
#. Malcolm makes a joke.
@@ -2338,7 +2566,7 @@ msgstr "Público do estudio"
#: engines/kyra/detection.cpp:63
msgid "Enable studio audience"
-msgstr "Activar o público do estudio"
+msgstr "Activa o público do estudio."
#. I18N: This option allows the user to skip text and cutscenes.
#: engines/kyra/detection.cpp:73
@@ -2347,16 +2575,16 @@ msgstr "Omisións"
#: engines/kyra/detection.cpp:74
msgid "Allow text and cutscenes to be skipped"
-msgstr "Permitir a omisión do texto e das secuencias"
+msgstr "Permite a omisión do texto e das secuencias."
#. I18N: Helium mode makes people sound like they've inhaled Helium.
#: engines/kyra/detection.cpp:84
msgid "Helium mode"
-msgstr "Modo helio"
+msgstr "Modo Helio"
#: engines/kyra/detection.cpp:85
msgid "Enable helium mode"
-msgstr "Activar o modo helio"
+msgstr "Activa o modo Helio."
#. I18N: When enabled, this option makes scrolling smoother when
#. changing from one screen to another.
@@ -2366,7 +2594,7 @@ msgstr "Desprazamento suave"
#: engines/kyra/detection.cpp:100
msgid "Enable smooth scrolling when walking"
-msgstr "Activar o desprazamento suave ao camiñar"
+msgstr "Activa o desprazamento suave ao camiñar."
#. 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
@@ -2377,7 +2605,7 @@ msgstr "Cursores flotantes"
#: engines/kyra/detection.cpp:113
msgid "Enable floating cursors"
-msgstr "Activar cursores flotantes"
+msgstr "Activa os cursores flotantes."
#. I18N: HP stands for Hit Points
#: engines/kyra/detection.cpp:127
@@ -2386,7 +2614,7 @@ msgstr "Barras de vida"
#: engines/kyra/detection.cpp:128
msgid "Enable hit point bar graphs"
-msgstr "Activar barras de vida"
+msgstr "Activa as barras de vida."
#: engines/kyra/lol.cpp:478
msgid "Attack 1"
@@ -2460,6 +2688,12 @@ msgid ""
"Do you wish to use this save game file with ScummVM?\n"
"\n"
msgstr ""
+"Atopouse o seguinte ficheiro de gardado orixinal:\n"
+"\n"
+"%s %s\n"
+"\n"
+"Queres usalo con ScummVM?\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:590
#, c-format
@@ -2467,6 +2701,8 @@ msgid ""
"A save game file was found in the specified slot %d. Overwrite?\n"
"\n"
msgstr ""
+"Atopouse un ficheiro de gardado no espazo %d. Sobreescribir?\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:623
#, c-format
@@ -2478,50 +2714,66 @@ msgid ""
"'import_savefile'.\n"
"\n"
msgstr ""
+"Importación exitosa de %d ficheiro(s) de gardado a ScummVM.\n"
+"Se queres importar manualmente outros ficheiros de gardado orixinais máis "
+"adiante,\n"
+"abre a consola de depuración de ScummVM e emprega o comando \"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 ~c~omprimido activado"
+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"
@@ -2530,15 +2782,23 @@ msgstr ""
"Non se pode gardar a partida no espazo %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:194
+msgid "Load file"
+msgstr "Cargar ficheiro"
+
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Cargando..."
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:209
+msgid "Save file"
+msgstr "Gardar ficheiro"
+
+#: 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"
@@ -2555,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"
@@ -2613,181 +2873,207 @@ msgstr "Intro alternativa"
#: engines/queen/detection.cpp:57
msgid "Use an alternative game intro (CD version only)"
-msgstr "Empregar unha introdución alternativa para o xogo (só versión en CD)"
+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 ""
+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:395
+msgid "Enable high resolution graphics/content"
+msgstr "Activa os gráficos ou o contido de alta resolución."
+
+#: 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:385
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
-msgstr "Dar preferencia aos efectos de son dixitais no canto dos sintéticos"
+msgstr "Dá preferencia aos efectos de son dixitais no canto dos sintéticos."
-#: engines/sci/detection.cpp:404
+#: 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:405
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
msgstr ""
-"Empregar unha tarxeta IBM Music Feature ou un módulo de sintetizador Yamaha "
-"FB-01 FM para a saída de MIDI"
+"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:415
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "Empregar son de CD"
-#: engines/sci/detection.cpp:416
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
-msgstr "Empregar son de CD no canto do do xogo, de ser o caso"
+msgstr "Emprega son de CD no canto do do xogo, de ser o caso."
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Empregar cursores de Windows"
-#: engines/sci/detection.cpp:427
+#: engines/sci/detection.cpp:457
msgid ""
"Use the Windows cursors (smaller and monochrome) instead of the DOS ones"
msgstr ""
-"Empregar os cursores de Windows (máis pequenos e monocromos) no canto dos de "
-"DOS"
+"Emprega os cursores de Windows (máis pequenos e monocromos) no canto dos de "
+"DOS."
-#: engines/sci/detection.cpp:437
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Empregar cursores prateados"
-#: engines/sci/detection.cpp:438
+#: engines/sci/detection.cpp:468
msgid ""
"Use the alternate set of silver cursors, instead of the normal golden ones"
msgstr ""
-"Empregar o xogo de cursores prateados alternativo, no canto dos dourados "
-"normais"
+"Emprega o xogo de cursores prateados alternativo, no canto dos dourados "
+"normais."
+
+#: engines/scumm/detection.cpp:1340
+#, fuzzy
+msgid "Show Object Line"
+msgstr "Mostrar etiquetas"
-#: engines/scumm/dialogs.cpp:176
+#: 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
-#, fuzzy
+#: 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
-#, fuzzy
+#: 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:600
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Só voz"
-#: engines/scumm/dialogs.cpp:601
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Voz e subtítulos"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Só subtítulos"
-#: engines/scumm/dialogs.cpp:610
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Voz e subs"
-#: engines/scumm/dialogs.cpp:656
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Selecciona un nivel de habilidade."
-#: engines/scumm/dialogs.cpp:658
+#: 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:662
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Práctica"
-#: engines/scumm/dialogs.cpp:663
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Experto"
@@ -2883,11 +3169,11 @@ msgstr "Mostrar consumo de memoria"
#: engines/scumm/help.cpp:98
msgid "Run in fast mode (*)"
-msgstr "Executar en modo rápido (*)"
+msgstr "Executar en modo Rápido (*)"
#: engines/scumm/help.cpp:99
msgid "Run in really fast mode (*)"
-msgstr "Executar en modo moi rápido (*)"
+msgstr "Executar en modo Moi rápido (*)"
#: engines/scumm/help.cpp:100
msgid "Toggle mouse capture"
@@ -3201,7 +3487,7 @@ msgstr "Obxecto dereito medio"
#: engines/scumm/help.cpp:280 engines/scumm/help.cpp:285
msgid "Switching characters:"
-msgstr "Cambiar caracteres:"
+msgstr "Cambiar personaxes:"
#: engines/scumm/help.cpp:282
msgid "Second kid"
@@ -3212,25 +3498,24 @@ msgid "Third kid"
msgstr "Rapaz 3"
#: engines/scumm/help.cpp:292
-#, fuzzy
msgid "Toggle Inventory/IQ Points display"
-msgstr "Activar/Desactivar pantalla de datos"
+msgstr "Activar/Desactivar inventario/puntos CI"
#: engines/scumm/help.cpp:293
msgid "Toggle Keyboard/Mouse Fighting (*)"
-msgstr ""
+msgstr "Activar/Desactivar combate con teclado/rato (*)"
#: engines/scumm/help.cpp:295
msgid "* Keyboard Fighting is always on,"
-msgstr ""
+msgstr "* O combate co teclado está sempre activado,"
#: engines/scumm/help.cpp:296
msgid " so despite the in-game message this"
-msgstr ""
+msgstr "de xeito que esta mensaxe"
#: engines/scumm/help.cpp:297
msgid " actually toggles Mouse Fighting Off/On"
-msgstr ""
+msgstr "realmente activa/desactiva o combate co rato."
#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
@@ -3267,7 +3552,7 @@ msgstr "Puñazo baixo"
#: engines/scumm/help.cpp:315
msgid "Sucker punch"
-msgstr ""
+msgstr "Puñazo letal"
#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
@@ -3325,7 +3610,23 @@ msgstr "Voar á dereita"
msgid "Fly to lower right"
msgstr "Voar á dereita abaixo"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/input.cpp:578
+msgid "Snap scroll on"
+msgstr "Axuste de desprazamento SI"
+
+#: engines/scumm/input.cpp:580
+msgid "Snap scroll off"
+msgstr "Axuste de desprazamento NON"
+
+#: engines/scumm/input.cpp:593
+msgid "Music volume: "
+msgstr "Volume de música:"
+
+#: engines/scumm/input.cpp:610
+msgid "Subtitle speed: "
+msgstr "Velocidade dos subtítulos:"
+
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3334,28 +3635,87 @@ 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
-#, fuzzy
+#: 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 ""
-"Maniac Mansion tería que empezar agora. Porén, ScummVM aínda non é quen de "
-"facelo. Para xogar, vai a Engadir xogo no menú de inicio de ScummVM e "
-"selecciona o directorio Maniac que está dentro do directorio Tentacle."
+"Maniac Mansion tería que empezar agora. Porén, os ficheiros do xogo teñen "
+"que estar no directorio \"Maniac\" dentro do directorio \"Tentacle\". "
+"Ademais, cómpre engadir o xogo a ScummVM."
#: 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 ""
+"Erro ao buscar o executable de Loom para Macintosh\n"
+"do que empregar os instrumentos. A música desactivarase."
#: 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 ""
+"Erro ao buscar o executable de Monkey Island para Macintosh\n"
+"do que empregar os instrumentos. A música desactivarase."
+
+#: engines/sherlock/detection.cpp:71
+msgid "Use original savegame dialog"
+msgstr "Empregar pantalla orixinal de gardado"
+
+#: engines/sherlock/detection.cpp:72
+msgid ""
+"Files button in-game shows original savegame dialog rather than the ScummVM "
+"menu"
+msgstr ""
+"O botón de ficheiros do xogo mostra a pantalla orixinal de gardado no canto "
+"do menú de ScummVM."
+
+#: engines/sherlock/detection.cpp:81
+msgid "Pixellated scene transitions"
+msgstr "Transicións de escenas pixeladas"
+
+#: engines/sherlock/detection.cpp:82
+msgid "When changing scenes, a randomized pixel transition is done"
+msgstr "Ao mudar de escena, mostrase una transición pixelada aleatoria."
+
+#: engines/sherlock/detection.cpp:91
+msgid "Don't show hotspots when moving mouse"
+msgstr "Non mostrar puntos de acceso ao mover o rato"
+
+#: engines/sherlock/detection.cpp:92
+msgid ""
+"Only show hotspot names after you actually click on a hotspot or action "
+"button"
+msgstr ""
+"Só mostra os nomes dos puntos de acceso despois de premer nun punto de "
+"acceso ou un botón de acción."
+
+#: engines/sherlock/detection.cpp:101
+msgid "Show character portraits"
+msgstr "Mostrar retratos de personaxes"
+
+#: engines/sherlock/detection.cpp:102
+msgid "Show portraits for the characters when conversing"
+msgstr "Mostra os retratos dos personaxes nas conversas."
+
+#: engines/sherlock/detection.cpp:111
+msgid "Slide dialogs into view"
+msgstr "Deslizar pantallas"
+
+#: engines/sherlock/detection.cpp:112
+msgid "Slide UI dialogs into view, rather than simply showing them immediately"
+msgstr "Desliza as pantallas da IU, no canto de mostralas directamente."
+
+#: engines/sherlock/detection.cpp:121
+msgid "Transparent windows"
+msgstr "Ventás transparentes"
+
+#: engines/sherlock/detection.cpp:122
+msgid "Show windows with a partially transparent background"
+msgstr "Mostra ventás cun fondo parcialmente transparente."
#: engines/sky/compact.cpp:130
msgid ""
@@ -3379,7 +3739,7 @@ msgstr "Intro de disquete"
#: engines/sky/detection.cpp:45
msgid "Use the floppy version's intro (CD version only)"
-msgstr "Empregar a introdución da versión en disquete (só versión en CD)"
+msgstr "Emprega a introdución da versión en disquete (só versión en CD)."
#: engines/sword1/animation.cpp:524
#, c-format
@@ -3456,15 +3816,24 @@ msgstr "Mostrar etiquetas"
#: engines/sword2/sword2.cpp:80
msgid "Show labels for objects on mouse hover"
-msgstr "Mostrar as etiquetas dos obxectos ao apuntar co rato"
+msgstr "Mostra as etiquetas dos obxectos ao apuntar co rato."
+
+#: 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:95
+#: 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"
@@ -3474,54 +3843,50 @@ msgstr ""
#: engines/wintermute/detection.cpp:58
msgid "Show FPS-counter"
-msgstr ""
+msgstr "Mostrar FPS"
#: engines/wintermute/detection.cpp:59
msgid "Show the current number of frames per second in the upper left corner"
-msgstr ""
+msgstr "Mostra o número actual de FPS na esquina superior esquerda."
#: engines/zvision/detection_tables.h:52
-#, fuzzy
msgid "Use the original save/load screens instead of the ScummVM interface"
msgstr ""
-"Empregar as pantallas orixinais de gardado e carga, no canto das de ScummVM"
+"Empregar as pantallas orixinais de gardado e carga, no canto da interface de "
+"ScummVM"
#: engines/zvision/detection_tables.h:61
msgid "Double FPS"
-msgstr ""
+msgstr "Dobrar FPS"
#: engines/zvision/detection_tables.h:62
msgid "Increase framerate from 30 to 60 FPS"
-msgstr ""
+msgstr "Aumenta os fotogramas de 30 a 60 FPS."
#: engines/zvision/detection_tables.h:71
-#, fuzzy
msgid "Enable Venus"
-msgstr "Activar o modo helio"
+msgstr "Activar Venus"
#: engines/zvision/detection_tables.h:72
-#, fuzzy
msgid "Enable the Venus help system"
-msgstr "Activar o modo helio"
+msgstr "Activa o sistema de axuda Venus."
#: engines/zvision/detection_tables.h:81
msgid "Disable animation while turning"
-msgstr ""
+msgstr "Desactivar animación nos xiros"
#: engines/zvision/detection_tables.h:82
msgid "Disable animation while turning in panorama mode"
-msgstr ""
+msgstr "Desactiva a animación nos xiros no modo Panorama."
#: engines/zvision/detection_tables.h:91
msgid "Use high resolution MPEG video"
-msgstr ""
+msgstr "Empregar modo de vídeo MPEG de alta resolución"
#: engines/zvision/detection_tables.h:92
-#, fuzzy
msgid "Use MPEG video from the DVD version, instead of lower resolution AVI"
msgstr ""
-"Empregar o xogo de cursores prateados alternativo, no canto dos dourados "
-"normais"
+"Emprega o vídeo MPEG da versión en DVD, no canto da AVI de baixa resolución."
#~ msgid "EGA undithering"
#~ msgstr "Non interpolación EGA"
@@ -3566,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 ac48bd5e62..69fc239a21 100644..100755
--- a/po/hu_HU.po
+++ b/po/hu_HU.po
@@ -1,14 +1,13 @@
# Hungarian translation for ScummVM.
-# Copyright (C) 2010-2015 The ScummVM Team
+# Copyright (C) 2010-2016 The ScummVM Team
# This file is distributed under the same license as the ScummVM package.
-# George Kormendi <grubycza@hotmail.com>, 2010.
-#
+# George Kormendi <grubycza@hotmail.com>, 2010, 2016.
msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.3.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2015-09-06 15:14+0200\n"
-"PO-Revision-Date: 2014-02-18 06:30+0100\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"
@@ -16,8 +15,8 @@ msgstr ""
"Content-Type: text/plain; charset=iso-8859-2\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Virtaal 0.7.1\n"
"X-Poedit-SourceCharset: iso-8859-1\n"
-"X-Generator: Poedit 1.6.4\n"
#: gui/about.cpp:94
#, c-format
@@ -54,28 +53,29 @@ msgid "Go up"
msgstr "Feljebb"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:74 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: 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/fluidsynth-dialog.cpp:152 engines/engine.cpp:483
-#: backends/platform/wii/options.cpp:48
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
-#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:191 engines/sword1/control.cpp:865
+#: 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 "Mégse"
#: gui/browser.cpp:76 gui/browser_osx.mm:103 gui/chooser.cpp:47
-#: gui/themebrowser.cpp:56
+#: gui/filebrowser-dialog.cpp:65 gui/themebrowser.cpp:56
msgid "Choose"
msgstr "Választ"
#: gui/editrecorddialog.cpp:58
msgid "Author:"
-msgstr ""
+msgstr "Szerzõ:"
#: gui/editrecorddialog.cpp:59 gui/launcher.cpp:204
msgid "Name:"
@@ -83,63 +83,180 @@ msgstr "Név:"
#: gui/editrecorddialog.cpp:60
msgid "Notes:"
-msgstr ""
+msgstr "Megjegyzés:"
-#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:75
+#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74
msgid "Ok"
+msgstr "Ok"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Choose file for loading"
+msgstr "Válassz betöltendõ fájlt"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Enter filename for saving"
+msgstr "Írd be a fájlnevet mentéshez"
+
+#: gui/filebrowser-dialog.cpp:132
+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: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 "Igen"
+
+#: 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 "Nem"
+
+#: gui/fluidsynth-dialog.cpp:68
+msgid "Reverb"
+msgstr "Forgatás"
+
+#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
+msgid "Active"
+msgstr "Aktív"
+
+#: gui/fluidsynth-dialog.cpp:72
+msgid "Room:"
+msgstr "Szoba:"
+
+#: gui/fluidsynth-dialog.cpp:79
+msgid "Damp:"
+msgstr "Csillapítás:"
+
+#: gui/fluidsynth-dialog.cpp:86
+msgid "Width:"
+msgstr "Szélesség:"
+
+#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
+msgid "Level:"
+msgstr "Szint:"
+
+#: gui/fluidsynth-dialog.cpp:100
+msgid "Chorus"
+msgstr "Kórus"
+
+#: gui/fluidsynth-dialog.cpp:104
+msgid "N:"
+msgstr "N:"
+
+#: gui/fluidsynth-dialog.cpp:118
+msgid "Speed:"
+msgstr "Sebesség:"
+
+#: gui/fluidsynth-dialog.cpp:125
+msgid "Depth:"
+msgstr "Mélység:"
+
+#: gui/fluidsynth-dialog.cpp:132
+msgid "Type:"
+msgstr "Típus:"
+
+#: gui/fluidsynth-dialog.cpp:135
+msgid "Sine"
+msgstr "Színusz"
+
+#: gui/fluidsynth-dialog.cpp:136
+msgid "Triangle"
+msgstr "Háromszög"
+
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
+msgid "Misc"
+msgstr "Vegyes"
+
+#: gui/fluidsynth-dialog.cpp:140
+msgid "Interpolation:"
+msgstr "Interpoláció:"
+
+#: gui/fluidsynth-dialog.cpp:143
+msgid "None (fastest)"
+msgstr "Nincs (gyorsabb)"
+
+#: gui/fluidsynth-dialog.cpp:144
+msgid "Linear"
+msgstr "Lineáris"
+
+#: gui/fluidsynth-dialog.cpp:145
+msgid "Fourth-order"
+msgstr "Negyedrangú"
+
+#: gui/fluidsynth-dialog.cpp:146
+msgid "Seventh-order"
+msgstr "Hetedrangú"
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset"
+msgstr "Reset"
+
+#: gui/fluidsynth-dialog.cpp:150
+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: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 "OK"
+
+#: gui/fluidsynth-dialog.cpp:217
+msgid ""
+"Do you really want to reset all FluidSynth settings to their default values?"
msgstr ""
+"Biztos visszaállítassz minden FluidSynth beállítást alapértelmezett értékre?"
-#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
+#: 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 "Bezár"
-#: gui/gui-manager.cpp:120
+#: gui/gui-manager.cpp:122
msgid "Mouse click"
msgstr "Egérkattintás"
-#: gui/gui-manager.cpp:124 base/main.cpp:319
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Billentyûzet beállítások"
-#: gui/gui-manager.cpp:128 base/main.cpp:323
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Billentyûk átállítása"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 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ó"
-#: gui/KeysDialog.h:36 gui/KeysDialog.cpp:145
-msgid "Choose an action to map"
-msgstr "Válassz mûveletet a kiosztáshoz"
-
#: gui/KeysDialog.cpp:41
msgid "Map"
msgstr "Kiosztás"
-#: gui/KeysDialog.cpp:42 gui/launcher.cpp:352 gui/launcher.cpp:1048
-#: gui/launcher.cpp:1052 gui/massadd.cpp:92 gui/options.cpp:1238
-#: gui/saveload-dialog.cpp:932 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:402 engines/engine.cpp:413
-#: 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/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 "OK"
-
#: gui/KeysDialog.cpp:49
msgid "Select an action and click 'Map'"
msgstr "Válassz mûveletet és katt a 'Kiosztás'-ra"
@@ -162,6 +279,10 @@ msgstr "Válassz egy mûveletet"
msgid "Press the key to associate"
msgstr "Nyomj egy billentyût a társításhoz"
+#: gui/KeysDialog.cpp:145 gui/KeysDialog.h:36
+msgid "Choose an action to map"
+msgstr "Válassz mûveletet a kiosztáshoz"
+
#: gui/launcher.cpp:193
msgid "Game"
msgstr "Játék"
@@ -202,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>"
@@ -225,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"
@@ -242,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ó"
@@ -255,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õ"
@@ -273,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:95
+#: 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:69
+#: 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 "Betöltés"
+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:1222
+#: 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/myst.cpp:245 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/myst.cpp:245
-#: engines/mohawk/riven.cpp:718 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:792
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -490,62 +612,42 @@ 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:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Igen"
-
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Nem"
-
-#: gui/launcher.cpp:841
+#: 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:853
+#: 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:867
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Válassztott játék:"
-#: gui/launcher.cpp:941
+#: 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:999
+#: 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:1048
+#: 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:1052
+#: 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:1159
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Masszív mód..."
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1165
msgid "Record..."
-msgstr ""
+msgstr "Felvétel..."
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
@@ -572,213 +674,207 @@ msgstr "%d új játékot találtam, %d elõzõleg hozzáadott játék kihagyva..."
#: gui/onscreendialog.cpp:101 gui/onscreendialog.cpp:103
msgid "Stop"
-msgstr ""
+msgstr "Állj"
#: gui/onscreendialog.cpp:106
msgid "Edit record description"
-msgstr ""
+msgstr "Felvétel leírás szerkesztése"
#: gui/onscreendialog.cpp:108
-#, fuzzy
msgid "Switch to Game"
-msgstr "Kapcsol"
+msgstr "Átvált játékra"
#: gui/onscreendialog.cpp:110
-#, fuzzy
msgid "Fast replay"
-msgstr "Gyors mód"
+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:2298
+#: 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"
@@ -786,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"
@@ -803,173 +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:1168 gui/fluidsynth-dialog.cpp:138
-msgid "Misc"
-msgstr "Vegyes"
-
-#: 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."
@@ -978,64 +1086,75 @@ msgstr ""
"témát, elõszõr válts át egy másik nyelvre."
#. I18N: You must leave "#" as is, only word 'next' is translatable
-#: gui/predictivedialog.cpp:87
+#: gui/predictivedialog.cpp:86
msgid "# next"
-msgstr ""
+msgstr "# következõ"
-#: gui/predictivedialog.cpp:88
+#: gui/predictivedialog.cpp:87
msgid "add"
-msgstr ""
+msgstr "hozzáad"
-#: gui/predictivedialog.cpp:92
-#, fuzzy
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
-msgstr "Töröl"
+msgstr "Karakter törlés"
-#: gui/predictivedialog.cpp:96
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
-msgstr ""
+msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:98
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
-msgstr ""
+msgstr "* Elõzõ"
+
+#. I18N: 'Num' means Numbers
+#: gui/predictivedialog.cpp:578
+msgid "* Num"
+msgstr "* Szám"
-#: gui/recorderdialog.cpp:64
+#. I18N: 'Abc' means Latin alphabet input
+#: gui/predictivedialog.cpp:581
+msgid "* Abc"
+msgstr "* Abc"
+
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
-msgstr ""
+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 ""
+msgstr "Felvétel"
-#: gui/recorderdialog.cpp:72
-#, fuzzy
+#: gui/recorderdialog.cpp:71
msgid "Playback"
-msgstr "Játék"
+msgstr "Visszajátszás"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
-msgstr ""
+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 ""
+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 ""
+msgstr "Megjegyzés:"
-#: gui/recorderdialog.cpp:155
-#, fuzzy
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
-msgstr "Biztos hogy törölni akarod ezt a játékállást?"
+msgstr "Biztos hogy törölni akarod ezt a felvételt?"
+
+#: gui/recorderdialog.cpp:173
+msgid "Unknown Author"
+msgstr "Ismeretlen Szerzõ"
#: gui/saveload-dialog.cpp:167
msgid "List view"
@@ -1097,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:"
@@ -1106,150 +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:661
+#: 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
-msgid "Clear value"
-msgstr "Érték törlése"
-
-#: gui/fluidsynth-dialog.cpp:68
-msgid "Reverb"
-msgstr "Forgatás"
-
-#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
-msgid "Active"
-msgstr "Aktív"
-
-#: gui/fluidsynth-dialog.cpp:72
-msgid "Room:"
-msgstr "Szoba:"
-
-#: gui/fluidsynth-dialog.cpp:79
-msgid "Damp:"
-msgstr "Csillapítás:"
-
-#: gui/fluidsynth-dialog.cpp:86
-msgid "Width:"
-msgstr "Szélesség:"
-
-#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
-msgid "Level:"
-msgstr "Szint:"
-
-#: gui/fluidsynth-dialog.cpp:100
-msgid "Chorus"
-msgstr "Kórus"
-
-#: gui/fluidsynth-dialog.cpp:104
-msgid "N:"
-msgstr "N:"
-
-#: gui/fluidsynth-dialog.cpp:118
-msgid "Speed:"
-msgstr "Sebesség:"
-
-#: gui/fluidsynth-dialog.cpp:125
-msgid "Depth:"
-msgstr "Mélység:"
-
-#: gui/fluidsynth-dialog.cpp:132
-msgid "Type:"
-msgstr "Típus:"
-
-#: gui/fluidsynth-dialog.cpp:135
-msgid "Sine"
-msgstr "Színusz"
-
-#: gui/fluidsynth-dialog.cpp:136
-msgid "Triangle"
-msgstr "Háromszög"
-
-#: gui/fluidsynth-dialog.cpp:140
-msgid "Interpolation:"
-msgstr "Interpoláció:"
-
-#: gui/fluidsynth-dialog.cpp:143
-msgid "None (fastest)"
-msgstr "Nincs (gyorsabb)"
-
-#: gui/fluidsynth-dialog.cpp:144
-msgid "Linear"
-msgstr "Lineáris"
+#: 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/fluidsynth-dialog.cpp:145
-msgid "Fourth-order"
-msgstr "Negyedrangú"
+#: 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/fluidsynth-dialog.cpp:146
-msgid "Seventh-order"
-msgstr "Hetedrangú"
+#: gui/updates-dialog.cpp:92
+msgid "Check for updates automatically"
+msgstr "Frissítések automatikus keresése"
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset"
-msgstr "Reset"
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr "Folyamatban"
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset all FluidSynth settings to their default values."
-msgstr "Minden FluidSynth beállítás alapértelmezett értékre."
-
-#: gui/fluidsynth-dialog.cpp:217
-msgid ""
-"Do you really want to reset all FluidSynth settings to their default values?"
-msgstr ""
-"Biztos visszaállítassz minden FluidSynth beállítást alapértelmezett értékre?"
+#: 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:228
+#: 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:306
+#: base/main.cpp:315
msgid "Menu"
msgstr "Menü"
-#: base/main.cpp:309 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:312 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:315
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Sor átlépése"
-#: base/main.cpp:507
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Hiba a játék futtatásakor:"
-#: base/main.cpp:554
+#: 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"
@@ -1317,16 +1374,59 @@ msgstr "Felhasználói megszakítás"
msgid "Unknown error"
msgstr "Ismeretlen hiba"
-#: engines/advancedDetector.cpp:317
+#. I18N: Hercules is graphics card name
+#: common/rendermode.cpp:35
+msgid "Hercules Green"
+msgstr "Hercules Zöld"
+
+#: common/rendermode.cpp:36
+msgid "Hercules Amber"
+msgstr "Hercules Sárga"
+
+#: common/rendermode.cpp:42
+msgid "PC-9821 (256 Colors)"
+msgstr "PC-9821 (256 Szín)"
+
+#: common/rendermode.cpp:43
+msgid "PC-9801 (16 Colors)"
+msgstr "PC-9801 (16 Szín)"
+
+#: common/rendermode.cpp:73
+msgctxt "lowres"
+msgid "Hercules Green"
+msgstr "Hercules Zöld"
+
+#: common/rendermode.cpp:74
+msgctxt "lowres"
+msgid "Hercules Amber"
+msgstr "Hercules Sárga"
+
+#: 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.:"
@@ -1334,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 "Betöltés"
+msgstr "~B~etöltés"
-#: engines/dialogs.cpp:91
+#: engines/dialogs.cpp:91 engines/mohawk/dialogs.cpp:97
msgid "~S~ave"
msgstr "Mentés"
@@ -1363,11 +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:803
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:873
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
-#: engines/toltecs/menu.cpp:281 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:"
@@ -1376,11 +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:803 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/neverhood/menumodule.cpp:873 engines/pegasus/pegasus.cpp:377
-#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
-#: engines/toltecs/menu.cpp:281 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"
@@ -1402,37 +1511,37 @@ 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"
+msgstr "~M~égse"
#: engines/dialogs.cpp:311
msgid "~K~eys"
msgstr "Billentyük"
-#: engines/engine.cpp:276
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Szín formátum nincs alkalmazva"
-#: engines/engine.cpp:284
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Videómód nincs átállítva: ' "
-#: engines/engine.cpp:293
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "Méretarány korrekció nem változott."
-#: engines/engine.cpp:298
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Teljesképernyõs beállítás nincs alkalmazva"
-#: engines/engine.cpp:398
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1446,7 +1555,7 @@ msgstr ""
"adatfájljait a merevlemezedre.\n"
"Nézd meg a README fájlt a részletekért."
-#: engines/engine.cpp:409
+#: 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"
@@ -1460,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:467
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1469,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:480
+#: 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 "
@@ -1479,10 +1588,14 @@ 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:483
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Indítás így is"
+#: audio/adlib.cpp:2290
+msgid "AdLib Emulator"
+msgstr "AdLib Emulátor"
+
#: audio/fmopl.cpp:62
msgid "MAME OPL emulator"
msgstr "MAME OPL emulátor"
@@ -1493,7 +1606,7 @@ msgstr "DOSBox OPL emulátor"
#: audio/fmopl.cpp:67
msgid "ALSA Direct FM"
-msgstr ""
+msgstr "ALSA Direct FM"
#: audio/mididrv.cpp:209
#, c-format
@@ -1534,31 +1647,35 @@ msgstr ""
"Az elsõdleges '%s' hangeszköz nem használható. Bõvebb információ a "
"naplófájlban."
-#: audio/null.h:44
-msgid "No music"
-msgstr "Nincs zene"
-
#: audio/mods/paula.cpp:196
msgid "Amiga Audio Emulator"
-msgstr "Amiga Audió Emulátor"
+msgstr "Amiga Hang Emulátor"
-#: audio/adlib.cpp:2291
-msgid "AdLib Emulator"
-msgstr "AdLib Emulátor"
+#: audio/null.h:44
+msgid "No music"
+msgstr "Nincs zene"
#: audio/softsynth/appleiigs.cpp:33
msgid "Apple II GS Emulator (NOT IMPLEMENTED)"
msgstr "Apple II GS Emulátor (NEM TÁMOGATOTT)"
-#: audio/softsynth/sid.cpp:1430
-msgid "C64 Audio Emulator"
-msgstr "C64 Audio Emulátor"
+#: audio/softsynth/cms.cpp:350
+msgid "Creative Music System Emulator"
+msgstr "Creative Zenei Rendszer Emulátor"
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33
+msgid "FM-Towns Audio"
+msgstr "FM-Towns Hang"
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58
+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"
@@ -1570,6 +1687,146 @@ msgstr "PC Speaker Emulátor"
msgid "IBM PCjr Emulator"
msgstr "IBM PCjr Emulátor"
+#: audio/softsynth/sid.cpp:1430
+msgid "C64 Audio Emulator"
+msgstr "C64 Audio Emulátor"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Do you really want to return to the Launcher?"
+msgstr "Biztos hogy visszatérsz az indítópulthoz?"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Launcher"
+msgstr "Indítópult"
+
+#: backends/events/default/default-events.cpp:218
+msgid "Do you really want to quit?"
+msgstr "Biztos hogy ki akarsz lépni ?"
+
+#: 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 "Kilépés"
+
+#: 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 "Érintõképernyõ 'Tap Mód' - Bal katt"
+
+#: 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 "Érintõképernyõ 'Tap Mód' - Jobb katt"
+
+#: 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 "Érintõképernyõ 'Tap Mód' - Lebegõ (Nincs katt)"
+
+#: backends/events/gph/gph-events.cpp:409
+msgid "Maximum Volume"
+msgstr "Maximum Hangerõ"
+
+#: backends/events/gph/gph-events.cpp:411
+msgid "Increasing Volume"
+msgstr "Hangerõ növelése"
+
+#: backends/events/gph/gph-events.cpp:417
+msgid "Minimal Volume"
+msgstr "Minimum Hangerõ"
+
+#: backends/events/gph/gph-events.cpp:419
+msgid "Decreasing Volume"
+msgstr "Hangerõ csökkentése"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Enabled"
+msgstr "Kattintás engedve"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Disabled"
+msgstr "Kattintás tiltva"
+
+#: backends/events/openpandora/op-events.cpp:174
+msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
+msgstr "Érintõképernyõ 'Érintésmód' - Lebegõ (DPad katt)"
+
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
+msgid "Do you want to quit ?"
+msgstr "Ki akarsz lépni ?"
+
+#. I18N: Trackpad mode toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:308
+msgid "Trackpad mode is now"
+msgstr "Trackpad mód most"
+
+#. 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 "BE"
+
+#: backends/events/webossdl/webossdl-events.cpp:311
+#: backends/events/webossdl/webossdl-events.cpp:338
+msgid "OFF"
+msgstr "KI"
+
+#: backends/events/webossdl/webossdl-events.cpp:315
+msgid "Swipe two fingers to the right to toggle."
+msgstr "Üsd két újjal hogy biztosan váltson."
+
+#. I18N: Auto-drag toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:335
+msgid "Auto-drag mode is now"
+msgstr "Auto-húz módban van"
+
+#: backends/events/webossdl/webossdl-events.cpp:342
+msgid "Swipe three fingers to the right to toggle."
+msgstr "Üsd három újjal hogy biztosan váltson."
+
+#: backends/graphics/opengl/opengl-graphics.cpp:126
+msgid "OpenGL"
+msgstr "OpenGL"
+
+#: backends/graphics/opengl/opengl-graphics.cpp:127
+msgid "OpenGL (No filtering)"
+msgstr "OpenGL (Nincs szûrés)"
+
+#: 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 "Normál (nincs átméretezés)"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:66
+msgctxt "lowres"
+msgid "Normal (no scaling)"
+msgstr "Normál (nincs átméretezés)"
+
+#: 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:2219
+msgid "Disabled aspect ratio correction"
+msgstr "Méretarány korrekció letiltva"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
+msgid "Active graphics filter:"
+msgstr "Aktív grafikus szûrõk:"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+msgid "Windowed mode"
+msgstr "Ablakos mód"
+
#: backends/keymapper/remap-dialog.cpp:48
msgid "Keymap:"
msgstr "Billentyûzet kiosztás:"
@@ -1599,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"
@@ -1609,7 +1866,7 @@ msgstr "ScummVM Fõmenü"
#: backends/platform/ds/arm9/source/dsoptions.cpp:63
msgid "~L~eft handed mode"
-msgstr "Balkezes mód:"
+msgstr "~B~alkezes mód"
#: backends/platform/ds/arm9/source/dsoptions.cpp:64
msgid "~I~ndy fight controls"
@@ -1675,18 +1932,26 @@ msgstr "Jóminõségü audió (lassabb)(újraindítás)"
msgid "Disable power off"
msgstr "Leállítás tiltva"
+#: 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 "Egér kattint-és-húz mód engedélyezve."
+#: 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 "Egér kattint-és-húz mód letiltva."
+#: 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 "Touchpad mód engedélyezve."
+#: 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 "Touchpad mód letiltva."
@@ -1697,9 +1962,9 @@ msgstr "Kattintás Mód"
#: 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
-#: backends/platform/tizen/form.cpp:275
msgid "Left Click"
msgstr "Bal katt"
@@ -1709,65 +1974,32 @@ msgstr "Középsõ katt"
#: backends/platform/maemo/maemo.cpp:220
#: backends/platform/symbian/src/SymbianActions.cpp:43
-#: backends/platform/wince/CEActionsSmartphone.cpp:44
#: backends/platform/tizen/form.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:44
msgid "Right Click"
msgstr "Jobb katt"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:77
+#: backends/platform/sdl/macosx/appmenu_osx.mm:88
msgid "Hide ScummVM"
msgstr "ScummVM elrejtése"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:82
+#: backends/platform/sdl/macosx/appmenu_osx.mm:93
msgid "Hide Others"
msgstr "Többi elrejtése"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:87
+#: backends/platform/sdl/macosx/appmenu_osx.mm:98
msgid "Show All"
msgstr "Mutasd mind"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:109
#: backends/platform/sdl/macosx/appmenu_osx.mm:120
+#: backends/platform/sdl/macosx/appmenu_osx.mm:131
msgid "Window"
msgstr "Ablak"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:114
+#: backends/platform/sdl/macosx/appmenu_osx.mm:125
msgid "Minimize"
msgstr "Kis méret"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:46
-msgid "Normal (no scaling)"
-msgstr "Normál (nincs átméretezés)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:65
-msgctxt "lowres"
-msgid "Normal (no scaling)"
-msgstr "Normál (nincs átméretezés)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
-msgid "Enabled aspect ratio correction"
-msgstr "Méretarány korrekció engedélyezve"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
-msgid "Disabled aspect ratio correction"
-msgstr "Méretarány korrekció letiltva"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
-msgid "Active graphics filter:"
-msgstr "Aktív grafikus szûrõk:"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
-msgid "Windowed mode"
-msgstr "Ablakos mód"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:118
-msgid "OpenGL"
-msgstr "OpenGL"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:119
-msgid "OpenGL (No filtering)"
-msgstr "OpenGL (Nincs szûrés)"
-
#: backends/platform/symbian/src/SymbianActions.cpp:38
#: backends/platform/wince/CEActionsSmartphone.cpp:39
msgid "Up"
@@ -1811,14 +2043,6 @@ msgstr "Szöveg átugrása"
msgid "Fast mode"
msgstr "Gyors mód"
-#: backends/platform/symbian/src/SymbianActions.cpp:52
-#: backends/platform/wince/CEActionsPocket.cpp:44
-#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: backends/events/default/default-events.cpp:218 engines/scumm/dialogs.cpp:192
-#: engines/scumm/help.cpp:83 engines/scumm/help.cpp:85
-msgid "Quit"
-msgstr "Kilépés"
-
#: backends/platform/symbian/src/SymbianActions.cpp:53
msgid "Debugger"
msgstr "Hibakeresõ"
@@ -1835,9 +2059,49 @@ msgstr "Virtuális billentyûzet"
msgid "Key mapper"
msgstr "Billentyû kiosztás"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:186
-msgid "Do you want to quit ?"
-msgstr "Ki akarsz lépni ?"
+#: backends/platform/tizen/form.cpp:263
+msgid "Right Click Once"
+msgstr "Jobb katt egyszer"
+
+#: backends/platform/tizen/form.cpp:271
+msgid "Move Only"
+msgstr "Csak lépés"
+
+#: backends/platform/tizen/form.cpp:294
+msgid "Escape Key"
+msgstr "Escape gomb"
+
+#: backends/platform/tizen/form.cpp:299
+msgid "Game Menu"
+msgstr "Játék Menü"
+
+#: backends/platform/tizen/form.cpp:304
+msgid "Show Keypad"
+msgstr "Kézi billentyûzet"
+
+#: backends/platform/tizen/form.cpp:309
+msgid "Control Mouse"
+msgstr "Egér irányitás"
+
+#: backends/platform/tizen/fs.cpp:259
+msgid "[ Data ]"
+msgstr "[ Adat ]"
+
+#: backends/platform/tizen/fs.cpp:263
+msgid "[ Resources ]"
+msgstr "[ Források ]"
+
+#: backends/platform/tizen/fs.cpp:267
+msgid "[ SDCard ]"
+msgstr "[ SD Kártya ]"
+
+#: backends/platform/tizen/fs.cpp:271
+msgid "[ Media ]"
+msgstr "[ Média ]"
+
+#: backends/platform/tizen/fs.cpp:275
+msgid "[ Shared ]"
+msgstr "[ Megosztott ]"
#: backends/platform/wii/options.cpp:51
msgid "Video"
@@ -2069,7 +2333,7 @@ msgstr "Válassz egy billentyût az 'Eszköztár rejtés' mûvelethez"
#: backends/platform/wince/wince-sdl.cpp:542
msgid "Map Zoom Up action (optional)"
-msgstr "Nagyítás mûvelet (opcionális)"
+msgstr "Térkép nagyítás mûvelet (opcionális)"
#: backends/platform/wince/wince-sdl.cpp:545
msgid "Map Zoom Down action (optional)"
@@ -2082,139 +2346,104 @@ msgstr ""
"Ne felejts billentyût társítani az 'Eszköztár rejtés' mûvelethez, hogy lásd "
"a teljes listát"
-#: backends/events/default/default-events.cpp:196
-msgid "Do you really want to return to the Launcher?"
-msgstr "Biztos hogy visszatérsz az indítópulthoz?"
-
-#: backends/events/default/default-events.cpp:196
-msgid "Launcher"
-msgstr "Indítópult"
-
-#: backends/events/default/default-events.cpp:218
-msgid "Do you really want to quit?"
-msgstr "Biztos hogy ki akarsz lépni ?"
-
-#: 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 "Érintõképernyõ 'Tap Mód' - Bal katt"
-
-#: 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 "Érintõképernyõ 'Tap Mód' - Jobb katt"
-
-#: 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 "Érintõképernyõ 'Tap Mód' - Lebegõ (Nincs katt)"
-
-#: backends/events/gph/gph-events.cpp:409
-msgid "Maximum Volume"
-msgstr "Maximum Hangerõ"
-
-#: backends/events/gph/gph-events.cpp:411
-msgid "Increasing Volume"
-msgstr "Hangerõ növelése"
-
-#: backends/events/gph/gph-events.cpp:417
-msgid "Minimal Volume"
-msgstr "Minimum Hangerõ"
-
-#: backends/events/gph/gph-events.cpp:419
-msgid "Decreasing Volume"
-msgstr "Hangerõ csökkentése"
-
-#: backends/events/openpandora/op-events.cpp:174
-msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
-msgstr "Érintõképernyõ 'Érintésmód' - Lebegõ (DPad katt)"
-
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Frissítések keresése..."
-#: backends/platform/tizen/form.cpp:263
-msgid "Right Click Once"
-msgstr "Jobb katt egyszer"
-
-#: backends/platform/tizen/form.cpp:271
-msgid "Move Only"
-msgstr "Csak lépés"
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+msgid "Color mode"
+msgstr "Szines mód"
-#: backends/platform/tizen/form.cpp:294
-msgid "Escape Key"
-msgstr "Escape gomb"
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr "Szines grafikát használ"
-#: backends/platform/tizen/form.cpp:299
-msgid "Game Menu"
-msgstr "Játék Menü"
-
-#: backends/platform/tizen/form.cpp:304
-msgid "Show Keypad"
-msgstr "Kézi billentyûzet"
-
-#: backends/platform/tizen/form.cpp:309
-msgid "Control Mouse"
-msgstr "Egér irányitás"
-
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Enabled"
-msgstr "Kattintás engedve"
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr "Pászta"
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Disabled"
-msgstr "Kattintás tiltva"
+#: engines/adl/detection.cpp:64
+msgid "Show scanlines"
+msgstr "Pászta megjelenítés"
-#: engines/agi/detection.cpp:147 engines/drascula/detection.cpp:302
-#: engines/dreamweb/detection.cpp:47 engines/neverhood/detection.cpp:160
-#: engines/sci/detection.cpp:394 engines/toltecs/detection.cpp:200
-#: engines/zvision/detection_tables.h:51
+#: 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 "Eredeti ment/tölt képernyõk használata"
-#: engines/agi/detection.cpp:148 engines/drascula/detection.cpp:303
-#: engines/dreamweb/detection.cpp:48 engines/neverhood/detection.cpp:161
-#: engines/sci/detection.cpp:395 engines/toltecs/detection.cpp:201
+#: 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 "Az eredeti mentés/betöltés képernyõ használata a ScummVM képek helyett"
#: engines/agi/detection.cpp:157
-#, fuzzy
msgid "Use an alternative palette"
-msgstr "Alternatív játékintro használata (csak CD verziónál)"
+msgstr "Alternatív paletta használat"
#: engines/agi/detection.cpp:158
msgid ""
"Use an alternative palette, common for all Amiga games. This was the old "
"behavior"
msgstr ""
+"Alternatív paletta használat, közös minden Amiga játéknál. Ez egy régi "
+"megoldás"
#: engines/agi/detection.cpp:167
-#, fuzzy
msgid "Mouse support"
-msgstr "Átugrás támogatás"
+msgstr "Egér támogatás"
#: engines/agi/detection.cpp:168
msgid ""
"Enables mouse support. Allows to use mouse for movement and in game menus."
msgstr ""
+"Egérmód engélyezve. Lehetõvé teszi az egérrel mozgatást játékban és "
+"játékmenükben."
+
+#: 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/saveload.cpp:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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"
@@ -2225,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"
@@ -2236,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"
@@ -2247,19 +2476,18 @@ 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ó"
#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
-#, fuzzy
msgid "Color Blind Mode"
-msgstr "Kattintás Mód"
+msgstr "Színvak Mód"
#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
-msgstr ""
+msgstr "Szinvak mód engedélyezve alapértelmezett"
#: engines/drascula/saveload.cpp:47
msgid ""
@@ -2278,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."
@@ -2308,17 +2536,17 @@ 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"
#: engines/hopkins/detection.cpp:76 engines/hopkins/detection.cpp:86
msgid "Gore Mode"
-msgstr ""
+msgstr "Gore Mód"
#: engines/hopkins/detection.cpp:77 engines/hopkins/detection.cpp:87
msgid "Enable Gore Mode when available"
-msgstr ""
+msgstr "Gore mód engedélyezés ha elérhetõ"
#. I18N: Studio audience adds an applause and cheering sounds whenever
#. Malcolm makes a joke.
@@ -2450,6 +2678,12 @@ msgid ""
"Do you wish to use this save game file with ScummVM?\n"
"\n"
msgstr ""
+"A következõ eredeti játékmentés fájlt találtam a játékkönyvtárban:\n"
+"\n"
+"%s %s\n"
+"\n"
+"Akarod hogy ezt a játékmentés fájlt használja a ScummVM?\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:590
#, c-format
@@ -2457,6 +2691,8 @@ msgid ""
"A save game file was found in the specified slot %d. Overwrite?\n"
"\n"
msgstr ""
+"Játékmentés található a választott %d slotban. Felülírjam?\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:623
#, c-format
@@ -2468,51 +2704,64 @@ msgid ""
"'import_savefile'.\n"
"\n"
msgstr ""
+"%d eredeti játékmentés fájlt sikeresen importálta a\n"
+"ScummVM. Ha késõbb manuálisan akarod importálni az eredeti játékmentéseket\n"
+"meg kell nyitnod a ScummVM debug konzolt és használd az 'import_savefile' "
+"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"
+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"
@@ -2521,15 +2770,23 @@ msgstr ""
"Játékállás nem menthetõ %i slotba\n"
"\n"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:194
+msgid "Load file"
+msgstr "Fájl betöltése"
+
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Játék betöltés..."
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:209
+msgid "Save file"
+msgstr "Fájl mentése"
+
+#: 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"
@@ -2545,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"
@@ -2605,27 +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 ""
+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:395
+msgid "Enable high resolution graphics/content"
+msgstr "Nagy felbontású grafika/tartalom engedélyezése"
+
+#: 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:385
+#: 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:404
+#: 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:405
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2633,147 +2907,153 @@ msgstr ""
"IBM Music Feature kártya vagy Yamaha FB-01 FM szintetizátor modul használata "
"MIDI kimenetre"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "CD audió használata"
-#: engines/sci/detection.cpp:416
+#: 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:426
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Windows kurzorok használata"
-#: engines/sci/detection.cpp:427
+#: 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:437
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Ezüst kurzor használata"
-#: engines/sci/detection.cpp:438
+#: 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
-#, fuzzy
+#: engines/scumm/dialogs.cpp:179
msgid "Are you sure you want to restart? (Y/N)Y"
-msgstr "Biztos hogy újra akarod indítani? (Y/N)"
+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
-#, fuzzy
+#: engines/scumm/dialogs.cpp:181
msgid "Are you sure you want to quit? (Y/N)Y"
-msgstr "Biztos hogy ki akarsz lépni? (Y/N)"
+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 "Elõzõ"
+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:600
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Csak beszéd"
-#: engines/scumm/dialogs.cpp:601
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Beszéd és felirat"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Csak felirat"
-#: engines/scumm/dialogs.cpp:610
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Beszéd & Felir"
-#: engines/scumm/dialogs.cpp:656
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Válassz hozzáértés szintet."
-#: engines/scumm/dialogs.cpp:658
+#: 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:662
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Gyakorlás"
-#: engines/scumm/dialogs.cpp:663
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Szakértõ"
@@ -3198,25 +3478,24 @@ msgid "Third kid"
msgstr "Harmadik gyerek"
#: engines/scumm/help.cpp:292
-#, fuzzy
msgid "Toggle Inventory/IQ Points display"
-msgstr "Adatképernyõ kapcsoló"
+msgstr "Leltár/IQ pont kijelzõ kapcsoló"
#: engines/scumm/help.cpp:293
msgid "Toggle Keyboard/Mouse Fighting (*)"
-msgstr ""
+msgstr "Billentyûzet/Egér harc kapcsoló (*)"
#: engines/scumm/help.cpp:295
msgid "* Keyboard Fighting is always on,"
-msgstr ""
+msgstr "* Harc billentyûzetrõl mindíg aktív,"
#: engines/scumm/help.cpp:296
msgid " so despite the in-game message this"
-msgstr ""
+msgstr " so despite the in-game message this"
#: engines/scumm/help.cpp:297
msgid " actually toggles Mouse Fighting Off/On"
-msgstr ""
+msgstr " egérrel harcolás mód átkapcsolás Be/Ki"
#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
@@ -3253,7 +3532,7 @@ msgstr "Alsó ütés"
#: engines/scumm/help.cpp:315
msgid "Sucker punch"
-msgstr ""
+msgstr "Váratlan ütés"
#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
@@ -3311,7 +3590,23 @@ msgstr "Jobbra repülés"
msgid "Fly to lower right"
msgstr "Jobbra le repülés"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/input.cpp:578
+msgid "Snap scroll on"
+msgstr "Finomgörgetés be"
+
+#: engines/scumm/input.cpp:580
+msgid "Snap scroll off"
+msgstr "Finomgörgetés ki"
+
+#: engines/scumm/input.cpp:593
+msgid "Music volume: "
+msgstr "Zene hangereje:"
+
+#: engines/scumm/input.cpp:610
+msgid "Subtitle speed: "
+msgstr "Felirat sebesség:"
+
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3320,28 +3615,88 @@ 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
-#, fuzzy
+#: 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 ""
-"Általában a Maniac Mansion indulna itt. De a ScummVM most nem indítja el. Ha "
-"játszani akarsz vele menj a ScummVM fõmenüben a 'Játék hozzáadás' ra és "
-"válaszd a 'Maniac' mappát a 'Tentacle' könyvtárában."
+"Általában a Maniac Mansion indulna most. De a mûködéshez a Maniac Mansion "
+"fájljainak, a 'Maniac' mappában kell lenni a Tentacle játékmappáján belül, "
+"és a játékot így adja hozzá a ScummVM a listához."
#: 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 ""
+"Nem található a 'Loom' Macintosh futtató állomány, hogy \n"
+"beolvassa a hangszereket. Zene le lessz tiltva."
#: 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 ""
+"Nem található a 'Monkey Island' Macintosh futtató állomány, hogy \n"
+"beolvassa a hangszereket. Zene le lessz tiltva."
+
+#: engines/sherlock/detection.cpp:71
+msgid "Use original savegame dialog"
+msgstr "Eredeti játékmentés párbeszéd használata"
+
+#: engines/sherlock/detection.cpp:72
+msgid ""
+"Files button in-game shows original savegame dialog rather than the ScummVM "
+"menu"
+msgstr ""
+"Fájl gomb a játékban, az eredeti játékmentés párbeszédet jeleníti meg a "
+"ScummVM-é helyett"
+
+#: engines/sherlock/detection.cpp:81
+msgid "Pixellated scene transitions"
+msgstr "Pixeles képátmenetek"
+
+#: engines/sherlock/detection.cpp:82
+msgid "When changing scenes, a randomized pixel transition is done"
+msgstr "Helyszínek váltásánál, egy randomizált pixel átmenet történik"
+
+#: engines/sherlock/detection.cpp:91
+msgid "Don't show hotspots when moving mouse"
+msgstr "Aktív pontok nem látszanak egérmozgatás közben"
+
+#: engines/sherlock/detection.cpp:92
+msgid ""
+"Only show hotspot names after you actually click on a hotspot or action "
+"button"
+msgstr ""
+"Aktív pontok neve csak akkor látszik, ha ténylegesen rákattint vagy "
+"akciógombot nyom"
+
+#: engines/sherlock/detection.cpp:101
+msgid "Show character portraits"
+msgstr "Karakter képe látható"
+
+#: engines/sherlock/detection.cpp:102
+msgid "Show portraits for the characters when conversing"
+msgstr "A karakterek képe látható beszélgetés közben"
+
+#: engines/sherlock/detection.cpp:111
+msgid "Slide dialogs into view"
+msgstr "Párbeszéd csúsztatás nézet"
+
+#: engines/sherlock/detection.cpp:112
+msgid "Slide UI dialogs into view, rather than simply showing them immediately"
+msgstr ""
+"UI párbeszédek csúsztatása ahelyett, hogy egyszerûen megjelenítené azonnal"
+
+#: engines/sherlock/detection.cpp:121
+msgid "Transparent windows"
+msgstr "Átlátszó ablakok"
+
+#: engines/sherlock/detection.cpp:122
+msgid "Show windows with a partially transparent background"
+msgstr "Ablakok megjelenítése részben átlászó háttérrel"
#: engines/sky/compact.cpp:130
msgid ""
@@ -3442,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"
@@ -3457,51 +3822,48 @@ msgstr ""
#: engines/wintermute/detection.cpp:58
msgid "Show FPS-counter"
-msgstr ""
+msgstr "FPS számláló látszik"
#: engines/wintermute/detection.cpp:59
msgid "Show the current number of frames per second in the upper left corner"
msgstr ""
+"A jelenlegi másodpercenkénti képkocka szám kijelzése a bal felsõ sarokban"
#: engines/zvision/detection_tables.h:52
-#, fuzzy
msgid "Use the original save/load screens instead of the ScummVM interface"
-msgstr "Az eredeti mentés/betöltés képernyõ használata a ScummVM képek helyett"
+msgstr "Használd az eredeti mentés/töltés képet a ScummVM felület helyett"
#: engines/zvision/detection_tables.h:61
msgid "Double FPS"
-msgstr ""
+msgstr "Dupla FPS"
#: engines/zvision/detection_tables.h:62
msgid "Increase framerate from 30 to 60 FPS"
-msgstr ""
+msgstr "Növeli a képfrissítést 30 ról 60 FPS-re"
#: engines/zvision/detection_tables.h:71
-#, fuzzy
msgid "Enable Venus"
-msgstr "Helium mód engedélyezve"
+msgstr "Venus engedélyezve"
#: engines/zvision/detection_tables.h:72
-#, fuzzy
msgid "Enable the Venus help system"
-msgstr "Helium mód engedélyezve"
+msgstr "Venus súgórendszer engedélyezve"
#: engines/zvision/detection_tables.h:81
msgid "Disable animation while turning"
-msgstr ""
+msgstr "Animáció tiltás bekapcsolás közben"
#: engines/zvision/detection_tables.h:82
msgid "Disable animation while turning in panorama mode"
-msgstr ""
+msgstr "Animáció tiltása panoráma mód bekapcsolása közben"
#: engines/zvision/detection_tables.h:91
msgid "Use high resolution MPEG video"
-msgstr ""
+msgstr "Nagyfelbontású MPEG videó használat"
#: engines/zvision/detection_tables.h:92
-#, fuzzy
msgid "Use MPEG video from the DVD version, instead of lower resolution AVI"
-msgstr "Alternatív ezüst kurzorszett használata, a normál arany helyett"
+msgstr "MPEG videót használ DVD verziónál, a kisebb felbontású AVI helyett"
#~ msgid "EGA undithering"
#~ msgstr "EGA szinjavítás"
@@ -3548,26 +3910,6 @@ msgstr "Alternatív ezüst kurzorszett használata, a normál arany 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"
-
-#~ msgid "Hercules Green"
-#~ msgstr "Hercules Zöld"
-
-#~ msgid "Hercules Amber"
-#~ msgstr "Hercules Sárga"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Green"
-#~ msgstr "Hercules Zöld"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Amber"
-#~ msgstr "Hercules Sárga"
-
-#~ msgid "Save game failed!"
-#~ msgstr "Játék mentése nem sikerült!"
-
#~ msgctxt "lowres"
#~ msgid "Add Game..."
#~ msgstr "Játék hozzáadás"
@@ -3592,8 +3934,5 @@ msgstr "Alternatív ezüst kurzorszett használata, a normál arany helyett"
#~ msgid "Command line argument not processed"
#~ msgstr "Parancssori paraméter nem mûködik"
-#~ msgid "FM Towns Emulator"
-#~ msgstr "FM Towns Emulátor"
-
#~ msgid "Invalid Path"
#~ msgstr "Érvénytelen mappa"
diff --git a/po/it_IT.po b/po/it_IT.po
index 28ec2960db..1313610398 100644
--- a/po/it_IT.po
+++ b/po/it_IT.po
@@ -1,5 +1,5 @@
# Italian translation for ScummVM.
-# Copyright (C) 2010-2015 The ScummVM Team
+# Copyright (C) 2010-2016 The ScummVM Team
# This file is distributed under the same license as the ScummVM package.
# Matteo 'Maff' Angelino <matteo.maff at gmail dot com>, 2010.
#
@@ -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: 2015-09-06 15:14+0200\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"
@@ -51,22 +51,23 @@ msgid "Go up"
msgstr "Su"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:74 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: 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/fluidsynth-dialog.cpp:152 engines/engine.cpp:483
-#: backends/platform/wii/options.cpp:48
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
-#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:191 engines/sword1/control.cpp:865
+#: 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 "Annulla"
#: gui/browser.cpp:76 gui/browser_osx.mm:103 gui/chooser.cpp:47
-#: gui/themebrowser.cpp:56
+#: gui/filebrowser-dialog.cpp:65 gui/themebrowser.cpp:56
msgid "Choose"
msgstr "Scegli"
@@ -82,61 +83,181 @@ msgstr "Nome:"
msgid "Notes:"
msgstr ""
-#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:75
+#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74
msgid "Ok"
msgstr ""
-#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
+#: gui/filebrowser-dialog.cpp:49
+msgid "Choose file for loading"
+msgstr ""
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Enter filename for saving"
+msgstr ""
+
+#: gui/filebrowser-dialog.cpp:132
+#, fuzzy
+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: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 "Sì"
+
+#: 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 "No"
+
+#: gui/fluidsynth-dialog.cpp:68
+msgid "Reverb"
+msgstr "Riverbero"
+
+#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
+msgid "Active"
+msgstr "Attivo"
+
+#: gui/fluidsynth-dialog.cpp:72
+msgid "Room:"
+msgstr "Stanza:"
+
+#: gui/fluidsynth-dialog.cpp:79
+msgid "Damp:"
+msgstr "Smorzamento:"
+
+#: gui/fluidsynth-dialog.cpp:86
+msgid "Width:"
+msgstr "Larghezza:"
+
+#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
+msgid "Level:"
+msgstr "Livello:"
+
+#: gui/fluidsynth-dialog.cpp:100
+msgid "Chorus"
+msgstr "Chorus"
+
+#: gui/fluidsynth-dialog.cpp:104
+msgid "N:"
+msgstr "N:"
+
+#: gui/fluidsynth-dialog.cpp:118
+msgid "Speed:"
+msgstr "Velocità:"
+
+#: gui/fluidsynth-dialog.cpp:125
+msgid "Depth:"
+msgstr "Profondità:"
+
+#: gui/fluidsynth-dialog.cpp:132
+msgid "Type:"
+msgstr "Tipo:"
+
+#: gui/fluidsynth-dialog.cpp:135
+msgid "Sine"
+msgstr "Seno"
+
+#: gui/fluidsynth-dialog.cpp:136
+msgid "Triangle"
+msgstr "Triangolo"
+
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
+msgid "Misc"
+msgstr "Varie"
+
+#: gui/fluidsynth-dialog.cpp:140
+msgid "Interpolation:"
+msgstr "Interpolazione:"
+
+#: gui/fluidsynth-dialog.cpp:143
+msgid "None (fastest)"
+msgstr "Nessuna (più veloce)"
+
+#: gui/fluidsynth-dialog.cpp:144
+msgid "Linear"
+msgstr "Lineare"
+
+#: gui/fluidsynth-dialog.cpp:145
+msgid "Fourth-order"
+msgstr "Quarto ordine"
+
+#: gui/fluidsynth-dialog.cpp:146
+msgid "Seventh-order"
+msgstr "Settimo ordine"
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset"
+msgstr "Ripristina"
+
+#: gui/fluidsynth-dialog.cpp:150
+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: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 "OK"
+
+#: gui/fluidsynth-dialog.cpp:217
+msgid ""
+"Do you really want to reset all FluidSynth settings to their default values?"
+msgstr ""
+"Sei sicuro di voler ripristinare tutte le impostazioni di FluidSynth al loro "
+"valore predefinito?"
+
+#: 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 "Chiudi"
-#: gui/gui-manager.cpp:120
+#: gui/gui-manager.cpp:122
msgid "Mouse click"
msgstr "Clic del mouse"
-#: gui/gui-manager.cpp:124 base/main.cpp:319
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Mostra tastiera"
-#: gui/gui-manager.cpp:128 base/main.cpp:323
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Riprogramma tasti"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 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"
-#: gui/KeysDialog.h:36 gui/KeysDialog.cpp:145
-msgid "Choose an action to map"
-msgstr "Scegli un'azione da mappare"
-
#: gui/KeysDialog.cpp:41
msgid "Map"
msgstr "Mappa"
-#: gui/KeysDialog.cpp:42 gui/launcher.cpp:352 gui/launcher.cpp:1048
-#: gui/launcher.cpp:1052 gui/massadd.cpp:92 gui/options.cpp:1238
-#: gui/saveload-dialog.cpp:932 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:402 engines/engine.cpp:413
-#: 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/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 "OK"
-
#: gui/KeysDialog.cpp:49
msgid "Select an action and click 'Map'"
msgstr "Seleziona un'azione e clicca 'Mappa'"
@@ -159,6 +280,10 @@ msgstr "Seleziona un'azione"
msgid "Press the key to associate"
msgstr "Premi il tasto da associare"
+#: gui/KeysDialog.cpp:145 gui/KeysDialog.h:36
+msgid "Choose an action to map"
+msgstr "Scegli un'azione da mappare"
+
#: gui/launcher.cpp:193
msgid "Game"
msgstr "Gioco"
@@ -200,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>"
@@ -223,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"
@@ -240,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"
@@ -253,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"
@@ -271,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:95
+#: 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:69
+#: 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:1222
+#: 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/myst.cpp:245 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/myst.cpp:245
-#: engines/mohawk/riven.cpp:718 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:792
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -488,63 +614,43 @@ msgstr ""
"Vuoi davvero eseguire il rilevatore di giochi in massa? Potrebbe aggiungere "
"un numero enorme di giochi."
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Sì"
-
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "No"
-
-#: gui/launcher.cpp:841
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM non ha potuto aprire la cartella specificata!"
-#: gui/launcher.cpp:853
+#: 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:867
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Scegli il gioco:"
-#: gui/launcher.cpp:941
+#: 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:999
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "Vuoi caricare il salvataggio?"
-#: gui/launcher.cpp:1048
+#: 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:1052
+#: 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:1159
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Agg. in massa..."
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr ""
@@ -589,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:2298
+#: 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"
@@ -724,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"
@@ -791,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"
@@ -808,173 +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:1168 gui/fluidsynth-dialog.cpp:138
-msgid "Misc"
-msgstr "Varie"
-
-#: 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."
@@ -983,65 +1097,80 @@ msgstr ""
"utilizzare questo tema devi prima cambiare la lingua."
#. I18N: You must leave "#" as is, only word 'next' is translatable
-#: gui/predictivedialog.cpp:87
+#: gui/predictivedialog.cpp:86
msgid "# next"
msgstr ""
-#: gui/predictivedialog.cpp:88
+#: gui/predictivedialog.cpp:87
msgid "add"
msgstr ""
-#: gui/predictivedialog.cpp:92
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
#, fuzzy
msgid "Delete char"
msgstr "Elimina"
-#: gui/predictivedialog.cpp:96
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
msgstr ""
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:98
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr ""
-#: gui/recorderdialog.cpp:64
+#. I18N: 'Num' means Numbers
+#: gui/predictivedialog.cpp:578
+msgid "* Num"
+msgstr ""
+
+#. I18N: 'Abc' means Latin alphabet input
+#: gui/predictivedialog.cpp:581
+msgid "* Abc"
+msgstr ""
+
+#: 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:173
+#, fuzzy
+msgid "Unknown Author"
+msgstr "Errore sconosciuto"
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr "Elenco"
@@ -1102,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:"
@@ -1111,152 +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:661
+#: 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
-msgid "Clear value"
-msgstr "Cancella"
-
-#: gui/fluidsynth-dialog.cpp:68
-msgid "Reverb"
-msgstr "Riverbero"
-
-#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
-msgid "Active"
-msgstr "Attivo"
-
-#: gui/fluidsynth-dialog.cpp:72
-msgid "Room:"
-msgstr "Stanza:"
-
-#: gui/fluidsynth-dialog.cpp:79
-msgid "Damp:"
-msgstr "Smorzamento:"
-
-#: gui/fluidsynth-dialog.cpp:86
-msgid "Width:"
-msgstr "Larghezza:"
-
-#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
-msgid "Level:"
-msgstr "Livello:"
-
-#: gui/fluidsynth-dialog.cpp:100
-msgid "Chorus"
-msgstr "Chorus"
-
-#: gui/fluidsynth-dialog.cpp:104
-msgid "N:"
-msgstr "N:"
-
-#: gui/fluidsynth-dialog.cpp:118
-msgid "Speed:"
-msgstr "Velocità:"
-
-#: gui/fluidsynth-dialog.cpp:125
-msgid "Depth:"
-msgstr "Profondità:"
-
-#: gui/fluidsynth-dialog.cpp:132
-msgid "Type:"
-msgstr "Tipo:"
-
-#: gui/fluidsynth-dialog.cpp:135
-msgid "Sine"
-msgstr "Seno"
-
-#: gui/fluidsynth-dialog.cpp:136
-msgid "Triangle"
-msgstr "Triangolo"
-
-#: gui/fluidsynth-dialog.cpp:140
-msgid "Interpolation:"
-msgstr "Interpolazione:"
-
-#: gui/fluidsynth-dialog.cpp:143
-msgid "None (fastest)"
-msgstr "Nessuna (più veloce)"
-
-#: gui/fluidsynth-dialog.cpp:144
-msgid "Linear"
-msgstr "Lineare"
-
-#: gui/fluidsynth-dialog.cpp:145
-msgid "Fourth-order"
-msgstr "Quarto ordine"
+#: 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/fluidsynth-dialog.cpp:146
-msgid "Seventh-order"
-msgstr "Settimo ordine"
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr ""
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset"
-msgstr "Ripristina"
+#: gui/updates-dialog.cpp:92
+#, fuzzy
+msgid "Check for updates automatically"
+msgstr "Cerca aggiornamenti..."
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset all FluidSynth settings to their default values."
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
msgstr ""
-"Ripristina tutte le impostazioni di FluidSynth al loro valore predefinito."
-#: gui/fluidsynth-dialog.cpp:217
-msgid ""
-"Do you really want to reset all FluidSynth settings to their default values?"
-msgstr ""
-"Sei sicuro di voler ripristinare tutte le impostazioni di FluidSynth al loro "
-"valore predefinito?"
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
+msgid "Clear value"
+msgstr "Cancella"
-#: base/main.cpp:228
+#: 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:306
+#: base/main.cpp:315
msgid "Menu"
msgstr "Menu"
-#: base/main.cpp:309 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:312 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:315
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Salta battuta"
-#: base/main.cpp:507
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Errore nell'esecuzione del gioco:"
-#: base/main.cpp:554
+#: 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"
@@ -1325,16 +1387,60 @@ msgstr "Utente cancellato"
msgid "Unknown error"
msgstr "Errore sconosciuto"
-#: engines/advancedDetector.cpp:317
+#. I18N: Hercules is graphics card name
+#: common/rendermode.cpp:35
+msgid "Hercules Green"
+msgstr "Hercules verde"
+
+#: common/rendermode.cpp:36
+msgid "Hercules Amber"
+msgstr "Hercules ambra"
+
+#: common/rendermode.cpp:42
+msgid "PC-9821 (256 Colors)"
+msgstr ""
+
+#: common/rendermode.cpp:43
+msgid "PC-9801 (16 Colors)"
+msgstr ""
+
+#: common/rendermode.cpp:73
+msgctxt "lowres"
+msgid "Hercules Green"
+msgstr "Hercules verde"
+
+#: common/rendermode.cpp:74
+msgctxt "lowres"
+msgid "Hercules Amber"
+msgstr "Hercules ambra"
+
+#: 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.:"
@@ -1342,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"
@@ -1371,11 +1477,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "~V~ai a elenco giochi"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:803
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:873
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
-#: engines/toltecs/menu.cpp:281 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:"
@@ -1384,11 +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:803 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/neverhood/menumodule.cpp:873 engines/pegasus/pegasus.cpp:377
-#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
-#: engines/toltecs/menu.cpp:281 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"
@@ -1412,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"
@@ -1426,23 +1541,23 @@ msgstr "~A~nnulla"
msgid "~K~eys"
msgstr "~T~asti"
-#: engines/engine.cpp:276
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Impossibile inizializzare il formato colore."
-#: engines/engine.cpp:284
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Impossibile cambiare la modalità video: '"
-#: engines/engine.cpp:293
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "Impossibile applicare l'impostazione proporzioni"
-#: engines/engine.cpp:298
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Impossibile applicare l'impostazione schermo intero."
-#: engines/engine.cpp:398
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1456,7 +1571,7 @@ msgstr ""
"sull'hard disk.\n"
"Vedi il file README per i dettagli."
-#: engines/engine.cpp:409
+#: 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"
@@ -1470,7 +1585,7 @@ msgstr ""
"la musica del gioco.\n"
"Vedi il file README per i dettagli."
-#: engines/engine.cpp:467
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1480,7 +1595,7 @@ msgstr ""
"per le informazioni di base e per le istruzioni su come ottenere ulteriore "
"assistenza."
-#: engines/engine.cpp:480
+#: 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 "
@@ -1490,10 +1605,14 @@ msgstr ""
"ScummVM. È quindi possibile che sia instabile, e i salvataggi potrebbero non "
"funzionare con future versioni di ScummVM."
-#: engines/engine.cpp:483
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Avvia comunque"
+#: audio/adlib.cpp:2290
+msgid "AdLib Emulator"
+msgstr "Emulatore AdLib"
+
#: audio/fmopl.cpp:62
msgid "MAME OPL emulator"
msgstr "Emulatore OPL MAME"
@@ -1547,31 +1666,37 @@ msgstr ""
"Il dispositivo audio preferito '%s' non può essere usato. Vedi il file log "
"per maggiori informazioni."
-#: audio/null.h:44
-msgid "No music"
-msgstr "Nessuna musica"
-
#: audio/mods/paula.cpp:196
msgid "Amiga Audio Emulator"
msgstr "Emulatore audio Amiga"
-#: audio/adlib.cpp:2291
-msgid "AdLib Emulator"
-msgstr "Emulatore AdLib"
+#: audio/null.h:44
+msgid "No music"
+msgstr "Nessuna musica"
#: audio/softsynth/appleiigs.cpp:33
msgid "Apple II GS Emulator (NOT IMPLEMENTED)"
msgstr "Emulatore Apple II GS (NON IMPLEMENTATO)"
-#: audio/softsynth/sid.cpp:1430
-msgid "C64 Audio Emulator"
-msgstr "Emulatore audio C64"
+#: audio/softsynth/cms.cpp:350
+msgid "Creative Music System Emulator"
+msgstr ""
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33
+#, fuzzy
+msgid "FM-Towns Audio"
+msgstr "Emulatore FM Towns"
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58
+#, fuzzy
+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"
@@ -1583,6 +1708,147 @@ msgstr "Emulatore PC Speaker"
msgid "IBM PCjr Emulator"
msgstr "Emulatore IBM PCjr"
+#: audio/softsynth/sid.cpp:1430
+msgid "C64 Audio Emulator"
+msgstr "Emulatore audio C64"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Do you really want to return to the Launcher?"
+msgstr "Sei sicuro di voler tornare all'elenco giochi?"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Launcher"
+msgstr "Elenco giochi"
+
+#: backends/events/default/default-events.cpp:218
+msgid "Do you really want to quit?"
+msgstr "Sei sicuro di voler uscire?"
+
+#: 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 "Esci"
+
+#: 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 "Touchscreen 'Tap Mode' - Clic sinistro"
+
+#: 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 "Touchscreen 'Tap Mode' - Clic destro"
+
+#: 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 "Touchscreen 'Tap Mode' - Passaggio del cursore (nessun clic)"
+
+#: backends/events/gph/gph-events.cpp:409
+msgid "Maximum Volume"
+msgstr "Volume massimo"
+
+#: backends/events/gph/gph-events.cpp:411
+msgid "Increasing Volume"
+msgstr "Aumento volume"
+
+#: backends/events/gph/gph-events.cpp:417
+msgid "Minimal Volume"
+msgstr "Volume minimo"
+
+#: backends/events/gph/gph-events.cpp:419
+msgid "Decreasing Volume"
+msgstr "Diminuzione volume"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Enabled"
+msgstr "Clic attivato"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Disabled"
+msgstr "Clic disattivato"
+
+#: backends/events/openpandora/op-events.cpp:174
+msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
+msgstr "Touchscreen 'Tap Mode' - Passaggio del cursore (clic DPad)"
+
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
+msgid "Do you want to quit ?"
+msgstr "Sei sicuro di voler uscire?"
+
+#. I18N: Trackpad mode toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:308
+#, fuzzy
+msgid "Trackpad mode is now"
+msgstr "Modalità touchpad disattivata."
+
+#. 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 ""
+
+#: backends/events/webossdl/webossdl-events.cpp:311
+#: backends/events/webossdl/webossdl-events.cpp:338
+msgid "OFF"
+msgstr ""
+
+#: backends/events/webossdl/webossdl-events.cpp:315
+msgid "Swipe two fingers to the right to toggle."
+msgstr ""
+
+#. I18N: Auto-drag toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:335
+msgid "Auto-drag mode is now"
+msgstr ""
+
+#: backends/events/webossdl/webossdl-events.cpp:342
+msgid "Swipe three fingers to the right to toggle."
+msgstr ""
+
+#: backends/graphics/opengl/opengl-graphics.cpp:126
+msgid "OpenGL"
+msgstr "OpenGL"
+
+#: backends/graphics/opengl/opengl-graphics.cpp:127
+msgid "OpenGL (No filtering)"
+msgstr "OpenGL (senza filtri)"
+
+#: 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 "Normale (nessun ridimensionamento)"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:66
+msgctxt "lowres"
+msgid "Normal (no scaling)"
+msgstr "Normale (no ridim.)"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
+msgid "Enabled aspect ratio correction"
+msgstr "Correzione proporzioni attivata"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
+msgid "Disabled aspect ratio correction"
+msgstr "Correzione proporzioni disattivata"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
+msgid "Active graphics filter:"
+msgstr "Filtro grafico attivo:"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+msgid "Windowed mode"
+msgstr "Modalità finestra"
+
#: backends/keymapper/remap-dialog.cpp:48
msgid "Keymap:"
msgstr "Mappa tasti:"
@@ -1612,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"
@@ -1688,18 +1954,26 @@ msgstr "Audio ad alta qualità (più lento) (riavviare)"
msgid "Disable power off"
msgstr "Disattiva spegnimento in chiusura"
+#: 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 "Modalità mouse-clicca-e-trascina attivata."
+#: 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 "Modalità mouse-clicca-e-trascina disattivata."
+#: 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 "Modalità touchpad attivata."
+#: 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 "Modalità touchpad disattivata."
@@ -1710,9 +1984,9 @@ msgstr "Modalità clic"
#: 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
-#: backends/platform/tizen/form.cpp:275
msgid "Left Click"
msgstr "Clic sinistro"
@@ -1722,65 +1996,32 @@ msgstr "Clic centrale"
#: backends/platform/maemo/maemo.cpp:220
#: backends/platform/symbian/src/SymbianActions.cpp:43
-#: backends/platform/wince/CEActionsSmartphone.cpp:44
#: backends/platform/tizen/form.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:44
msgid "Right Click"
msgstr "Clic destro"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:77
+#: backends/platform/sdl/macosx/appmenu_osx.mm:88
msgid "Hide ScummVM"
msgstr "Nascondi ScummVM"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:82
+#: backends/platform/sdl/macosx/appmenu_osx.mm:93
msgid "Hide Others"
msgstr "Nascondi altre"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:87
+#: backends/platform/sdl/macosx/appmenu_osx.mm:98
msgid "Show All"
msgstr "Mostra tutte"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:109
#: backends/platform/sdl/macosx/appmenu_osx.mm:120
+#: backends/platform/sdl/macosx/appmenu_osx.mm:131
msgid "Window"
msgstr "Finestra"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:114
+#: backends/platform/sdl/macosx/appmenu_osx.mm:125
msgid "Minimize"
msgstr "Contrai"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:46
-msgid "Normal (no scaling)"
-msgstr "Normale (nessun ridimensionamento)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:65
-msgctxt "lowres"
-msgid "Normal (no scaling)"
-msgstr "Normale (no ridim.)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
-msgid "Enabled aspect ratio correction"
-msgstr "Correzione proporzioni attivata"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
-msgid "Disabled aspect ratio correction"
-msgstr "Correzione proporzioni disattivata"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
-msgid "Active graphics filter:"
-msgstr "Filtro grafico attivo:"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
-msgid "Windowed mode"
-msgstr "Modalità finestra"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:118
-msgid "OpenGL"
-msgstr "OpenGL"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:119
-msgid "OpenGL (No filtering)"
-msgstr "OpenGL (senza filtri)"
-
#: backends/platform/symbian/src/SymbianActions.cpp:38
#: backends/platform/wince/CEActionsSmartphone.cpp:39
msgid "Up"
@@ -1824,14 +2065,6 @@ msgstr "Salta testo"
msgid "Fast mode"
msgstr "Modalità veloce"
-#: backends/platform/symbian/src/SymbianActions.cpp:52
-#: backends/platform/wince/CEActionsPocket.cpp:44
-#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: backends/events/default/default-events.cpp:218 engines/scumm/dialogs.cpp:192
-#: engines/scumm/help.cpp:83 engines/scumm/help.cpp:85
-msgid "Quit"
-msgstr "Esci"
-
#: backends/platform/symbian/src/SymbianActions.cpp:53
msgid "Debugger"
msgstr "Debugger"
@@ -1848,9 +2081,50 @@ msgstr "Tastiera virtuale"
msgid "Key mapper"
msgstr "Programmatore tasti"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:186
-msgid "Do you want to quit ?"
-msgstr "Sei sicuro di voler uscire?"
+#: backends/platform/tizen/form.cpp:263
+msgid "Right Click Once"
+msgstr "Un clic destro"
+
+#: backends/platform/tizen/form.cpp:271
+msgid "Move Only"
+msgstr "Muovi soltanto"
+
+#: backends/platform/tizen/form.cpp:294
+msgid "Escape Key"
+msgstr "Tasto Esc"
+
+#: backends/platform/tizen/form.cpp:299
+msgid "Game Menu"
+msgstr "Menu di gioco"
+
+#: backends/platform/tizen/form.cpp:304
+msgid "Show Keypad"
+msgstr "Mostra tastierino numerico"
+
+#: backends/platform/tizen/form.cpp:309
+msgid "Control Mouse"
+msgstr "Controllo mouse"
+
+#: backends/platform/tizen/fs.cpp:259
+msgid "[ Data ]"
+msgstr ""
+
+#: backends/platform/tizen/fs.cpp:263
+msgid "[ Resources ]"
+msgstr ""
+
+#: backends/platform/tizen/fs.cpp:267
+msgid "[ SDCard ]"
+msgstr ""
+
+#: backends/platform/tizen/fs.cpp:271
+msgid "[ Media ]"
+msgstr ""
+
+#: backends/platform/tizen/fs.cpp:275
+#, fuzzy
+msgid "[ Shared ]"
+msgstr "Condivisione:"
#: backends/platform/wii/options.cpp:51
msgid "Video"
@@ -2097,102 +2371,39 @@ msgstr ""
"Non dimenticare di mappare un tasto per l'azione \"Nascondi barra degli "
"strumenti\" per vedere l'intero inventario"
-#: backends/events/default/default-events.cpp:196
-msgid "Do you really want to return to the Launcher?"
-msgstr "Sei sicuro di voler tornare all'elenco giochi?"
-
-#: backends/events/default/default-events.cpp:196
-msgid "Launcher"
-msgstr "Elenco giochi"
-
-#: backends/events/default/default-events.cpp:218
-msgid "Do you really want to quit?"
-msgstr "Sei sicuro di voler uscire?"
-
-#: 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 "Touchscreen 'Tap Mode' - Clic sinistro"
-
-#: 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 "Touchscreen 'Tap Mode' - Clic destro"
-
-#: 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 "Touchscreen 'Tap Mode' - Passaggio del cursore (nessun clic)"
-
-#: backends/events/gph/gph-events.cpp:409
-msgid "Maximum Volume"
-msgstr "Volume massimo"
-
-#: backends/events/gph/gph-events.cpp:411
-msgid "Increasing Volume"
-msgstr "Aumento volume"
-
-#: backends/events/gph/gph-events.cpp:417
-msgid "Minimal Volume"
-msgstr "Volume minimo"
-
-#: backends/events/gph/gph-events.cpp:419
-msgid "Decreasing Volume"
-msgstr "Diminuzione volume"
-
-#: backends/events/openpandora/op-events.cpp:174
-msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
-msgstr "Touchscreen 'Tap Mode' - Passaggio del cursore (clic DPad)"
-
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Cerca aggiornamenti..."
-#: backends/platform/tizen/form.cpp:263
-msgid "Right Click Once"
-msgstr "Un clic destro"
-
-#: backends/platform/tizen/form.cpp:271
-msgid "Move Only"
-msgstr "Muovi soltanto"
-
-#: backends/platform/tizen/form.cpp:294
-msgid "Escape Key"
-msgstr "Tasto Esc"
-
-#: backends/platform/tizen/form.cpp:299
-msgid "Game Menu"
-msgstr "Menu di gioco"
-
-#: backends/platform/tizen/form.cpp:304
-msgid "Show Keypad"
-msgstr "Mostra tastierino numerico"
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "Modalità clic"
-#: backends/platform/tizen/form.cpp:309
-msgid "Control Mouse"
-msgstr "Controllo mouse"
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Enabled"
-msgstr "Clic attivato"
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Disabled"
-msgstr "Clic disattivato"
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "Mostra etichette oggetti"
-#: engines/agi/detection.cpp:147 engines/drascula/detection.cpp:302
-#: engines/dreamweb/detection.cpp:47 engines/neverhood/detection.cpp:160
-#: engines/sci/detection.cpp:394 engines/toltecs/detection.cpp:200
-#: engines/zvision/detection_tables.h:51
+#: 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 "Usa schermate di salvataggio originali"
-#: engines/agi/detection.cpp:148 engines/drascula/detection.cpp:303
-#: engines/dreamweb/detection.cpp:48 engines/neverhood/detection.cpp:161
-#: engines/sci/detection.cpp:395 engines/toltecs/detection.cpp:201
+#: 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 ""
"Usa le schermate originali di salvataggio e caricamento, al posto di quelle "
@@ -2219,19 +2430,46 @@ msgid ""
"Enables mouse support. Allows to use mouse for movement and in game menus."
msgstr ""
-#: engines/agi/saveload.cpp:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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"
@@ -2242,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"
@@ -2253,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"
@@ -2264,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!"
@@ -2296,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."
@@ -2326,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"
@@ -2487,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"
@@ -2538,15 +2786,25 @@ msgstr ""
"Impossibile salvare nella posizione %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:194
+#, fuzzy
+msgid "Load file"
+msgstr "Carica gioco:"
+
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Caricamento..."
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:209
+#, fuzzy
+msgid "Save file"
+msgstr "Salvataggio fallito!"
+
+#: 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"
@@ -2563,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"
@@ -2623,27 +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:395
+#, fuzzy
+msgid "Enable high resolution graphics/content"
+msgstr "Attiva le barre di Hit Point"
+
+#: 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:385
+#: 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:404
+#: 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:405
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2651,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:415
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "Usa audio da CD"
-#: engines/sci/detection.cpp:416
+#: 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:426
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Usa cursori di Windows"
-#: engines/sci/detection.cpp:427
+#: 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:437
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Usa cursori d'argento"
-#: engines/sci/detection.cpp:438
+#: 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:600
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Solo voci"
-#: engines/scumm/dialogs.cpp:601
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Voci e testo"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Solo testo"
-#: engines/scumm/dialogs.cpp:610
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Voci e testo"
-#: engines/scumm/dialogs.cpp:656
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Selezionate un livello di difficoltà."
-#: engines/scumm/dialogs.cpp:658
+#: engines/scumm/dialogs.cpp:656
msgid "Refer to your Loom(TM) manual for help."
msgstr "Consultate il manuale delle istruzioni."
-#: engines/scumm/dialogs.cpp:662
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Base"
-#: engines/scumm/dialogs.cpp:663
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Expert"
@@ -3332,7 +3618,26 @@ msgstr "Vola a destra"
msgid "Fly to lower right"
msgstr "Vola in basso a destra"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/input.cpp:578
+#, fuzzy
+msgid "Snap scroll on"
+msgstr "Scorrimento morbido"
+
+#: engines/scumm/input.cpp:580
+msgid "Snap scroll off"
+msgstr ""
+
+#: engines/scumm/input.cpp:593
+#, fuzzy
+msgid "Music volume: "
+msgstr "Volume musica:"
+
+#: engines/scumm/input.cpp:610
+#, fuzzy
+msgid "Subtitle speed: "
+msgstr "Velocità testo:"
+
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3341,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 "
@@ -3365,6 +3670,60 @@ msgid ""
"instruments from. Music will be disabled."
msgstr ""
+#: engines/sherlock/detection.cpp:71
+#, fuzzy
+msgid "Use original savegame dialog"
+msgstr "Usa schermate di salvataggio originali"
+
+#: engines/sherlock/detection.cpp:72
+msgid ""
+"Files button in-game shows original savegame dialog rather than the ScummVM "
+"menu"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:81
+msgid "Pixellated scene transitions"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:82
+msgid "When changing scenes, a randomized pixel transition is done"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:91
+msgid "Don't show hotspots when moving mouse"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:92
+msgid ""
+"Only show hotspot names after you actually click on a hotspot or action "
+"button"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:101
+#, fuzzy
+msgid "Show character portraits"
+msgstr "Cambia personaggio"
+
+#: engines/sherlock/detection.cpp:102
+msgid "Show portraits for the characters when conversing"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:111
+msgid "Slide dialogs into view"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:112
+msgid "Slide UI dialogs into view, rather than simply showing them immediately"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:121
+msgid "Transparent windows"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:122
+msgid "Show windows with a partially transparent background"
+msgstr ""
+
#: engines/sky/compact.cpp:130
msgid ""
"Unable to find \"sky.cpt\" file!\n"
@@ -3467,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"
@@ -3579,26 +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"
-
-#~ msgid "Hercules Green"
-#~ msgstr "Hercules verde"
-
-#~ msgid "Hercules Amber"
-#~ msgstr "Hercules ambra"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Green"
-#~ msgstr "Hercules verde"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Amber"
-#~ msgstr "Hercules ambra"
-
-#~ msgid "Save game failed!"
-#~ msgstr "Salvataggio fallito!"
-
#~ msgctxt "lowres"
#~ msgid "Add Game..."
#~ msgstr "Agg. gioco..."
@@ -3612,8 +3960,5 @@ msgstr ""
#~ msgid "Command line argument not processed"
#~ msgstr "Argomento della linea di comando non eseguito"
-#~ msgid "FM Towns Emulator"
-#~ msgstr "Emulatore FM Towns"
-
#~ msgid "Invalid Path"
#~ msgstr "Percorso non valido"
diff --git a/po/module.mk b/po/module.mk
index 88bf7d5d12..8311b76a66 100644
--- a/po/module.mk
+++ b/po/module.mk
@@ -2,7 +2,7 @@ POTFILE := $(srcdir)/po/scummvm.pot
POFILES := $(wildcard $(srcdir)/po/*.po)
CPFILES := $(wildcard $(srcdir)/po/*.cp)
-ENGINE_INPUT_POTFILES := $(wildcard $(srcdir)/engines/*/POTFILES)
+ENGINE_INPUT_POTFILES := $(sort $(wildcard $(srcdir)/engines/*/POTFILES))
updatepot:
cat $(srcdir)/po/POTFILES $(ENGINE_INPUT_POTFILES) | \
xgettext -f - -D $(srcdir) -d scummvm --c++ -k_ -k_s -k_c:1,2c -k_sc:1,2c --add-comments=I18N\
diff --git a/po/nb_NO.po b/po/nb_NO.po
index 0b2816ad2f..f683f85535 100644
--- a/po/nb_NO.po
+++ b/po/nb_NO.po
@@ -1,5 +1,5 @@
# Norwegian (Bokmaal) translation for ScummVM.
-# Copyright (C) 2010-2015 The ScummVM Team
+# Copyright (C) 2010-2016 The ScummVM Team
# This file is distributed under the same license as the ScummVM package.
# Einar Johan T. Sømåen <einarjohants@gmail.com>, 2010.
#
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.3.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2015-09-06 15:14+0200\n"
-"PO-Revision-Date: 2014-07-11 00:02+0100\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"
"Language: Norsk (bokmaal)\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Poedit-SourceCharset: iso-8859-1\n"
-"X-Generator: Poedit 1.5.5\n"
+"X-Generator: Poedit 1.8.7\n"
#: gui/about.cpp:94
#, c-format
@@ -54,28 +54,29 @@ msgid "Go up"
msgstr "Oppover"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:74 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: 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/fluidsynth-dialog.cpp:152 engines/engine.cpp:483
-#: backends/platform/wii/options.cpp:48
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
-#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:191 engines/sword1/control.cpp:865
+#: 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 "Avbryt"
#: gui/browser.cpp:76 gui/browser_osx.mm:103 gui/chooser.cpp:47
-#: gui/themebrowser.cpp:56
+#: gui/filebrowser-dialog.cpp:65 gui/themebrowser.cpp:56
msgid "Choose"
msgstr "Velg"
#: gui/editrecorddialog.cpp:58
msgid "Author:"
-msgstr ""
+msgstr "Forfatter:"
#: gui/editrecorddialog.cpp:59 gui/launcher.cpp:204
msgid "Name:"
@@ -83,63 +84,180 @@ msgstr "Navn:"
#: gui/editrecorddialog.cpp:60
msgid "Notes:"
-msgstr ""
+msgstr "Notater:"
-#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:75
+#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74
msgid "Ok"
+msgstr "Ok"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Choose file for loading"
+msgstr "Velg fil for lasting"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Enter filename for saving"
+msgstr "Skriv inn filnavn for lagring"
+
+#: gui/filebrowser-dialog.cpp:132
+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: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 "Ja"
+
+#: 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 "Nei"
+
+#: gui/fluidsynth-dialog.cpp:68
+msgid "Reverb"
+msgstr "Romklang"
+
+#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
+msgid "Active"
+msgstr "Aktiv"
+
+#: gui/fluidsynth-dialog.cpp:72
+msgid "Room:"
+msgstr "Rom:"
+
+#: gui/fluidsynth-dialog.cpp:79
+msgid "Damp:"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:86
+msgid "Width:"
+msgstr "Bredde:"
+
+#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
+msgid "Level:"
+msgstr "Nivå:"
+
+#: gui/fluidsynth-dialog.cpp:100
+msgid "Chorus"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:104
+msgid "N:"
+msgstr "N:"
+
+#: gui/fluidsynth-dialog.cpp:118
+msgid "Speed:"
+msgstr "Hastighet:"
+
+#: gui/fluidsynth-dialog.cpp:125
+msgid "Depth:"
+msgstr "Dybde:"
+
+#: gui/fluidsynth-dialog.cpp:132
+msgid "Type:"
+msgstr "Type:"
+
+#: gui/fluidsynth-dialog.cpp:135
+msgid "Sine"
+msgstr "Sinus"
+
+#: gui/fluidsynth-dialog.cpp:136
+msgid "Triangle"
+msgstr "Trekant"
+
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
+msgid "Misc"
+msgstr "Diverse"
+
+#: gui/fluidsynth-dialog.cpp:140
+msgid "Interpolation:"
+msgstr "Interpolering:"
+
+#: gui/fluidsynth-dialog.cpp:143
+msgid "None (fastest)"
+msgstr "Ingen (raskest)"
+
+#: gui/fluidsynth-dialog.cpp:144
+msgid "Linear"
+msgstr "Linjær"
+
+#: gui/fluidsynth-dialog.cpp:145
+msgid "Fourth-order"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:146
+msgid "Seventh-order"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset"
+msgstr "Nullstill"
+
+#: gui/fluidsynth-dialog.cpp:150
+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: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 "OK"
+
+#: gui/fluidsynth-dialog.cpp:217
+msgid ""
+"Do you really want to reset all FluidSynth settings to their default values?"
msgstr ""
+"Vil du virkelig nullstille alle FluidSynth-instillinger til standardverdier?"
-#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
+#: 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 "Lukk"
-#: gui/gui-manager.cpp:120
+#: gui/gui-manager.cpp:122
msgid "Mouse click"
msgstr "Musklikk"
-#: gui/gui-manager.cpp:124 base/main.cpp:319
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Vis tastatur"
-#: gui/gui-manager.cpp:128 base/main.cpp:323
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Omkoble taster"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 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"
-#: gui/KeysDialog.h:36 gui/KeysDialog.cpp:145
-msgid "Choose an action to map"
-msgstr "Velg en handling for kobling"
-
#: gui/KeysDialog.cpp:41
msgid "Map"
msgstr "Koble"
-#: gui/KeysDialog.cpp:42 gui/launcher.cpp:352 gui/launcher.cpp:1048
-#: gui/launcher.cpp:1052 gui/massadd.cpp:92 gui/options.cpp:1238
-#: gui/saveload-dialog.cpp:932 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:402 engines/engine.cpp:413
-#: 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/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 "OK"
-
#: gui/KeysDialog.cpp:49
msgid "Select an action and click 'Map'"
msgstr "Velg en handling, og trykk 'Koble'"
@@ -162,6 +280,10 @@ msgstr "Vennligst velg en handling"
msgid "Press the key to associate"
msgstr "Trykk tasten som skal kobles"
+#: gui/KeysDialog.cpp:145 gui/KeysDialog.h:36
+msgid "Choose an action to map"
+msgstr "Velg en handling for kobling"
+
#: gui/launcher.cpp:193
msgid "Game"
msgstr "Spill"
@@ -204,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>"
@@ -227,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"
@@ -244,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"
@@ -257,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"
@@ -275,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:95
+#: 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:69
+#: 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:1222
+#: 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/myst.cpp:245 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/myst.cpp:245
-#: engines/mohawk/riven.cpp:718 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:792
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -492,60 +615,40 @@ msgstr ""
"Vil du virkelig kjøre flerspill-finneren? Dette kan potensielt legge til et "
"stort antall spill."
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Ja"
-
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Nei"
-
-#: gui/launcher.cpp:841
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM kunne ikke åpne den valgte mappen!"
-#: gui/launcher.cpp:853
+#: 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:867
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Velg spill:"
-#: gui/launcher.cpp:941
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "Vil du virkelig fjerne denne spillkonfigurasjonen?"
-#: gui/launcher.cpp:999
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "Vil du laste et lagret spill?"
-#: gui/launcher.cpp:1048
+#: 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:1052
+#: 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:1159
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Legg til flere..."
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr ""
@@ -576,148 +679,146 @@ msgstr ""
#: gui/onscreendialog.cpp:101 gui/onscreendialog.cpp:103
msgid "Stop"
-msgstr ""
+msgstr "Stopp"
#: gui/onscreendialog.cpp:106
msgid "Edit record description"
msgstr ""
#: gui/onscreendialog.cpp:108
-#, fuzzy
msgid "Switch to Game"
-msgstr "Bytt"
+msgstr "Bytt til Spill"
#: gui/onscreendialog.cpp:110
-#, fuzzy
msgid "Fast replay"
-msgstr "Rask modus"
+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:2298
+#: 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"
@@ -725,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"
@@ -790,188 +887,202 @@ 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"
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:1168 gui/fluidsynth-dialog.cpp:138
-msgid "Misc"
-msgstr "Diverse"
-
-#: 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."
@@ -980,64 +1091,75 @@ msgstr ""
"temaet, må du bytte til et annet språk først."
#. I18N: You must leave "#" as is, only word 'next' is translatable
-#: gui/predictivedialog.cpp:87
+#: gui/predictivedialog.cpp:86
msgid "# next"
-msgstr ""
+msgstr "# neste"
-#: gui/predictivedialog.cpp:88
+#: gui/predictivedialog.cpp:87
msgid "add"
msgstr ""
-#: gui/predictivedialog.cpp:92
-#, fuzzy
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
-msgstr "Slett"
+msgstr ""
-#: gui/predictivedialog.cpp:96
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
-msgstr ""
+msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:98
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr ""
-#: gui/recorderdialog.cpp:64
+#. I18N: 'Num' means Numbers
+#: gui/predictivedialog.cpp:578
+msgid "* Num"
+msgstr "* Tall"
+
+#. I18N: 'Abc' means Latin alphabet input
+#: gui/predictivedialog.cpp:581
+msgid "* Abc"
+msgstr "* Abc"
+
+#: 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
-#, fuzzy
+#: gui/recorderdialog.cpp:71
msgid "Playback"
-msgstr "Spill"
+msgstr ""
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
-msgstr ""
+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 ""
+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 ""
+msgstr "Notater: "
-#: gui/recorderdialog.cpp:155
-#, fuzzy
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
-msgstr "Vil du virkelig slette dette lagrede spillet?"
+msgstr ""
+
+#: gui/recorderdialog.cpp:173
+msgid "Unknown Author"
+msgstr "Ukjent Forfatter"
#: gui/saveload-dialog.cpp:167
msgid "List view"
@@ -1099,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:"
@@ -1108,150 +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:661
+#: 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
-msgid "Clear value"
-msgstr "Tøm verdi"
-
-#: gui/fluidsynth-dialog.cpp:68
-msgid "Reverb"
-msgstr "Romklang"
-
-#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
-msgid "Active"
-msgstr "Aktiv"
-
-#: gui/fluidsynth-dialog.cpp:72
-msgid "Room:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:79
-msgid "Damp:"
+#: 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/fluidsynth-dialog.cpp:86
-msgid "Width:"
-msgstr "Bredde:"
-
-#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
-msgid "Level:"
-msgstr "Nivå:"
-
-#: gui/fluidsynth-dialog.cpp:100
-msgid "Chorus"
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
msgstr ""
-#: gui/fluidsynth-dialog.cpp:104
-msgid "N:"
-msgstr "N:"
-
-#: gui/fluidsynth-dialog.cpp:118
-msgid "Speed:"
-msgstr "Hastighet:"
-
-#: gui/fluidsynth-dialog.cpp:125
-msgid "Depth:"
-msgstr "Dybde:"
-
-#: gui/fluidsynth-dialog.cpp:132
-msgid "Type:"
-msgstr "Type:"
-
-#: gui/fluidsynth-dialog.cpp:135
-msgid "Sine"
-msgstr "Sinus"
-
-#: gui/fluidsynth-dialog.cpp:136
-msgid "Triangle"
-msgstr "Trekant"
-
-#: gui/fluidsynth-dialog.cpp:140
-msgid "Interpolation:"
-msgstr "Interpolering:"
-
-#: gui/fluidsynth-dialog.cpp:143
-msgid "None (fastest)"
-msgstr "Ingen (raskest)"
-
-#: gui/fluidsynth-dialog.cpp:144
-msgid "Linear"
-msgstr "Linjær"
-
-#: gui/fluidsynth-dialog.cpp:145
-msgid "Fourth-order"
-msgstr ""
+#: gui/updates-dialog.cpp:92
+#, fuzzy
+msgid "Check for updates automatically"
+msgstr "Sjekk for oppdateringer..."
-#: gui/fluidsynth-dialog.cpp:146
-msgid "Seventh-order"
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
msgstr ""
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset"
-msgstr "Nullstill"
-
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset all FluidSynth settings to their default values."
-msgstr "Nullstill alle FluidSynth-instillinger til standardverdier"
-
-#: gui/fluidsynth-dialog.cpp:217
-msgid ""
-"Do you really want to reset all FluidSynth settings to their default values?"
-msgstr ""
-"Vil du virkelig nullstille alle FluidSynth-instillinger til standardverdier?"
+#: 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:228
+#: 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:306
+#: base/main.cpp:315
msgid "Menu"
msgstr "Meny"
-#: base/main.cpp:309 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:312 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:315
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Hopp over linje"
-#: base/main.cpp:507
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Problem ved kjøring av spill:"
-#: base/main.cpp:554
+#: 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"
@@ -1319,17 +1376,61 @@ msgstr "Brukeren avbrøt"
msgid "Unknown error"
msgstr "Ukjent feil"
-#: engines/advancedDetector.cpp:317
+#. I18N: Hercules is graphics card name
+#: common/rendermode.cpp:35
+msgid "Hercules Green"
+msgstr "Hercules Grønn"
+
+#: common/rendermode.cpp:36
+msgid "Hercules Amber"
+msgstr "Hercules Oransje"
+
+#: common/rendermode.cpp:42
+msgid "PC-9821 (256 Colors)"
+msgstr "PC-9821 (256 Farger)"
+
+#: common/rendermode.cpp:43
+msgid "PC-9801 (16 Colors)"
+msgstr "PC-9801 (16 Farger)"
+
+#: common/rendermode.cpp:73
+msgctxt "lowres"
+msgid "Hercules Green"
+msgstr "Hercules Grønn"
+
+#: common/rendermode.cpp:74
+msgctxt "lowres"
+msgid "Hercules Amber"
+msgstr "Hercules Oransje"
+
+#: 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.:"
@@ -1337,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"
@@ -1366,11 +1467,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "~T~ilbake til oppstarter"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:803
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:873
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
-#: engines/toltecs/menu.cpp:281 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:"
@@ -1379,11 +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:803 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/neverhood/menumodule.cpp:873 engines/pegasus/pegasus.cpp:377
-#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
-#: engines/toltecs/menu.cpp:281 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"
@@ -1406,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"
@@ -1420,23 +1530,23 @@ msgstr "~A~vbryt"
msgid "~K~eys"
msgstr "~T~aster"
-#: engines/engine.cpp:276
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Kunne ikke initalisere fargeformat."
-#: engines/engine.cpp:284
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Kunne ikke veksle til videomodus: '"
-#: engines/engine.cpp:293
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "Kunne ikke aktivere aspektrate-innstilling."
-#: engines/engine.cpp:298
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Kunne ikke aktivere fullskjermsinnstilling."
-#: engines/engine.cpp:398
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1450,7 +1560,7 @@ msgstr ""
"datafilene til harddisken din istedet.\n"
"Se README-filen for detaljer."
-#: engines/engine.cpp:409
+#: 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"
@@ -1464,7 +1574,7 @@ msgstr ""
"kunne høre på spillets musikk.\n"
"Se README-filen for detaljer."
-#: engines/engine.cpp:467
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1473,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:480
+#: 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 "
@@ -1483,10 +1593,14 @@ 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:483
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Start allikevel"
+#: audio/adlib.cpp:2290
+msgid "AdLib Emulator"
+msgstr "AdLib Emulator"
+
#: audio/fmopl.cpp:62
msgid "MAME OPL emulator"
msgstr "MAME OPL emulator"
@@ -1497,7 +1611,7 @@ msgstr "DOSBox OPL emulator"
#: audio/fmopl.cpp:67
msgid "ALSA Direct FM"
-msgstr ""
+msgstr "ALSA Direct FM"
#: audio/mididrv.cpp:209
#, c-format
@@ -1540,31 +1654,35 @@ msgstr ""
"Den foretrukne lydenheten '%s' kan ikke brukes. Se i logg-filen for mer "
"informasjon."
-#: audio/null.h:44
-msgid "No music"
-msgstr "Ingen musikk"
-
#: audio/mods/paula.cpp:196
msgid "Amiga Audio Emulator"
msgstr "Amiga Lydemulator"
-#: audio/adlib.cpp:2291
-msgid "AdLib Emulator"
-msgstr "AdLib Emulator"
+#: audio/null.h:44
+msgid "No music"
+msgstr "Ingen musikk"
#: audio/softsynth/appleiigs.cpp:33
msgid "Apple II GS Emulator (NOT IMPLEMENTED)"
msgstr "Apple II GS Emulator (IKKE IMPLEMENTERT)"
-#: audio/softsynth/sid.cpp:1430
-msgid "C64 Audio Emulator"
-msgstr "C64 Lydemulator"
+#: audio/softsynth/cms.cpp:350
+msgid "Creative Music System Emulator"
+msgstr "Creative Music System Emulator"
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33
+msgid "FM-Towns Audio"
+msgstr "FM Towns Lyd"
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58
+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"
@@ -1576,6 +1694,146 @@ msgstr "PC Speaker Emulator"
msgid "IBM PCjr Emulator"
msgstr "IBM PCjr Emulator"
+#: audio/softsynth/sid.cpp:1430
+msgid "C64 Audio Emulator"
+msgstr "C64 Lydemulator"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Do you really want to return to the Launcher?"
+msgstr "Vil du virkelig returnere til oppstarteren?"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Launcher"
+msgstr "Oppstarter"
+
+#: backends/events/default/default-events.cpp:218
+msgid "Do you really want to quit?"
+msgstr "Vil du virkelig avslutte?"
+
+#: 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 "Avslutt"
+
+#: 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 "Touchskjerm 'Tapmodus' - Venstreklikk"
+
+#: 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 "Touchskjerm 'Tapmodus' - Høyreklikk"
+
+#: 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 "Touchskjerm 'Tapmodus' - Sveve (Ingen Klikk)"
+
+#: backends/events/gph/gph-events.cpp:409
+msgid "Maximum Volume"
+msgstr "Maksimalt Volum"
+
+#: backends/events/gph/gph-events.cpp:411
+msgid "Increasing Volume"
+msgstr "Øker volum"
+
+#: backends/events/gph/gph-events.cpp:417
+msgid "Minimal Volume"
+msgstr "Minimalt Volum"
+
+#: backends/events/gph/gph-events.cpp:419
+msgid "Decreasing Volume"
+msgstr "Senker volum"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Enabled"
+msgstr "Klikking aktivert"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Disabled"
+msgstr "Klikking deaktivert"
+
+#: backends/events/openpandora/op-events.cpp:174
+msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
+msgstr "Touchskjerm 'Tapmodus' - Sveve (DPad Klikk)"
+
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
+msgid "Do you want to quit ?"
+msgstr "Vil du avslutte?"
+
+#. I18N: Trackpad mode toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:308
+msgid "Trackpad mode is now"
+msgstr "Trackpadmodus er nå"
+
+#. 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 "PÅ"
+
+#: backends/events/webossdl/webossdl-events.cpp:311
+#: backends/events/webossdl/webossdl-events.cpp:338
+msgid "OFF"
+msgstr "AV"
+
+#: backends/events/webossdl/webossdl-events.cpp:315
+msgid "Swipe two fingers to the right to toggle."
+msgstr "Sveip to fingre til høyre for å slå av/på"
+
+#. I18N: Auto-drag toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:335
+msgid "Auto-drag mode is now"
+msgstr "Auto-dramodus er nå"
+
+#: backends/events/webossdl/webossdl-events.cpp:342
+msgid "Swipe three fingers to the right to toggle."
+msgstr "Sveip tre fingre til høyre for å veksle"
+
+#: backends/graphics/opengl/opengl-graphics.cpp:126
+msgid "OpenGL"
+msgstr "OpenGL"
+
+#: backends/graphics/opengl/opengl-graphics.cpp:127
+msgid "OpenGL (No filtering)"
+msgstr "OpenGL (Ingen filtrering)"
+
+#: 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 "Normal (ingen skalering)"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:66
+msgctxt "lowres"
+msgid "Normal (no scaling)"
+msgstr "Normal (ingen skalering)"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
+msgid "Enabled aspect ratio correction"
+msgstr "Aspekt-rate korrigering aktivert"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
+msgid "Disabled aspect ratio correction"
+msgstr "Aspekt-rate korrigering deaktivert"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
+msgid "Active graphics filter:"
+msgstr "Aktivt grafikkfilter:"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+msgid "Windowed mode"
+msgstr "Vindusmodus"
+
#: backends/keymapper/remap-dialog.cpp:48
msgid "Keymap:"
msgstr "Tastkobling:"
@@ -1605,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"
@@ -1681,18 +1939,26 @@ msgstr "Høy lydkvalitet (tregere) (omstart)"
msgid "Disable power off"
msgstr "Deaktiver strømsparing"
+#: 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 "Mus-klikk-og-dra-modus aktivert."
+#: 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 "Mus-klikk-og-dra-modus-deaktivert."
+#: 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 "Touchpad-modus aktivert."
+#: 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 "Touchpad-modus deaktivert."
@@ -1703,9 +1969,9 @@ msgstr "Klikkmodus"
#: 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
-#: backends/platform/tizen/form.cpp:275
msgid "Left Click"
msgstr "Venstreklikk"
@@ -1715,65 +1981,32 @@ msgstr "Midtklikk"
#: backends/platform/maemo/maemo.cpp:220
#: backends/platform/symbian/src/SymbianActions.cpp:43
-#: backends/platform/wince/CEActionsSmartphone.cpp:44
#: backends/platform/tizen/form.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:44
msgid "Right Click"
msgstr "Høyreklikk"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:77
+#: backends/platform/sdl/macosx/appmenu_osx.mm:88
msgid "Hide ScummVM"
msgstr "Skjul ScummVM"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:82
+#: backends/platform/sdl/macosx/appmenu_osx.mm:93
msgid "Hide Others"
msgstr "Skjul andre"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:87
+#: backends/platform/sdl/macosx/appmenu_osx.mm:98
msgid "Show All"
msgstr "Vis alle"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:109
#: backends/platform/sdl/macosx/appmenu_osx.mm:120
+#: backends/platform/sdl/macosx/appmenu_osx.mm:131
msgid "Window"
msgstr "Vindu"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:114
+#: backends/platform/sdl/macosx/appmenu_osx.mm:125
msgid "Minimize"
msgstr "Minimer"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:46
-msgid "Normal (no scaling)"
-msgstr "Normal (ingen skalering)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:65
-msgctxt "lowres"
-msgid "Normal (no scaling)"
-msgstr "Normal (ingen skalering)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
-msgid "Enabled aspect ratio correction"
-msgstr "Aspekt-rate korrigering aktivert"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
-msgid "Disabled aspect ratio correction"
-msgstr "Aspekt-rate korrigering deaktivert"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
-msgid "Active graphics filter:"
-msgstr "Aktivt grafikkfilter:"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
-msgid "Windowed mode"
-msgstr "Vindusmodus"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:118
-msgid "OpenGL"
-msgstr "OpenGL"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:119
-msgid "OpenGL (No filtering)"
-msgstr "OpenGL (Ingen filtrering)"
-
#: backends/platform/symbian/src/SymbianActions.cpp:38
#: backends/platform/wince/CEActionsSmartphone.cpp:39
msgid "Up"
@@ -1817,14 +2050,6 @@ msgstr "Hopp over tekst"
msgid "Fast mode"
msgstr "Rask modus"
-#: backends/platform/symbian/src/SymbianActions.cpp:52
-#: backends/platform/wince/CEActionsPocket.cpp:44
-#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: backends/events/default/default-events.cpp:218 engines/scumm/dialogs.cpp:192
-#: engines/scumm/help.cpp:83 engines/scumm/help.cpp:85
-msgid "Quit"
-msgstr "Avslutt"
-
#: backends/platform/symbian/src/SymbianActions.cpp:53
msgid "Debugger"
msgstr "Debugger"
@@ -1841,9 +2066,49 @@ msgstr "Virtuelt tastatur"
msgid "Key mapper"
msgstr "Tastkobler"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:186
-msgid "Do you want to quit ?"
-msgstr "Vil du avslutte?"
+#: backends/platform/tizen/form.cpp:263
+msgid "Right Click Once"
+msgstr "Høyreklikk én gang"
+
+#: backends/platform/tizen/form.cpp:271
+msgid "Move Only"
+msgstr "Kun Beveg"
+
+#: backends/platform/tizen/form.cpp:294
+msgid "Escape Key"
+msgstr "ESC-tast"
+
+#: backends/platform/tizen/form.cpp:299
+msgid "Game Menu"
+msgstr "Spillmeny"
+
+#: backends/platform/tizen/form.cpp:304
+msgid "Show Keypad"
+msgstr "Vis talltastatur"
+
+#: backends/platform/tizen/form.cpp:309
+msgid "Control Mouse"
+msgstr "Styr Mus"
+
+#: backends/platform/tizen/fs.cpp:259
+msgid "[ Data ]"
+msgstr "[ Data ]"
+
+#: backends/platform/tizen/fs.cpp:263
+msgid "[ Resources ]"
+msgstr "[ Ressurser ]"
+
+#: backends/platform/tizen/fs.cpp:267
+msgid "[ SDCard ]"
+msgstr "[ SDKort ]"
+
+#: backends/platform/tizen/fs.cpp:271
+msgid "[ Media ]"
+msgstr "[ Media ]"
+
+#: backends/platform/tizen/fs.cpp:275
+msgid "[ Shared ]"
+msgstr "[ Delt ]"
#: backends/platform/wii/options.cpp:51
msgid "Video"
@@ -2091,139 +2356,104 @@ msgstr ""
"Ikke glem å koble en tast til handlingen 'Skjul verktøylinje' for å se hele "
"inventaret"
-#: backends/events/default/default-events.cpp:196
-msgid "Do you really want to return to the Launcher?"
-msgstr "Vil du virkelig returnere til oppstarteren?"
-
-#: backends/events/default/default-events.cpp:196
-msgid "Launcher"
-msgstr "Oppstarter"
-
-#: backends/events/default/default-events.cpp:218
-msgid "Do you really want to quit?"
-msgstr "Vil du virkelig avslutte?"
-
-#: 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 "Touchskjerm 'Tapmodus' - Venstreklikk"
-
-#: 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 "Touchskjerm 'Tapmodus' - Høyreklikk"
-
-#: 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 "Touchskjerm 'Tapmodus' - Sveve (Ingen Klikk)"
-
-#: backends/events/gph/gph-events.cpp:409
-msgid "Maximum Volume"
-msgstr "Maksimalt Volum"
-
-#: backends/events/gph/gph-events.cpp:411
-msgid "Increasing Volume"
-msgstr "Øker volum"
-
-#: backends/events/gph/gph-events.cpp:417
-msgid "Minimal Volume"
-msgstr "Minimalt Volum"
-
-#: backends/events/gph/gph-events.cpp:419
-msgid "Decreasing Volume"
-msgstr "Senker volum"
-
-#: backends/events/openpandora/op-events.cpp:174
-msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
-msgstr "Touchskjerm 'Tapmodus' - Sveve (DPad Klikk)"
-
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Sjekk for oppdateringer..."
-#: backends/platform/tizen/form.cpp:263
-msgid "Right Click Once"
-msgstr "Høyreklikk én gang"
-
-#: backends/platform/tizen/form.cpp:271
-msgid "Move Only"
-msgstr "Kun Beveg"
-
-#: backends/platform/tizen/form.cpp:294
-msgid "Escape Key"
-msgstr "ESC-tast"
-
-#: backends/platform/tizen/form.cpp:299
-msgid "Game Menu"
-msgstr "Spillmeny"
-
-#: backends/platform/tizen/form.cpp:304
-msgid "Show Keypad"
-msgstr "Vis talltastatur"
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "Fargeblindmodus"
-#: backends/platform/tizen/form.cpp:309
-msgid "Control Mouse"
-msgstr "Styr Mus"
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Enabled"
-msgstr "Klikking aktivert"
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Disabled"
-msgstr "Klikking deaktivert"
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "Vis objektmerkelapper"
-#: engines/agi/detection.cpp:147 engines/drascula/detection.cpp:302
-#: engines/dreamweb/detection.cpp:47 engines/neverhood/detection.cpp:160
-#: engines/sci/detection.cpp:394 engines/toltecs/detection.cpp:200
-#: engines/zvision/detection_tables.h:51
+#: 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 "Bruk originale lagre/laste-skjermer"
-#: engines/agi/detection.cpp:148 engines/drascula/detection.cpp:303
-#: engines/dreamweb/detection.cpp:48 engines/neverhood/detection.cpp:161
-#: engines/sci/detection.cpp:395 engines/toltecs/detection.cpp:201
+#: 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 "Bruk de originale lagre/laste-skjermene, istedenfor ScummVM-variantene"
#: engines/agi/detection.cpp:157
-#, fuzzy
msgid "Use an alternative palette"
-msgstr "Bruk en alternativ intro (Kun for CD-versjon)"
+msgstr "Bruk en alternativ palett"
#: engines/agi/detection.cpp:158
msgid ""
"Use an alternative palette, common for all Amiga games. This was the old "
"behavior"
msgstr ""
+"Bruk en alternativ palett, fells for alle Amigaspill. Dette var den gamle "
+"oppførselen"
#: engines/agi/detection.cpp:167
-#, fuzzy
msgid "Mouse support"
-msgstr "Hopp over"
+msgstr "Musstøtte"
#: engines/agi/detection.cpp:168
msgid ""
"Enables mouse support. Allows to use mouse for movement and in game menus."
msgstr ""
+"Aktiver musstøtte. Tillater å bruke mus for bevegelse og i spillmenyer."
+
+#: 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:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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"
@@ -2234,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"
@@ -2245,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"
@@ -2256,19 +2486,18 @@ 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'!"
#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
-#, fuzzy
msgid "Color Blind Mode"
-msgstr "Klikkmodus"
+msgstr "Fargeblindmodus"
#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
-msgstr ""
+msgstr "Aktiver fargeblindmodus som standard"
#: engines/drascula/saveload.cpp:47
msgid ""
@@ -2288,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."
@@ -2318,17 +2547,17 @@ 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."
#: engines/hopkins/detection.cpp:76 engines/hopkins/detection.cpp:86
msgid "Gore Mode"
-msgstr ""
+msgstr "Gørrmodus"
#: engines/hopkins/detection.cpp:77 engines/hopkins/detection.cpp:87
msgid "Enable Gore Mode when available"
-msgstr ""
+msgstr "Aktiver gørrmodus når tilgjengelig"
#. I18N: Studio audience adds an applause and cheering sounds whenever
#. Malcolm makes a joke.
@@ -2342,9 +2571,8 @@ msgstr "Aktiver studiopublikum"
#. I18N: This option allows the user to skip text and cutscenes.
#: engines/kyra/detection.cpp:73
-#, fuzzy
msgid "Skip support"
-msgstr "Hopp over"
+msgstr "Hopp over-støtte"
#: engines/kyra/detection.cpp:74
msgid "Allow text and cutscenes to be skipped"
@@ -2461,6 +2689,12 @@ msgid ""
"Do you wish to use this save game file with ScummVM?\n"
"\n"
msgstr ""
+"Det følgende originale lagrede spillet ble funnet i spillstien din:\n"
+"\n"
+"%s %s\n"
+"\n"
+"Vil du bruke dette lagrede spillet med ScummVM?\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:590
#, c-format
@@ -2468,6 +2702,8 @@ msgid ""
"A save game file was found in the specified slot %d. Overwrite?\n"
"\n"
msgstr ""
+"Et lagret spill ble funnet i den valgte posisjonen %d. Overskrive?\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:623
#, c-format
@@ -2479,50 +2715,64 @@ msgid ""
"'import_savefile'.\n"
"\n"
msgstr ""
+"%d originale lagrede spill har blitt importert vellykket til ScummVM.\n"
+"Hvis du vil importere flere originale lagrede spill senere, må du åpne\n"
+"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"
@@ -2531,15 +2781,23 @@ msgstr ""
"Kan ikke lagre spilltilstand i posisjon %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:194
+msgid "Load file"
+msgstr "Last fil"
+
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Laster spill..."
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:209
+msgid "Save file"
+msgstr "Lagre fil"
+
+#: 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"
@@ -2556,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"
@@ -2616,27 +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 ""
+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:395
+msgid "Enable high resolution graphics/content"
+msgstr "Aktiver høyoppløselig grafikk/innhold"
+
+#: 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:385
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
msgstr "Foretrekk digitale lydeffekter fremfor syntetiske"
-#: engines/sci/detection.cpp:404
+#: 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:405
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2644,148 +2919,155 @@ msgstr ""
"Bruk et IBM Music Feature-kort eller en Yamaha FB-01 FM-synthmodul til MIDI "
"output"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "Bruk CD-lyd"
-#: engines/sci/detection.cpp:416
+#: 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:426
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Bruk Windows-muspekere"
-#: engines/sci/detection.cpp:427
+#: 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:437
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Bruk sølvmuspekere"
-#: engines/sci/detection.cpp:438
+#: 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
-#, fuzzy
+#: engines/scumm/dialogs.cpp:179
msgid "Are you sure you want to restart? (Y/N)Y"
-msgstr "Er du sikker på at du vil avslutte? (Y/N)"
+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
-#, fuzzy
+#: 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? (Y/N)"
+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:600
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Kun tale"
-#: engines/scumm/dialogs.cpp:601
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Tale og undertekster"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Kun undertekster"
-#: engines/scumm/dialogs.cpp:610
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Tekst & Tale"
-#: engines/scumm/dialogs.cpp:656
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Velg ferdighetsnivå"
-#: engines/scumm/dialogs.cpp:658
+#: 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:662
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Trening"
-#: engines/scumm/dialogs.cpp:663
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Ekspert"
@@ -3215,19 +3497,19 @@ msgstr ""
#: engines/scumm/help.cpp:293
msgid "Toggle Keyboard/Mouse Fighting (*)"
-msgstr ""
+msgstr "Velg Tastatur/Mus-slåssing (*)"
#: engines/scumm/help.cpp:295
msgid "* Keyboard Fighting is always on,"
-msgstr ""
+msgstr "* Tastaturslåssing er alltid på,"
#: engines/scumm/help.cpp:296
msgid " so despite the in-game message this"
-msgstr ""
+msgstr " så til tross for beskjeden i spillet, vil"
#: engines/scumm/help.cpp:297
msgid " actually toggles Mouse Fighting Off/On"
-msgstr ""
+msgstr " dette faktisk slå musslåssing av/på"
#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
@@ -3322,7 +3604,23 @@ msgstr "Fly til høyre"
msgid "Fly to lower right"
msgstr "Fly til nedre høyre"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/input.cpp:578
+msgid "Snap scroll on"
+msgstr ""
+
+#: engines/scumm/input.cpp:580
+msgid "Snap scroll off"
+msgstr ""
+
+#: engines/scumm/input.cpp:593
+msgid "Music volume: "
+msgstr "Musikkvolum: "
+
+#: engines/scumm/input.cpp:610
+msgid "Subtitle speed: "
+msgstr "Teksthastighet: "
+
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3331,28 +3629,87 @@ msgstr ""
"Ekte MIDI-støtte krever «Roland Upgrade» fra LucasArts,\n"
"men %s mangler. Bruker AdLib istedet."
-#: engines/scumm/scumm.cpp:2644
-#, fuzzy
+#: 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 ""
-"Vanligvis, ville Maniac Mansion ha startet nå. Men ScummVM støtter ikke det "
-"ennå. Så, for å spille Maniac Mansion, gå til 'Legg til spill' i ScummVM-"
-"hovedmenyen og velg 'Maniac'-undermappa i Tentacle-mappa."
+"Vanligvis, ville Maniac Mansion ha startet nå. Men for at det skal fungere "
+"må Maniac Mansion-filene ligge i «Maniac» mappa inni Tentacle-spillmappa, og "
+"spillet må være lagt til i ScummVM."
#: 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 ""
+"Kunne ikke finne Macintosh binærfila «Loom» for å lese instrumenter\n"
+"fra den. Musikk vil bli deaktivert."
#: 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 ""
+"Kunne ikke finne Macintosh-binærfila «Monkey Island» for å lese\n"
+"instrumenter fra den. Musikk vil bli deaktivert."
+
+#: engines/sherlock/detection.cpp:71
+msgid "Use original savegame dialog"
+msgstr "Bruk original lagringsdialog"
+
+#: engines/sherlock/detection.cpp:72
+msgid ""
+"Files button in-game shows original savegame dialog rather than the ScummVM "
+"menu"
+msgstr ""
+"«Files»-knappen i spillet viser original lagre/laste-dialog istedenfor "
+"ScummVM menyen"
+
+#: engines/sherlock/detection.cpp:81
+msgid "Pixellated scene transitions"
+msgstr "Pikselerte sceneoverganger"
+
+#: engines/sherlock/detection.cpp:82
+msgid "When changing scenes, a randomized pixel transition is done"
+msgstr "Under scenskifter vil en tilfeldig pikselovergang bli gjort"
+
+#: engines/sherlock/detection.cpp:91
+msgid "Don't show hotspots when moving mouse"
+msgstr "Ikke vis hotspots når du beveger musa"
+
+#: engines/sherlock/detection.cpp:92
+msgid ""
+"Only show hotspot names after you actually click on a hotspot or action "
+"button"
+msgstr ""
+"Vis hotspots først etter at du faktisk har klikket på en hotspot eller "
+"handlingsknapp"
+
+#: engines/sherlock/detection.cpp:101
+msgid "Show character portraits"
+msgstr "Vis karakterportretter"
+
+#: engines/sherlock/detection.cpp:102
+msgid "Show portraits for the characters when conversing"
+msgstr "Vis portretter for karakterene når de snakker sammen"
+
+#: engines/sherlock/detection.cpp:111
+msgid "Slide dialogs into view"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:112
+msgid "Slide UI dialogs into view, rather than simply showing them immediately"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:121
+msgid "Transparent windows"
+msgstr "Gjennomsiktige vinduer"
+
+#: engines/sherlock/detection.cpp:122
+msgid "Show windows with a partially transparent background"
+msgstr "Vis vinduer med en delvis gjennomsiktig bakgrunn"
#: engines/sky/compact.cpp:130
msgid ""
@@ -3449,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"
@@ -3464,52 +3830,52 @@ msgstr ""
#: engines/wintermute/detection.cpp:58
msgid "Show FPS-counter"
-msgstr ""
+msgstr "Vis FPS-teller"
#: engines/wintermute/detection.cpp:59
msgid "Show the current number of frames per second in the upper left corner"
msgstr ""
+"Vis det gjeldende antall bilder per sekund (FPS) i øvre venstre hjørne av "
+"skjermen"
#: engines/zvision/detection_tables.h:52
-#, fuzzy
msgid "Use the original save/load screens instead of the ScummVM interface"
-msgstr "Bruk de originale lagre/laste-skjermene, istedenfor ScummVM-variantene"
+msgstr ""
+"Bruk de originale lagre/laste-skjermene istedenfor ScummVM-grensesnittet"
#: engines/zvision/detection_tables.h:61
msgid "Double FPS"
-msgstr ""
+msgstr "Dobbel FPS"
#: engines/zvision/detection_tables.h:62
msgid "Increase framerate from 30 to 60 FPS"
-msgstr ""
+msgstr "Øk bilderate fra 30 til 60 FPS"
#: engines/zvision/detection_tables.h:71
-#, fuzzy
msgid "Enable Venus"
-msgstr "Aktiver helium-modus"
+msgstr "Aktiver Venus"
#: engines/zvision/detection_tables.h:72
-#, fuzzy
msgid "Enable the Venus help system"
-msgstr "Aktiver helium-modus"
+msgstr "Aktiver Venus hjelpesystemet"
#: engines/zvision/detection_tables.h:81
msgid "Disable animation while turning"
-msgstr ""
+msgstr "Deaktiver animasjoner under snuing"
#: engines/zvision/detection_tables.h:82
msgid "Disable animation while turning in panorama mode"
-msgstr ""
+msgstr "Deaktiver animasjoner under snuing i panoramamodus"
#: engines/zvision/detection_tables.h:91
msgid "Use high resolution MPEG video"
-msgstr ""
+msgstr "Bruk høyoppløst MPEG-video"
#: engines/zvision/detection_tables.h:92
-#, fuzzy
msgid "Use MPEG video from the DVD version, instead of lower resolution AVI"
msgstr ""
-"Bruk det alternative settet med sølvmuspekere, istedenfor de normale gylne."
+"Bruk MPEG-video fra DVD-versjonen istedenfor AVI-versjonen med lavere "
+"oppløsning"
#~ msgid "EGA undithering"
#~ msgstr "EGA av-dithering"
@@ -3555,26 +3921,6 @@ msgstr ""
#~ msgid "Active filter mode: Nearest"
#~ msgstr "Aktiv filtermodus: Nærmeste"
-#~ msgid "Enable Roland GS Mode"
-#~ msgstr "Aktiver Roland GS-modus"
-
-#~ msgid "Hercules Green"
-#~ msgstr "Hercules Grønn"
-
-#~ msgid "Hercules Amber"
-#~ msgstr "Hercules Oransje"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Green"
-#~ msgstr "Hercules Grønn"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Amber"
-#~ msgstr "Hercules Oransje"
-
-#~ msgid "Save game failed!"
-#~ msgstr "Lagret spill:"
-
#~ msgctxt "lowres"
#~ msgid "Add Game..."
#~ msgstr "Legg til spill..."
@@ -3588,8 +3934,5 @@ msgstr ""
#~ msgid "Command line argument not processed"
#~ msgstr "Kommandolinjeargument ikke behandlet"
-#~ msgid "FM Towns Emulator"
-#~ msgstr "FM Towns Emulator"
-
#~ msgid "Invalid Path"
#~ msgstr "Ugyldig sti"
diff --git a/po/nl_NL.po b/po/nl_NL.po
index 0cca1a004e..b5e70af11f 100644
--- a/po/nl_NL.po
+++ b/po/nl_NL.po
@@ -1,21 +1,21 @@
-# LANGUAGE translation for ScummVM.
-# Copyright (C) 2014-2015 The ScummVM Team
+# Dutch translation for ScummVM.
+# Copyright (C) 2014-2016 The ScummVM Team
# This file is distributed under the same license as the ScummVM package.
# FIRST AUTHOR scummvm@bencastricum.nl, 2014.
#
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: 2015-09-06 15:14+0200\n"
-"PO-Revision-Date: 2014-11-25 20:46+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.6.10\n"
+"X-Generator: Poedit 1.8.8\n"
"X-Poedit-SourceCharset: iso-8859-1\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -54,28 +54,29 @@ msgid "Go up"
msgstr "Ga omhoog"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:74 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: 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/fluidsynth-dialog.cpp:152 engines/engine.cpp:483
-#: backends/platform/wii/options.cpp:48
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
-#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:191 engines/sword1/control.cpp:865
+#: 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 "Annuleren"
#: gui/browser.cpp:76 gui/browser_osx.mm:103 gui/chooser.cpp:47
-#: gui/themebrowser.cpp:56
+#: gui/filebrowser-dialog.cpp:65 gui/themebrowser.cpp:56
msgid "Choose"
msgstr "Selecteer"
#: gui/editrecorddialog.cpp:58
msgid "Author:"
-msgstr ""
+msgstr "Auteur:"
#: gui/editrecorddialog.cpp:59 gui/launcher.cpp:204
msgid "Name:"
@@ -83,63 +84,181 @@ msgstr "Naam:"
#: gui/editrecorddialog.cpp:60
msgid "Notes:"
-msgstr ""
+msgstr "Notities:"
-#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:75
+#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74
msgid "Ok"
+msgstr "Ok"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Choose file for loading"
+msgstr "Selecteer te laden bestand"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Enter filename for saving"
+msgstr "Geef bestandsnaam voor bewaren"
+
+#: gui/filebrowser-dialog.cpp:132
+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: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 "Ja"
+
+#: 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 "Nee"
+
+#: gui/fluidsynth-dialog.cpp:68
+msgid "Reverb"
+msgstr "Reverb"
+
+#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
+msgid "Active"
+msgstr "Actief"
+
+#: gui/fluidsynth-dialog.cpp:72
+msgid "Room:"
+msgstr "Kamer:"
+
+#: gui/fluidsynth-dialog.cpp:79
+msgid "Damp:"
+msgstr "Damp:"
+
+#: gui/fluidsynth-dialog.cpp:86
+msgid "Width:"
+msgstr "Breedte:"
+
+#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
+msgid "Level:"
+msgstr "Level:"
+
+#: gui/fluidsynth-dialog.cpp:100
+msgid "Chorus"
+msgstr "Koor"
+
+#: gui/fluidsynth-dialog.cpp:104
+msgid "N:"
+msgstr "N:"
+
+#: gui/fluidsynth-dialog.cpp:118
+msgid "Speed:"
+msgstr "Snelheid:"
+
+#: gui/fluidsynth-dialog.cpp:125
+msgid "Depth:"
+msgstr "Diepte:"
+
+#: gui/fluidsynth-dialog.cpp:132
+msgid "Type:"
+msgstr "Type:"
+
+#: gui/fluidsynth-dialog.cpp:135
+msgid "Sine"
+msgstr "Sinus"
+
+#: gui/fluidsynth-dialog.cpp:136
+msgid "Triangle"
+msgstr "Driehoek"
+
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
+msgid "Misc"
+msgstr "Misc"
+
+#: gui/fluidsynth-dialog.cpp:140
+msgid "Interpolation:"
+msgstr "Interpolatie:"
+
+#: gui/fluidsynth-dialog.cpp:143
+msgid "None (fastest)"
+msgstr "Geen (snelst)"
+
+#: gui/fluidsynth-dialog.cpp:144
+msgid "Linear"
+msgstr "Lineair"
+
+#: gui/fluidsynth-dialog.cpp:145
+msgid "Fourth-order"
+msgstr "Vierde-order"
+
+#: gui/fluidsynth-dialog.cpp:146
+msgid "Seventh-order"
+msgstr "Zevende-order"
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset"
+msgstr "Reset"
+
+#: gui/fluidsynth-dialog.cpp:150
+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: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 "OK"
+
+#: gui/fluidsynth-dialog.cpp:217
+msgid ""
+"Do you really want to reset all FluidSynth settings to their default values?"
msgstr ""
+"Wilt u echt alle FluidSynth instellingen terugzetten naar de standaard "
+"waarden?"
-#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
+#: 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 "Sluiten"
-#: gui/gui-manager.cpp:120
+#: gui/gui-manager.cpp:122
msgid "Mouse click"
msgstr "Muisklik"
-#: gui/gui-manager.cpp:124 base/main.cpp:319
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Toon toetsenbord"
-#: gui/gui-manager.cpp:128 base/main.cpp:323
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Toetsen opnieuw koppelen"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 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"
-#: gui/KeysDialog.h:36 gui/KeysDialog.cpp:145
-msgid "Choose an action to map"
-msgstr "Selecteer een actie om te koppelen"
-
#: gui/KeysDialog.cpp:41
msgid "Map"
msgstr "Koppel"
-#: gui/KeysDialog.cpp:42 gui/launcher.cpp:352 gui/launcher.cpp:1048
-#: gui/launcher.cpp:1052 gui/massadd.cpp:92 gui/options.cpp:1238
-#: gui/saveload-dialog.cpp:932 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:402 engines/engine.cpp:413
-#: 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/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 "OK"
-
#: gui/KeysDialog.cpp:49
msgid "Select an action and click 'Map'"
msgstr "Selecteer een actie en klik 'Koppel'"
@@ -162,6 +281,10 @@ msgstr "Selecteer een actie a.u.b."
msgid "Press the key to associate"
msgstr "Druk op de te associëren toets"
+#: gui/KeysDialog.cpp:145 gui/KeysDialog.h:36
+msgid "Choose an action to map"
+msgstr "Selecteer een actie om te koppelen"
+
#: gui/launcher.cpp:193
msgid "Game"
msgstr "Spel"
@@ -204,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>"
@@ -227,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"
@@ -244,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"
@@ -257,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"
@@ -275,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:95
+#: 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:69
+#: 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:1222
+#: 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/myst.cpp:245 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/myst.cpp:245
-#: engines/mohawk/riven.cpp:718 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:792
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -494,63 +618,43 @@ msgstr ""
"Wilt u echt de mass game detector draaien? Dit voegt potentieel een groot "
"aantal spellen toe."
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Ja"
-
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Nee"
-
-#: gui/launcher.cpp:841
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM kon de opgegeven map niet openen!"
-#: gui/launcher.cpp:853
+#: 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:867
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Kies het spel:"
-#: gui/launcher.cpp:941
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "Wilt u echt deze spelconfiguratie verwijderen?"
-#: gui/launcher.cpp:999
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "Wilt u het opgeslagen spel laden?"
-#: gui/launcher.cpp:1048
+#: 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:1052
+#: 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:1159
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
-msgstr ""
+msgstr "Mass Add..."
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1165
msgid "Record..."
-msgstr ""
+msgstr "Opnemen..."
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
@@ -570,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
@@ -581,148 +685,146 @@ msgstr ""
#: gui/onscreendialog.cpp:101 gui/onscreendialog.cpp:103
msgid "Stop"
-msgstr ""
+msgstr "Stop"
#: gui/onscreendialog.cpp:106
msgid "Edit record description"
-msgstr ""
+msgstr "Bewerk beschrijving opname"
#: gui/onscreendialog.cpp:108
-#, fuzzy
msgid "Switch to Game"
-msgstr "Schakel"
+msgstr "Schakel naar Spel"
#: gui/onscreendialog.cpp:110
-#, fuzzy
msgid "Fast replay"
-msgstr "Snelle modus"
+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:2298
+#: 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"
@@ -730,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"
@@ -798,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"
@@ -815,175 +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:1168 gui/fluidsynth-dialog.cpp:138
-msgid "Misc"
-msgstr "Misc"
-
-#: 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."
@@ -992,64 +1102,75 @@ msgstr ""
"dit thema wilt gebruiken dient u eerst een andere taal te selecteren."
#. I18N: You must leave "#" as is, only word 'next' is translatable
-#: gui/predictivedialog.cpp:87
+#: gui/predictivedialog.cpp:86
msgid "# next"
-msgstr ""
+msgstr "# volgende"
-#: gui/predictivedialog.cpp:88
+#: gui/predictivedialog.cpp:87
msgid "add"
-msgstr ""
+msgstr "voeg toe"
-#: gui/predictivedialog.cpp:92
-#, fuzzy
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
-msgstr "Verwijderen"
+msgstr "Karakter verwijderen"
-#: gui/predictivedialog.cpp:96
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
-msgstr ""
+msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:98
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
-msgstr ""
+msgstr "* Pre"
+
+#. I18N: 'Num' means Numbers
+#: gui/predictivedialog.cpp:578
+msgid "* Num"
+msgstr "* Num"
-#: gui/recorderdialog.cpp:64
+#. I18N: 'Abc' means Latin alphabet input
+#: gui/predictivedialog.cpp:581
+msgid "* Abc"
+msgstr "* Abc"
+
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
-msgstr ""
+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 ""
+msgstr "Opnemen"
-#: gui/recorderdialog.cpp:72
-#, fuzzy
+#: gui/recorderdialog.cpp:71
msgid "Playback"
-msgstr "Spelen"
+msgstr "Opnieuw afspelen"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
-msgstr ""
+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 ""
+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 ""
+msgstr "Notities"
-#: gui/recorderdialog.cpp:155
-#, fuzzy
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
-msgstr "Wilt u dit opgeslagen spel echt verwijderen?"
+msgstr "Wilt u deze opname echt verwijderen?"
+
+#: gui/recorderdialog.cpp:173
+msgid "Unknown Author"
+msgstr "Onbekende Auteur"
#: gui/saveload-dialog.cpp:167
msgid "List view"
@@ -1111,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:"
@@ -1120,151 +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:661
+#: 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
-msgid "Clear value"
-msgstr "Veld leegmaken"
-
-#: gui/fluidsynth-dialog.cpp:68
-msgid "Reverb"
-msgstr "Reverb"
-
-#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
-msgid "Active"
-msgstr "Actief"
-
-#: gui/fluidsynth-dialog.cpp:72
-msgid "Room:"
-msgstr "Kamer:"
-
-#: gui/fluidsynth-dialog.cpp:79
-msgid "Damp:"
-msgstr "Damp:"
-
-#: gui/fluidsynth-dialog.cpp:86
-msgid "Width:"
-msgstr "Breedte:"
-
-#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
-msgid "Level:"
-msgstr "Level:"
-
-#: gui/fluidsynth-dialog.cpp:100
-msgid "Chorus"
-msgstr "Koor"
-
-#: gui/fluidsynth-dialog.cpp:104
-msgid "N:"
-msgstr "N:"
-
-#: gui/fluidsynth-dialog.cpp:118
-msgid "Speed:"
-msgstr "Snelheid:"
-
-#: gui/fluidsynth-dialog.cpp:125
-msgid "Depth:"
-msgstr "Diepte:"
-
-#: gui/fluidsynth-dialog.cpp:132
-msgid "Type:"
-msgstr "Type:"
-
-#: gui/fluidsynth-dialog.cpp:135
-msgid "Sine"
-msgstr "Sinus"
-
-#: gui/fluidsynth-dialog.cpp:136
-msgid "Triangle"
-msgstr "Driehoek"
-
-#: gui/fluidsynth-dialog.cpp:140
-msgid "Interpolation:"
-msgstr "Interpolatie:"
-
-#: gui/fluidsynth-dialog.cpp:143
-msgid "None (fastest)"
-msgstr "Geen (snelst)"
-
-#: gui/fluidsynth-dialog.cpp:144
-msgid "Linear"
-msgstr "Lineair"
-
-#: gui/fluidsynth-dialog.cpp:145
-msgid "Fourth-order"
-msgstr "Vierde-order"
+#: 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/fluidsynth-dialog.cpp:146
-msgid "Seventh-order"
-msgstr "Zevende-order"
+#: 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/fluidsynth-dialog.cpp:150
-msgid "Reset"
-msgstr "Reset"
+#: gui/updates-dialog.cpp:92
+msgid "Check for updates automatically"
+msgstr "Automatisch controleren op updates"
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset all FluidSynth settings to their default values."
-msgstr "Alle FluidSynth instellingen terugzetten naar de standaard waarden."
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr "Ga verder"
-#: gui/fluidsynth-dialog.cpp:217
-msgid ""
-"Do you really want to reset all FluidSynth settings to their default values?"
-msgstr ""
-"Wilt u echt alle FluidSynth instellingen terugzetten naar de standaard "
-"waarden?"
+#: 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:228
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "Engine ondersteunt debug level '%s' niet"
-#: base/main.cpp:306
+#: base/main.cpp:315
msgid "Menu"
msgstr "Menu"
-#: base/main.cpp:309 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:312 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:315
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Regel overslaan"
-#: base/main.cpp:507
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Fout tijdens het starten van spel:"
-#: base/main.cpp:554
+#: 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"
@@ -1333,17 +1391,60 @@ msgstr "Gebruiker annuleerde"
msgid "Unknown error"
msgstr "Onbekende fout"
-#: engines/advancedDetector.cpp:317
+#. I18N: Hercules is graphics card name
+#: common/rendermode.cpp:35
+msgid "Hercules Green"
+msgstr "Hercules Groen"
+
+#: common/rendermode.cpp:36
+msgid "Hercules Amber"
+msgstr "Hercules Amber"
+
+#: common/rendermode.cpp:42
+msgid "PC-9821 (256 Colors)"
+msgstr "PC-9821 (256 Kleuren)"
+
+#: common/rendermode.cpp:43
+msgid "PC-9801 (16 Colors)"
+msgstr "PC-9801 (16 Kleuren)"
+
+#: common/rendermode.cpp:73
+msgctxt "lowres"
+msgid "Hercules Green"
+msgstr "Hercules Groen"
+
+#: common/rendermode.cpp:74
+msgctxt "lowres"
+msgid "Hercules Amber"
+msgstr "Hercules Amber"
+
+#: 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.:"
@@ -1351,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"
@@ -1380,11 +1481,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "S~t~artmenu"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:803
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:873
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
-#: engines/toltecs/menu.cpp:281 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:"
@@ -1393,11 +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:803 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/neverhood/menumodule.cpp:873 engines/pegasus/pegasus.cpp:377
-#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
-#: engines/toltecs/menu.cpp:281 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"
@@ -1421,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"
@@ -1435,24 +1545,24 @@ msgstr "~A~nnuleer"
msgid "~K~eys"
msgstr "~T~oetsen"
-#: engines/engine.cpp:276
+#: 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:284
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Kon niet schakelen naar videomodus: '"
-#: engines/engine.cpp:293
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "Pixelverhoudinginstelling kon niet toegepast worden."
-#: engines/engine.cpp:298
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Kon volledig-scherminstelling niet toepassen."
-#: engines/engine.cpp:398
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1466,7 +1576,7 @@ msgstr ""
"bestanden naar uw harddisk te kopieren.\n"
"Voor details kijk in de README."
-#: engines/engine.cpp:409
+#: 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"
@@ -1479,7 +1589,7 @@ msgstr ""
"CD rip programma om te kunnen luisteren naar\n"
"het spelmuziek. Voor details kijk in de README."
-#: engines/engine.cpp:467
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1489,7 +1599,7 @@ msgstr ""
"voor basisinformatie, en voor instructies voor het verkrijgen van verdere "
"assistentie."
-#: engines/engine.cpp:480
+#: 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 "
@@ -1500,10 +1610,14 @@ msgstr ""
"instabiel is, en opgeslagen spellen zullen mogelijk niet werken in "
"toekomstige versies van ScummVM."
-#: engines/engine.cpp:483
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Evengoed starten"
+#: audio/adlib.cpp:2290
+msgid "AdLib Emulator"
+msgstr "AdLib Emulator"
+
#: audio/fmopl.cpp:62
msgid "MAME OPL emulator"
msgstr "MAME OPL emulator"
@@ -1514,7 +1628,7 @@ msgstr "DOSBox OPL emulator"
#: audio/fmopl.cpp:67
msgid "ALSA Direct FM"
-msgstr ""
+msgstr "ALSA Direct FM"
#: audio/mididrv.cpp:209
#, c-format
@@ -1557,31 +1671,35 @@ msgstr ""
"Het voorkeursaudioapparaat '%s' kan niet gebruikt worden. Zie het logbestand "
"voor meer informatie."
-#: audio/null.h:44
-msgid "No music"
-msgstr "Geen muziek"
-
#: audio/mods/paula.cpp:196
msgid "Amiga Audio Emulator"
msgstr "Amiga Audio Emulator"
-#: audio/adlib.cpp:2291
-msgid "AdLib Emulator"
-msgstr "AdLib Emulator"
+#: audio/null.h:44
+msgid "No music"
+msgstr "Geen muziek"
#: audio/softsynth/appleiigs.cpp:33
msgid "Apple II GS Emulator (NOT IMPLEMENTED)"
msgstr "Apple II GS Emulator (NIET GEÏMPLEMENTEERD)"
-#: audio/softsynth/sid.cpp:1430
-msgid "C64 Audio Emulator"
-msgstr "C64 Audio Emulator"
+#: audio/softsynth/cms.cpp:350
+msgid "Creative Music System Emulator"
+msgstr "Creative Music System Emulator"
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33
+msgid "FM-Towns Audio"
+msgstr "FM-Towns Geluid"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58
+msgid "PC-98 Audio"
+msgstr "PC-98 Geluid"
+
+#: 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"
@@ -1593,6 +1711,146 @@ msgstr "PC Speaker Emulator"
msgid "IBM PCjr Emulator"
msgstr "IBM PCjr Emulator"
+#: audio/softsynth/sid.cpp:1430
+msgid "C64 Audio Emulator"
+msgstr "C64 Audio Emulator"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Do you really want to return to the Launcher?"
+msgstr "Wilt u echt terug naar het startmenu?"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Launcher"
+msgstr "Startmenu"
+
+#: backends/events/default/default-events.cpp:218
+msgid "Do you really want to quit?"
+msgstr "Wilt u echt stoppen?"
+
+#: 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 "Stoppen"
+
+#: 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 "Touchscreen 'Tap Modus' - Linker klik"
+
+#: 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 "Touchscreen 'Tap Modus' - Rechter Klik"
+
+#: 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 "Touchscreen 'Tap Modus' - Zweven (Geen Klik)"
+
+#: backends/events/gph/gph-events.cpp:409
+msgid "Maximum Volume"
+msgstr "Maximale Volume"
+
+#: backends/events/gph/gph-events.cpp:411
+msgid "Increasing Volume"
+msgstr "Volume omhoog"
+
+#: backends/events/gph/gph-events.cpp:417
+msgid "Minimal Volume"
+msgstr "Minimale Volume"
+
+#: backends/events/gph/gph-events.cpp:419
+msgid "Decreasing Volume"
+msgstr "Volume omlaag"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Enabled"
+msgstr "Klikken Aangezet"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Disabled"
+msgstr "Klikken Uitgeschakeld"
+
+#: backends/events/openpandora/op-events.cpp:174
+msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
+msgstr "Touchscreen 'Tap Modus' - Zweven (DPad Klik)"
+
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
+msgid "Do you want to quit ?"
+msgstr "Wilt u stoppen?"
+
+#. I18N: Trackpad mode toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:308
+msgid "Trackpad mode is now"
+msgstr "Trackpadmodus is nu"
+
+#. 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 "AAN"
+
+#: backends/events/webossdl/webossdl-events.cpp:311
+#: backends/events/webossdl/webossdl-events.cpp:338
+msgid "OFF"
+msgstr "UIT"
+
+#: backends/events/webossdl/webossdl-events.cpp:315
+msgid "Swipe two fingers to the right to toggle."
+msgstr "Swipe twee vingers naar rechts om te schakelen."
+
+#. I18N: Auto-drag toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:335
+msgid "Auto-drag mode is now"
+msgstr "Auto-sleep modus is nu"
+
+#: backends/events/webossdl/webossdl-events.cpp:342
+msgid "Swipe three fingers to the right to toggle."
+msgstr "Swipe drie vingers naar rechts om te schakelen."
+
+#: backends/graphics/opengl/opengl-graphics.cpp:126
+msgid "OpenGL"
+msgstr "OpenGL"
+
+#: backends/graphics/opengl/opengl-graphics.cpp:127
+msgid "OpenGL (No filtering)"
+msgstr "OpenGL (geen filters)"
+
+#: 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 "Normaal (niet schalen)"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:66
+msgctxt "lowres"
+msgid "Normal (no scaling)"
+msgstr "Normaal (niet schalen)"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
+msgid "Enabled aspect ratio correction"
+msgstr "Pixelverhoudingcorrectie ingeschakeld"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
+msgid "Disabled aspect ratio correction"
+msgstr "Pixelverhoudingcorrectie uitgeschakeld"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
+msgid "Active graphics filter:"
+msgstr "Actieve grafische filter:"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+msgid "Windowed mode"
+msgstr "Venstermodus"
+
#: backends/keymapper/remap-dialog.cpp:48
msgid "Keymap:"
msgstr "Toetskoppeling:"
@@ -1622,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"
@@ -1698,18 +1956,26 @@ msgstr "Hoge kwaliteit audio (langzamer) (opnieuw opstarten)"
msgid "Disable power off"
msgstr "Power-off uitschakelen"
+#: 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 "Muis-klik-en-sleepmodus aangezet."
+#: 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 "Muis-klik-en-sleepmodus uitgezet."
+#: 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 "Touchpadmodus ingeschakeld."
+#: 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 "Touchpadmodus uitgeschakeld."
@@ -1720,9 +1986,9 @@ msgstr "Klik Modus"
#: 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
-#: backends/platform/tizen/form.cpp:275
msgid "Left Click"
msgstr "Linker Klik"
@@ -1732,65 +1998,32 @@ msgstr "Middelste Klik"
#: backends/platform/maemo/maemo.cpp:220
#: backends/platform/symbian/src/SymbianActions.cpp:43
-#: backends/platform/wince/CEActionsSmartphone.cpp:44
#: backends/platform/tizen/form.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:44
msgid "Right Click"
msgstr "Rechter klik"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:77
+#: backends/platform/sdl/macosx/appmenu_osx.mm:88
msgid "Hide ScummVM"
msgstr "Verberg ScummVM"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:82
+#: backends/platform/sdl/macosx/appmenu_osx.mm:93
msgid "Hide Others"
msgstr "Verberg Anderen"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:87
+#: backends/platform/sdl/macosx/appmenu_osx.mm:98
msgid "Show All"
msgstr "Toon Alles"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:109
#: backends/platform/sdl/macosx/appmenu_osx.mm:120
+#: backends/platform/sdl/macosx/appmenu_osx.mm:131
msgid "Window"
msgstr "Venster"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:114
+#: backends/platform/sdl/macosx/appmenu_osx.mm:125
msgid "Minimize"
msgstr "Minimaliseer"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:46
-msgid "Normal (no scaling)"
-msgstr "Normaal (niet schalen)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:65
-msgctxt "lowres"
-msgid "Normal (no scaling)"
-msgstr "Normaal (niet schalen)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
-msgid "Enabled aspect ratio correction"
-msgstr "Pixelverhoudingcorrectie ingeschakeld"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
-msgid "Disabled aspect ratio correction"
-msgstr "Pixelverhoudingcorrectie uitgeschakeld"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
-msgid "Active graphics filter:"
-msgstr "Actieve grafische filter:"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
-msgid "Windowed mode"
-msgstr "Venstermodus"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:118
-msgid "OpenGL"
-msgstr "OpenGL"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:119
-msgid "OpenGL (No filtering)"
-msgstr "OpenGL (geen filters)"
-
#: backends/platform/symbian/src/SymbianActions.cpp:38
#: backends/platform/wince/CEActionsSmartphone.cpp:39
msgid "Up"
@@ -1824,7 +2057,7 @@ msgstr "Meerdere Functies"
#: backends/platform/symbian/src/SymbianActions.cpp:48
msgid "Swap character"
-msgstr "Verwissel karakter"
+msgstr "Verwissel personage"
#: backends/platform/symbian/src/SymbianActions.cpp:49
msgid "Skip text"
@@ -1834,14 +2067,6 @@ msgstr "Text overslaan"
msgid "Fast mode"
msgstr "Snelle modus"
-#: backends/platform/symbian/src/SymbianActions.cpp:52
-#: backends/platform/wince/CEActionsPocket.cpp:44
-#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: backends/events/default/default-events.cpp:218 engines/scumm/dialogs.cpp:192
-#: engines/scumm/help.cpp:83 engines/scumm/help.cpp:85
-msgid "Quit"
-msgstr "Stoppen"
-
#: backends/platform/symbian/src/SymbianActions.cpp:53
msgid "Debugger"
msgstr "Debugger"
@@ -1858,9 +2083,49 @@ msgstr "Virtueel toetsenbord"
msgid "Key mapper"
msgstr "Toets koppeltool"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:186
-msgid "Do you want to quit ?"
-msgstr "Wilt u stoppen?"
+#: backends/platform/tizen/form.cpp:263
+msgid "Right Click Once"
+msgstr "Rechter klik eenmalig"
+
+#: backends/platform/tizen/form.cpp:271
+msgid "Move Only"
+msgstr "Alleen Verplaatsen"
+
+#: backends/platform/tizen/form.cpp:294
+msgid "Escape Key"
+msgstr "Escape Toets"
+
+#: backends/platform/tizen/form.cpp:299
+msgid "Game Menu"
+msgstr "Spel Menu"
+
+#: backends/platform/tizen/form.cpp:304
+msgid "Show Keypad"
+msgstr "Toon Toetsenblok"
+
+#: backends/platform/tizen/form.cpp:309
+msgid "Control Mouse"
+msgstr "Muis Besturing"
+
+#: backends/platform/tizen/fs.cpp:259
+msgid "[ Data ]"
+msgstr "[ Data ]"
+
+#: backends/platform/tizen/fs.cpp:263
+msgid "[ Resources ]"
+msgstr "[ Resources ]"
+
+#: backends/platform/tizen/fs.cpp:267
+msgid "[ SDCard ]"
+msgstr "[ SDCard ]"
+
+#: backends/platform/tizen/fs.cpp:271
+msgid "[ Media ]"
+msgstr "[ Media ]"
+
+#: backends/platform/tizen/fs.cpp:275
+msgid "[ Shared ]"
+msgstr "[ Gedeeld ]"
#: backends/platform/wii/options.cpp:51
msgid "Video"
@@ -2109,141 +2374,107 @@ msgstr ""
"Vergeet niet de 'Verberg werkbalk' te koppelen aan een toets om de hele "
"inventaris te zien."
-#: backends/events/default/default-events.cpp:196
-msgid "Do you really want to return to the Launcher?"
-msgstr "Wilt u echt terug naar het startmenu?"
-
-#: backends/events/default/default-events.cpp:196
-msgid "Launcher"
-msgstr "Startmenu"
-
-#: backends/events/default/default-events.cpp:218
-msgid "Do you really want to quit?"
-msgstr "Wilt u echt stoppen?"
-
-#: 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 "Touchscreen 'Tap Modus' - Linker klik"
-
-#: 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 "Touchscreen 'Tap Modus' - Rechter Klik"
-
-#: 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 "Touchscreen 'Tap Modus' - Zweven (Geen Klik)"
-
-#: backends/events/gph/gph-events.cpp:409
-msgid "Maximum Volume"
-msgstr "Maximale Volume"
-
-#: backends/events/gph/gph-events.cpp:411
-msgid "Increasing Volume"
-msgstr "Volume omhoog"
-
-#: backends/events/gph/gph-events.cpp:417
-msgid "Minimal Volume"
-msgstr "Minimale Volume"
-
-#: backends/events/gph/gph-events.cpp:419
-msgid "Decreasing Volume"
-msgstr "Volume omlaag"
-
-#: backends/events/openpandora/op-events.cpp:174
-msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
-msgstr "Touchscreen 'Tap Modus' - Zweven (DPad Klik)"
-
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Controleren op updates..."
-#: backends/platform/tizen/form.cpp:263
-msgid "Right Click Once"
-msgstr "Rechter klik eenmalig"
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+msgid "Color mode"
+msgstr "Kleurenmodus"
-#: backends/platform/tizen/form.cpp:271
-msgid "Move Only"
-msgstr "Alleen Verplaatsen"
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr "Gebruik kleurenafbeeldingen"
-#: backends/platform/tizen/form.cpp:294
-msgid "Escape Key"
-msgstr "Escape Toets"
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr "scanlines"
-#: backends/platform/tizen/form.cpp:299
-msgid "Game Menu"
-msgstr "Spel Menu"
-
-#: backends/platform/tizen/form.cpp:304
-msgid "Show Keypad"
-msgstr "Toon Toetsenblok"
-
-#: backends/platform/tizen/form.cpp:309
-msgid "Control Mouse"
-msgstr "Muis Besturing"
-
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Enabled"
-msgstr "Klikken Aangezet"
-
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Disabled"
-msgstr "Klikken Uitgeschakeld"
+#: engines/adl/detection.cpp:64
+msgid "Show scanlines"
+msgstr "Toon scanlines"
-#: engines/agi/detection.cpp:147 engines/drascula/detection.cpp:302
-#: engines/dreamweb/detection.cpp:47 engines/neverhood/detection.cpp:160
-#: engines/sci/detection.cpp:394 engines/toltecs/detection.cpp:200
-#: engines/zvision/detection_tables.h:51
+#: 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 "Gebruik originele opslaan/laad schermen"
-#: engines/agi/detection.cpp:148 engines/drascula/detection.cpp:303
-#: engines/dreamweb/detection.cpp:48 engines/neverhood/detection.cpp:161
-#: engines/sci/detection.cpp:395 engines/toltecs/detection.cpp:201
+#: 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 ""
"Gebruik de originele opslaan/laden schermen, in plaats van die van ScummVM"
#: engines/agi/detection.cpp:157
-#, fuzzy
msgid "Use an alternative palette"
-msgstr ""
-"Gebruik een alternatieve versie van de intro (alleen voor de CD versie)"
+msgstr "Gebruik een alternatieve palet"
#: engines/agi/detection.cpp:158
msgid ""
"Use an alternative palette, common for all Amiga games. This was the old "
"behavior"
msgstr ""
+"Gebruik een alternatieve palet, gemeenschappelijk voor alle Amiga spellen. "
+"Dit was het oude gedrag"
#: engines/agi/detection.cpp:167
-#, fuzzy
msgid "Mouse support"
-msgstr "Support overslaan"
+msgstr "Muis ondersteuning"
#: engines/agi/detection.cpp:168
msgid ""
"Enables mouse support. Allows to use mouse for movement and in game menus."
msgstr ""
+"Zet muis ondersteuning aan. Maakt het mogelijk om de muis te gebruiken voor "
+"bewegen en in spelmenus."
-#: engines/agi/saveload.cpp:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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"
@@ -2254,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"
@@ -2265,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"
@@ -2276,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!"
@@ -2307,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."
@@ -2337,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."
@@ -2507,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"
@@ -2564,15 +2803,23 @@ msgstr ""
"Spel opslaan in slot %i mislukt\n"
"\n"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:194
+msgid "Load file"
+msgstr "Laad bestand"
+
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Spel laden..."
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:209
+msgid "Save file"
+msgstr "Bestand opslaan"
+
+#: 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"
@@ -2589,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"
@@ -2650,27 +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 ""
+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:395
+msgid "Enable high resolution graphics/content"
+msgstr "Gebruik hoge resolutie beelden"
+
+#: 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:385
+#: 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:404
+#: 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:405
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2678,149 +2943,157 @@ msgstr ""
"Gebruik een IBM Music Feature kaart of eem Yamaha FB-01 FM synth module voor "
"MIDI"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "Gebruik CD audio"
-#: engines/sci/detection.cpp:416
+#: 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:426
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Gebruik Windows muisaanwijzers"
-#: engines/sci/detection.cpp:427
+#: 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:437
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Gebruik zilveren muisaanwijzers"
-#: engines/sci/detection.cpp:438
+#: 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:600
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Alleen Spraak"
-#: engines/scumm/dialogs.cpp:601
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Spraak and Subtitels"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Alleen subtitels"
-#: engines/scumm/dialogs.cpp:610
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Tekst en Spraak"
-#: engines/scumm/dialogs.cpp:656
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Selecteer een vakkundigheidsniveau."
-#: engines/scumm/dialogs.cpp:658
+#: 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:662
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Oefenen"
-#: engines/scumm/dialogs.cpp:663
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Expert"
@@ -3234,7 +3507,7 @@ msgstr "Rechter middelste voorwerp"
#: engines/scumm/help.cpp:280 engines/scumm/help.cpp:285
msgid "Switching characters:"
-msgstr "Verwissel karakters:"
+msgstr "Verwissel personages:"
#: engines/scumm/help.cpp:282
msgid "Second kid"
@@ -3245,25 +3518,24 @@ msgid "Third kid"
msgstr "Derde kind"
#: engines/scumm/help.cpp:292
-#, fuzzy
msgid "Toggle Inventory/IQ Points display"
-msgstr "Aan-/Uitzetten centreren van Datascherm"
+msgstr "Schakel tussen bezittingen/IQ punten weergave"
#: engines/scumm/help.cpp:293
msgid "Toggle Keyboard/Mouse Fighting (*)"
-msgstr ""
+msgstr "Schakel tussen Toetsenbord/Muis vechten (*)"
#: engines/scumm/help.cpp:295
msgid "* Keyboard Fighting is always on,"
-msgstr ""
+msgstr "Toetsenbord vechten is altijd aan,"
#: engines/scumm/help.cpp:296
msgid " so despite the in-game message this"
-msgstr ""
+msgstr " dus ondanks het bericht in het spel dit"
#: engines/scumm/help.cpp:297
msgid " actually toggles Mouse Fighting Off/On"
-msgstr ""
+msgstr " schakelt eigenlijk Muis vechten uit/aan."
#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
@@ -3300,7 +3572,7 @@ msgstr "Stoot laag"
#: engines/scumm/help.cpp:315
msgid "Sucker punch"
-msgstr ""
+msgstr "Sucker punch"
#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
@@ -3358,7 +3630,23 @@ msgstr "Vlieg naar rechts"
msgid "Fly to lower right"
msgstr "Vlieg naar rechts omlaag"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/input.cpp:578
+msgid "Snap scroll on"
+msgstr "Snap scrollen aan"
+
+#: engines/scumm/input.cpp:580
+msgid "Snap scroll off"
+msgstr "Snap scroll uit"
+
+#: engines/scumm/input.cpp:593
+msgid "Music volume: "
+msgstr "Muziek volume:"
+
+#: engines/scumm/input.cpp:610
+msgid "Subtitle speed: "
+msgstr "Snelheid ondertitels:"
+
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3367,16 +3655,15 @@ 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
-#, fuzzy
+#: 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 ""
-"Normaal gesproken zou Maniac Mansion nu starten. Maar ScummVM doet dat nog "
-"niet. Om het te spelen, ga naar \"Spel Toevoegen\" in het ScummVM start menu "
-"en selecteer de map 'Maniac' in de Tentacle map."
+"Normaal gesproken zou Maniac Mansion nu starten. Maar om dat te laten werken "
+"moeten de Maniac Mansion bestanden in de 'Maniac' folder in de Tentacle "
+"spelfolder staan, en het spel moet worden toegevoegd aan ScummVM."
#: engines/scumm/players/player_v3m.cpp:129
msgid ""
@@ -3394,6 +3681,63 @@ msgstr ""
"De 'Monkey Island' Macintosh executable is niet gevonden om de instrumenten "
"van te laden. Muziek wordt uitgeschakeld."
+#: engines/sherlock/detection.cpp:71
+msgid "Use original savegame dialog"
+msgstr "Gebruik originele spel-opslaan schermen"
+
+#: engines/sherlock/detection.cpp:72
+msgid ""
+"Files button in-game shows original savegame dialog rather than the ScummVM "
+"menu"
+msgstr ""
+"In-game knop Files toont originele spel opslaan dialoogvenster in plaats van "
+"het ScummVM menu"
+
+#: engines/sherlock/detection.cpp:81
+msgid "Pixellated scene transitions"
+msgstr "Pixellated scèneovergangen"
+
+#: engines/sherlock/detection.cpp:82
+msgid "When changing scenes, a randomized pixel transition is done"
+msgstr ""
+"Bij scene wijzigingen wordt er een willekeurig pixel transitie gebruikt"
+
+#: engines/sherlock/detection.cpp:91
+msgid "Don't show hotspots when moving mouse"
+msgstr "Toon geen hotspots als de muis beweegt"
+
+#: engines/sherlock/detection.cpp:92
+msgid ""
+"Only show hotspot names after you actually click on a hotspot or action "
+"button"
+msgstr ""
+"Toon alleen hotspots wanneer er daadwerkelijk op hotspot of actieknop "
+"geklikt word"
+
+#: engines/sherlock/detection.cpp:101
+msgid "Show character portraits"
+msgstr "Toon personage portretfoto's"
+
+#: engines/sherlock/detection.cpp:102
+msgid "Show portraits for the characters when conversing"
+msgstr "Toon portretten van de personages bij het converseren"
+
+#: engines/sherlock/detection.cpp:111
+msgid "Slide dialogs into view"
+msgstr "Schuif dialoogvensters in beeld"
+
+#: engines/sherlock/detection.cpp:112
+msgid "Slide UI dialogs into view, rather than simply showing them immediately"
+msgstr "Schuif dialoogvensters in beeld, in plaats van onmiddellijk tonen"
+
+#: engines/sherlock/detection.cpp:121
+msgid "Transparent windows"
+msgstr "Transparante vensters"
+
+#: engines/sherlock/detection.cpp:122
+msgid "Show windows with a partially transparent background"
+msgstr "Toon vensters met een gedeeltelijk transparante achtergrond"
+
#: engines/sky/compact.cpp:130
msgid ""
"Unable to find \"sky.cpt\" file!\n"
@@ -3492,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"
@@ -3516,50 +3869,41 @@ msgid "Show the current number of frames per second in the upper left corner"
msgstr "Toon de huidige Frames Per Second teller in de linkerbovenhoek"
#: engines/zvision/detection_tables.h:52
-#, fuzzy
msgid "Use the original save/load screens instead of the ScummVM interface"
msgstr ""
-"Gebruik de originele opslaan/laden schermen, in plaats van die van ScummVM"
+"Gebruik de originele opslaan/laden schermen, in plaats van die van de "
+"ScummVM interface"
#: engines/zvision/detection_tables.h:61
msgid "Double FPS"
-msgstr ""
+msgstr "Dubbele FPS"
#: engines/zvision/detection_tables.h:62
msgid "Increase framerate from 30 to 60 FPS"
-msgstr ""
+msgstr "Verhoog framerate van 30 naar 60 FPS"
#: engines/zvision/detection_tables.h:71
-#, fuzzy
msgid "Enable Venus"
-msgstr "Helium-modus aangezet"
+msgstr "Gebruik Venus"
#: engines/zvision/detection_tables.h:72
-#, fuzzy
msgid "Enable the Venus help system"
-msgstr "Helium-modus aangezet"
+msgstr "Gebruik het Venus help systeem"
#: engines/zvision/detection_tables.h:81
msgid "Disable animation while turning"
-msgstr ""
+msgstr "Stop animatie tijdens draaien"
#: engines/zvision/detection_tables.h:82
msgid "Disable animation while turning in panorama mode"
-msgstr ""
+msgstr "Stop animatie tijdens draaien in panorama modus"
#: engines/zvision/detection_tables.h:91
msgid "Use high resolution MPEG video"
-msgstr ""
+msgstr "Gebruik hoge resolutie MPEG video"
#: engines/zvision/detection_tables.h:92
-#, fuzzy
msgid "Use MPEG video from the DVD version, instead of lower resolution AVI"
msgstr ""
-"Gebruik de alternative set van zilveren cursors, in plaats van de normale "
-"gouden"
-
-#~ msgid "EGA undithering"
-#~ msgstr "EGA undithering"
-
-#~ msgid "Enable undithering in EGA games"
-#~ msgstr "Undithering inschakelen in EGA spellen"
+"Gebruik de MPEG video van de DVD versie, in plaats van de lagere resolutie "
+"AVI"
diff --git a/po/nn_NO.po b/po/nn_NO.po
index 35f461e6d2..d52ab96aaf 100644
--- a/po/nn_NO.po
+++ b/po/nn_NO.po
@@ -1,5 +1,5 @@
# Norwegian (Nynorsk) translation for ScummVM.
-# Copyright (C) 2010-2015 The ScummVM Team
+# Copyright (C) 2010-2016 The ScummVM Team
# This file is distributed under the same license as the ScummVM package.
# Einar Johan T. Sømåen <einarjohants@gmail.com>, 2010.
#
@@ -7,9 +7,9 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.3.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2015-09-06 15:14+0200\n"
-"PO-Revision-Date: 2014-07-11 00:04+0100\n"
-"Last-Translator: Einar Johan Trøan Sømåen <einarjohants@gmail.com>\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"
"Language: Norsk (nynorsk)\n"
"MIME-Version: 1.0\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"X-Poedit-SourceCharset: iso-8859-1\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Poedit 1.5.5\n"
+"X-Generator: Poedit 1.8.7\n"
#: gui/about.cpp:94
#, c-format
@@ -54,28 +54,29 @@ msgid "Go up"
msgstr "Oppover"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:74 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: 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/fluidsynth-dialog.cpp:152 engines/engine.cpp:483
-#: backends/platform/wii/options.cpp:48
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
-#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:191 engines/sword1/control.cpp:865
+#: 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 "Avbryt"
#: gui/browser.cpp:76 gui/browser_osx.mm:103 gui/chooser.cpp:47
-#: gui/themebrowser.cpp:56
+#: gui/filebrowser-dialog.cpp:65 gui/themebrowser.cpp:56
msgid "Choose"
msgstr "Vel"
#: gui/editrecorddialog.cpp:58
msgid "Author:"
-msgstr ""
+msgstr "Forfattar:"
#: gui/editrecorddialog.cpp:59 gui/launcher.cpp:204
msgid "Name:"
@@ -83,63 +84,180 @@ msgstr "Namn:"
#: gui/editrecorddialog.cpp:60
msgid "Notes:"
-msgstr ""
+msgstr "Notatar:"
-#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:75
+#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74
msgid "Ok"
+msgstr "Ok"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Choose file for loading"
+msgstr "Vel fil for lasting"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Enter filename for saving"
+msgstr "Skriv inn filnamn for lagring"
+
+#: gui/filebrowser-dialog.cpp:132
+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: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 "Ja"
+
+#: 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 "Nei"
+
+#: gui/fluidsynth-dialog.cpp:68
+msgid "Reverb"
+msgstr "Romklang"
+
+#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
+msgid "Active"
+msgstr "Aktiv"
+
+#: gui/fluidsynth-dialog.cpp:72
+msgid "Room:"
+msgstr "Rom:"
+
+#: gui/fluidsynth-dialog.cpp:79
+msgid "Damp:"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:86
+msgid "Width:"
+msgstr "Bredde:"
+
+#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
+msgid "Level:"
+msgstr "Nivå:"
+
+#: gui/fluidsynth-dialog.cpp:100
+msgid "Chorus"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:104
+msgid "N:"
+msgstr "N:"
+
+#: gui/fluidsynth-dialog.cpp:118
+msgid "Speed:"
+msgstr "Hastighet:"
+
+#: gui/fluidsynth-dialog.cpp:125
+msgid "Depth:"
+msgstr "Dybde:"
+
+#: gui/fluidsynth-dialog.cpp:132
+msgid "Type:"
+msgstr "Type:"
+
+#: gui/fluidsynth-dialog.cpp:135
+msgid "Sine"
+msgstr "Sinus"
+
+#: gui/fluidsynth-dialog.cpp:136
+msgid "Triangle"
+msgstr "Triangel"
+
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
+msgid "Misc"
+msgstr "Diverse"
+
+#: gui/fluidsynth-dialog.cpp:140
+msgid "Interpolation:"
+msgstr "Interpolering:"
+
+#: gui/fluidsynth-dialog.cpp:143
+msgid "None (fastest)"
+msgstr "Ingen (raskast)"
+
+#: gui/fluidsynth-dialog.cpp:144
+msgid "Linear"
+msgstr "Linjær"
+
+#: gui/fluidsynth-dialog.cpp:145
+msgid "Fourth-order"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:146
+msgid "Seventh-order"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset"
+msgstr "Nullstill"
+
+#: gui/fluidsynth-dialog.cpp:150
+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: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 "OK"
+
+#: gui/fluidsynth-dialog.cpp:217
+msgid ""
+"Do you really want to reset all FluidSynth settings to their default values?"
msgstr ""
+"Vil du verkeleg sette alle FluidSynth-innstillingar til standardverdiar?"
-#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
+#: 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 "Steng"
-#: gui/gui-manager.cpp:120
+#: gui/gui-manager.cpp:122
msgid "Mouse click"
msgstr "Musklikk"
-#: gui/gui-manager.cpp:124 base/main.cpp:319
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Syn Tastatur"
-#: gui/gui-manager.cpp:128 base/main.cpp:323
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Omkople tastar"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 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"
-#: gui/KeysDialog.h:36 gui/KeysDialog.cpp:145
-msgid "Choose an action to map"
-msgstr "Vel ei handling for kopling:"
-
#: gui/KeysDialog.cpp:41
msgid "Map"
msgstr "Kople"
-#: gui/KeysDialog.cpp:42 gui/launcher.cpp:352 gui/launcher.cpp:1048
-#: gui/launcher.cpp:1052 gui/massadd.cpp:92 gui/options.cpp:1238
-#: gui/saveload-dialog.cpp:932 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:402 engines/engine.cpp:413
-#: 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/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 "OK"
-
#: gui/KeysDialog.cpp:49
msgid "Select an action and click 'Map'"
msgstr "Vel ei handling, og klikk 'Kople'"
@@ -162,6 +280,10 @@ msgstr "Vel ei handling"
msgid "Press the key to associate"
msgstr "Trykk tasten du vil kople"
+#: gui/KeysDialog.cpp:145 gui/KeysDialog.h:36
+msgid "Choose an action to map"
+msgstr "Vel ei handling for kopling:"
+
#: gui/launcher.cpp:193
msgid "Game"
msgstr "Spel"
@@ -204,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>"
@@ -227,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"
@@ -244,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"
@@ -257,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"
@@ -275,277 +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 ""
+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 ""
+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
-#, fuzzy
+#: gui/launcher.cpp:549
msgid "Select additional game directory"
-msgstr "Vel mappe med speldata"
+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 ""
+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:95
+#: 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:69
+#: 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 ""
+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:1222
+#: 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/myst.cpp:245 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/myst.cpp:245
-#: engines/mohawk/riven.cpp:718 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:792
+#: 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:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Ja"
-
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Nei"
-
-#: gui/launcher.cpp:841
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM kunne ikkje åpne den velde mappa!"
-#: gui/launcher.cpp:853
+#: 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:867
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Vel spelet:"
-#: gui/launcher.cpp:941
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "Vil du verkeleg fjerne denne spelkonfigurasjonen?"
-#: gui/launcher.cpp:999
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "Vil du laste det lagra spelet?"
-#: gui/launcher.cpp:1048
+#: 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:1052
+#: 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:1159
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Legg til fleire..."
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr ""
@@ -568,156 +670,153 @@ msgid "Scanned %d directories ..."
msgstr "Søkt i %d mappar ..."
#: gui/massadd.cpp:269
-#, fuzzy, c-format
+#, c-format
msgid "Discovered %d new games, ignored %d previously added games ..."
-msgstr "Oppdaga %d nye spel ..."
+msgstr ""
+"Oppdaga %d nye spel, ignorerte %d spel som har vorte lagt til tidlegare..."
#: gui/onscreendialog.cpp:101 gui/onscreendialog.cpp:103
msgid "Stop"
-msgstr ""
+msgstr "Stopp"
#: gui/onscreendialog.cpp:106
msgid "Edit record description"
msgstr ""
#: gui/onscreendialog.cpp:108
-#, fuzzy
msgid "Switch to Game"
-msgstr "Bytt"
+msgstr "Bytt til spel"
#: gui/onscreendialog.cpp:110
-#, fuzzy
msgid "Fast replay"
-msgstr "Rask modus"
+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 ""
+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 ""
+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:2298
+#: 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
-#, fuzzy
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Preferred Dev.:"
-msgstr "Føretrukken eining:"
+msgstr ""
-#: gui/options.cpp:771
-#, fuzzy
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Music Device:"
-msgstr "Ingen musikk"
+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"
@@ -725,252 +824,261 @@ 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 ""
+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 ""
+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"
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
-#, fuzzy
+#: gui/options.cpp:891
msgid "Roland GS Device (enable MT-32 mappings)"
-msgstr "Ekte Roland MT-32 (deaktiver GM-emulering)"
+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 ""
+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:1168 gui/fluidsynth-dialog.cpp:138
-msgid "Misc"
-msgstr "Diverse"
-
-#: 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."
@@ -979,64 +1087,75 @@ msgstr ""
"temaet må du bytte til eit anna språk først."
#. I18N: You must leave "#" as is, only word 'next' is translatable
-#: gui/predictivedialog.cpp:87
+#: gui/predictivedialog.cpp:86
msgid "# next"
-msgstr ""
+msgstr "# neste"
-#: gui/predictivedialog.cpp:88
+#: gui/predictivedialog.cpp:87
msgid "add"
msgstr ""
-#: gui/predictivedialog.cpp:92
-#, fuzzy
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
-msgstr "Slett"
+msgstr ""
-#: gui/predictivedialog.cpp:96
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
-msgstr ""
+msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:98
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr ""
-#: gui/recorderdialog.cpp:64
+#. I18N: 'Num' means Numbers
+#: gui/predictivedialog.cpp:578
+msgid "* Num"
+msgstr "* Tal"
+
+#. I18N: 'Abc' means Latin alphabet input
+#: gui/predictivedialog.cpp:581
+msgid "* Abc"
+msgstr "* Abc"
+
+#: 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
-#, fuzzy
+#: gui/recorderdialog.cpp:71
msgid "Playback"
-msgstr "Spel"
+msgstr ""
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
-msgstr ""
+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 ""
+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 ""
+msgstr "Notatar: "
-#: gui/recorderdialog.cpp:155
-#, fuzzy
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
-msgstr "Vil du verkeleg slette det lagra spelet?"
+msgstr ""
+
+#: gui/recorderdialog.cpp:173
+msgid "Unknown Author"
+msgstr "Ukjend Forfattar"
#: gui/saveload-dialog.cpp:167
msgid "List view"
@@ -1098,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 ""
@@ -1107,150 +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:661
+#: 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
-msgid "Clear value"
-msgstr "Tøm verdi"
-
-#: gui/fluidsynth-dialog.cpp:68
-msgid "Reverb"
-msgstr "Romklang"
-
-#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
-msgid "Active"
-msgstr "Aktiv"
-
-#: gui/fluidsynth-dialog.cpp:72
-msgid "Room:"
+#: 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/fluidsynth-dialog.cpp:79
-msgid "Damp:"
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
msgstr ""
-#: gui/fluidsynth-dialog.cpp:86
-msgid "Width:"
-msgstr "Bredde:"
-
-#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
-msgid "Level:"
-msgstr "Nivå:"
-
-#: gui/fluidsynth-dialog.cpp:100
-msgid "Chorus"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:104
-msgid "N:"
-msgstr "N:"
-
-#: gui/fluidsynth-dialog.cpp:118
-msgid "Speed:"
-msgstr "Hastighet:"
-
-#: gui/fluidsynth-dialog.cpp:125
-msgid "Depth:"
-msgstr "Dybde:"
-
-#: gui/fluidsynth-dialog.cpp:132
-msgid "Type:"
-msgstr "Type:"
-
-#: gui/fluidsynth-dialog.cpp:135
-msgid "Sine"
-msgstr "Sinus"
-
-#: gui/fluidsynth-dialog.cpp:136
-msgid "Triangle"
-msgstr "Triangel"
-
-#: gui/fluidsynth-dialog.cpp:140
-msgid "Interpolation:"
-msgstr "Interpolering:"
-
-#: gui/fluidsynth-dialog.cpp:143
-msgid "None (fastest)"
-msgstr "Ingen (raskast)"
-
-#: gui/fluidsynth-dialog.cpp:144
-msgid "Linear"
-msgstr "Linjær"
-
-#: gui/fluidsynth-dialog.cpp:145
-msgid "Fourth-order"
-msgstr ""
+#: gui/updates-dialog.cpp:92
+#, fuzzy
+msgid "Check for updates automatically"
+msgstr "SJå etter oppdateringar..."
-#: gui/fluidsynth-dialog.cpp:146
-msgid "Seventh-order"
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
msgstr ""
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset"
-msgstr "Nullstill"
-
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset all FluidSynth settings to their default values."
-msgstr "Nullstill alle FluidSynth-instillingar til standardverdiar"
-
-#: gui/fluidsynth-dialog.cpp:217
-#, fuzzy
-msgid ""
-"Do you really want to reset all FluidSynth settings to their default values?"
-msgstr "Vil du verkeleg slette det lagra spelet?"
+#: 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:228
+#: 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:306
+#: base/main.cpp:315
msgid "Menu"
msgstr "Meny"
-#: base/main.cpp:309 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:312 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:315
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Hopp over linje"
-#: base/main.cpp:507
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Feil under køyring av spel:"
-#: base/main.cpp:554
+#: 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."
@@ -1312,23 +1366,67 @@ msgstr "Spelmotor-plugin støttar ikkje lagra tilstandar."
#: common/error.cpp:71
msgid "User canceled"
-msgstr ""
+msgstr "Brukar avbraut"
#: common/error.cpp:75
msgid "Unknown error"
msgstr "Ukjend feil"
-#: engines/advancedDetector.cpp:317
+#. I18N: Hercules is graphics card name
+#: common/rendermode.cpp:35
+msgid "Hercules Green"
+msgstr "Hercules Grønn"
+
+#: common/rendermode.cpp:36
+msgid "Hercules Amber"
+msgstr "Hercules Raudgul"
+
+#: common/rendermode.cpp:42
+msgid "PC-9821 (256 Colors)"
+msgstr "PC-9821 (256 Fargar)"
+
+#: common/rendermode.cpp:43
+msgid "PC-9801 (16 Colors)"
+msgstr "PC-9801 (16 Fargar)"
+
+#: common/rendermode.cpp:73
+msgctxt "lowres"
+msgid "Hercules Green"
+msgstr "Hercules Grønn"
+
+#: common/rendermode.cpp:74
+msgctxt "lowres"
+msgid "Hercules Amber"
+msgstr "Hercules Raudgul"
+
+#: 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.:"
@@ -1336,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"
@@ -1365,11 +1463,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "Tilbake til Oppsta~r~tar"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:803
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:873
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
-#: engines/toltecs/menu.cpp:281 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:"
@@ -1378,11 +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:803 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/neverhood/menumodule.cpp:873 engines/pegasus/pegasus.cpp:377
-#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
-#: engines/toltecs/menu.cpp:281 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"
@@ -1392,6 +1499,9 @@ msgid ""
"the README for basic information, and for instructions on how to obtain "
"further assistance."
msgstr ""
+"Orsak, men denne spelmotoren støtter for augeblikket ikkje hjelp i spelet. "
+"Vennlegst se i README-fila for grunnlegjande informasjon, og for "
+"instruksjonar om korleis du kan få ytterlegare hjelp."
#: engines/dialogs.cpp:234 engines/pegasus/pegasus.cpp:393
#, c-format
@@ -1399,14 +1509,17 @@ msgid ""
"Gamestate save failed (%s)! Please consult the README for basic information, "
"and for instructions on how to obtain further assistance."
msgstr ""
+"Speltilstandslagring feila (%s)!. Vennligst sjå i README-fila for "
+"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"
@@ -1414,24 +1527,23 @@ msgstr "~A~vbryt"
msgid "~K~eys"
msgstr "~T~astar"
-#: engines/engine.cpp:276
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
-msgstr ""
+msgstr "Høgkvalitetslyd (treigare) (omstart)"
-#: engines/engine.cpp:284
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Kunne ikkje veksle til videomodus: '"
-#: engines/engine.cpp:293
-#, fuzzy
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
-msgstr "Veksle aspekt-korrigering"
+msgstr "Kunne ikkje slå på aspekt-korrigering"
-#: engines/engine.cpp:298
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
-msgstr ""
+msgstr "Kunne ikkje aktiver fullskjermsinnstilling."
-#: engines/engine.cpp:398
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1439,8 +1551,13 @@ msgid ""
"the data files to your hard disk instead.\n"
"See the README file for details."
msgstr ""
+"Det ser ut til at du speler dette spelet rett frå\n"
+"CD. Dette er kjend for å skape problemar,\n"
+"og det er derfor tilråda at du kopierar\n"
+"datafilane til harddisken din istaden. \n"
+"Sjå README-fila for detaljar."
-#: engines/engine.cpp:409
+#: 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"
@@ -1449,14 +1566,17 @@ msgid ""
"See the README file for details."
msgstr ""
-#: engines/engine.cpp:467
+#: 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 ""
+"Speltilstandslasting feila (%s)!. Vennligst sjå i README-fila for "
+"grunnlegjande informasjon, og for instruskjonar om korleis du kan få "
+"ytterlegare hjelp."
-#: engines/engine.cpp:480
+#: 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 "
@@ -1466,10 +1586,14 @@ 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:483
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Start allikevel"
+#: audio/adlib.cpp:2290
+msgid "AdLib Emulator"
+msgstr "AdLib Emulator"
+
#: audio/fmopl.cpp:62
msgid "MAME OPL emulator"
msgstr "MAME OPL emulator"
@@ -1480,7 +1604,7 @@ msgstr "DOSBox OPL emulator"
#: audio/fmopl.cpp:67
msgid "ALSA Direct FM"
-msgstr ""
+msgstr "ALSA Direct FM"
#: audio/mididrv.cpp:209
#, c-format
@@ -1488,11 +1612,13 @@ msgid ""
"The selected audio device '%s' was not found (e.g. might be turned off or "
"disconnected)."
msgstr ""
+"Den valde lydeininga '%s' vart ikkje funne (t.d. kan den vere avslått eller "
+"fråkopla)"
#: 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 ""
+msgstr "Prøver å nytte den neste tilgjengelege eininga..."
#: audio/mididrv.cpp:221
#, c-format
@@ -1500,6 +1626,8 @@ msgid ""
"The selected audio device '%s' cannot be used. See log file for more "
"information."
msgstr ""
+"Den foretrukne lydeininga '%s' kan ikkje nyttast. Sjå loggfila for meir "
+"informasjon."
#: audio/mididrv.cpp:257
#, c-format
@@ -1507,6 +1635,8 @@ msgid ""
"The preferred audio device '%s' was not found (e.g. might be turned off or "
"disconnected)."
msgstr ""
+"Den foretrukne lydeininga '%s' vart ikkje funne (t.d. kan den vere avslått "
+"eller fråkopla)"
#: audio/mididrv.cpp:272
#, c-format
@@ -1514,33 +1644,38 @@ msgid ""
"The preferred audio device '%s' cannot be used. See log file for more "
"information."
msgstr ""
-
-#: audio/null.h:44
-msgid "No music"
-msgstr "Ingen musikk"
+"Den foretrukne lydeininga '%s' kan ikkje nyttast. Sjå loggfila for meir "
+"informasjon."
#: audio/mods/paula.cpp:196
msgid "Amiga Audio Emulator"
msgstr "Amiga Lydemulator"
-#: audio/adlib.cpp:2291
-msgid "AdLib Emulator"
-msgstr "AdLib Emulator"
+#: audio/null.h:44
+msgid "No music"
+msgstr "Ingen musikk"
#: audio/softsynth/appleiigs.cpp:33
msgid "Apple II GS Emulator (NOT IMPLEMENTED)"
msgstr "Apple II GS Emulator (IKKJE IMPLEMENTERT)"
-#: audio/softsynth/sid.cpp:1430
-msgid "C64 Audio Emulator"
-msgstr "C64 Lydemulator"
+#: audio/softsynth/cms.cpp:350
+msgid "Creative Music System Emulator"
+msgstr "Creative Music System Emulator"
-#: audio/softsynth/mt32.cpp:200
-#, fuzzy
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33
+msgid "FM-Towns Audio"
+msgstr "FM-Towns Lyd"
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58
+msgid "PC-98 Audio"
+msgstr "PC-98 Lyd"
+
+#: audio/softsynth/mt32.cpp:196
msgid "Initializing MT-32 Emulator"
-msgstr "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"
@@ -1552,14 +1687,153 @@ msgstr "PC Speaker Emulator"
msgid "IBM PCjr Emulator"
msgstr "IBM PCjr Emulator"
+#: audio/softsynth/sid.cpp:1430
+msgid "C64 Audio Emulator"
+msgstr "C64 Lydemulator"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Do you really want to return to the Launcher?"
+msgstr "Vil du verkeleg gå tilbake til oppstartaren?"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Launcher"
+msgstr "Oppstartar"
+
+#: backends/events/default/default-events.cpp:218
+msgid "Do you really want to quit?"
+msgstr "Vil du verkeleg avslutte?"
+
+#: 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 "Avslutt"
+
+#: 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 "Touchscreen 'Tap Mode' - Venstreklikk"
+
+#: 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 "Touchscreen 'Tap Mode' - Høgreklikk"
+
+#: 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 ""
+
+#: backends/events/gph/gph-events.cpp:409
+msgid "Maximum Volume"
+msgstr "Maks Volum"
+
+#: backends/events/gph/gph-events.cpp:411
+msgid "Increasing Volume"
+msgstr "Auker Volum"
+
+#: backends/events/gph/gph-events.cpp:417
+msgid "Minimal Volume"
+msgstr "Minste Volum"
+
+#: backends/events/gph/gph-events.cpp:419
+msgid "Decreasing Volume"
+msgstr "Senkar Volum"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Enabled"
+msgstr "Klikking aktivert"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Disabled"
+msgstr "Klikking Deaktivert"
+
+#: backends/events/openpandora/op-events.cpp:174
+msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
+msgstr ""
+
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
+msgid "Do you want to quit ?"
+msgstr "Vil du avslutte?"
+
+#. I18N: Trackpad mode toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:308
+msgid "Trackpad mode is now"
+msgstr "Trackpadmodus er no"
+
+#. 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 "PÅ"
+
+#: backends/events/webossdl/webossdl-events.cpp:311
+#: backends/events/webossdl/webossdl-events.cpp:338
+msgid "OFF"
+msgstr "AV"
+
+#: backends/events/webossdl/webossdl-events.cpp:315
+msgid "Swipe two fingers to the right to toggle."
+msgstr ""
+
+#. I18N: Auto-drag toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:335
+msgid "Auto-drag mode is now"
+msgstr ""
+
+#: backends/events/webossdl/webossdl-events.cpp:342
+msgid "Swipe three fingers to the right to toggle."
+msgstr "Sveip tre fingre til høgre for å veksle"
+
+#: backends/graphics/opengl/opengl-graphics.cpp:126
+msgid "OpenGL"
+msgstr "OpenGL"
+
+#: backends/graphics/opengl/opengl-graphics.cpp:127
+msgid "OpenGL (No filtering)"
+msgstr "OpenGL (Ingen filtrering)"
+
+#: 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 "Normal (ikkje skaler)"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:66
+msgctxt "lowres"
+msgid "Normal (no scaling)"
+msgstr "Normal (ikkje skaler)"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
+msgid "Enabled aspect ratio correction"
+msgstr "Aspekt-korrigering aktivert"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
+msgid "Disabled aspect ratio correction"
+msgstr "Aspekt-korrigering ikkje aktivert"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
+msgid "Active graphics filter:"
+msgstr "Aktivt grafikkfilter:"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+msgid "Windowed mode"
+msgstr "Vindusmodus"
+
#: backends/keymapper/remap-dialog.cpp:48
msgid "Keymap:"
msgstr "Tastkopling:"
#: backends/keymapper/remap-dialog.cpp:67
-#, fuzzy
msgid " (Effective)"
-msgstr " (Aktivt)"
+msgstr ""
#: backends/keymapper/remap-dialog.cpp:107
msgid " (Active)"
@@ -1582,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"
@@ -1658,23 +1932,29 @@ msgstr ""
msgid "Disable power off"
msgstr "Deaktiver strømsparing"
+#: 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 ""
+#: 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 ""
+#: backends/platform/ios7/ios7_osys_events.cpp:322
+#: backends/platform/ios7/ios7_osys_events.cpp:540
#: backends/platform/iphone/osys_events.cpp:313
-#, fuzzy
msgid "Touchpad mode enabled."
-msgstr "~O~vergangar aktivert"
+msgstr "Touchpadmodus påslått."
+#: backends/platform/ios7/ios7_osys_events.cpp:324
+#: backends/platform/ios7/ios7_osys_events.cpp:542
#: backends/platform/iphone/osys_events.cpp:315
-#, fuzzy
msgid "Touchpad mode disabled."
-msgstr "Deaktivert GFX"
+msgstr "Touchpadmodus avslått."
#: backends/platform/maemo/maemo.cpp:208
msgid "Click Mode"
@@ -1682,9 +1962,9 @@ msgstr "Klikkmodus"
#: 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
-#: backends/platform/tizen/form.cpp:275
msgid "Left Click"
msgstr "Venstreklikk"
@@ -1694,67 +1974,32 @@ msgstr "Midtklikk"
#: backends/platform/maemo/maemo.cpp:220
#: backends/platform/symbian/src/SymbianActions.cpp:43
-#: backends/platform/wince/CEActionsSmartphone.cpp:44
#: backends/platform/tizen/form.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:44
msgid "Right Click"
msgstr "Høgreklikk"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:77
+#: backends/platform/sdl/macosx/appmenu_osx.mm:88
msgid "Hide ScummVM"
msgstr "Skjul ScummVM"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:82
+#: backends/platform/sdl/macosx/appmenu_osx.mm:93
msgid "Hide Others"
msgstr "Skjul Andre"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:87
+#: backends/platform/sdl/macosx/appmenu_osx.mm:98
msgid "Show All"
msgstr "Syn alle"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:109
#: backends/platform/sdl/macosx/appmenu_osx.mm:120
+#: backends/platform/sdl/macosx/appmenu_osx.mm:131
msgid "Window"
msgstr "Vindu"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:114
+#: backends/platform/sdl/macosx/appmenu_osx.mm:125
msgid "Minimize"
msgstr "Minimer"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:46
-msgid "Normal (no scaling)"
-msgstr "Normal (ikkje skaler)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:65
-msgctxt "lowres"
-msgid "Normal (no scaling)"
-msgstr "Normal (ikkje skaler)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
-#, fuzzy
-msgid "Enabled aspect ratio correction"
-msgstr "Aspekt-korrigering"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
-#, fuzzy
-msgid "Disabled aspect ratio correction"
-msgstr "Aspekt-korrigering"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
-msgid "Active graphics filter:"
-msgstr "Aktivt grafikkfilter:"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
-msgid "Windowed mode"
-msgstr "Vindusmodus"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:118
-msgid "OpenGL"
-msgstr "OpenGL"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:119
-msgid "OpenGL (No filtering)"
-msgstr "OpenGL (Ingen filtrering)"
-
#: backends/platform/symbian/src/SymbianActions.cpp:38
#: backends/platform/wince/CEActionsSmartphone.cpp:39
msgid "Up"
@@ -1784,29 +2029,20 @@ msgstr "Sone"
#: backends/platform/wince/CEActionsPocket.cpp:54
#: backends/platform/wince/CEActionsSmartphone.cpp:48
msgid "Multi Function"
-msgstr ""
+msgstr "Multifunksjon"
#: backends/platform/symbian/src/SymbianActions.cpp:48
msgid "Swap character"
-msgstr ""
+msgstr "Bytt karakter"
#: backends/platform/symbian/src/SymbianActions.cpp:49
-#, fuzzy
msgid "Skip text"
-msgstr "Hopp over tekstlinje"
+msgstr "Hopp over tekst"
#: backends/platform/symbian/src/SymbianActions.cpp:51
msgid "Fast mode"
msgstr "Rask modus"
-#: backends/platform/symbian/src/SymbianActions.cpp:52
-#: backends/platform/wince/CEActionsPocket.cpp:44
-#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: backends/events/default/default-events.cpp:218 engines/scumm/dialogs.cpp:192
-#: engines/scumm/help.cpp:83 engines/scumm/help.cpp:85
-msgid "Quit"
-msgstr "Avslutt"
-
#: backends/platform/symbian/src/SymbianActions.cpp:53
msgid "Debugger"
msgstr "Debugger"
@@ -1823,9 +2059,49 @@ msgstr "Virtuelt tastatur"
msgid "Key mapper"
msgstr "Tastkopler"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:186
-msgid "Do you want to quit ?"
-msgstr "Vil du avslutte?"
+#: backends/platform/tizen/form.cpp:263
+msgid "Right Click Once"
+msgstr "Høgreklikk ein gong"
+
+#: backends/platform/tizen/form.cpp:271
+msgid "Move Only"
+msgstr ""
+
+#: backends/platform/tizen/form.cpp:294
+msgid "Escape Key"
+msgstr "Escape Tast"
+
+#: backends/platform/tizen/form.cpp:299
+msgid "Game Menu"
+msgstr "Spelmeny"
+
+#: backends/platform/tizen/form.cpp:304
+msgid "Show Keypad"
+msgstr "Syn taltastatur"
+
+#: backends/platform/tizen/form.cpp:309
+msgid "Control Mouse"
+msgstr ""
+
+#: backends/platform/tizen/fs.cpp:259
+msgid "[ Data ]"
+msgstr "[ Data ]"
+
+#: backends/platform/tizen/fs.cpp:263
+msgid "[ Resources ]"
+msgstr "[ Ressursar ]"
+
+#: backends/platform/tizen/fs.cpp:267
+msgid "[ SDCard ]"
+msgstr "[ SDKort ]"
+
+#: backends/platform/tizen/fs.cpp:271
+msgid "[ Media ]"
+msgstr "[ Media ]"
+
+#: backends/platform/tizen/fs.cpp:275
+msgid "[ Shared ]"
+msgstr "[ Delt ]"
#: backends/platform/wii/options.cpp:51
msgid "Video"
@@ -1852,9 +2128,8 @@ msgid "Input"
msgstr "Input"
#: backends/platform/wii/options.cpp:74
-#, fuzzy
msgid "GC Pad sensitivity:"
-msgstr "Sensitivitet"
+msgstr "GC Pad Sensitivitet"
#: backends/platform/wii/options.cpp:80
msgid "GC Pad acceleration:"
@@ -1889,9 +2164,8 @@ msgid "Server:"
msgstr "Teinar:"
#: backends/platform/wii/options.cpp:110
-#, fuzzy
msgid "Share:"
-msgstr ", delt ressurs ikkje montert"
+msgstr "Delt:"
#: backends/platform/wii/options.cpp:114
msgid "Username:"
@@ -1934,9 +2208,8 @@ msgid "Network up"
msgstr "Nettverket er oppe"
#: backends/platform/wii/options.cpp:166
-#, fuzzy
msgid ", error while mounting the share"
-msgstr "Feil under montering av DVD"
+msgstr ", feil under montering av delt ressurs"
#: backends/platform/wii/options.cpp:168
msgid ", share not mounted"
@@ -1947,19 +2220,17 @@ msgid "Network down"
msgstr "Nettverket er nede"
#: backends/platform/wii/options.cpp:178
-#, fuzzy
msgid "Initializing network"
-msgstr "Init nettverk"
+msgstr "Initialiserar nettverk"
#: backends/platform/wii/options.cpp:182
-#, fuzzy
msgid "Timeout while initializing network"
-msgstr "Initialiserer nettverk"
+msgstr ""
#: backends/platform/wii/options.cpp:186
-#, fuzzy, c-format
+#, c-format
msgid "Network not initialized (%d)"
-msgstr "Init nettverk"
+msgstr "Nettverk ikkje initialisert (%d)"
#: backends/platform/wince/CEActionsPocket.cpp:46
msgid "Hide Toolbar"
@@ -2076,118 +2347,45 @@ msgstr ""
"Ikkje gløym å kople ein tast til 'Skjul verktøylinje' for å se heile "
"inventaret"
-#: backends/events/default/default-events.cpp:196
-msgid "Do you really want to return to the Launcher?"
-msgstr "Vil du verkeleg gå tilbake til oppstartaren?"
-
-#: backends/events/default/default-events.cpp:196
-msgid "Launcher"
-msgstr "Oppstartar"
-
-#: backends/events/default/default-events.cpp:218
-msgid "Do you really want to quit?"
-msgstr "Vil du verkeleg avslutte?"
-
-#: backends/events/gph/gph-events.cpp:385
-#: backends/events/gph/gph-events.cpp:428
-#: backends/events/openpandora/op-events.cpp:168
-#, fuzzy
-msgid "Touchscreen 'Tap Mode' - Left Click"
-msgstr "Tap for venstre-klikk, dobbelt-tap for høgre-klikk"
-
-#: backends/events/gph/gph-events.cpp:387
-#: backends/events/gph/gph-events.cpp:430
-#: backends/events/openpandora/op-events.cpp:170
-#, fuzzy
-msgid "Touchscreen 'Tap Mode' - Right Click"
-msgstr "Tap for venstre-klikk, dobbelt-tap for høgre-klikk"
-
-#: 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 ""
-
-#: backends/events/gph/gph-events.cpp:409
-msgid "Maximum Volume"
-msgstr "Maks Volum"
-
-#: backends/events/gph/gph-events.cpp:411
-#, fuzzy
-msgid "Increasing Volume"
-msgstr "Volum"
-
-#: backends/events/gph/gph-events.cpp:417
-#, fuzzy
-msgid "Minimal Volume"
-msgstr "Volum"
-
-#: backends/events/gph/gph-events.cpp:419
-#, fuzzy
-msgid "Decreasing Volume"
-msgstr "Volum"
-
-#: backends/events/openpandora/op-events.cpp:174
-msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
-msgstr ""
-
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "SJå etter oppdateringar..."
-#: backends/platform/tizen/form.cpp:263
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
#, fuzzy
-msgid "Right Click Once"
-msgstr "Høgreklikk"
+msgid "Color mode"
+msgstr "Fargeblindmodus"
-#: backends/platform/tizen/form.cpp:271
-#, fuzzy
-msgid "Move Only"
-msgstr "Tale"
-
-#: backends/platform/tizen/form.cpp:294
-msgid "Escape Key"
-msgstr "Escape Tast"
-
-#: backends/platform/tizen/form.cpp:299
-msgid "Game Menu"
-msgstr "Spelmeny"
-
-#: backends/platform/tizen/form.cpp:304
-msgid "Show Keypad"
-msgstr "Syn taltastatur"
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
-#: backends/platform/tizen/form.cpp:309
-#, fuzzy
-msgid "Control Mouse"
-msgstr "Musklikk"
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
+#: engines/adl/detection.cpp:64
#, fuzzy
-msgid "Clicking Enabled"
-msgstr "~O~vergangar aktivert"
-
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Disabled"
-msgstr "Klikking Deaktivert"
+msgid "Show scanlines"
+msgstr "Syn objektmerkelappar"
-#: engines/agi/detection.cpp:147 engines/drascula/detection.cpp:302
-#: engines/dreamweb/detection.cpp:47 engines/neverhood/detection.cpp:160
-#: engines/sci/detection.cpp:394 engines/toltecs/detection.cpp:200
-#: engines/zvision/detection_tables.h:51
+#: 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 "Nytt opprinnelege skjermar for lagring/lasting"
-#: engines/agi/detection.cpp:148 engines/drascula/detection.cpp:303
-#: engines/dreamweb/detection.cpp:48 engines/neverhood/detection.cpp:161
-#: engines/sci/detection.cpp:395 engines/toltecs/detection.cpp:201
+#: 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 ""
#: engines/agi/detection.cpp:157
-#, fuzzy
msgid "Use an alternative palette"
-msgstr "Nytt diskettversjonens åpning (Kun CD-versjon)"
+msgstr "Nytt ein alternativ palett"
#: engines/agi/detection.cpp:158
msgid ""
@@ -2196,28 +2394,54 @@ msgid ""
msgstr ""
#: engines/agi/detection.cpp:167
-#, fuzzy
msgid "Mouse support"
-msgstr "Hopp over"
+msgstr "Musstøtte"
#: engines/agi/detection.cpp:168
msgid ""
"Enables mouse support. Allows to use mouse for movement and in game menus."
msgstr ""
-#: engines/agi/saveload.cpp:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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"
@@ -2225,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"
@@ -2233,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"
@@ -2241,19 +2465,18 @@ msgid ""
"%s"
msgstr ""
-#: engines/agos/animation.cpp:557
+#: engines/agos/animation.cpp:558
#, c-format
msgid "Cutscene file '%s' not found!"
msgstr ""
#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
-#, fuzzy
msgid "Color Blind Mode"
-msgstr "Klikkmodus"
+msgstr "Fargeblindmodus"
#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
-msgstr ""
+msgstr "Slå på fargeblindmodus som standard"
#: engines/drascula/saveload.cpp:47
msgid ""
@@ -2265,22 +2488,28 @@ msgid ""
"Press OK to convert them now, otherwise you will be asked again the next "
"time you start the game.\n"
msgstr ""
+"ScummVM oppdaga at du har gamle spellagringar for Drascula som vi kan "
+"konvertere.\n"
+"Det gamle spellagringsformatet er ikkje lenger støtta, så du vil ikkje vere "
+"i stand til å laste dei om du ikkje konverterar dei\n"
+"\n"
+"Trykk OK for å konvertere dei no, ellers kjem du til å verte spurt neste "
+"gong du startar spelet.\n"
-#: engines/dreamweb/detection.cpp:57
-#, fuzzy
+#: engines/dreamweb/detection.cpp:58
msgid "Use bright palette mode"
-msgstr "Øvre høgre gjenstand"
+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."
@@ -2290,26 +2519,24 @@ msgid "Failed to delete file."
msgstr "Klarte ikkje slette fil."
#: engines/groovie/detection.cpp:312
-#, fuzzy
msgid "Fast movie speed"
-msgstr "Rask modus"
+msgstr "Rask filmfart"
#: engines/groovie/detection.cpp:313
msgid "Play movies at an increased speed"
msgstr "Spel filmar med auka hastighet"
-#: engines/groovie/script.cpp:408
-#, fuzzy
+#: engines/groovie/script.cpp:407
msgid "Failed to save game"
-msgstr "Lagra spel:"
+msgstr "Klarte ikkje lagre spel"
#: engines/hopkins/detection.cpp:76 engines/hopkins/detection.cpp:86
msgid "Gore Mode"
-msgstr ""
+msgstr "Gørrmodus"
#: engines/hopkins/detection.cpp:77 engines/hopkins/detection.cpp:87
msgid "Enable Gore Mode when available"
-msgstr ""
+msgstr "Slå på gørrmodus når tilgjengeleg"
#. I18N: Studio audience adds an applause and cheering sounds whenever
#. Malcolm makes a joke.
@@ -2323,46 +2550,42 @@ msgstr "Aktiver studiopublikum"
#. I18N: This option allows the user to skip text and cutscenes.
#: engines/kyra/detection.cpp:73
-#, fuzzy
msgid "Skip support"
-msgstr "Hopp over"
+msgstr "Hopp over-støtte"
#: engines/kyra/detection.cpp:74
msgid "Allow text and cutscenes to be skipped"
-msgstr ""
+msgstr "Tillat å hoppe over tekst og cutscenes"
#. I18N: Helium mode makes people sound like they've inhaled Helium.
#: engines/kyra/detection.cpp:84
-#, fuzzy
msgid "Helium mode"
-msgstr "Grafikkmodus:"
+msgstr "Heliummodus"
#: engines/kyra/detection.cpp:85
-#, fuzzy
msgid "Enable helium mode"
-msgstr "Grafikkmodus:"
+msgstr "Slå på heliummodus"
#. I18N: When enabled, this option makes scrolling smoother when
#. changing from one screen to another.
#: engines/kyra/detection.cpp:99
msgid "Smooth scrolling"
-msgstr ""
+msgstr "Mjuk rulling"
#: engines/kyra/detection.cpp:100
msgid "Enable smooth scrolling when walking"
-msgstr ""
+msgstr "Slå på mjuk rulling under gåing"
#. 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
-#, fuzzy
msgid "Floating cursors"
-msgstr "Vanleg peikar"
+msgstr "Flytande peikarar"
#: engines/kyra/detection.cpp:113
msgid "Enable floating cursors"
-msgstr ""
+msgstr "Slå på flytande peikarar"
#. I18N: HP stands for Hit Points
#: engines/kyra/detection.cpp:127
@@ -2374,61 +2597,52 @@ msgid "Enable hit point bar graphs"
msgstr ""
#: engines/kyra/lol.cpp:478
-#, fuzzy
msgid "Attack 1"
-msgstr "byttast 7, 4, og 1 med"
+msgstr "Åtak 1"
#: engines/kyra/lol.cpp:479
msgid "Attack 2"
-msgstr ""
+msgstr "Åtak 2"
#: engines/kyra/lol.cpp:480
-#, fuzzy
msgid "Attack 3"
-msgstr "9, 6, og 3, henhaldsvis."
+msgstr "Åtak 3"
#: engines/kyra/lol.cpp:481
msgid "Move Forward"
-msgstr ""
+msgstr "Beveg Framover"
#: engines/kyra/lol.cpp:482
-#, fuzzy
msgid "Move Back"
-msgstr "Bakoversteg"
+msgstr "Beveg Bakover"
#: engines/kyra/lol.cpp:483
-#, fuzzy
msgid "Slide Left"
-msgstr "Venstre"
+msgstr "Skli til Venstre"
#: engines/kyra/lol.cpp:484
-#, fuzzy
msgid "Slide Right"
-msgstr "Høgre"
+msgstr "Skli til Høyre"
#: engines/kyra/lol.cpp:485 engines/pegasus/pegasus.cpp:2509
-#, fuzzy
msgid "Turn Left"
-msgstr "Slå på"
+msgstr "Snu til Venstre"
#: engines/kyra/lol.cpp:486 engines/pegasus/pegasus.cpp:2510
-#, fuzzy
msgid "Turn Right"
-msgstr "Slå på"
+msgstr "Snu til Høyre"
#: engines/kyra/lol.cpp:487
-#, fuzzy
msgid "Rest"
-msgstr "Gjenopprett"
+msgstr "Kvil"
#: engines/kyra/lol.cpp:488
msgid "Options"
msgstr "Val"
#: engines/kyra/lol.cpp:489
-#, fuzzy
msgid "Choose Spell"
-msgstr "Vel"
+msgstr ""
#: engines/kyra/sound_midi.cpp:477
msgid ""
@@ -2468,50 +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
-#, fuzzy
+#: engines/mohawk/dialogs.cpp:181
msgid "~D~rop Page"
-msgstr "Søkt i %d mappar ..."
+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"
@@ -2520,15 +2743,23 @@ msgstr ""
"Kan ikkje lagre spel i spor %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:194
+msgid "Load file"
+msgstr "Last fil:"
+
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Lastar spel..."
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:209
+msgid "Save file"
+msgstr "Lagra fil:"
+
+#: 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"
@@ -2538,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"
@@ -2559,9 +2790,8 @@ msgid "Up/Zoom In/Move Forward/Open Doors"
msgstr ""
#: engines/pegasus/pegasus.cpp:2508
-#, fuzzy
msgid "Down/Zoom Out"
-msgstr "Zoom ned"
+msgstr "Ned/Zoom Ut"
#: engines/pegasus/pegasus.cpp:2511
msgid "Display/Hide Inventory Tray"
@@ -2572,9 +2802,8 @@ msgid "Display/Hide Biochip Tray"
msgstr ""
#: engines/pegasus/pegasus.cpp:2513
-#, fuzzy
msgid "Action/Select"
-msgstr "Vel ei handling, og klikk 'Kople'"
+msgstr "Handling/Vel"
#: engines/pegasus/pegasus.cpp:2514
msgid "Toggle Center Data Display"
@@ -2590,183 +2819,205 @@ msgstr "Skjul/Vis pausemeny"
#: engines/queen/detection.cpp:56
msgid "Alternative intro"
-msgstr ""
+msgstr "Alternativ intro"
#: engines/queen/detection.cpp:57
-#, fuzzy
msgid "Use an alternative game intro (CD version only)"
-msgstr "Nytt diskettversjonens åpning (Kun CD-versjon)"
+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:395
+msgid "Enable high resolution graphics/content"
+msgstr "Nytt høgoppløyseleg grafikk/innhald"
+
+#: 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:385
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
msgstr ""
-#: engines/sci/detection.cpp:404
+#: 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:405
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
msgstr ""
+"Nytt eit IBM Music Feature-kort eller ein Yamaha FB-01 FM synth modul for "
+"MIDI avspeling"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "Nytt CD-lyd"
-#: engines/sci/detection.cpp:416
+#: 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:426
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Nytt Windospeikarar"
-#: engines/sci/detection.cpp:427
+#: 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:437
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Nytt sølvpeikarar"
-#: engines/sci/detection.cpp:438
+#: 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 ""
+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
-#, fuzzy
+#: 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 (Y/N)?"
+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
-#, fuzzy
+#: 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 (Y/N)?"
+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
-#, fuzzy
+#: engines/scumm/dialogs.cpp:190
msgid "Insert save/load game disk"
-msgstr "Vil du åpne eller lagre spelet?"
+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
-#, fuzzy
+#: engines/scumm/dialogs.cpp:192
msgid "The game was NOT saved (disk full?)"
-msgstr "Full speltittel:"
+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:600
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Berre Tale"
-#: engines/scumm/dialogs.cpp:601
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Tale og undertekstar"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Berre undertekstar"
-#: engines/scumm/dialogs.cpp:610
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Tekst & Tale"
-#: engines/scumm/dialogs.cpp:656
-#, fuzzy
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
-msgstr "Gå til forrige mappenivå"
+msgstr ""
-#: engines/scumm/dialogs.cpp:658
+#: 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:662
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
-msgstr ""
+msgstr "Øving"
-#: engines/scumm/dialogs.cpp:663
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Ekspert"
@@ -2897,9 +3148,8 @@ msgid " since they may cause crashes"
msgstr " dei kan forårsake kræsj og"
#: engines/scumm/help.cpp:111
-#, fuzzy
msgid " or incorrect game behavior."
-msgstr "Spel"
+msgstr " eller feilaktig speloppførsel."
#: engines/scumm/help.cpp:115
msgid "Spinning drafts on the keyboard:"
@@ -3304,35 +3554,106 @@ msgstr "Fly til høgre"
msgid "Fly to lower right"
msgstr "Fly til nedre høgre"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/input.cpp:578
+msgid "Snap scroll on"
+msgstr ""
+
+#: engines/scumm/input.cpp:580
+msgid "Snap scroll off"
+msgstr ""
+
+#: engines/scumm/input.cpp:593
+msgid "Music volume: "
+msgstr "Musikkvolum:"
+
+#: engines/scumm/input.cpp:610
+msgid "Subtitle speed: "
+msgstr "Subtitle speed: "
+
+#: 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
-#, fuzzy
+#: 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 ""
-"Opprinneleg, skulle Maniac Mansion ha starta no. Men ScummVM støttar ikkje "
-"det enno. For å spele Maniac Mansion, gå til 'Legg til spel' i ScummVM-"
-"menyen og vel 'Maniac'-undermappa i 'Tentacle'-mappa."
+"Opprinneleg, skulle Maniac Mansion ha starta no. Men for at det skal virke "
+"må du ha datafilane til Maniac Mansion i «Maniac»-mappa inni «Tentacle»-"
+"spelmappa, og spelet må vere lagt til i ScummVM."
#: 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 ""
+"Kunne ikkje finne Macintosh-binærfila «Loom» for å lese\n"
+"instrumenter frå den. Musikk vert deaktivert."
#: 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 ""
+"Kunne ikkje finne Macintosh-binærfila «Monkey Island» for å lese\n"
+"instrumentar frå den. Musikk vert deaktivert."
+
+#: engines/sherlock/detection.cpp:71
+msgid "Use original savegame dialog"
+msgstr "Nytt opprinnelege skjerm for lagring/lasting"
+
+#: engines/sherlock/detection.cpp:72
+msgid ""
+"Files button in-game shows original savegame dialog rather than the ScummVM "
+"menu"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:81
+msgid "Pixellated scene transitions"
+msgstr "Pikselerte sceneovergangar"
+
+#: engines/sherlock/detection.cpp:82
+msgid "When changing scenes, a randomized pixel transition is done"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:91
+msgid "Don't show hotspots when moving mouse"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:92
+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"
+msgstr "Syn karakterportrettar"
+
+#: engines/sherlock/detection.cpp:102
+msgid "Show portraits for the characters when conversing"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:111
+msgid "Slide dialogs into view"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:112
+msgid "Slide UI dialogs into view, rather than simply showing them immediately"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:121
+msgid "Transparent windows"
+msgstr "Gjennomsiktige vindauge"
+
+#: engines/sherlock/detection.cpp:122
+msgid "Show windows with a partially transparent background"
+msgstr ""
#: engines/sky/compact.cpp:130
msgid ""
@@ -3359,21 +3680,21 @@ msgstr "Nytt diskettversjonens åpning (Kun CD-versjon)"
#: engines/sword1/animation.cpp:524
#, c-format
msgid "PSX stream cutscene '%s' cannot be played in paletted mode"
-msgstr ""
+msgstr "PSX strømme cutscene '%s' kan ikkje avspelast i pallettmodus"
#: engines/sword1/animation.cpp:545 engines/sword2/animation.cpp:445
msgid "DXA cutscenes found but ScummVM has been built without zlib"
-msgstr ""
+msgstr "DXA cutscenar funne, men ScummVM vart bygd utan zlib"
#: 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 ""
+msgstr "MPEG-2 cutscenar funne, men ScummVM er bygd utan MPEG-2 støtte"
#: engines/sword1/animation.cpp:568 engines/sword2/animation.cpp:470
-#, fuzzy, c-format
+#, c-format
msgid "Cutscene '%s' not found"
-msgstr "Hopp over cutscene"
+msgstr "Cutscene '%s' ikkje funne"
#: engines/sword1/control.cpp:863
msgid ""
@@ -3385,6 +3706,13 @@ msgid ""
"Press OK to convert them now, otherwise you will be asked again the next "
"time you start the game.\n"
msgstr ""
+"ScummVM oppdaga at du har gamle lagra speltilstandar for Broken Sword 1 som "
+"vi kan konvertere.\n"
+"Det gamle formatet for lagra speltilstandar støttast ikkje lengre, så du vil "
+"ikkje kunne laste dei utan å konvertere dei.\n"
+"\n"
+"Trykk OK for å konvertere dei no, ellers vil du bli spurt igjen neste gong "
+"du starter spelet.\n"
#: engines/sword1/control.cpp:1232
#, c-format
@@ -3392,6 +3720,9 @@ 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 ""
+"Målet for den lagrede speltilstanden finst!\n"
+"Vil du ta vare på den gamle tilstanden (%s) eller den nye (%s)?\n"
+" \n"
#: engines/sword1/control.cpp:1235
msgid "Keep the old one"
@@ -3408,75 +3739,86 @@ msgstr "Dette er slutten på Broken Sword 1-demoen"
#: engines/sword2/animation.cpp:425
msgid ""
"PSX cutscenes found but ScummVM has been built without RGB color support"
-msgstr ""
+msgstr "PSX cutscenar vart funne, men ScummVM er bygd utan RGB fargestøtte"
#: engines/sword2/sword2.cpp:79
-#, fuzzy
msgid "Show object labels"
-msgstr "Objekt"
+msgstr "Syn objektmerkelappar"
#: engines/sword2/sword2.cpp:80
msgid "Show labels for objects on mouse hover"
+msgstr "Syn merkelappar for objekt når musa er over dei"
+
+#: engines/sword25/detection.cpp:46
+msgid "Use English speech"
msgstr ""
-#: engines/teenagent/resources.cpp:95
+#: 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"
msgstr ""
+"Fila teenagent.dat er komprimert og zlib er ikkje inkludert i binærfila, "
+"vennlegs dekomprimer den."
#: engines/wintermute/detection.cpp:58
msgid "Show FPS-counter"
-msgstr ""
+msgstr "Syn FPS-teller"
#: engines/wintermute/detection.cpp:59
msgid "Show the current number of frames per second in the upper left corner"
msgstr ""
+"Vis det gjeldande antall bilete per sekund i øvre venstre hjørne av skjermen"
#: engines/zvision/detection_tables.h:52
-#, fuzzy
msgid "Use the original save/load screens instead of the ScummVM interface"
-msgstr "Nytt opprinnelege skjermar for lagring/lasting"
+msgstr ""
+"Nytt opprinnelege skjermar for lagring/lasting istadenfor ScummVM "
+"grensesnittet"
#: engines/zvision/detection_tables.h:61
msgid "Double FPS"
-msgstr ""
+msgstr "Dobbel FPS"
#: engines/zvision/detection_tables.h:62
msgid "Increase framerate from 30 to 60 FPS"
-msgstr ""
+msgstr "Auk bilderate frå 30 til 60 FPS"
#: engines/zvision/detection_tables.h:71
-#, fuzzy
msgid "Enable Venus"
-msgstr "Grafikkmodus:"
+msgstr "Slå på Venus"
#: engines/zvision/detection_tables.h:72
-#, fuzzy
msgid "Enable the Venus help system"
-msgstr "Grafikkmodus:"
+msgstr "Slå på Venus-hjelpesystemet"
#: engines/zvision/detection_tables.h:81
msgid "Disable animation while turning"
-msgstr ""
+msgstr "Slå av animasjonar under snuing"
#: engines/zvision/detection_tables.h:82
msgid "Disable animation while turning in panorama mode"
-msgstr ""
+msgstr "Slå av animasjonar under snuing i panoramamodus"
#: engines/zvision/detection_tables.h:91
msgid "Use high resolution MPEG video"
-msgstr ""
+msgstr "Nytt høgoppløyseleg MPEG-video"
#: engines/zvision/detection_tables.h:92
-#, fuzzy
msgid "Use MPEG video from the DVD version, instead of lower resolution AVI"
-msgstr "Nytt det alternative settet med sølvpeikarar, istaden for dei gylne"
+msgstr ""
+"Nytt MPEG video frå DVD-versjonen, framfor AVI-versjonen med lågare "
+"oppløysning"
#~ msgctxt "lowres"
#~ msgid "Mass Add..."
@@ -3502,27 +3844,6 @@ msgstr "Nytt det alternative settet med sølvpeikarar, istaden for dei gylne"
#~ msgid "Current display mode"
#~ msgstr "Gjeldende videomodus:"
-#~ msgid "Enable Roland GS Mode"
-#~ msgstr "Aktiver Roland GS-modus"
-
-#~ msgid "Hercules Green"
-#~ msgstr "Hercules Grønn"
-
-#~ msgid "Hercules Amber"
-#~ msgstr "Hercules Raudgul"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Green"
-#~ msgstr "Hercules Grønn"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Amber"
-#~ msgstr "Hercules Raudgul"
-
-#, fuzzy
-#~ msgid "Save game failed!"
-#~ msgstr "Lagra spel:"
-
#~ msgctxt "lowres"
#~ msgid "Add Game..."
#~ msgstr "Legg til spill..."
@@ -3533,8 +3854,5 @@ msgstr "Nytt det alternative settet med sølvpeikarar, istaden for dei gylne"
#~ msgid "Discovered %d new games."
#~ msgstr "Oppdaga %d nye spel."
-#~ msgid "FM Towns Emulator"
-#~ msgstr "FM Towns Emulator"
-
#~ msgid "Invalid Path"
#~ msgstr "Ugyldig sti"
diff --git a/po/pl_PL.po b/po/pl_PL.po
index 233fa02599..7e1ab14800 100644
--- a/po/pl_PL.po
+++ b/po/pl_PL.po
@@ -1,5 +1,5 @@
# Polish translation for ScummVM.
-# Copyright (C) 2010-2015 The ScummVM Team
+# Copyright (C) 2010-2016 The ScummVM Team
# This file is distributed under the same license as the ScummVM package.
# Grajpopolsku.pl <grajpopolsku@gmail.com>, 2011-2013.
#
@@ -7,14 +7,16 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.3.0\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2015-09-06 15:14+0200\n"
-"PO-Revision-Date: 2014-07-02 12:28+0100\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"
"Language: Polski\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=iso-8859-2\n"
"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=((n==1) ? 0 : ((n%10>=2 && n%10<=4 && (n"
+"%100<10 || n%100>=20)) ? 1 : 2));\n"
"X-Poedit-KeywordsList: _;gettext;gettext_noop\n"
"X-Poedit-Basepath: .\n"
"X-Poedit-Language: Polish\n"
@@ -55,28 +57,29 @@ msgid "Go up"
msgstr "W górê"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:74 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: 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/fluidsynth-dialog.cpp:152 engines/engine.cpp:483
-#: backends/platform/wii/options.cpp:48
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
-#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:191 engines/sword1/control.cpp:865
+#: 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 "Anuluj"
#: gui/browser.cpp:76 gui/browser_osx.mm:103 gui/chooser.cpp:47
-#: gui/themebrowser.cpp:56
+#: gui/filebrowser-dialog.cpp:65 gui/themebrowser.cpp:56
msgid "Choose"
msgstr "Wybierz"
#: gui/editrecorddialog.cpp:58
msgid "Author:"
-msgstr ""
+msgstr "Autor:"
#: gui/editrecorddialog.cpp:59 gui/launcher.cpp:204
msgid "Name:"
@@ -84,63 +87,180 @@ msgstr "Nazwa:"
#: gui/editrecorddialog.cpp:60
msgid "Notes:"
-msgstr ""
+msgstr "Uwagi:"
-#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:75
+#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74
msgid "Ok"
+msgstr "Ok"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Choose file for loading"
+msgstr "Wybierz plik do wczytania"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Enter filename for saving"
+msgstr "Podaj nazwê pliku do zapisania"
+
+#: gui/filebrowser-dialog.cpp:132
+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: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 "Tak"
+
+#: 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 "Nie"
+
+#: gui/fluidsynth-dialog.cpp:68
+msgid "Reverb"
+msgstr "Pog³os"
+
+#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
+msgid "Active"
+msgstr "Aktywny"
+
+#: gui/fluidsynth-dialog.cpp:72
+msgid "Room:"
+msgstr "Przestrzeñ:"
+
+#: gui/fluidsynth-dialog.cpp:79
+msgid "Damp:"
+msgstr "T³umienie:"
+
+#: gui/fluidsynth-dialog.cpp:86
+msgid "Width:"
+msgstr "Szeroko¶æ:"
+
+#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
+msgid "Level:"
+msgstr "Poziom:"
+
+#: gui/fluidsynth-dialog.cpp:100
+msgid "Chorus"
+msgstr "Chorus"
+
+#: gui/fluidsynth-dialog.cpp:104
+msgid "N:"
+msgstr "N:"
+
+#: gui/fluidsynth-dialog.cpp:118
+msgid "Speed:"
+msgstr "Szybko¶æ:"
+
+#: gui/fluidsynth-dialog.cpp:125
+msgid "Depth:"
+msgstr "G³êbia:"
+
+#: gui/fluidsynth-dialog.cpp:132
+msgid "Type:"
+msgstr "Typ:"
+
+#: gui/fluidsynth-dialog.cpp:135
+msgid "Sine"
+msgstr "Sinus"
+
+#: gui/fluidsynth-dialog.cpp:136
+msgid "Triangle"
+msgstr "Trójk±t"
+
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
+msgid "Misc"
+msgstr "Ró¿ne"
+
+#: gui/fluidsynth-dialog.cpp:140
+msgid "Interpolation:"
+msgstr "Interpolacja:"
+
+#: gui/fluidsynth-dialog.cpp:143
+msgid "None (fastest)"
+msgstr "Brak (najszybsze)"
+
+#: gui/fluidsynth-dialog.cpp:144
+msgid "Linear"
+msgstr "Liniowa"
+
+#: gui/fluidsynth-dialog.cpp:145
+msgid "Fourth-order"
+msgstr "Czterostopniowa"
+
+#: gui/fluidsynth-dialog.cpp:146
+msgid "Seventh-order"
+msgstr "Siedmiostopniowa"
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset"
+msgstr "Reset"
+
+#: gui/fluidsynth-dialog.cpp:150
+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: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 "OK"
+
+#: gui/fluidsynth-dialog.cpp:217
+msgid ""
+"Do you really want to reset all FluidSynth settings to their default values?"
msgstr ""
+"Na pewno chcesz przywróciæ domy¶lne warto¶ci wszystkich ustawieñ FluidSynth?"
-#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
+#: 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 "Zamknij"
-#: gui/gui-manager.cpp:120
+#: gui/gui-manager.cpp:122
msgid "Mouse click"
msgstr "Klikniêcie"
-#: gui/gui-manager.cpp:124 base/main.cpp:319
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Wy¶wietl klawiaturê"
-#: gui/gui-manager.cpp:128 base/main.cpp:323
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Dostosuj klawisze"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 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"
-#: gui/KeysDialog.h:36 gui/KeysDialog.cpp:145
-msgid "Choose an action to map"
-msgstr "Wybierz akcjê do przypisania"
-
#: gui/KeysDialog.cpp:41
msgid "Map"
msgstr "Przypisz"
-#: gui/KeysDialog.cpp:42 gui/launcher.cpp:352 gui/launcher.cpp:1048
-#: gui/launcher.cpp:1052 gui/massadd.cpp:92 gui/options.cpp:1238
-#: gui/saveload-dialog.cpp:932 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:402 engines/engine.cpp:413
-#: 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/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 "OK"
-
#: gui/KeysDialog.cpp:49
msgid "Select an action and click 'Map'"
msgstr "Wybierz akcjê i kliknij 'Przypisz'"
@@ -148,7 +268,7 @@ msgstr "Wybierz akcjê i kliknij 'Przypisz'"
#: gui/KeysDialog.cpp:80 gui/KeysDialog.cpp:102 gui/KeysDialog.cpp:141
#, c-format
msgid "Associated key : %s"
-msgstr "Przypisany klawisz : %s"
+msgstr "Przypisany klawisz: %s"
#: gui/KeysDialog.cpp:82 gui/KeysDialog.cpp:104 gui/KeysDialog.cpp:143
#, c-format
@@ -163,6 +283,10 @@ msgstr "Wybierz akcjê"
msgid "Press the key to associate"
msgstr "Wci¶nij klawisz do przypisania"
+#: gui/KeysDialog.cpp:145 gui/KeysDialog.h:36
+msgid "Choose an action to map"
+msgstr "Wybierz akcjê do przypisania"
+
#: gui/launcher.cpp:193
msgid "Game"
msgstr "Gra"
@@ -203,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>"
@@ -226,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"
@@ -243,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"
@@ -256,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¶æ"
@@ -274,277 +398,258 @@ 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:95
+#: 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:69
+#: 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:1222
+#: 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/myst.cpp:245 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/myst.cpp:245
-#: engines/mohawk/riven.cpp:718 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:792
+#: 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:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Tak"
-
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Nie"
-
-#: gui/launcher.cpp:841
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM nie mo¿e otworzyæ katalogu!"
-#: gui/launcher.cpp:853
+#: 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:867
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Wybierz grê:"
-#: gui/launcher.cpp:941
+#: 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:999
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "Chcesz wczytaæ zapis stanu gry?"
-#: gui/launcher.cpp:1048
+#: 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:1052
+#: 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:1159
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
-msgstr "Masowe dodawanie..."
+msgstr "Przeszukaj..."
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1165
msgid "Record..."
-msgstr ""
+msgstr "Nagraj..."
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
@@ -557,162 +662,160 @@ msgstr "Skanowanie zakoñczone!"
#: gui/massadd.cpp:262
#, c-format
msgid "Discovered %d new games, ignored %d previously added games."
-msgstr "Wykryto %d nowych gier, zignorowano %d poprzednio dodanych."
+msgstr "Wykryto %d now± grê, zignorowano %d poprzednio dodanych."
#: gui/massadd.cpp:266
#, c-format
msgid "Scanned %d directories ..."
-msgstr "Przeskanowano %d katalogów ..."
+msgstr "Przeskanowano %d katalog..."
#: gui/massadd.cpp:269
#, c-format
msgid "Discovered %d new games, ignored %d previously added games ..."
-msgstr "Wykryto %d nowych gier, zignorowano %d poprzednio dodanych..."
+msgstr "Wykryto %d now± grê, zignorowano %d poprzednio dodanych..."
#: gui/onscreendialog.cpp:101 gui/onscreendialog.cpp:103
msgid "Stop"
-msgstr ""
+msgstr "Stop"
#: gui/onscreendialog.cpp:106
msgid "Edit record description"
-msgstr ""
+msgstr "Edytuj opis nagrania"
#: gui/onscreendialog.cpp:108
-#, fuzzy
msgid "Switch to Game"
-msgstr "Prze³±cz"
+msgstr "Prze³±cz do gry"
#: gui/onscreendialog.cpp:110
-#, fuzzy
msgid "Fast replay"
-msgstr "Tryb szybki"
+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:2298
+#: 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"
@@ -720,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"
@@ -788,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"
@@ -805,173 +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:1168 gui/fluidsynth-dialog.cpp:138
-msgid "Misc"
-msgstr "Ró¿ne"
-
-#: 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."
@@ -980,64 +1091,75 @@ msgstr ""
"najpierw swój jêzyk."
#. I18N: You must leave "#" as is, only word 'next' is translatable
-#: gui/predictivedialog.cpp:87
+#: gui/predictivedialog.cpp:86
msgid "# next"
-msgstr ""
+msgstr "# nastêpny"
-#: gui/predictivedialog.cpp:88
+#: gui/predictivedialog.cpp:87
msgid "add"
-msgstr ""
+msgstr "dodaj"
-#: gui/predictivedialog.cpp:92
-#, fuzzy
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
-msgstr "Skasuj"
+msgstr "Usuñ znak"
-#: gui/predictivedialog.cpp:96
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
-msgstr ""
+msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:98
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
-msgstr ""
+msgstr "* Pre"
+
+#. I18N: 'Num' means Numbers
+#: gui/predictivedialog.cpp:578
+msgid "* Num"
+msgstr "* Num"
-#: gui/recorderdialog.cpp:64
+#. I18N: 'Abc' means Latin alphabet input
+#: gui/predictivedialog.cpp:581
+msgid "* Abc"
+msgstr "* Abc"
+
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
-msgstr ""
+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 ""
+msgstr "Nagrywaj"
-#: gui/recorderdialog.cpp:72
-#, fuzzy
+#: gui/recorderdialog.cpp:71
msgid "Playback"
-msgstr "Uruchom"
+msgstr "Odtwarzaj"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
-msgstr ""
+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 ""
+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 ""
+msgstr "Uwagi: "
-#: gui/recorderdialog.cpp:155
-#, fuzzy
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
-msgstr "Na pewno chcesz skasowaæ ten zapis?"
+msgstr "Na pewno chcesz usun±æ to nagranie?"
+
+#: gui/recorderdialog.cpp:173
+msgid "Unknown Author"
+msgstr "Nieznany autor"
#: gui/saveload-dialog.cpp:167
msgid "List view"
@@ -1099,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:"
@@ -1108,150 +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:661
+#: 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
-msgid "Clear value"
-msgstr "Wyczy¶æ"
-
-#: gui/fluidsynth-dialog.cpp:68
-msgid "Reverb"
-msgstr "Pog³os"
-
-#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
-msgid "Active"
-msgstr "Aktywny"
-
-#: gui/fluidsynth-dialog.cpp:72
-msgid "Room:"
-msgstr "Przestrzeñ:"
-
-#: gui/fluidsynth-dialog.cpp:79
-msgid "Damp:"
-msgstr "T³umienie:"
-
-#: gui/fluidsynth-dialog.cpp:86
-msgid "Width:"
-msgstr "Szeroko¶æ:"
-
-#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
-msgid "Level:"
-msgstr "Poziom:"
-
-#: gui/fluidsynth-dialog.cpp:100
-msgid "Chorus"
-msgstr "Chorus"
-
-#: gui/fluidsynth-dialog.cpp:104
-msgid "N:"
-msgstr "N:"
-
-#: gui/fluidsynth-dialog.cpp:118
-msgid "Speed:"
-msgstr "Szybko¶æ:"
-
-#: gui/fluidsynth-dialog.cpp:125
-msgid "Depth:"
-msgstr "G³êbia:"
-
-#: gui/fluidsynth-dialog.cpp:132
-msgid "Type:"
-msgstr "Typ:"
-
-#: gui/fluidsynth-dialog.cpp:135
-msgid "Sine"
-msgstr "Sinus"
-
-#: gui/fluidsynth-dialog.cpp:136
-msgid "Triangle"
-msgstr "Trójk±t"
-
-#: gui/fluidsynth-dialog.cpp:140
-msgid "Interpolation:"
-msgstr "Interpolacja:"
-
-#: gui/fluidsynth-dialog.cpp:143
-msgid "None (fastest)"
-msgstr "Brak (najszybsze)"
-
-#: gui/fluidsynth-dialog.cpp:144
-msgid "Linear"
-msgstr "Liniowa"
-
-#: gui/fluidsynth-dialog.cpp:145
-msgid "Fourth-order"
-msgstr "Czterostopniowa"
-
-#: gui/fluidsynth-dialog.cpp:146
-msgid "Seventh-order"
-msgstr "Siedmiostopniowa"
+#: 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/fluidsynth-dialog.cpp:150
-msgid "Reset"
-msgstr "Reset"
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr ""
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset all FluidSynth settings to their default values."
-msgstr "Przywróæ domy¶lne warto¶ci wszystkich ustawieñ FluidSynth."
+#: gui/updates-dialog.cpp:92
+#, fuzzy
+msgid "Check for updates automatically"
+msgstr "Sprawd¼ aktualizacjê..."
-#: gui/fluidsynth-dialog.cpp:217
-msgid ""
-"Do you really want to reset all FluidSynth settings to their default values?"
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
msgstr ""
-"Na pewno chcesz przywróciæ domy¶lne warto¶ci wszystkich ustawieñ FluidSynth?"
-#: base/main.cpp:228
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
+msgid "Clear value"
+msgstr "Wyczy¶æ"
+
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "Silnik nie wspiera poziomu debugowania '%s'"
-#: base/main.cpp:306
+#: base/main.cpp:315
msgid "Menu"
msgstr "Menu"
-#: base/main.cpp:309 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:312 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:315
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Pomiñ liniê"
-#: base/main.cpp:507
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "B³±d podczas uruchamiania gry:"
-#: base/main.cpp:554
+#: 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"
@@ -1319,16 +1376,60 @@ msgstr "Przerwane przez u¿ytkownika"
msgid "Unknown error"
msgstr "Nieznany b³±d"
-#: engines/advancedDetector.cpp:317
+#. I18N: Hercules is graphics card name
+#: common/rendermode.cpp:35
+msgid "Hercules Green"
+msgstr "Zielony Hercules"
+
+#: common/rendermode.cpp:36
+msgid "Hercules Amber"
+msgstr "Bursztynowy Hercules"
+
+#: common/rendermode.cpp:42
+msgid "PC-9821 (256 Colors)"
+msgstr "PC-9821 (256 kolorów)"
+
+#: common/rendermode.cpp:43
+msgid "PC-9801 (16 Colors)"
+msgstr "PC-9801 (16 kolorów)"
+
+#: common/rendermode.cpp:73
+msgctxt "lowres"
+msgid "Hercules Green"
+msgstr "Zielony Hercules"
+
+#: common/rendermode.cpp:74
+msgctxt "lowres"
+msgid "Hercules Amber"
+msgstr "Bursztynowy Hercules"
+
+#: 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.:"
@@ -1336,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"
@@ -1365,11 +1466,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "~P~owrót do launchera"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:803
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:873
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
-#: engines/toltecs/menu.cpp:281 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:"
@@ -1378,11 +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:803 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/neverhood/menumodule.cpp:873 engines/pegasus/pegasus.cpp:377
-#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
-#: engines/toltecs/menu.cpp:281 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"
@@ -1405,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"
@@ -1419,23 +1529,23 @@ msgstr "~A~nuluj"
msgid "~K~eys"
msgstr "~K~lawisze"
-#: engines/engine.cpp:276
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Nie uda³o siê zainicjalizowaæ formatu kolorów."
-#: engines/engine.cpp:284
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Nie uda³o siê prze³±czyæ w tryb wideo: '"
-#: engines/engine.cpp:293
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "Nie uda³o siê zastosowaæ ustawienia formatu obrazu."
-#: engines/engine.cpp:298
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Nie uda³o siê zastosowaæ ustawienia pe³nego ekranu."
-#: engines/engine.cpp:398
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1447,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:409
+#: 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"
@@ -1459,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:467
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1468,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:480
+#: 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 "
@@ -1478,10 +1588,14 @@ 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:483
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "W³±cz mimo tego"
+#: audio/adlib.cpp:2290
+msgid "AdLib Emulator"
+msgstr "Emulator AdLib"
+
#: audio/fmopl.cpp:62
msgid "MAME OPL emulator"
msgstr "Emulator OPL MAME"
@@ -1492,7 +1606,7 @@ msgstr "Emulator OPL DOSBox"
#: audio/fmopl.cpp:67
msgid "ALSA Direct FM"
-msgstr ""
+msgstr "Bezpo¶rednie FM Alsa"
#: audio/mididrv.cpp:209
#, c-format
@@ -1535,31 +1649,35 @@ msgstr ""
"Nie mo¿na u¿yæ preferowanego urz±dzenia audio '%s'. Dalsze szczegó³y s± "
"dostêpne w pliku dziennika."
-#: audio/null.h:44
-msgid "No music"
-msgstr "Brak muzyki"
-
#: audio/mods/paula.cpp:196
msgid "Amiga Audio Emulator"
msgstr "Emulator d¼wiêku Amigi"
-#: audio/adlib.cpp:2291
-msgid "AdLib Emulator"
-msgstr "Emulator AdLib"
+#: audio/null.h:44
+msgid "No music"
+msgstr "Brak muzyki"
#: audio/softsynth/appleiigs.cpp:33
msgid "Apple II GS Emulator (NOT IMPLEMENTED)"
msgstr "Emulator Apple II GS (NIE ZAIMPLEMENTOWANY)"
-#: audio/softsynth/sid.cpp:1430
-msgid "C64 Audio Emulator"
-msgstr "Emulator d¼wiêku C64"
+#: audio/softsynth/cms.cpp:350
+msgid "Creative Music System Emulator"
+msgstr "Emulator Creative Music System"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33
+msgid "FM-Towns Audio"
+msgstr "D¼wiêk FM-Towns"
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58
+msgid "PC-98 Audio"
+msgstr "D¼wiêk PC-98"
+
+#: 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"
@@ -1571,6 +1689,146 @@ msgstr "Emulator brzêczyka"
msgid "IBM PCjr Emulator"
msgstr "Emulator IBM PCjr"
+#: audio/softsynth/sid.cpp:1430
+msgid "C64 Audio Emulator"
+msgstr "Emulator d¼wiêku C64"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Do you really want to return to the Launcher?"
+msgstr "Na pewno chcesz powróciæ do launchera?"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Launcher"
+msgstr "Launcher"
+
+#: backends/events/default/default-events.cpp:218
+msgid "Do you really want to quit?"
+msgstr "Na pewno chcesz wyj¶æ?"
+
+#: 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 "Zakoñcz"
+
+#: 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 "Dotkniêcie ekranu - klikniêcie LPM"
+
+#: 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 "Dotkniêcie ekranu - klikniêcie PPM"
+
+#: 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 "Dotkniêcie ekranu - przytrzymanie (brak klikniêcia)"
+
+#: backends/events/gph/gph-events.cpp:409
+msgid "Maximum Volume"
+msgstr "Maksymalna g³o¶no¶æ"
+
+#: backends/events/gph/gph-events.cpp:411
+msgid "Increasing Volume"
+msgstr "Zwiêkszenie g³o¶no¶ci"
+
+#: backends/events/gph/gph-events.cpp:417
+msgid "Minimal Volume"
+msgstr "Minimalna g³o¶no¶æ"
+
+#: backends/events/gph/gph-events.cpp:419
+msgid "Decreasing Volume"
+msgstr "Zmniejszenie g³o¶no¶ci"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Enabled"
+msgstr "Klikanie w³±czone"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Disabled"
+msgstr "Klikanie wy³±czone"
+
+#: backends/events/openpandora/op-events.cpp:174
+msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
+msgstr "Dotkniêcie ekranu - przytrzymanie (krzy¿ak klika)"
+
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
+msgid "Do you want to quit ?"
+msgstr "Chcesz wyj¶æ?"
+
+#. I18N: Trackpad mode toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:308
+msgid "Trackpad mode is now"
+msgstr "Tryb g³adzika jest"
+
+#. 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 "w³±czony"
+
+#: backends/events/webossdl/webossdl-events.cpp:311
+#: backends/events/webossdl/webossdl-events.cpp:338
+msgid "OFF"
+msgstr "wy³±czony"
+
+#: backends/events/webossdl/webossdl-events.cpp:315
+msgid "Swipe two fingers to the right to toggle."
+msgstr "Przesuñ dwoma palcami, ¿eby zmieniæ."
+
+#. I18N: Auto-drag toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:335
+msgid "Auto-drag mode is now"
+msgstr "Tryb automatycznego przeci±gania jest"
+
+#: backends/events/webossdl/webossdl-events.cpp:342
+msgid "Swipe three fingers to the right to toggle."
+msgstr "Przesuñ trzema palcami, ¿eby zmieniæ."
+
+#: backends/graphics/opengl/opengl-graphics.cpp:126
+msgid "OpenGL"
+msgstr "OpenGL"
+
+#: backends/graphics/opengl/opengl-graphics.cpp:127
+msgid "OpenGL (No filtering)"
+msgstr "OpenGL (bez filtrowania)"
+
+#: 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 "Zwyk³y (bez skalowania)"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:66
+msgctxt "lowres"
+msgid "Normal (no scaling)"
+msgstr "Zwyk³y (bez skalowania)"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
+msgid "Enabled aspect ratio correction"
+msgstr "W³±czono korekcjê formatu obrazu"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
+msgid "Disabled aspect ratio correction"
+msgstr "Wy³±czono korekcjê formatu obrazu"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
+msgid "Active graphics filter:"
+msgstr "Aktywny filtr graficzny:"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+msgid "Windowed mode"
+msgstr "Okno"
+
#: backends/keymapper/remap-dialog.cpp:48
msgid "Keymap:"
msgstr "Klawisze:"
@@ -1600,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"
@@ -1634,7 +1892,7 @@ msgstr "Przesuniêcie Y ekranu do dotykania"
#: backends/platform/ds/arm9/source/dsoptions.cpp:87
msgid "Use laptop trackpad-style cursor control"
-msgstr "U¿yj kursora w stylu trackpada z laptopa do sterowania"
+msgstr "U¿yj kursora w stylu g³adzika laptopa do sterowania"
#: backends/platform/ds/arm9/source/dsoptions.cpp:88
msgid "Tap for left click, double tap right click"
@@ -1676,18 +1934,26 @@ msgstr "D¼wiêk wysokiej jako¶ci (wolniejszy) (restart)"
msgid "Disable power off"
msgstr "Nie wy³±czaj zasilania"
+#: 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 "W³±czono tryb kliknij i przeci±gaj."
+#: 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 "Wy³±czono tryb kliknij i przeci±gaj."
+#: 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 "Tryb touchpada w³±czony."
+#: 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 "Tryb touchpada wy³±czony."
@@ -1698,9 +1964,9 @@ msgstr "Tryb klikania"
#: 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
-#: backends/platform/tizen/form.cpp:275
msgid "Left Click"
msgstr "Klikniêcie LPM"
@@ -1710,65 +1976,32 @@ msgstr "¦rodkowy przycisk"
#: backends/platform/maemo/maemo.cpp:220
#: backends/platform/symbian/src/SymbianActions.cpp:43
-#: backends/platform/wince/CEActionsSmartphone.cpp:44
#: backends/platform/tizen/form.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:44
msgid "Right Click"
msgstr "Klikniêcie PPM"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:77
+#: backends/platform/sdl/macosx/appmenu_osx.mm:88
msgid "Hide ScummVM"
msgstr "Ukryj ScummVM"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:82
+#: backends/platform/sdl/macosx/appmenu_osx.mm:93
msgid "Hide Others"
msgstr "Ukryj pozosta³e"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:87
+#: backends/platform/sdl/macosx/appmenu_osx.mm:98
msgid "Show All"
msgstr "Poka¿ wszystkie"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:109
#: backends/platform/sdl/macosx/appmenu_osx.mm:120
+#: backends/platform/sdl/macosx/appmenu_osx.mm:131
msgid "Window"
msgstr "Okno"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:114
+#: backends/platform/sdl/macosx/appmenu_osx.mm:125
msgid "Minimize"
msgstr "Miniaturka"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:46
-msgid "Normal (no scaling)"
-msgstr "Zwyk³y (bez skalowania)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:65
-msgctxt "lowres"
-msgid "Normal (no scaling)"
-msgstr "Zwyk³y (bez skalowania)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
-msgid "Enabled aspect ratio correction"
-msgstr "W³±czono korekcjê formatu obrazu"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
-msgid "Disabled aspect ratio correction"
-msgstr "Wy³±czono korekcjê formatu obrazu"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
-msgid "Active graphics filter:"
-msgstr "Aktywny filtr graficzny:"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
-msgid "Windowed mode"
-msgstr "Okno"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:118
-msgid "OpenGL"
-msgstr "OpenGL"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:119
-msgid "OpenGL (No filtering)"
-msgstr "OpenGL (bez filtrowania)"
-
#: backends/platform/symbian/src/SymbianActions.cpp:38
#: backends/platform/wince/CEActionsSmartphone.cpp:39
msgid "Up"
@@ -1812,14 +2045,6 @@ msgstr "Pomiñ tekst"
msgid "Fast mode"
msgstr "Tryb szybki"
-#: backends/platform/symbian/src/SymbianActions.cpp:52
-#: backends/platform/wince/CEActionsPocket.cpp:44
-#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: backends/events/default/default-events.cpp:218 engines/scumm/dialogs.cpp:192
-#: engines/scumm/help.cpp:83 engines/scumm/help.cpp:85
-msgid "Quit"
-msgstr "Zakoñcz"
-
#: backends/platform/symbian/src/SymbianActions.cpp:53
msgid "Debugger"
msgstr "Debugger"
@@ -1836,9 +2061,49 @@ msgstr "Wirtualna klawiatura"
msgid "Key mapper"
msgstr "Mapper klawiszy"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:186
-msgid "Do you want to quit ?"
-msgstr "Chcesz wyj¶æ?"
+#: backends/platform/tizen/form.cpp:263
+msgid "Right Click Once"
+msgstr "Pojedyncze klikniêcie PPM"
+
+#: backends/platform/tizen/form.cpp:271
+msgid "Move Only"
+msgstr "Tylko ruch"
+
+#: backends/platform/tizen/form.cpp:294
+msgid "Escape Key"
+msgstr "Przycisk wyj¶cia"
+
+#: backends/platform/tizen/form.cpp:299
+msgid "Game Menu"
+msgstr "Menu gry"
+
+#: backends/platform/tizen/form.cpp:304
+msgid "Show Keypad"
+msgstr "Poka¿ klawiaturê"
+
+#: backends/platform/tizen/form.cpp:309
+msgid "Control Mouse"
+msgstr "Steruj myszk±"
+
+#: backends/platform/tizen/fs.cpp:259
+msgid "[ Data ]"
+msgstr "[ Dane ]"
+
+#: backends/platform/tizen/fs.cpp:263
+msgid "[ Resources ]"
+msgstr "[ Zasoby ]"
+
+#: backends/platform/tizen/fs.cpp:267
+msgid "[ SDCard ]"
+msgstr "[ Karta SD ]"
+
+#: backends/platform/tizen/fs.cpp:271
+msgid "[ Media ]"
+msgstr "[ Media ]"
+
+#: backends/platform/tizen/fs.cpp:275
+msgid "[ Shared ]"
+msgstr "[ Wspó³dzielone ]"
#: backends/platform/wii/options.cpp:51
msgid "Video"
@@ -2083,139 +2348,105 @@ msgstr ""
"Nie zapomnij przypisaæ klawisza 'Ukryj pasek narzêdzi', by widzieæ ca³y "
"ekwipunek"
-#: backends/events/default/default-events.cpp:196
-msgid "Do you really want to return to the Launcher?"
-msgstr "Na pewno chcesz powróciæ do launchera?"
-
-#: backends/events/default/default-events.cpp:196
-msgid "Launcher"
-msgstr "Launcher"
-
-#: backends/events/default/default-events.cpp:218
-msgid "Do you really want to quit?"
-msgstr "Na pewno chcesz wyj¶æ?"
-
-#: 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 "Dotkniêcie ekranu - klikniêcie LPM"
-
-#: 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 "Dotkniêcie ekranu - klikniêcie PPM"
-
-#: 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 "Dotkniêcie ekranu - przytrzymanie (brak klikniêcia)"
-
-#: backends/events/gph/gph-events.cpp:409
-msgid "Maximum Volume"
-msgstr "Maksymalna g³o¶no¶æ"
-
-#: backends/events/gph/gph-events.cpp:411
-msgid "Increasing Volume"
-msgstr "Zwiêkszenie g³o¶no¶ci"
-
-#: backends/events/gph/gph-events.cpp:417
-msgid "Minimal Volume"
-msgstr "Minimalna g³o¶no¶æ"
-
-#: backends/events/gph/gph-events.cpp:419
-msgid "Decreasing Volume"
-msgstr "Zmniejszenie g³o¶no¶ci"
-
-#: backends/events/openpandora/op-events.cpp:174
-msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
-msgstr "Dotkniêcie ekranu - przytrzymanie (krzy¿ak klika)"
-
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Sprawd¼ aktualizacjê..."
-#: backends/platform/tizen/form.cpp:263
-msgid "Right Click Once"
-msgstr "Pojedyncze klikniêcie PPM"
-
-#: backends/platform/tizen/form.cpp:271
-msgid "Move Only"
-msgstr "Tylko ruch"
-
-#: backends/platform/tizen/form.cpp:294
-msgid "Escape Key"
-msgstr "Przycisk wyj¶cia"
-
-#: backends/platform/tizen/form.cpp:299
-msgid "Game Menu"
-msgstr "Menu gry"
-
-#: backends/platform/tizen/form.cpp:304
-msgid "Show Keypad"
-msgstr "Poka¿ klawiaturê"
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "Tryb dla daltonistów"
-#: backends/platform/tizen/form.cpp:309
-msgid "Control Mouse"
-msgstr "Steruj myszk±"
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Enabled"
-msgstr "Klikanie w³±czone"
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Disabled"
-msgstr "Klikanie wy³±czone"
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "Poka¿ etykiety obiektów"
-#: engines/agi/detection.cpp:147 engines/drascula/detection.cpp:302
-#: engines/dreamweb/detection.cpp:47 engines/neverhood/detection.cpp:160
-#: engines/sci/detection.cpp:394 engines/toltecs/detection.cpp:200
-#: engines/zvision/detection_tables.h:51
+#: 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 "U¿yj oryginalnych ekranów odczytu/zapisu"
-#: engines/agi/detection.cpp:148 engines/drascula/detection.cpp:303
-#: engines/dreamweb/detection.cpp:48 engines/neverhood/detection.cpp:161
-#: engines/sci/detection.cpp:395 engines/toltecs/detection.cpp:201
+#: 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 "U¿yj oryginalnych ekranów odczytu/zapisu zamiast tych ze ScummVM"
#: engines/agi/detection.cpp:157
-#, fuzzy
msgid "Use an alternative palette"
-msgstr "U¿yj alternatywnego intra (tylko dla wersji CD)"
+msgstr "U¿yj alternatywnej palety"
#: engines/agi/detection.cpp:158
msgid ""
"Use an alternative palette, common for all Amiga games. This was the old "
"behavior"
msgstr ""
+"U¿yj alternatywnej palety dla wszystkich amigowych gier. Takie by³o dawne "
+"zachowanie"
#: engines/agi/detection.cpp:167
-#, fuzzy
msgid "Mouse support"
-msgstr "Obs³uga pomijania"
+msgstr "Obs³uga myszki"
#: engines/agi/detection.cpp:168
msgid ""
"Enables mouse support. Allows to use mouse for movement and in game menus."
msgstr ""
+"W³±cza obs³ugê myszki. Pozwala na u¿ycie myszki do przemieszczania i w menu "
+"gry."
+
+#: 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/saveload.cpp:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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"
@@ -2226,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"
@@ -2237,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"
@@ -2248,19 +2479,18 @@ 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'!"
#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
-#, fuzzy
msgid "Color Blind Mode"
-msgstr "Tryb klikania"
+msgstr "Tryb dla daltonistów"
#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
-msgstr ""
+msgstr "Domy¶lnie w³±cz tryb dla daltonistów"
#: engines/drascula/saveload.cpp:47
msgid ""
@@ -2279,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."
@@ -2309,17 +2539,17 @@ 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"
#: engines/hopkins/detection.cpp:76 engines/hopkins/detection.cpp:86
msgid "Gore Mode"
-msgstr ""
+msgstr "Tryb krwi"
#: engines/hopkins/detection.cpp:77 engines/hopkins/detection.cpp:87
msgid "Enable Gore Mode when available"
-msgstr ""
+msgstr "W³±cz tryb krwi, je¶li jest dostêpny"
#. I18N: Studio audience adds an applause and cheering sounds whenever
#. Malcolm makes a joke.
@@ -2450,6 +2680,12 @@ msgid ""
"Do you wish to use this save game file with ScummVM?\n"
"\n"
msgstr ""
+"W ¶cie¿ce gry znaleziono oryginalny zapis gry:\n"
+"\n"
+"%s %s\n"
+"\n"
+"Chcesz u¿yæ tego zapisu w ScummVM?\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:590
#, c-format
@@ -2457,6 +2693,8 @@ msgid ""
"A save game file was found in the specified slot %d. Overwrite?\n"
"\n"
msgstr ""
+"W wybranym slocie %d znaleziono zapis gry. Nadpisaæ?\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:623
#, c-format
@@ -2468,50 +2706,64 @@ msgid ""
"'import_savefile'.\n"
"\n"
msgstr ""
+"Pomy¶lnie zaimportowano %d oryginalny zapis gry do ScummVM. Je¶li pó¼niej "
+"zechcesz zaimportowaæ oryginalne zapisy, bêdziesz musia³ otworzyæ konsolê "
+"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"
@@ -2520,15 +2772,23 @@ msgstr ""
"Nie mo¿na zapisaæ w slocie %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:194
+msgid "Load file"
+msgstr "Wczytaj plik"
+
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Wczytywanie stanu gry..."
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:209
+msgid "Save file"
+msgstr "Zapisz plik"
+
+#: 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"
@@ -2544,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"
@@ -2604,27 +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 ""
+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:395
+msgid "Enable high resolution graphics/content"
+msgstr "W³±cz grafikê/zawarto¶æ wysokiej rozdzielczo¶ci"
+
+#: 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:385
+#: 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:404
+#: 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:405
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2632,149 +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:415
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "U¿yj CD audio"
-#: engines/sci/detection.cpp:416
+#: 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:426
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "U¿yj windowsowych kursorów"
-#: engines/sci/detection.cpp:427
+#: 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:437
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "U¿yj srebrnych kursorów"
-#: engines/sci/detection.cpp:438
+#: 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
-#, fuzzy
+#: engines/scumm/dialogs.cpp:179
msgid "Are you sure you want to restart? (Y/N)Y"
-msgstr "Na pewno chcesz zrestartowaæ grê? (T/N)T"
+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
-#, fuzzy
+#: engines/scumm/dialogs.cpp:181
msgid "Are you sure you want to quit? (Y/N)Y"
-msgstr "Na pewno chcesz wyj¶æ? (T/N)T"
+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:600
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Tylko mowa"
-#: engines/scumm/dialogs.cpp:601
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Mowa i napisy"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Tylko napisy"
-#: engines/scumm/dialogs.cpp:610
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Mowa i napisy"
-#: engines/scumm/dialogs.cpp:656
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Wybierz poziom umiejêtno¶ci."
-#: engines/scumm/dialogs.cpp:658
+#: 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:662
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Trening"
-#: engines/scumm/dialogs.cpp:663
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Ekspert"
@@ -3199,25 +3484,24 @@ msgid "Third kid"
msgstr "Trzeci dzieciak"
#: engines/scumm/help.cpp:292
-#, fuzzy
msgid "Toggle Inventory/IQ Points display"
-msgstr "W³±cz/wy³±cz widok danych"
+msgstr "W³±cz/wy³±cz widok ekwipunku/punktów IQ"
#: engines/scumm/help.cpp:293
msgid "Toggle Keyboard/Mouse Fighting (*)"
-msgstr ""
+msgstr "Prze³±cz miêdzy walk± klawiatur± a mysz± (*)"
#: engines/scumm/help.cpp:295
msgid "* Keyboard Fighting is always on,"
-msgstr ""
+msgstr "* Walka klawiatur± jest zawsze w³±czona,"
#: engines/scumm/help.cpp:296
msgid " so despite the in-game message this"
-msgstr ""
+msgstr " wiêc wbrew komunikatowi w grze"
#: engines/scumm/help.cpp:297
msgid " actually toggles Mouse Fighting Off/On"
-msgstr ""
+msgstr " to ustawienie w³±cza/wy³±cza walkê mysz±"
#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
@@ -3254,7 +3538,7 @@ msgstr "Niskie uderzenie"
#: engines/scumm/help.cpp:315
msgid "Sucker punch"
-msgstr ""
+msgstr "Cios z zaskoczenia"
#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
@@ -3312,7 +3596,23 @@ msgstr "Leæ w prawo"
msgid "Fly to lower right"
msgstr "Leæ w dó³, w prawo"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/input.cpp:578
+msgid "Snap scroll on"
+msgstr "Przesuwanie skokowe w³±czone"
+
+#: engines/scumm/input.cpp:580
+msgid "Snap scroll off"
+msgstr "Przesuwanie skokowe wy³±czone"
+
+#: engines/scumm/input.cpp:593
+msgid "Music volume: "
+msgstr "G³o¶no¶æ muzyki: "
+
+#: engines/scumm/input.cpp:610
+msgid "Subtitle speed: "
+msgstr "Prêd. napisów: "
+
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3321,28 +3621,87 @@ msgstr ""
"Natywne wsparcie MIDI wymaga aktualizacji Rolanda od LucasArts,\n"
"ale brakuje %s. Prze³±czam na tryb AdLib."
-#: engines/scumm/scumm.cpp:2644
-#, fuzzy
+#: 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 ""
-"Zwykle w tym momencie uruchomi³oby siê Maniac Mansion, ale ScummVM jeszcze "
-"tego nie obs³uguje. Aby zagraæ, u¿yj \"Dodaj grê...\" z menu startowego "
-"ScummVM i wybierz podkatalog \"Maniac\" z katalogu gry Tentacle."
+"Zwykle w tym momencie uruchomi³oby siê Maniac Mansion. Ale ¿eby to "
+"zadzia³a³o, pliki Maniac Mansion musz± znajdowaæ siê w podkatalogu \"Maniac"
+"\" w katalogu gry Day of the Tentacle, a gra musi byæ dodana do ScummVM."
#: 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 ""
+"Nie znaleziono pliku wykonywalnego \"Loom\" dla Macintosha do odczytania "
+"instrumentów. Muzyka bêdzie wy³±czona."
#: 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 ""
+"Nie znaleziono pliku wykonywalnego \"Monkey Island\" dla Macintosha do "
+"odczytania instrumentów. Muzyka bêdzie wy³±czona."
+
+#: engines/sherlock/detection.cpp:71
+msgid "Use original savegame dialog"
+msgstr "U¿ywaj oryginalnego ekranu odczytu/zapisu"
+
+#: engines/sherlock/detection.cpp:72
+msgid ""
+"Files button in-game shows original savegame dialog rather than the ScummVM "
+"menu"
+msgstr ""
+"Przycisk zapisu w grze wy¶wietla oryginalny ekran odczytu/zapisu zamiast "
+"menu ScummVM"
+
+#: engines/sherlock/detection.cpp:81
+msgid "Pixellated scene transitions"
+msgstr "Pikselizowane przej¶cia miêdzy scenami"
+
+#: engines/sherlock/detection.cpp:82
+msgid "When changing scenes, a randomized pixel transition is done"
+msgstr "U¿ywaj losowej pikselizacji przy zmianie sceny"
+
+#: engines/sherlock/detection.cpp:91
+msgid "Don't show hotspots when moving mouse"
+msgstr "Nie wy¶wietlaj hotspotów przy poruszaniu mysz±"
+
+#: engines/sherlock/detection.cpp:92
+msgid ""
+"Only show hotspot names after you actually click on a hotspot or action "
+"button"
+msgstr ""
+"Wy¶wietlaj nazwy hotspotów dopiero po klikniêciu ich lub u¿yciu przycisku "
+"akcji"
+
+#: engines/sherlock/detection.cpp:101
+msgid "Show character portraits"
+msgstr "Wy¶wietl portrety postaci"
+
+#: engines/sherlock/detection.cpp:102
+msgid "Show portraits for the characters when conversing"
+msgstr "Wy¶wietl portrety postaci podczas rozmowy"
+
+#: engines/sherlock/detection.cpp:111
+msgid "Slide dialogs into view"
+msgstr "Przysuñ okna"
+
+#: engines/sherlock/detection.cpp:112
+msgid "Slide UI dialogs into view, rather than simply showing them immediately"
+msgstr "Przysuñ okna interfejsu zamiast wy¶wietliæ je od razu"
+
+#: engines/sherlock/detection.cpp:121
+msgid "Transparent windows"
+msgstr "Przezroczyste okna"
+
+#: engines/sherlock/detection.cpp:122
+msgid "Show windows with a partially transparent background"
+msgstr "Wy¶wietlaj okna z pó³przezroczystym t³em"
#: engines/sky/compact.cpp:130
msgid ""
@@ -3447,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"
+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"
@@ -3462,52 +3830,47 @@ msgstr ""
#: engines/wintermute/detection.cpp:58
msgid "Show FPS-counter"
-msgstr ""
+msgstr "Poka¿ licznik klatek na sekundê"
#: engines/wintermute/detection.cpp:59
msgid "Show the current number of frames per second in the upper left corner"
-msgstr ""
+msgstr "Wy¶wietl aktualn± liczbê klatek na sekundê w lewym, górnym logu"
#: engines/zvision/detection_tables.h:52
-#, fuzzy
msgid "Use the original save/load screens instead of the ScummVM interface"
-msgstr "U¿yj oryginalnych ekranów odczytu/zapisu zamiast tych ze ScummVM"
+msgstr "U¿yj oryginalnych ekranów odczytu/zapisu zamiast interfejsu ScummVM"
#: engines/zvision/detection_tables.h:61
msgid "Double FPS"
-msgstr ""
+msgstr "Podwójna liczba klatek"
#: engines/zvision/detection_tables.h:62
msgid "Increase framerate from 30 to 60 FPS"
-msgstr ""
+msgstr "Zwiêksz liczbê klatek na sekundê z 30 do 60"
#: engines/zvision/detection_tables.h:71
-#, fuzzy
msgid "Enable Venus"
-msgstr "W³±cz tryb helowy"
+msgstr "W³±cz Venus"
#: engines/zvision/detection_tables.h:72
-#, fuzzy
msgid "Enable the Venus help system"
-msgstr "W³±cz tryb helowy"
+msgstr "W³±cz system pomocy Venus"
#: engines/zvision/detection_tables.h:81
msgid "Disable animation while turning"
-msgstr ""
+msgstr "Wy³±cz animacjê podczas obrotu"
#: engines/zvision/detection_tables.h:82
msgid "Disable animation while turning in panorama mode"
-msgstr ""
+msgstr "Wy³±cz animacjê podczas trybu panoramy"
#: engines/zvision/detection_tables.h:91
msgid "Use high resolution MPEG video"
-msgstr ""
+msgstr "U¿yj wideo MPEG w wysokiej rozdzielczo¶ci"
#: engines/zvision/detection_tables.h:92
-#, fuzzy
msgid "Use MPEG video from the DVD version, instead of lower resolution AVI"
-msgstr ""
-"U¿yj alternatywnego zestawu srebrnych kursorów zamiast zwyk³ych z³otych"
+msgstr "U¿yj wideo MPEG z wersji DVD zamiast AVI ni¿szej rozdzielczo¶ci"
#~ msgid "EGA undithering"
#~ msgstr "Anty-dithering EGA"
@@ -3556,26 +3919,6 @@ msgstr ""
#~ msgid "Active filter mode: Nearest"
#~ msgstr "Aktywny tryb filtru: najbli¿szy s±siad"
-#~ msgid "Enable Roland GS Mode"
-#~ msgstr "W³±cz tryb Roland GS"
-
-#~ msgid "Hercules Green"
-#~ msgstr "Zielony Hercules"
-
-#~ msgid "Hercules Amber"
-#~ msgstr "Bursztynowy Hercules"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Green"
-#~ msgstr "Zielony Hercules"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Amber"
-#~ msgstr "Bursztynowy Hercules"
-
-#~ msgid "Save game failed!"
-#~ msgstr "Nie uda³o siê zapisaæ stanu gry!"
-
#~ msgctxt "lowres"
#~ msgid "Add Game..."
#~ msgstr "Dodaj grê..."
@@ -3589,8 +3932,5 @@ msgstr ""
#~ msgid "Command line argument not processed"
#~ msgstr "Argument wiersza poleceñ nie zosta³ przetworzony"
-#~ msgid "FM Towns Emulator"
-#~ msgstr "Emulator FM Towns"
-
#~ msgid "Invalid Path"
#~ msgstr "Niew³a¶ciwa ¶cie¿ka"
diff --git a/po/pt_BR.po b/po/pt_BR.po
index dae84f8e09..41a8ad15c7 100644
--- a/po/pt_BR.po
+++ b/po/pt_BR.po
@@ -1,5 +1,5 @@
# Portuguese (Brazilian) translation for ScummVM.
-# Copyright (C) 2010-2015 The ScummVM Team
+# Copyright (C) 2010-2016 The ScummVM Team
# This file is distributed under the same license as the ScummVM package.
# Saulo Benigno <saulobenigno@gmail.com>, 2010.
#
@@ -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: 2015-09-06 15:14+0200\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"
@@ -56,22 +56,23 @@ msgid "Go up"
msgstr "Acima"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:74 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: 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/fluidsynth-dialog.cpp:152 engines/engine.cpp:483
-#: backends/platform/wii/options.cpp:48
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
-#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:191 engines/sword1/control.cpp:865
+#: 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 "Cancelar"
#: gui/browser.cpp:76 gui/browser_osx.mm:103 gui/chooser.cpp:47
-#: gui/themebrowser.cpp:56
+#: gui/filebrowser-dialog.cpp:65 gui/themebrowser.cpp:56
msgid "Choose"
msgstr "Escolher"
@@ -87,62 +88,183 @@ msgstr "Nome:"
msgid "Notes:"
msgstr ""
-#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:75
+#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74
msgid "Ok"
msgstr ""
-#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
+#: gui/filebrowser-dialog.cpp:49
+msgid "Choose file for loading"
+msgstr ""
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Enter filename for saving"
+msgstr ""
+
+#: gui/filebrowser-dialog.cpp:132
+#, fuzzy
+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: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 "Sim"
+
+#: 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 "Não"
+
+#: gui/fluidsynth-dialog.cpp:68
+#, fuzzy
+msgid "Reverb"
+msgstr "Nunca"
+
+#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
+#, fuzzy
+msgid "Active"
+msgstr "(Ativo)"
+
+#: gui/fluidsynth-dialog.cpp:72
+msgid "Room:"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:79
+msgid "Damp:"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:86
+msgid "Width:"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
+msgid "Level:"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:100
+msgid "Chorus"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:104
+msgid "N:"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:118
+#, fuzzy
+msgid "Speed:"
+msgstr "Voz"
+
+#: gui/fluidsynth-dialog.cpp:125
+msgid "Depth:"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:132
+msgid "Type:"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:135
+msgid "Sine"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:136
+msgid "Triangle"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
+msgid "Misc"
+msgstr "Outros"
+
+#: gui/fluidsynth-dialog.cpp:140
+msgid "Interpolation:"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:143
+msgid "None (fastest)"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:144
+msgid "Linear"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:145
+msgid "Fourth-order"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:146
+msgid "Seventh-order"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset all FluidSynth settings to their default values."
+msgstr ""
+
+#: 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 "OK"
+
+#: gui/fluidsynth-dialog.cpp:217
+#, fuzzy
+msgid ""
+"Do you really want to reset all FluidSynth settings to their default values?"
+msgstr "Você realmente deseja voltar para o menu principal?"
+
+#: 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 "Fechar"
-#: gui/gui-manager.cpp:120
+#: gui/gui-manager.cpp:122
msgid "Mouse click"
msgstr "Clique do mouse"
-#: gui/gui-manager.cpp:124 base/main.cpp:319
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Mostrar teclado"
-#: gui/gui-manager.cpp:128 base/main.cpp:323
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Remapear teclas"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 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"
-#: gui/KeysDialog.h:36 gui/KeysDialog.cpp:145
-msgid "Choose an action to map"
-msgstr "Selecione uma ação para mapear"
-
#: gui/KeysDialog.cpp:41
msgid "Map"
msgstr "Mapear"
-#: gui/KeysDialog.cpp:42 gui/launcher.cpp:352 gui/launcher.cpp:1048
-#: gui/launcher.cpp:1052 gui/massadd.cpp:92 gui/options.cpp:1238
-#: gui/saveload-dialog.cpp:932 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:402 engines/engine.cpp:413
-#: 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/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 "OK"
-
#: gui/KeysDialog.cpp:49
msgid "Select an action and click 'Map'"
msgstr "Selecione uma ação e clique 'Mapear'"
@@ -165,6 +287,10 @@ msgstr "Por favor selecione uma ação"
msgid "Press the key to associate"
msgstr "Pressione a tecla para associar"
+#: gui/KeysDialog.cpp:145 gui/KeysDialog.h:36
+msgid "Choose an action to map"
+msgstr "Selecione uma ação para mapear"
+
#: gui/launcher.cpp:193
msgid "Game"
msgstr "Jogo"
@@ -205,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>"
@@ -229,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"
@@ -246,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"
@@ -259,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"
@@ -277,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:95
+#: 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:69
+#: 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:1222
+#: 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/myst.cpp:245 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/myst.cpp:245
-#: engines/mohawk/riven.cpp:718 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:792
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -495,62 +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:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Sim"
-
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Não"
-
-#: gui/launcher.cpp:841
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM não conseguiu abrir a pasta especificada!"
-#: gui/launcher.cpp:853
+#: 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:867
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Escolha o jogo:"
-#: gui/launcher.cpp:941
+#: 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:999
+#: gui/launcher.cpp:1003
#, fuzzy
msgid "Do you want to load saved game?"
msgstr "Você deseja carregar ou salvar o jogo?"
-#: gui/launcher.cpp:1048
+#: 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:1052
+#: 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:1159
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Multi-Adição..."
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr ""
@@ -599,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:2298
+#: 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"
@@ -732,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"
@@ -799,191 +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:1168 gui/fluidsynth-dialog.cpp:138
-msgid "Misc"
-msgstr "Outros"
-
-#: 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."
@@ -992,65 +1107,80 @@ msgstr ""
"este tema você precisa mudar para outro idioma."
#. I18N: You must leave "#" as is, only word 'next' is translatable
-#: gui/predictivedialog.cpp:87
+#: gui/predictivedialog.cpp:86
msgid "# next"
msgstr ""
-#: gui/predictivedialog.cpp:88
+#: gui/predictivedialog.cpp:87
msgid "add"
msgstr ""
-#: gui/predictivedialog.cpp:92
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
#, fuzzy
msgid "Delete char"
msgstr "Excluir"
-#: gui/predictivedialog.cpp:96
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
msgstr ""
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:98
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr ""
-#: gui/recorderdialog.cpp:64
+#. I18N: 'Num' means Numbers
+#: gui/predictivedialog.cpp:578
+msgid "* Num"
+msgstr ""
+
+#. I18N: 'Abc' means Latin alphabet input
+#: gui/predictivedialog.cpp:581
+msgid "* Abc"
+msgstr ""
+
+#: 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:173
+#, fuzzy
+msgid "Unknown Author"
+msgstr "Erro desconhecido"
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr ""
@@ -1114,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 ""
@@ -1123,157 +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:661
+#: 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
-msgid "Clear value"
-msgstr "Limpar valor"
-
-#: gui/fluidsynth-dialog.cpp:68
-#, fuzzy
-msgid "Reverb"
-msgstr "Nunca"
-
-#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
-#, fuzzy
-msgid "Active"
-msgstr "(Ativo)"
-
-#: gui/fluidsynth-dialog.cpp:72
-msgid "Room:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:79
-msgid "Damp:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:86
-msgid "Width:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
-msgid "Level:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:100
-msgid "Chorus"
+#: 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/fluidsynth-dialog.cpp:104
-msgid "N:"
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
msgstr ""
-#: gui/fluidsynth-dialog.cpp:118
+#: gui/updates-dialog.cpp:92
#, fuzzy
-msgid "Speed:"
-msgstr "Voz"
-
-#: gui/fluidsynth-dialog.cpp:125
-msgid "Depth:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:132
-msgid "Type:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:135
-msgid "Sine"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:136
-msgid "Triangle"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:140
-msgid "Interpolation:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:143
-msgid "None (fastest)"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:144
-msgid "Linear"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:145
-msgid "Fourth-order"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:146
-msgid "Seventh-order"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset"
-msgstr ""
+msgid "Check for updates automatically"
+msgstr "Procurar por Atualizações..."
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset all FluidSynth settings to their default values."
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
msgstr ""
-#: gui/fluidsynth-dialog.cpp:217
-#, fuzzy
-msgid ""
-"Do you really want to reset all FluidSynth settings to their default values?"
-msgstr "Você realmente deseja voltar para o menu principal?"
+#: 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:228
+#: 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:306
+#: base/main.cpp:315
msgid "Menu"
msgstr "Menu"
-#: base/main.cpp:309 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:312 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:315
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Pula linha"
-#: base/main.cpp:507
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Erro ao executar o jogo:"
-#: base/main.cpp:554
+#: 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 "
@@ -1343,17 +1405,61 @@ msgstr "Usuário cancelou"
msgid "Unknown error"
msgstr "Erro desconhecido"
-#: engines/advancedDetector.cpp:317
+#. 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 ""
+
+#: common/rendermode.cpp:43
+msgid "PC-9801 (16 Colors)"
+msgstr ""
+
+#: 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 "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.:"
@@ -1361,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"
@@ -1390,11 +1496,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "~V~oltar ao menu"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:803
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:873
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
-#: engines/toltecs/menu.cpp:281 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:"
@@ -1403,11 +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:803 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/neverhood/menumodule.cpp:873 engines/pegasus/pegasus.cpp:377
-#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
-#: engines/toltecs/menu.cpp:281 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"
@@ -1431,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"
@@ -1445,23 +1560,23 @@ msgstr "~C~ancelar"
msgid "~K~eys"
msgstr "~T~eclas"
-#: engines/engine.cpp:276
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Não foi possível inicializar o formato de cor."
-#: engines/engine.cpp:284
+#: 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:293
+#: 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:298
+#: 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:398
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1475,7 +1590,7 @@ msgstr ""
"os arquivos de dados para o disco rígido.\n"
"Consulte o arquivo README para mais detalhes."
-#: engines/engine.cpp:409
+#: 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"
@@ -1489,7 +1604,7 @@ msgstr ""
"para ouvir a música do jogo.\n"
"Consulte o arquivo README para mais detalhes."
-#: engines/engine.cpp:467
+#: engines/engine.cpp:533
#, fuzzy, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1499,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:480
+#: 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 "
@@ -1509,10 +1624,14 @@ 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:483
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Iniciar de qualquer maneira"
+#: audio/adlib.cpp:2290
+msgid "AdLib Emulator"
+msgstr "Emulador AdLib"
+
#: audio/fmopl.cpp:62
msgid "MAME OPL emulator"
msgstr "Emulador MAME OPL"
@@ -1566,31 +1685,37 @@ msgstr ""
"O dispositivo de áudio preferido '%s' não pode ser usado. Veja o arquivo de "
"log para mais informações."
-#: audio/null.h:44
-msgid "No music"
-msgstr "Sem música"
-
#: audio/mods/paula.cpp:196
msgid "Amiga Audio Emulator"
msgstr "Emulador Som Amiga"
-#: audio/adlib.cpp:2291
-msgid "AdLib Emulator"
-msgstr "Emulador AdLib"
+#: audio/null.h:44
+msgid "No music"
+msgstr "Sem música"
#: audio/softsynth/appleiigs.cpp:33
msgid "Apple II GS Emulator (NOT IMPLEMENTED)"
msgstr "Emulador Apple II GS (NÃO IMPLEMENTADO)"
-#: audio/softsynth/sid.cpp:1430
-msgid "C64 Audio Emulator"
-msgstr "Emulador Som C64"
+#: audio/softsynth/cms.cpp:350
+msgid "Creative Music System Emulator"
+msgstr ""
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33
+#, fuzzy
+msgid "FM-Towns Audio"
+msgstr "Emulador FM Towns"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58
+#, fuzzy
+msgid "PC-98 Audio"
+msgstr "Áudio"
+
+#: 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"
@@ -1602,6 +1727,149 @@ msgstr "Emulador PC Speaker"
msgid "IBM PCjr Emulator"
msgstr "Emulador IBM PCjr"
+#: audio/softsynth/sid.cpp:1430
+msgid "C64 Audio Emulator"
+msgstr "Emulador Som C64"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Do you really want to return to the Launcher?"
+msgstr "Você realmente deseja voltar para o menu principal?"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Launcher"
+msgstr "Menu principal"
+
+#: backends/events/default/default-events.cpp:218
+msgid "Do you really want to quit?"
+msgstr "Você realmente deseja sair?"
+
+#: 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 "Sair"
+
+#: 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 "Touchscreen 'Modo Toque' - Clique Esquerdo"
+
+#: 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 "Touchscreen 'Modo Toque' - Clique Direito"
+
+#: 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 "Touchscreen 'Modo Toque' - Acima (Sem Clicar)"
+
+#: backends/events/gph/gph-events.cpp:409
+msgid "Maximum Volume"
+msgstr "Volume máximo"
+
+#: backends/events/gph/gph-events.cpp:411
+msgid "Increasing Volume"
+msgstr "Aumentando Volume"
+
+#: backends/events/gph/gph-events.cpp:417
+msgid "Minimal Volume"
+msgstr "Volume mínimo"
+
+#: backends/events/gph/gph-events.cpp:419
+msgid "Decreasing Volume"
+msgstr "Diminuindo Volume"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Enabled"
+msgstr "Clicando Habilitado"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Disabled"
+msgstr "Clicando Desabilitado"
+
+#: backends/events/openpandora/op-events.cpp:174
+#, fuzzy
+msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
+msgstr "Touchscreen 'Modo Toque' - Acima (Sem Clicar)"
+
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
+msgid "Do you want to quit ?"
+msgstr "Você deseja sair ?"
+
+#. I18N: Trackpad mode toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:308
+#, fuzzy
+msgid "Trackpad mode is now"
+msgstr "Modo Touchpad desligado."
+
+#. 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 ""
+
+#: backends/events/webossdl/webossdl-events.cpp:311
+#: backends/events/webossdl/webossdl-events.cpp:338
+msgid "OFF"
+msgstr ""
+
+#: backends/events/webossdl/webossdl-events.cpp:315
+msgid "Swipe two fingers to the right to toggle."
+msgstr ""
+
+#. I18N: Auto-drag toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:335
+msgid "Auto-drag mode is now"
+msgstr ""
+
+#: backends/events/webossdl/webossdl-events.cpp:342
+msgid "Swipe three fingers to the right to toggle."
+msgstr ""
+
+#: backends/graphics/opengl/opengl-graphics.cpp:126
+#, fuzzy
+msgid "OpenGL"
+msgstr "Abrir"
+
+#: backends/graphics/opengl/opengl-graphics.cpp:127
+msgid "OpenGL (No filtering)"
+msgstr ""
+
+#: 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 "Normal (sem escala)"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:66
+msgctxt "lowres"
+msgid "Normal (no scaling)"
+msgstr "Normal (sem escala)"
+
+#: 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:2219
+msgid "Disabled aspect ratio correction"
+msgstr "Correção de proporção desabilitada"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
+msgid "Active graphics filter:"
+msgstr "Ativa os filtros gráficos"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+msgid "Windowed mode"
+msgstr "Modo janela"
+
#: backends/keymapper/remap-dialog.cpp:48
msgid "Keymap:"
msgstr "Mapa de Teclas:"
@@ -1632,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"
@@ -1708,18 +1976,26 @@ msgstr "Som de alta qualidade (mais lento) (reiniciar)"
msgid "Disable power off"
msgstr "Desativar desligamento"
+#: 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 "Modo clique-e-arraste do mouse ligado."
+#: 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 "Modo clique-e-arraste do mouse desligado."
+#: 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 "Modo Touchpad ligado."
+#: 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 "Modo Touchpad desligado."
@@ -1730,9 +2006,9 @@ msgstr ""
#: 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
-#: backends/platform/tizen/form.cpp:275
msgid "Left Click"
msgstr "Clique com o botão esquerdo"
@@ -1743,66 +2019,32 @@ msgstr "Item do meio na esquerda"
#: backends/platform/maemo/maemo.cpp:220
#: backends/platform/symbian/src/SymbianActions.cpp:43
-#: backends/platform/wince/CEActionsSmartphone.cpp:44
#: backends/platform/tizen/form.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:44
msgid "Right Click"
msgstr "Clique com o botão direito"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:77
+#: backends/platform/sdl/macosx/appmenu_osx.mm:88
msgid "Hide ScummVM"
msgstr "Ocultar ScummVM"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:82
+#: backends/platform/sdl/macosx/appmenu_osx.mm:93
msgid "Hide Others"
msgstr "Ocultar Outros"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:87
+#: backends/platform/sdl/macosx/appmenu_osx.mm:98
msgid "Show All"
msgstr "Mostrar Tudo"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:109
#: backends/platform/sdl/macosx/appmenu_osx.mm:120
+#: backends/platform/sdl/macosx/appmenu_osx.mm:131
msgid "Window"
msgstr "Janela"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:114
+#: backends/platform/sdl/macosx/appmenu_osx.mm:125
msgid "Minimize"
msgstr "Minimizar"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:46
-msgid "Normal (no scaling)"
-msgstr "Normal (sem escala)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:65
-msgctxt "lowres"
-msgid "Normal (no scaling)"
-msgstr "Normal (sem escala)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
-msgid "Enabled aspect ratio correction"
-msgstr "Correção de proporção habilitada"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
-msgid "Disabled aspect ratio correction"
-msgstr "Correção de proporção desabilitada"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
-msgid "Active graphics filter:"
-msgstr "Ativa os filtros gráficos"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
-msgid "Windowed mode"
-msgstr "Modo janela"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:118
-#, fuzzy
-msgid "OpenGL"
-msgstr "Abrir"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:119
-msgid "OpenGL (No filtering)"
-msgstr ""
-
#: backends/platform/symbian/src/SymbianActions.cpp:38
#: backends/platform/wince/CEActionsSmartphone.cpp:39
msgid "Up"
@@ -1846,14 +2088,6 @@ msgstr "Pular texto"
msgid "Fast mode"
msgstr "Modo rápido"
-#: backends/platform/symbian/src/SymbianActions.cpp:52
-#: backends/platform/wince/CEActionsPocket.cpp:44
-#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: backends/events/default/default-events.cpp:218 engines/scumm/dialogs.cpp:192
-#: engines/scumm/help.cpp:83 engines/scumm/help.cpp:85
-msgid "Quit"
-msgstr "Sair"
-
#: backends/platform/symbian/src/SymbianActions.cpp:53
msgid "Debugger"
msgstr "Depurador"
@@ -1870,9 +2104,50 @@ msgstr "Teclado virtual"
msgid "Key mapper"
msgstr "Mapeador de Teclas"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:186
-msgid "Do you want to quit ?"
-msgstr "Você deseja sair ?"
+#: backends/platform/tizen/form.cpp:263
+msgid "Right Click Once"
+msgstr "Clique com o botão direito apenas uma vez"
+
+#: backends/platform/tizen/form.cpp:271
+msgid "Move Only"
+msgstr "Apenas mover"
+
+#: backends/platform/tizen/form.cpp:294
+msgid "Escape Key"
+msgstr "Tecla Escape"
+
+#: backends/platform/tizen/form.cpp:299
+msgid "Game Menu"
+msgstr "Menu do jogo"
+
+#: backends/platform/tizen/form.cpp:304
+msgid "Show Keypad"
+msgstr "Mostrar teclado"
+
+#: backends/platform/tizen/form.cpp:309
+msgid "Control Mouse"
+msgstr "Controle do Mouse"
+
+#: backends/platform/tizen/fs.cpp:259
+msgid "[ Data ]"
+msgstr ""
+
+#: backends/platform/tizen/fs.cpp:263
+msgid "[ Resources ]"
+msgstr ""
+
+#: backends/platform/tizen/fs.cpp:267
+msgid "[ SDCard ]"
+msgstr ""
+
+#: backends/platform/tizen/fs.cpp:271
+msgid "[ Media ]"
+msgstr ""
+
+#: backends/platform/tizen/fs.cpp:275
+#, fuzzy
+msgid "[ Shared ]"
+msgstr "Compartilhamento:"
#: backends/platform/wii/options.cpp:51
msgid "Video"
@@ -2120,103 +2395,37 @@ msgstr ""
"Não se esqueça de mapear uma tecla para \"Ocultar a barra de ferramentas\" "
"para ver todo o seu inventário"
-#: backends/events/default/default-events.cpp:196
-msgid "Do you really want to return to the Launcher?"
-msgstr "Você realmente deseja voltar para o menu principal?"
-
-#: backends/events/default/default-events.cpp:196
-msgid "Launcher"
-msgstr "Menu principal"
-
-#: backends/events/default/default-events.cpp:218
-msgid "Do you really want to quit?"
-msgstr "Você realmente deseja sair?"
-
-#: 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 "Touchscreen 'Modo Toque' - Clique Esquerdo"
-
-#: 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 "Touchscreen 'Modo Toque' - Clique Direito"
-
-#: 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 "Touchscreen 'Modo Toque' - Acima (Sem Clicar)"
-
-#: backends/events/gph/gph-events.cpp:409
-msgid "Maximum Volume"
-msgstr "Volume máximo"
-
-#: backends/events/gph/gph-events.cpp:411
-msgid "Increasing Volume"
-msgstr "Aumentando Volume"
-
-#: backends/events/gph/gph-events.cpp:417
-msgid "Minimal Volume"
-msgstr "Volume mínimo"
-
-#: backends/events/gph/gph-events.cpp:419
-msgid "Decreasing Volume"
-msgstr "Diminuindo Volume"
-
-#: backends/events/openpandora/op-events.cpp:174
-#, fuzzy
-msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
-msgstr "Touchscreen 'Modo Toque' - Acima (Sem Clicar)"
-
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Procurar por Atualizações..."
-#: backends/platform/tizen/form.cpp:263
-msgid "Right Click Once"
-msgstr "Clique com o botão direito apenas uma vez"
-
-#: backends/platform/tizen/form.cpp:271
-msgid "Move Only"
-msgstr "Apenas mover"
-
-#: backends/platform/tizen/form.cpp:294
-msgid "Escape Key"
-msgstr "Tecla Escape"
-
-#: backends/platform/tizen/form.cpp:299
-msgid "Game Menu"
-msgstr "Menu do jogo"
-
-#: backends/platform/tizen/form.cpp:304
-msgid "Show Keypad"
-msgstr "Mostrar teclado"
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+msgid "Color mode"
+msgstr ""
-#: backends/platform/tizen/form.cpp:309
-msgid "Control Mouse"
-msgstr "Controle do Mouse"
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Enabled"
-msgstr "Clicando Habilitado"
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Disabled"
-msgstr "Clicando Desabilitado"
+#: engines/adl/detection.cpp:64
+msgid "Show scanlines"
+msgstr ""
-#: engines/agi/detection.cpp:147 engines/drascula/detection.cpp:302
-#: engines/dreamweb/detection.cpp:47 engines/neverhood/detection.cpp:160
-#: engines/sci/detection.cpp:394 engines/toltecs/detection.cpp:200
-#: engines/zvision/detection_tables.h:51
+#: 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 ""
-#: engines/agi/detection.cpp:148 engines/drascula/detection.cpp:303
-#: engines/dreamweb/detection.cpp:48 engines/neverhood/detection.cpp:161
-#: engines/sci/detection.cpp:395 engines/toltecs/detection.cpp:201
+#: 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 ""
@@ -2239,19 +2448,46 @@ msgid ""
"Enables mouse support. Allows to use mouse for movement and in game menus."
msgstr ""
-#: engines/agi/saveload.cpp:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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"
@@ -2262,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"
@@ -2273,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"
@@ -2284,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!"
@@ -2316,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 ""
@@ -2333,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 ""
@@ -2354,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"
@@ -2524,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"
@@ -2575,15 +2821,25 @@ msgstr ""
"Não é possível salvar o jogo na posição %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:194
+#, fuzzy
+msgid "Load file"
+msgstr "Carregar jogo:"
+
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Carregando jogo..."
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:209
+#, fuzzy
+msgid "Save file"
+msgstr "Falha ao salvar jogo!"
+
+#: 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"
@@ -2600,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"
@@ -2661,175 +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:395
+msgid "Enable high resolution graphics/content"
+msgstr ""
+
+#: 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:385
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
msgstr ""
-#: engines/sci/detection.cpp:404
+#: engines/sci/detection.cpp:434
msgid "Use IMF/Yamaha FB-01 for MIDI output"
msgstr ""
-#: engines/sci/detection.cpp:405
+#: 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:415
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr ""
-#: engines/sci/detection.cpp:416
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
msgstr ""
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr ""
-#: engines/sci/detection.cpp:427
+#: engines/sci/detection.cpp:457
msgid ""
"Use the Windows cursors (smaller and monochrome) instead of the DOS ones"
msgstr ""
-#: engines/sci/detection.cpp:437
+#: engines/sci/detection.cpp:467
#, fuzzy
msgid "Use silver cursors"
msgstr "Cursor normal"
-#: engines/sci/detection.cpp:438
+#: 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:600
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Somente Voz"
-#: engines/scumm/dialogs.cpp:601
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Voz e Legendas"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Somente Legendas"
-#: engines/scumm/dialogs.cpp:610
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Voz e Legendas"
-#: engines/scumm/dialogs.cpp:656
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr ""
-#: engines/scumm/dialogs.cpp:658
+#: engines/scumm/dialogs.cpp:656
msgid "Refer to your Loom(TM) manual for help."
msgstr ""
-#: engines/scumm/dialogs.cpp:662
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr ""
-#: engines/scumm/dialogs.cpp:663
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr ""
@@ -3366,7 +3647,26 @@ msgstr "Voar para direita"
msgid "Fly to lower right"
msgstr "Voar para direita inferior"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/input.cpp:578
+#, fuzzy
+msgid "Snap scroll on"
+msgstr "Descer na lista"
+
+#: engines/scumm/input.cpp:580
+msgid "Snap scroll off"
+msgstr ""
+
+#: engines/scumm/input.cpp:593
+#, fuzzy
+msgid "Music volume: "
+msgstr "Volume da Música:"
+
+#: engines/scumm/input.cpp:610
+#, fuzzy
+msgid "Subtitle speed: "
+msgstr "Rapidez legendas:"
+
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3376,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 "
@@ -3400,6 +3700,59 @@ msgid ""
"instruments from. Music will be disabled."
msgstr ""
+#: engines/sherlock/detection.cpp:71
+msgid "Use original savegame dialog"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:72
+msgid ""
+"Files button in-game shows original savegame dialog rather than the ScummVM "
+"menu"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:81
+msgid "Pixellated scene transitions"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:82
+msgid "When changing scenes, a randomized pixel transition is done"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:91
+msgid "Don't show hotspots when moving mouse"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:92
+msgid ""
+"Only show hotspot names after you actually click on a hotspot or action "
+"button"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:101
+#, fuzzy
+msgid "Show character portraits"
+msgstr "Trocador de caracteres"
+
+#: engines/sherlock/detection.cpp:102
+msgid "Show portraits for the characters when conversing"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:111
+msgid "Slide dialogs into view"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:112
+msgid "Slide UI dialogs into view, rather than simply showing them immediately"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:121
+msgid "Transparent windows"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:122
+msgid "Show windows with a partially transparent background"
+msgstr ""
+
#: engines/sky/compact.cpp:130
msgid ""
"Unable to find \"sky.cpt\" file!\n"
@@ -3503,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"
@@ -3610,26 +3972,6 @@ msgstr ""
#~ msgid "Active filter mode: Nearest"
#~ msgstr "Filtro de imagem ativo: Nearest"
-#~ msgid "Enable Roland GS Mode"
-#~ msgstr "Ligar modo Roland GS"
-
-#~ msgid "Hercules Green"
-#~ msgstr "Hercules Green"
-
-#~ msgid "Hercules Amber"
-#~ msgstr "Hercules Amber"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Green"
-#~ msgstr "Hercules Green"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Amber"
-#~ msgstr "Hercules Amber"
-
-#~ msgid "Save game failed!"
-#~ msgstr "Falha ao salvar jogo!"
-
#~ msgctxt "lowres"
#~ msgid "Add Game..."
#~ msgstr "Adicionar Jogo..."
@@ -3643,8 +3985,5 @@ msgstr ""
#~ msgid "Command line argument not processed"
#~ msgstr "Linha de comando não processada"
-#~ msgid "FM Towns Emulator"
-#~ msgstr "Emulador FM Towns"
-
#~ msgid "Invalid Path"
#~ msgstr "Pasta inválida"
diff --git a/po/ru_RU.po b/po/ru_RU.po
index 6941d5773a..4979c5a072 100644
--- a/po/ru_RU.po
+++ b/po/ru_RU.po
@@ -1,23 +1,23 @@
# Russian translation for ScummVM.
-# Copyright (C) 2010-2015 The ScummVM Team
+# Copyright (C) 2010-2016 The ScummVM Team
# This file is distributed under the same license as the ScummVM package.
-# Eugene Sandulenko <sev@scummvm.org>, 2010-2014
+# Eugene Sandulenko <sev@scummvm.org>, 2010-2016
#
msgid ""
msgstr ""
-"Project-Id-Version: ScummVM 1.3.0svn\n"
+"Project-Id-Version: ScummVM 1.8.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2015-09-06 15:14+0200\n"
-"PO-Revision-Date: 2014-07-02 17:20+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"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=iso-8859-5\n"
"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n"
-"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
-"X-Generator: Poedit 1.5.5\n"
+"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
+"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
+"X-Generator: Poedit 1.8.7\n"
#: gui/about.cpp:94
#, c-format
@@ -38,7 +38,7 @@ msgstr "¿ÞÚÐ×Ðâì áÚàëâëÕ äÐÙÛë"
#: gui/browser.cpp:68
msgid "Show files marked with the hidden attribute"
-msgstr "¿ÞÚÐ×Ðâì äÐÙÛë á ÐâàØÑãâÞÜ \"áÚàëâì\""
+msgstr "¿ÞÚÐ×Ðâì äÐÙÛë á ÐâàØÑãâÞÜ \"áÚàëâëÙ\""
#: gui/browser.cpp:72
msgid "Go up"
@@ -54,28 +54,29 @@ msgid "Go up"
msgstr "²ÒÕàå"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:74 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: 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/fluidsynth-dialog.cpp:152 engines/engine.cpp:483
-#: backends/platform/wii/options.cpp:48
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
-#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:191 engines/sword1/control.cpp:865
+#: 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 "¾âÜÕÝÐ"
#: gui/browser.cpp:76 gui/browser_osx.mm:103 gui/chooser.cpp:47
-#: gui/themebrowser.cpp:56
+#: gui/filebrowser-dialog.cpp:65 gui/themebrowser.cpp:56
msgid "Choose"
msgstr "²ëÑàÐâì"
#: gui/editrecorddialog.cpp:58
msgid "Author:"
-msgstr ""
+msgstr "°ÒâÞà:"
#: gui/editrecorddialog.cpp:59 gui/launcher.cpp:204
msgid "Name:"
@@ -83,63 +84,181 @@ msgstr "½Ð×ÒÐÝØÕ:"
#: gui/editrecorddialog.cpp:60
msgid "Notes:"
-msgstr ""
+msgstr "·ÐÜÕâÚØ:"
-#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:75
+#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74
msgid "Ok"
+msgstr "Ok"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Choose file for loading"
+msgstr "²ëÑÕàØâÕ äÐÙÛ ÔÛï ×ÐÓàã×ÚØ"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Enter filename for saving"
+msgstr "²ÒÕÔØâÕ ØÜï äÐÙÛÐ ÔÛï ×ÐßØáØ"
+
+#: gui/filebrowser-dialog.cpp:132
+msgid "Do you really want to overwrite the file?"
+msgstr "²ë ÔÕÙáâÒØâÕÛìÝÞ åÞâØâÕ ßÕàÕ×ÐßØáÐâì íâÞâ äÐÙÛ?"
+
+#: 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 "´Ð"
+
+#: 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 "½Õâ"
+
+#: gui/fluidsynth-dialog.cpp:68
+msgid "Reverb"
+msgstr "ÀÕÒÕàÑÕàÐæØï"
+
+#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
+msgid "Active"
+msgstr "°ÚâØÒÝÞ"
+
+#: gui/fluidsynth-dialog.cpp:72
+msgid "Room:"
+msgstr "ºÞÜÝÐâÐ:"
+
+#: gui/fluidsynth-dialog.cpp:79
+msgid "Damp:"
+msgstr "²ÛÐÖÝÞáâì:"
+
+#: gui/fluidsynth-dialog.cpp:86
+msgid "Width:"
+msgstr "ÈØàØÝÐ:"
+
+#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
+msgid "Level:"
+msgstr "ÃàÞÒÕÝì:"
+
+#: gui/fluidsynth-dialog.cpp:100
+msgid "Chorus"
+msgstr "ÅÞà"
+
+#: gui/fluidsynth-dialog.cpp:104
+msgid "N:"
+msgstr "N:"
+
+#: gui/fluidsynth-dialog.cpp:118
+msgid "Speed:"
+msgstr "ÁÚÞàÞáâì:"
+
+#: gui/fluidsynth-dialog.cpp:125
+msgid "Depth:"
+msgstr "³ÛãÑØÝÐ:"
+
+#: gui/fluidsynth-dialog.cpp:132
+msgid "Type:"
+msgstr "ÂØß:"
+
+#: gui/fluidsynth-dialog.cpp:135
+msgid "Sine"
+msgstr "ÁØÝãáÞØÔÐ"
+
+#: gui/fluidsynth-dialog.cpp:136
+msgid "Triangle"
+msgstr "ÂàÕãÓÞÛìÝÐï"
+
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
+msgid "Misc"
+msgstr "ÀÐ×ÝÞÕ"
+
+#: gui/fluidsynth-dialog.cpp:140
+msgid "Interpolation:"
+msgstr "¸ÝâÕàßÞÛïæØï:"
+
+#: gui/fluidsynth-dialog.cpp:143
+msgid "None (fastest)"
+msgstr "½Õâ (ÑëáâàëÙ)"
+
+#: gui/fluidsynth-dialog.cpp:144
+msgid "Linear"
+msgstr "»ØÝÕÙÝÐï"
+
+#: gui/fluidsynth-dialog.cpp:145
+msgid "Fourth-order"
+msgstr "ÇÕâÒÕàâÞÓÞ ßÞàïÔÚÐ"
+
+#: gui/fluidsynth-dialog.cpp:146
+msgid "Seventh-order"
+msgstr "ÁÕÔìÜÞÓÞ ßÞàïÔÚÐ"
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset"
+msgstr "ÁÑàÞá"
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset all FluidSynth settings to their default values."
+msgstr "ÁÑàÞáØâì ÒáÕ ãáâÐÝÞÒÚØ FluidSynth Ò ×ÝÐçÕÝØï ßÞ ãÜÞÛçÐÝØî."
+
+#: 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 "OK"
+
+#: gui/fluidsynth-dialog.cpp:217
+msgid ""
+"Do you really want to reset all FluidSynth settings to their default values?"
msgstr ""
+"²ë ÔÕÙáâÒØâÕÛìÝÞ åÞâØâÕ áÑàÞáØâì ÒáÕ ãáâÐÝÞÒÚØ FluidSynth Ò ×ÝÐçÕÝØï ßÞ "
+"ãÜÞÛçÐÝØî?"
-#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
+#: 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 "·ÐÚàëâì"
-#: gui/gui-manager.cpp:120
+#: gui/gui-manager.cpp:122
msgid "Mouse click"
msgstr "ºÛØÚ Üëèìî"
-#: gui/gui-manager.cpp:124 base/main.cpp:319
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "¿ÞÚÐ×Ðâì ÚÛÐÒØÐâãàã"
-#: gui/gui-manager.cpp:128 base/main.cpp:323
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "¿ÕàÕÝÐ×ÝÐçØâì ÚÛÐÒØèØ"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:87
+#: gui/gui-manager.cpp:133 base/main.cpp:335 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "¿ÕàÕÚÛîçÕÝØÕ ÝÐ ÒÕáì íÚàÐÝ"
-#: gui/KeysDialog.h:36 gui/KeysDialog.cpp:145
-msgid "Choose an action to map"
-msgstr "²ëÑÕàØâÕ ÔÕÙáâÒØÕ ÔÛï ÝÐ×ÝÐçÕÝØï"
-
#: gui/KeysDialog.cpp:41
msgid "Map"
msgstr "½Ð×ÝÐçØâì"
-#: gui/KeysDialog.cpp:42 gui/launcher.cpp:352 gui/launcher.cpp:1048
-#: gui/launcher.cpp:1052 gui/massadd.cpp:92 gui/options.cpp:1238
-#: gui/saveload-dialog.cpp:932 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:402 engines/engine.cpp:413
-#: 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/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 "OK"
-
#: gui/KeysDialog.cpp:49
msgid "Select an action and click 'Map'"
msgstr "²ëÑÕàØâÕ ÔÕÙáâÒØÕ Ø ÚÛØÚÝØâÕ '½Ð×ÝÐçØâì'"
@@ -162,6 +281,10 @@ msgstr "¿ÞÖÐÛãÙáâÐ, ÒëÑÕàØâÕ ÔÕÙáâÒØÕ"
msgid "Press the key to associate"
msgstr "½ÐÖÜØâÕ ÚÛÐÒØèã ÔÛï ÝÐ×ÝÐçÕÝØï"
+#: gui/KeysDialog.cpp:145 gui/KeysDialog.h:36
+msgid "Choose an action to map"
+msgstr "²ëÑÕàØâÕ ÔÕÙáâÒØÕ ÔÛï ÝÐ×ÝÐçÕÝØï"
+
#: gui/launcher.cpp:193
msgid "Game"
msgstr "¸ÓàÐ"
@@ -203,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 "<ßÞ ãÜÞÛçÐÝØî>"
@@ -226,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 "³àä"
@@ -243,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 "°ãÔØÞ"
@@ -256,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 "³àÞÜÚ"
@@ -274,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:95
+#: 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:69
+#: 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 ÔÛï âÞÓÞ, çâÞÑë ÔÞÑÐÒØâì ÝÕáÚÞÛìÚÞ ØÓà"
+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:1222
+#: 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/myst.cpp:245 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/myst.cpp:245
-#: engines/mohawk/riven.cpp:718 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:792
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -491,61 +615,41 @@ msgstr ""
"²ë ÔÕÙáâÒØâÕÛìÝÞ åÞâØâÕ ×ÐßãáâØâì ÔÕâÕÚâÞà ÒáÕå ØÓà? ÍâÞ ßÞâÕÝæØÐÛìÝÞ ÜÞÖÕâ "
"ÔÞÑÐÒØâì ÑÞÛìèÞÕ ÚÞÛØçÕáâÒÞ ØÓà."
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "´Ð"
-
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "½Õâ"
-
-#: gui/launcher.cpp:841
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM ÝÕ ÜÞÖÕâ ÞâÚàëâì ãÚÐ×ÐÝÝãî ÔØàÕÚâÞàØî!"
-#: gui/launcher.cpp:853
+#: gui/launcher.cpp:857
msgid "ScummVM could not find any game in the specified directory!"
msgstr "ScummVM ÝÕ ÜÞÖÕâ ÝÐÙâØ ØÓàã Ò ãÚÐ×ÐÝÝÞÙ ÔØàÕÚâÞàØØ!"
-#: gui/launcher.cpp:867
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "²ëÑÕàØâÕ ØÓàã:"
-#: gui/launcher.cpp:941
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "²ë ÔÕÙáâÒØâÕÛìÝÞ åÞâØâÕ ãÔÐÛØâì ÝÐáâàÞÙÚØ ÔÛï íâÞÙ ØÓàë?"
-#: gui/launcher.cpp:999
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "²ë åÞâØâÕ ×ÐÓàã×Øâì ØÓàã?"
-#: gui/launcher.cpp:1048
+#: gui/launcher.cpp:1052
msgid "This game does not support loading games from the launcher."
msgstr "ÍâÐ ØÓàÐ ÝÕ ßÞÔÔÕàÖØÒÐÕâ ×ÐÓàã×Úã áÞåàÐÝÕÝØÙ çÕàÕ× ÓÛÐÒÝÞÕ ÜÕÝî."
-#: gui/launcher.cpp:1052
+#: gui/launcher.cpp:1056
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr "ScummVM ÝÕ áÜÞÓ ÝÐÙâØ ÔÒØÖÞÚ ÔÛï ×ÐßãáÚÐ ÒëÑàÐÝÝÞÙ ØÓàë!"
-#: gui/launcher.cpp:1159
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "¼ÝÞÓÞ ØÓà..."
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1165
msgid "Record..."
-msgstr ""
+msgstr "·ÐßØáì..."
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
@@ -572,149 +676,147 @@ msgstr "½ÐÙÔÕÝÞ %d ÝÞÒëå ØÓà, ßàÞßãéÕÝÞ %d àÐÝÕÕ ÔÞÑÐÒÛÕÝÝëå ØÓà ..."
#: gui/onscreendialog.cpp:101 gui/onscreendialog.cpp:103
msgid "Stop"
-msgstr ""
+msgstr "ÁâÞß"
#: gui/onscreendialog.cpp:106
msgid "Edit record description"
-msgstr ""
+msgstr "ÀÕÔÐÚâØàÞÒÐâì ÞßØáÐÝØÕ ×ÐßØáØ"
#: gui/onscreendialog.cpp:108
-#, fuzzy
msgid "Switch to Game"
-msgstr "¿ÕàÕÚÛîçØâì"
+msgstr "¿ÕàÕÚÛîçØâìáï Ò ØÓàã"
#: gui/onscreendialog.cpp:110
-#, fuzzy
msgid "Fast replay"
-msgstr "±ëáâàëÙ àÕÖØÜ"
+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:2298
+#: 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"
@@ -722,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"
@@ -791,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"
@@ -808,175 +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:1168 gui/fluidsynth-dialog.cpp:138
-msgid "Misc"
-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."
@@ -985,64 +1095,75 @@ msgstr ""
"ØáßÞÛì×ÞÒÐâì íâã âÕÜã, ÒÐÜ ÝÕÞÑåÞÔØÜÞ áÝÐçÐÛÐ ßÕàÕÚÛîçØâìáï ÝÐ ÔàãÓÞÙ ï×ëÚ."
#. I18N: You must leave "#" as is, only word 'next' is translatable
-#: gui/predictivedialog.cpp:87
+#: gui/predictivedialog.cpp:86
msgid "# next"
-msgstr ""
+msgstr "# áÛÕÔ"
-#: gui/predictivedialog.cpp:88
+#: gui/predictivedialog.cpp:87
msgid "add"
-msgstr ""
+msgstr "ÔÞÑ"
-#: gui/predictivedialog.cpp:92
-#, fuzzy
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
-msgstr "ÃÔÐÛØâì"
+msgstr "ÃÔÐÛØâì áØÜÒÞÛ"
-#: gui/predictivedialog.cpp:96
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
-msgstr ""
+msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:98
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
-msgstr ""
+msgstr "* Pre"
+
+#. I18N: 'Num' means Numbers
+#: gui/predictivedialog.cpp:578
+msgid "* Num"
+msgstr "* Æäà"
-#: gui/recorderdialog.cpp:64
+#. I18N: 'Abc' means Latin alphabet input
+#: gui/predictivedialog.cpp:581
+msgid "* Abc"
+msgstr "* Abc"
+
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
-msgstr ""
+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 ""
+msgstr "·ÐßØáÐâì"
-#: gui/recorderdialog.cpp:72
-#, fuzzy
+#: gui/recorderdialog.cpp:71
msgid "Playback"
-msgstr "¸ÓàÐâì"
+msgstr "²ÞáßàÞØ×ÒÕáâØ"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
-msgstr ""
+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 ""
+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 ""
+msgstr "·ÐÜÕâÚØ: "
-#: gui/recorderdialog.cpp:155
-#, fuzzy
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
-msgstr "²ë ÔÕÙáâÒØâÕÛìÝÞ åÞâØâÕ ãÔÐÛØâì íâÞ áÞåàÐÝÕÝØÕ?"
+msgstr "²ë ÔÕÙáâÒØâÕÛìÝÞ åÞâØâÕ ãÔÐÛØâì íâã ×ÐßØáì?"
+
+#: gui/recorderdialog.cpp:173
+msgid "Unknown Author"
+msgstr "½ÕØ×ÒÕáâÝëÙ ÐÒâÞà"
#: gui/saveload-dialog.cpp:167
msgid "List view"
@@ -1104,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:"
@@ -1113,151 +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:661
+#: 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
-msgid "Clear value"
-msgstr "¾çØáâØâì ×ÝÐçÕÝØÕ"
-
-#: gui/fluidsynth-dialog.cpp:68
-msgid "Reverb"
-msgstr "ÀÕÒÕàÑÕàÐæØï"
-
-#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
-msgid "Active"
-msgstr "°ÚâØÒÝÞ"
-
-#: gui/fluidsynth-dialog.cpp:72
-msgid "Room:"
-msgstr "ºÞÜÝÐâÐ:"
-
-#: gui/fluidsynth-dialog.cpp:79
-msgid "Damp:"
-msgstr "²ÛÐÖÝÞáâì:"
-
-#: gui/fluidsynth-dialog.cpp:86
-msgid "Width:"
-msgstr "ÈØàØÝÐ:"
-
-#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
-msgid "Level:"
-msgstr "ÃàÞÒÕÝì:"
-
-#: gui/fluidsynth-dialog.cpp:100
-msgid "Chorus"
-msgstr "ÅÞà"
-
-#: gui/fluidsynth-dialog.cpp:104
-msgid "N:"
-msgstr "N:"
-
-#: gui/fluidsynth-dialog.cpp:118
-msgid "Speed:"
-msgstr "ÁÚÞàÞáâì:"
-
-#: gui/fluidsynth-dialog.cpp:125
-msgid "Depth:"
-msgstr "³ÛãÑØÝÐ:"
-
-#: gui/fluidsynth-dialog.cpp:132
-msgid "Type:"
-msgstr "ÂØß:"
-
-#: gui/fluidsynth-dialog.cpp:135
-msgid "Sine"
-msgstr "ÁØÝãáÞØÔÐ"
-
-#: gui/fluidsynth-dialog.cpp:136
-msgid "Triangle"
-msgstr "ÂàÕãÓÞÛìÝÐï"
-
-#: gui/fluidsynth-dialog.cpp:140
-msgid "Interpolation:"
-msgstr "¸ÝâÕàßÞÛïæØï:"
-
-#: gui/fluidsynth-dialog.cpp:143
-msgid "None (fastest)"
-msgstr "½Õâ (ÑëáâàëÙ)"
-
-#: gui/fluidsynth-dialog.cpp:144
-msgid "Linear"
-msgstr "»ØÝÕÙÝÐï"
-
-#: gui/fluidsynth-dialog.cpp:145
-msgid "Fourth-order"
-msgstr "ÇÕâÒÕàâÞÓÞ ßÞàïÔÚÐ"
+#: 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/fluidsynth-dialog.cpp:146
-msgid "Seventh-order"
-msgstr "ÁÕÔìÜÞÓÞ ßÞàïÔÚÐ"
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr "(²ë ÒáÕÓÔÐ ÜÞÖÕâÕ ÒÚÛîçØâì Õñ Ò ÝÐáâàÞÙÚÐå ÝÐ ×ÐÚÛÐÔÚÕ \"ÀÐ×ÝÞÕ\")"
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset"
-msgstr "ÁÑàÞá"
+#: gui/updates-dialog.cpp:92
+msgid "Check for updates automatically"
+msgstr "°ÒâÞÜÐâØçÕáÚØ ßàÞÒÕàïâì ÞÑÝÞÒÛÕÝØï"
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset all FluidSynth settings to their default values."
-msgstr "ÁÑàÞáØâì ÒáÕ ãáâÐÝÞÒÚØ FluidSynth Ò ×ÝÐçÕÝØï ßÞ ãÜÞÛçÐÝØî."
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr "¿àÞÔÞÛÖØâì"
-#: gui/fluidsynth-dialog.cpp:217
-msgid ""
-"Do you really want to reset all FluidSynth settings to their default values?"
-msgstr ""
-"²ë ÔÕÙáâÒØâÕÛìÝÞ åÞâØâÕ áÑàÞáØâì ÒáÕ ãáâÐÝÞÒÚØ FluidSynth Ò ×ÝÐçÕÝØï ßÞ "
-"ãÜÞÛçÐÝØî?"
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
+msgid "Clear value"
+msgstr "¾çØáâØâì ×ÝÐçÕÝØÕ"
-#: base/main.cpp:228
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "´ÒØÖÞÚ ÝÕ ßÞÔÔÕàÖØÒÐÕâ ãàÞÒÕÝì ÞâÛÐÔÚØ '%s'"
-#: base/main.cpp:306
+#: base/main.cpp:315
msgid "Menu"
msgstr "¼ÕÝî"
-#: base/main.cpp:309 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:312 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:315
+#: base/main.cpp:324
msgid "Skip line"
msgstr "¿àÞßãáâØâì áâàÞÚã"
-#: base/main.cpp:507
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "¾èØÑÚÐ ×ÐßãáÚÐ ØÓàë:"
-#: base/main.cpp:554
+#: base/main.cpp:571
msgid "Could not find any engine capable of running the selected game"
msgstr "½Õ ÜÞÓã ÝÐÙâØ ÔÒØÖÞÚ ÔÛï ×ÐßãáÚÐ ÒëÑàÐÝÝÞÙ ØÓàë"
@@ -1325,17 +1383,60 @@ msgstr "¿àÕàÒÐÝÞ ßÞÛì×ÞÒÐâÕÛÕÜ"
msgid "Unknown error"
msgstr "½ÕØ×ÒÕáâÝÐï ÞèØÑÚÐ"
-#: engines/advancedDetector.cpp:317
+#. I18N: Hercules is graphics card name
+#: common/rendermode.cpp:35
+msgid "Hercules Green"
+msgstr "Hercules ·ÕÛñÝëÙ"
+
+#: common/rendermode.cpp:36
+msgid "Hercules Amber"
+msgstr "Hercules ÏÝâÐàÝëÙ"
+
+#: common/rendermode.cpp:42
+msgid "PC-9821 (256 Colors)"
+msgstr "PC-9821 (256 æÒÕâÞÒ)"
+
+#: common/rendermode.cpp:43
+msgid "PC-9801 (16 Colors)"
+msgstr "PC-9801 (16 æÒÕâÞÒ)"
+
+#: common/rendermode.cpp:73
+msgctxt "lowres"
+msgid "Hercules Green"
+msgstr "Hercules ·ÕÛñÝëÙ"
+
+#: common/rendermode.cpp:74
+msgctxt "lowres"
+msgid "Hercules Amber"
+msgstr "Hercules ÏÝâÐàÝëÙ"
+
+#: 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 "ØÓàë, ÚÞâÞàãî Òë ßëâÐÕâÕáì ÔÞÑÐÒØâì, Ø ãÚÐÖØâÕ Õñ ÒÕàáØî, ï×ëÚ Ø â.Ô."
@@ -1343,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 "~·~ÐßØáÐâì"
@@ -1372,11 +1473,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "~²~ ÓÛÐÒÝÞÕ ÜÕÝî"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:803
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:873
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
-#: engines/toltecs/menu.cpp:281 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 "ÁÞåàÐÝØâì ØÓàã:"
@@ -1385,11 +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:803 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/neverhood/menumodule.cpp:873 engines/pegasus/pegasus.cpp:377
-#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
-#: engines/toltecs/menu.cpp:281 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 "ÁÞåàÐÝØâì"
@@ -1413,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 "¾~â~ÜÕÝÐ"
@@ -1427,23 +1537,23 @@ msgstr "¾~â~ÜÕÝÐ"
msgid "~K~eys"
msgstr "~º~ÛÐÒØèØ"
-#: engines/engine.cpp:276
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "½Õ ÜÞÓã ØÝØæØÐÛØ×ØàÞÒÐâì äÞàÜÐâ æÒÕâÐ."
-#: engines/engine.cpp:284
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "½Õ ãÔÐÛÞáì ßÕàÕÚÛîçØâì ÒØÔÕÞàÕÖØÜ: '"
-#: engines/engine.cpp:293
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "½Õ ãÔÐÛÞáì ØáßÞÛì×ÞÒÐâì ÚÞààÕÚæØî áÞÞâÝÞèÕÝØï áâÞàÞÝ."
-#: engines/engine.cpp:298
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "½Õ ÜÞÓã ßàØÜÕÝØâì ßÞÛÝÞíÚàÐÝÝëÙ àÕÖØÜ."
-#: engines/engine.cpp:398
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1457,7 +1567,7 @@ msgstr ""
"ÝÐ ÖñáâÚØÙ ÔØáÚ. ¿ÞÔàÞÑÝÞáâØ ÜÞÖÝÞ ÝÐÙâØ Ò\n"
"äÐÙÛÕ README."
-#: engines/engine.cpp:409
+#: 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"
@@ -1472,7 +1582,7 @@ msgstr ""
"ßÞïÒØâáï Üã×ëÚÐ. ¿ÞÔàÞÑÝÞáâØ ÜÞÖÝÞ ÝÐÙâØ Ò\n"
"äÐÙÛÕ README."
-#: engines/engine.cpp:467
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1482,7 +1592,7 @@ msgstr ""
"README ×Ð ÑÐ×ÞÒÞÙ ØÝäÞàÜÐæØÕÙ, Ð âÐÚÖÕ ØÝáâàãÚæØïÜØ Þ âÞÜ, ÚÐÚ ßÞÛãçØâì "
"ÔÐÛìÝÕÙèãî ßÞÜÞéì."
-#: engines/engine.cpp:480
+#: 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 "
@@ -1492,10 +1602,14 @@ msgstr ""
"ßÞÔÔÕàÖØÒÐÕâáï ScummVM ßÞÛÝÞáâìî. ¾ÝÐ, áÚÞàÕÕ ÒáÕÓÞ, ÝÕ ÑãÔÕâ àÐÑÞâÐâì "
"áâÐÑØÛìÝÞ, Ø áÞåàÐÝÕÝØï ØÓà ÜÞÓãâ ÝÕ àÐÑÞâÐâì Ò ÑãÔãéØå ÒÕàáØïå ScummVM."
-#: engines/engine.cpp:483
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "²áñ àÐÒÝÞ ×ÐßãáâØâì"
+#: audio/adlib.cpp:2290
+msgid "AdLib Emulator"
+msgstr "ÍÜãÛïâÞà AdLib"
+
#: audio/fmopl.cpp:62
msgid "MAME OPL emulator"
msgstr "ÍÜãÛïâÞà MAME OPL"
@@ -1506,7 +1620,7 @@ msgstr "ÍÜãÛïâÞà DOSBox OPL"
#: audio/fmopl.cpp:67
msgid "ALSA Direct FM"
-msgstr ""
+msgstr "¿àïÜÞÙ FM ALSA"
#: audio/mididrv.cpp:209
#, c-format
@@ -1549,42 +1663,186 @@ msgstr ""
"¿àÕÔßÞçâØâÕÛìÝÞÕ ×ÒãÚÞÒÞÕ ãáâàÞÙáâÒÞ '%s' ÝÕ ÜÞÖÕâ Ñëâì ØáßÞÛì×ÞÒÐÝÞ. "
"ÁÜÞâàØâÕ äÐÙÛ ßàÞâÞÚÞÛÐ ÔÛï ÑÞÛÕÕ ßÞÔàÞÑÝÞÙ ØÝäÞàÜÐæØØ."
-#: audio/null.h:44
-msgid "No music"
-msgstr "±Õ× Üã×ëÚØ"
-
#: audio/mods/paula.cpp:196
msgid "Amiga Audio Emulator"
msgstr "ÍÜãÛïâÞà ×ÒãÚÐ Amiga"
-#: audio/adlib.cpp:2291
-msgid "AdLib Emulator"
-msgstr "ÍÜãÛïâÞà AdLib"
+#: audio/null.h:44
+msgid "No music"
+msgstr "±Õ× Üã×ëÚØ"
#: audio/softsynth/appleiigs.cpp:33
msgid "Apple II GS Emulator (NOT IMPLEMENTED)"
msgstr "ÍÜãÛïâÞà Apple II GS (ÞâáãâáâÒãÕâ)"
-#: audio/softsynth/sid.cpp:1430
-msgid "C64 Audio Emulator"
-msgstr "ÍÜãÛïâÞà ×ÒãÚÐ C64"
+#: audio/softsynth/cms.cpp:350
+msgid "Creative Music System Emulator"
+msgstr "ÍÜãÛïâÞà Creative Music System"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33
+msgid "FM-Towns Audio"
+msgstr "°ãÔØÞ FM-Towns"
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58
+msgid "PC-98 Audio"
+msgstr "°ãÔØÞ PC-98"
+
+#: 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"
#: audio/softsynth/pcspk.cpp:139
msgid "PC Speaker Emulator"
-msgstr "ÍÜãÛïâÞà PC áßØÚÕàÐ"
+msgstr "ÍÜãÛïâÞà PC-áßØÚÕàÐ"
#: audio/softsynth/pcspk.cpp:158
msgid "IBM PCjr Emulator"
msgstr "ÍÜãÛïâÞà IBM PCjr"
+#: audio/softsynth/sid.cpp:1430
+msgid "C64 Audio Emulator"
+msgstr "ÍÜãÛïâÞà ×ÒãÚÐ C64"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Do you really want to return to the Launcher?"
+msgstr "²ë ÔÕÙáâÒØâÕÛìÝÞ åÞâØâÕ ÒÕàÝãâìáï Ò ÓÛÐÒÝÞÕ ÜÕÝî?"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Launcher"
+msgstr "³ÛÐÒÝÞÕ ÜÕÝî"
+
+#: backends/events/default/default-events.cpp:218
+msgid "Do you really want to quit?"
+msgstr "²ë ÔÕÙáâÒØâÕÛìÝÞ åÞâØâÕ ÒëÙâØ?"
+
+#: 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 "²ëåÞÔ"
+
+#: 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 "ÀÕÖØÜ 'ÚÐáÐÝØÙ' âÐçáÚàØÝÐ - »ÕÒëÙ ÚÛØÚ"
+
+#: 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 "ÀÕÖØÜ 'ÚÐáÐÝØÙ' âÐçáÚàØÝÐ - ¿àÐÒëÙ ÚÛØÚ"
+
+#: 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 "ÀÕÖØÜ 'ÚÐáÐÝØÙ' âÐçáÚàØÝÐ - ¿àÞÛñâ (ÑÕ× ÚÛØÚÐ)"
+
+#: backends/events/gph/gph-events.cpp:409
+msgid "Maximum Volume"
+msgstr "¼ÐÚáØÜÐÛìÝÐï ÓàÞÜÚÞáâì"
+
+#: backends/events/gph/gph-events.cpp:411
+msgid "Increasing Volume"
+msgstr "ÃÒÕÛØçÕÝØÕ ÓàÞÜÚÞáâØ"
+
+#: backends/events/gph/gph-events.cpp:417
+msgid "Minimal Volume"
+msgstr "¼ØÝØÜÐÛìÝÐï ÓàÞÜÚÞáâì"
+
+#: backends/events/gph/gph-events.cpp:419
+msgid "Decreasing Volume"
+msgstr "ÃÜÕÝìèÕÝØÕ ÓàÞÜÚÞáâØ"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Enabled"
+msgstr "ÉÕÛçÚØ ÒÚÛîçÕÝë"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Disabled"
+msgstr "ÉÕÛçÚØ ÒëÚÛîçÕÝë"
+
+#: backends/events/openpandora/op-events.cpp:174
+msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
+msgstr "ÀÕÖØÜ 'ÚÐáÐÝØÙ' âÐçáÚàØÝÐ - ¿àÞÛñâ (ÚÛØÚØ DPad)"
+
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
+msgid "Do you want to quit ?"
+msgstr "²ë ÔÕÙáâÒØâÕÛìÝÞ åÞâØâÕ ÒëÙâØ?"
+
+#. I18N: Trackpad mode toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:308
+msgid "Trackpad mode is now"
+msgstr "ÀÕÖØÜ âàÕÚßÐÔÐ áÕÙçÐá"
+
+#. 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 "²º»"
+
+#: backends/events/webossdl/webossdl-events.cpp:311
+#: backends/events/webossdl/webossdl-events.cpp:338
+msgid "OFF"
+msgstr "²Ëº»"
+
+#: backends/events/webossdl/webossdl-events.cpp:315
+msgid "Swipe two fingers to the right to toggle."
+msgstr "¿àÞÒÕÔØâÕ ÔÒãÜï ßÐÛìæÐÜØ ÝÐßàÐÒÞ ÔÛï ßÕàÕÚÛîçÕÝØï."
+
+#. I18N: Auto-drag toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:335
+msgid "Auto-drag mode is now"
+msgstr "ÀÕÖØÜ ÐÒâÞÔàíÓÐ áÕÙçÐá"
+
+#: backends/events/webossdl/webossdl-events.cpp:342
+msgid "Swipe three fingers to the right to toggle."
+msgstr "¿àÞÒÕÔØâÕ âàÕÜï ßÐÛìæÐÜØ ÝÐßàÐÒÞ ÔÛï ßÕàÕÚÛîçÕÝØï."
+
+#: 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 "±Õ× ãÒÕÛØçÕÝØï"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:66
+msgctxt "lowres"
+msgid "Normal (no scaling)"
+msgstr "±Õ× ãÒÕÛØçÕÝØï"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
+msgid "Enabled aspect ratio correction"
+msgstr "ºÞààÕÚæØï áÞÞâÝÞèÕÝØï áâÞàÞÝ ÒÚÛîçÕÝÐ"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
+msgid "Disabled aspect ratio correction"
+msgstr "ºÞààÕÚæØï áÞÞâÝÞèÕÝØï áâÞàÞÝ ÒëÚÛîçÕÝÐ"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
+msgid "Active graphics filter:"
+msgstr "°ÚâØÒÝëÙ ÓàÐäØçÕáÚØÙ äØÛìâà:"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+msgid "Windowed mode"
+msgstr "¾ÚÞÝÝëÙ àÕÖØÜ"
+
#: backends/keymapper/remap-dialog.cpp:48
msgid "Keymap:"
msgstr "ÂÐÑÛØæÐ ÚÛÐÒØè:"
@@ -1614,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 "~·~ÐÚàëâì"
@@ -1668,7 +1926,7 @@ msgstr "¼ÐáèâÐÑ ÓÛÐÒÝÞÓÞ íÚàÐÝÐ:"
#: backends/platform/ds/arm9/source/dsoptions.cpp:107
msgid "Hardware scale (fast, but low quality)"
-msgstr "ÅÐàÔÒÐàÝÞÕ ÜÐáèâÐÑØàÞÒÐÝØÕ (ÑëáâàÞ, ÝÞ ÝØ×ÚÞÓÞ ÚÐçÕáâÒÐ)"
+msgstr "°ßßÐàÐâÝÞÕ ÜÐáèâÐÑØàÞÒÐÝØÕ (ÑëáâàÞ, ÝÞ ÝØ×ÚÞÓÞ ÚÐçÕáâÒÐ)"
#: backends/platform/ds/arm9/source/dsoptions.cpp:108
msgid "Software scale (good quality, but slower)"
@@ -1690,18 +1948,26 @@ msgstr "²ëáÞÚÞÕ ÚÐçÕáâÒÞ ×ÒãÚÐ (ÜÕÔÛÕÝÝÕÕ) (àÕÑãâ)"
msgid "Disable power off"
msgstr "·ÐßàÕâØâì ÒëÚÛîçÕÝØÕ"
+#: 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 "ÀÕÖØÜ ÜëèØ ÝÐÖÐâì-Ø-âïÝãâì ÒÚÛîçñÝ."
+#: 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 "ÀÕÖØÜ ÜëèØ ÝÐÖÐâì-Ø-âïÝãâì ÒëÚÛîçÕÝ."
+#: 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 "ÀÕÖØÜ âÐçßÐÔÐ ÒÚÛîçñÝ."
+#: 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 "ÀÕÖØÜ âÐçßÐÔÐ ÒëÚÛîçÕÝ."
@@ -1712,9 +1978,9 @@ msgstr "ÀÕÖØÜ éÕÛçÚÐ"
#: 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
-#: backends/platform/tizen/form.cpp:275
msgid "Left Click"
msgstr "»ÕÒëÙ éÕÛçÞÚ"
@@ -1724,64 +1990,31 @@ msgstr "ÁàÕÔÝØÙ éÕÛçÞÚ"
#: backends/platform/maemo/maemo.cpp:220
#: backends/platform/symbian/src/SymbianActions.cpp:43
-#: backends/platform/wince/CEActionsSmartphone.cpp:44
#: backends/platform/tizen/form.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:44
msgid "Right Click"
msgstr "¿àÐÒëÙ éÕÛçÞÚ"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:77
+#: backends/platform/sdl/macosx/appmenu_osx.mm:88
msgid "Hide ScummVM"
msgstr "ÁÚàëâì ScummVM"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:82
+#: backends/platform/sdl/macosx/appmenu_osx.mm:93
msgid "Hide Others"
msgstr "ÁÚàëâì ÞáâÐÛìÝëÕ"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:87
+#: backends/platform/sdl/macosx/appmenu_osx.mm:98
msgid "Show All"
msgstr "¿ÞÚÐ×Ðâì ÒáÕ"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:109
#: backends/platform/sdl/macosx/appmenu_osx.mm:120
+#: backends/platform/sdl/macosx/appmenu_osx.mm:131
msgid "Window"
msgstr "¾ÚÝÞ"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:114
+#: backends/platform/sdl/macosx/appmenu_osx.mm:125
msgid "Minimize"
-msgstr "ÃÑàÐâì Ò Dock"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:46
-msgid "Normal (no scaling)"
-msgstr "±Õ× ãÒÕÛØçÕÝØï"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:65
-msgctxt "lowres"
-msgid "Normal (no scaling)"
-msgstr "±Õ× ãÒÕÛØçÕÝØï"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
-msgid "Enabled aspect ratio correction"
-msgstr "ºÞààÕÚæØï áÞÞâÝÞèÕÝØï áâÞàÞÝ ÒÚÛîçÕÝÐ"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
-msgid "Disabled aspect ratio correction"
-msgstr "ºÞààÕÚæØï áÞÞâÝÞèÕÝØï áâÞàÞÝ ÒëÚÛîçÕÝÐ"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
-msgid "Active graphics filter:"
-msgstr "°ÚâØÒÝëÙ ÓàÐäØçÕáÚØÙ äØÛìâà:"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
-msgid "Windowed mode"
-msgstr "¾ÚÞÝÝëÙ àÕÖØÜ"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:118
-msgid "OpenGL"
-msgstr "OpenGL"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:119
-msgid "OpenGL (No filtering)"
-msgstr "OpenGL (ÑÕ× äØÛìâàÞÒ)"
+msgstr "ÁÒÕàÝãâì"
#: backends/platform/symbian/src/SymbianActions.cpp:38
#: backends/platform/wince/CEActionsSmartphone.cpp:39
@@ -1826,14 +2059,6 @@ msgstr "¿àÞßãáâØâì âÕÚáâ"
msgid "Fast mode"
msgstr "±ëáâàëÙ àÕÖØÜ"
-#: backends/platform/symbian/src/SymbianActions.cpp:52
-#: backends/platform/wince/CEActionsPocket.cpp:44
-#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: backends/events/default/default-events.cpp:218 engines/scumm/dialogs.cpp:192
-#: engines/scumm/help.cpp:83 engines/scumm/help.cpp:85
-msgid "Quit"
-msgstr "²ëåÞÔ"
-
#: backends/platform/symbian/src/SymbianActions.cpp:53
msgid "Debugger"
msgstr "¾âÛÐÔçØÚ"
@@ -1850,9 +2075,49 @@ msgstr "²ØàâãÐÛìÝÐï ÚÛÐÒØÐâãàÐ"
msgid "Key mapper"
msgstr "½Ð×ÝÐçÕÝØÕ ÚÛÐÒØè"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:186
-msgid "Do you want to quit ?"
-msgstr "²ë ÔÕÙáâÒØâÕÛìÝÞ åÞâØâÕ ÒëÙâØ?"
+#: backends/platform/tizen/form.cpp:263
+msgid "Right Click Once"
+msgstr "¾ÔØÝ ßàÐÒëÙ éÕÛçÞÚ"
+
+#: backends/platform/tizen/form.cpp:271
+msgid "Move Only"
+msgstr "ÂÞÛìÚÞ ßÕàÕÜÕáâØâì"
+
+#: backends/platform/tizen/form.cpp:294
+msgid "Escape Key"
+msgstr "ºÛÐÒØèÐ ESC"
+
+#: backends/platform/tizen/form.cpp:299
+msgid "Game Menu"
+msgstr "¼ÕÝî ØÓàë"
+
+#: backends/platform/tizen/form.cpp:304
+msgid "Show Keypad"
+msgstr "¿ÞÚÐ×Ðâì ÚÛÐÒØÐâãàã"
+
+#: backends/platform/tizen/form.cpp:309
+msgid "Control Mouse"
+msgstr "ÃßàÐÒÛÕÝØÕ Üëèìî"
+
+#: backends/platform/tizen/fs.cpp:259
+msgid "[ Data ]"
+msgstr "[ ´ÐÝÝëÕ ]"
+
+#: backends/platform/tizen/fs.cpp:263
+msgid "[ Resources ]"
+msgstr "[ ÀÕáãàáë ]"
+
+#: backends/platform/tizen/fs.cpp:267
+msgid "[ SDCard ]"
+msgstr "[ SD-ÚÐàâÐ ]"
+
+#: backends/platform/tizen/fs.cpp:271
+msgid "[ Media ]"
+msgstr "[ ¼ÕÔØÐ ]"
+
+#: backends/platform/tizen/fs.cpp:275
+msgid "[ Shared ]"
+msgstr "[ ÁÕâÕÒÐï ßÐßÚÐ ]"
#: backends/platform/wii/options.cpp:51
msgid "Video"
@@ -1880,11 +2145,11 @@ msgstr "²ÒÞÔ"
#: backends/platform/wii/options.cpp:74
msgid "GC Pad sensitivity:"
-msgstr "ÇãÒáâÒØâÕÛìÝÞáâì GC ßÐÔÐ:"
+msgstr "ÇãÒáâÒØâÕÛìÝÞáâì GC-ßÐÔÐ:"
#: backends/platform/wii/options.cpp:80
msgid "GC Pad acceleration:"
-msgstr "ÃáÚÞàÕÝØÕ GC ßÐÔÐ:"
+msgstr "ÃáÚÞàÕÝØÕ GC-ßÐÔÐ:"
#: backends/platform/wii/options.cpp:86
msgid "DVD"
@@ -1940,7 +2205,7 @@ msgstr "¾âÚÛîçâì SMB"
#: backends/platform/wii/options.cpp:143
msgid "DVD Mounted successfully"
-msgstr "DVD ßÞÔÚÛîçÕÝ ãáßÕèÝÞ"
+msgstr "DVD ßÞÔÚÛîçñÝ ãáßÕèÝÞ"
#: backends/platform/wii/options.cpp:146
msgid "Error while mounting the DVD"
@@ -1948,7 +2213,7 @@ msgstr "¾èØÑÚÐ ÒÞ ÒàÕÜï ßÞÔÚÛîçÕÝØï DVD"
#: backends/platform/wii/options.cpp:148
msgid "DVD not mounted"
-msgstr "DVD ÝÕ ßÞÔÚÛîçÕÝ"
+msgstr "DVD ÝÕ ßÞÔÚÛîçñÝ"
#: backends/platform/wii/options.cpp:161
msgid "Network up, share mounted"
@@ -2080,7 +2345,7 @@ msgstr "½Ð×ÝÐçØâì ÔÕÙáâÒØÕ 'áßàïâÐâì ßÐÝÕÛì ØÝáâàãÜÕÝâÞÒ'"
#: backends/platform/wince/wince-sdl.cpp:533
msgid "You must map a key to the 'Hide toolbar' action to play this game"
-msgstr "²ë ÔÞÛÖÝë ÝÐ×ÝÐçØâì ÚÛÐÒØèã ÝÐ ÔÕÙâáâÒØÕ 'Hide toolbar' ÔÛï íâÞÙ ØÓàë"
+msgstr "²ë ÔÞÛÖÝë ÝÐ×ÝÐçØâì ÚÛÐÒØèã ÝÐ ÔÕÙáâÒØÕ 'Hide toolbar' ÔÛï íâÞÙ ØÓàë"
#: backends/platform/wince/wince-sdl.cpp:542
msgid "Map Zoom Up action (optional)"
@@ -2097,141 +2362,109 @@ msgstr ""
"½Õ ×ÐÑãÔìâÕ ÝÐ×ÝÐçØâì ÚÛÐÒØèã ÔÛï ÔÕÙáâÒØï 'Hide Toolbar', çâÞÑë ãÒØÔÕâì "
"ÒÕáì ØÝÒÕÝâÐàì Ò ØÓàÕ"
-#: backends/events/default/default-events.cpp:196
-msgid "Do you really want to return to the Launcher?"
-msgstr "²ë ÔÕÙáâÒØâÕÛìÝÞ åÞâØâÕ ÒÕàÝãâìáï Ò ÓÛÐÒÝÞÕ ÜÕÝî?"
-
-#: backends/events/default/default-events.cpp:196
-msgid "Launcher"
-msgstr "³ÛÐÒÝÞÕ ÜÕÝî"
-
-#: backends/events/default/default-events.cpp:218
-msgid "Do you really want to quit?"
-msgstr "²ë ÔÕÙáâÒØâÕÛìÝÞ åÞâØâÕ ÒëÙâØ?"
-
-#: 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 "ÀÕÖØÜ 'ÚÐáÐÝØÙ' âÐçáÚàØÝÐ - »ÕÒëÙ ÚÛØÚ"
-
-#: 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 "ÀÕÖØÜ 'ÚÐáÐÝØÙ' âÐçáÚàØÝÐ - ¿àÐÒëÙ ÚÛØÚ"
-
-#: 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 "ÀÕÖØÜ 'ÚÐáÐÝØÙ' âÐçáÚàØÝÐ - ¿àÞÛñâ (ÑÕ× ÚÛØÚÐ)"
-
-#: backends/events/gph/gph-events.cpp:409
-msgid "Maximum Volume"
-msgstr "¼ÐÚáØÜÐÛìÝÐï ÓàÞÜÚÞáâì"
-
-#: backends/events/gph/gph-events.cpp:411
-msgid "Increasing Volume"
-msgstr "ÃÒÕÛØçÕÝØÕ ÓàÞÜÚÞáâØ"
-
-#: backends/events/gph/gph-events.cpp:417
-msgid "Minimal Volume"
-msgstr "¼ØÝØÜÐÛìÝÐï ÓàÞÜÚÞáâì"
-
-#: backends/events/gph/gph-events.cpp:419
-msgid "Decreasing Volume"
-msgstr "ÃÜÕÝìèÕÝØÕ ÓàÞÜÚÞáâØ"
-
-#: backends/events/openpandora/op-events.cpp:174
-msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
-msgstr "ÀÕÖØÜ 'ÚÐáÐÝØÙ' âÐçáÚàØÝÐ - ¿àÞÛñâ (ÚÛØÚØ DPad)"
-
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
-msgstr "¿àÞÒÕàïî ÞÑÝÞÒÛÕÝØï..."
-
-#: backends/platform/tizen/form.cpp:263
-msgid "Right Click Once"
-msgstr "¾ÔØÝ ßàÐÒëÙ éÕÛçÞÚ"
-
-#: backends/platform/tizen/form.cpp:271
-msgid "Move Only"
-msgstr "ÂÞÛìÚÞ ßÕàÕÜÕáâØâì"
-
-#: backends/platform/tizen/form.cpp:294
-msgid "Escape Key"
-msgstr "ºÛÐÒØèÐ ESC"
-
-#: backends/platform/tizen/form.cpp:299
-msgid "Game Menu"
-msgstr "¼ÕÝî ØÓàë"
+msgstr "¿àÞÒÕàØâì ÞÑÝÞÒÛÕÝØï..."
-#: backends/platform/tizen/form.cpp:304
-msgid "Show Keypad"
-msgstr "¿ÞÚÐ×Ðâì ÚÛÐÒØÐâãàã"
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "ÀÕÖØÜ ÑÕ× æÒÕâÐ"
-#: backends/platform/tizen/form.cpp:309
-msgid "Control Mouse"
-msgstr "ÃßàÐÒÛÕÝØÕ Üëèìî"
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Enabled"
-msgstr "ÉÕÛçÚØ ÒÚÛîçÕÝë"
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Disabled"
-msgstr "ÉÕÛçÚØ ÒëÚÛîçÕÝë"
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "¿ÞÚÐ×ëÒÐâì áâàÞÚã ÞÑêÕÚâÞÒ"
-#: engines/agi/detection.cpp:147 engines/drascula/detection.cpp:302
-#: engines/dreamweb/detection.cpp:47 engines/neverhood/detection.cpp:160
-#: engines/sci/detection.cpp:394 engines/toltecs/detection.cpp:200
-#: engines/zvision/detection_tables.h:51
+#: 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 "¸áßÞÛì×ÞÒÐâì ÞàØÓØÝÐÛìÝëÕ íÚàÐÝë ×ÐßØáØ/çâÕÝØï ØÓàë"
-#: engines/agi/detection.cpp:148 engines/drascula/detection.cpp:303
-#: engines/dreamweb/detection.cpp:48 engines/neverhood/detection.cpp:161
-#: engines/sci/detection.cpp:395 engines/toltecs/detection.cpp:201
+#: 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 ""
-"¸áßÞÛì×ÞÒÐâì ÞàØÓØÝÐÛìÝëÕ íÚàÐÝë ×ÐßØáØ Ø áÞåàÐÝÕÝØï ØÓàë ÒÜÕáâÞ áÔÕÛÐÝÝëå Ò "
+"¸áßÞÛì×ÞÒÐâì ÞàØÓØÝÐÛìÝëÕ íÚàÐÝë çâÕÝØï Ø áÞåàÐÝÕÝØï ØÓàë ÒÜÕáâÞ áÔÕÛÐÝÝëå Ò "
"ScummVM"
#: engines/agi/detection.cpp:157
-#, fuzzy
msgid "Use an alternative palette"
-msgstr "¸áßÞÛì×ÞÒÐâì ÐÛìâÕàÝÐâØÒÝÞÕ ÒáâãßÛÕÝØÕ (âÞÛìÚÞ ÔÛï CD ÒÕàáØØ ØÓàë)"
+msgstr "¸áßÞÛì×ÞÒÐâì ÐÛìâÕàÝÐâØÒÝãî ßÐÛØâàã"
#: engines/agi/detection.cpp:158
msgid ""
"Use an alternative palette, common for all Amiga games. This was the old "
"behavior"
msgstr ""
+"¸áßÞÛì×ÞÒÐâì ÐÛìâÕàÝÐâØÒÝãî ßÐÛØâàã ÔÛï ÒáÕå ØÓà Amiga. ÍâÞ ÑëÛÞ áâÐàÞÕ "
+"ßÞÒÕÔÕÝØÕ"
#: engines/agi/detection.cpp:167
-#, fuzzy
msgid "Mouse support"
-msgstr "¿ÞÔÔÕàÖÚÐ ßàÞßãáÚÞÒ"
+msgstr "¿ÞÔÔÕàÖÚÐ ÜëèØ"
#: engines/agi/detection.cpp:168
msgid ""
"Enables mouse support. Allows to use mouse for movement and in game menus."
msgstr ""
+"²ÚÛîçÐÕâ ßÞÔÔÕàÖÚã ÜëèØ. ¿Þ×ÒÞÛïÕâ ØáßÞÛì×ÞÒÐâì Üëèì ÔÛï ßÕàÕÜÕéÕÝØï Ø Ò "
+"ÜÕÝî ØÓàë."
+
+#: 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/saveload.cpp:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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"
@@ -2242,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"
@@ -2253,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"
@@ -2264,19 +2497,18 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/animation.cpp:557
+#: engines/agos/animation.cpp:558
#, c-format
msgid "Cutscene file '%s' not found!"
msgstr "ÄÐÙÛ ×ÐáâÐÒÚØ '%s' ÝÕ ÝÐÙÔÕÝ!"
#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
-#, fuzzy
msgid "Color Blind Mode"
-msgstr "ÀÕÖØÜ éÕÛçÚÐ"
+msgstr "ÀÕÖØÜ ÑÕ× æÒÕâÐ"
#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
-msgstr ""
+msgstr "²ÚÛîçØâì àÕÖØÜ ÔÛï ÛîÔÕÙ áÞ áÛÐÑëÜ ÒÞáßàØïâØÕÜ æÒÕâÐ"
#: engines/drascula/saveload.cpp:47
msgid ""
@@ -2290,26 +2522,26 @@ msgid ""
msgstr ""
"ScummVM ÞÑÝÐàãÖØÛ ã ÒÐá áÞåàÐÝÕÝØï ØÓàë Drascula Ò áâÐàÞÜ äÞàÜÐâÕ, ÚÞâÞàëÕ "
"ÝÕÞÑåÞÔØÜÞ ßàÕÞÑàÐ×ÞÒÐâì.\n"
-"ÁâÐàëÙ äÞàÜÐâ ÑÞÛìèÕ ÝÕ ßÞÔÔÕàÖØÒÐÕâáï, Ø Òë ÝÕ áÜÞÖÕâÕ ×ÐÓàã×Øâì áÞåàÐÝÕÝØï "
-"ÕáÛØ ÝÕ ßàÕÞÑàÐ×ãÕâÕ Øå.\n"
+"ÁâÐàëÙ äÞàÜÐâ ÑÞÛìèÕ ÝÕ ßÞÔÔÕàÖØÒÐÕâáï, Ø Òë ÝÕ áÜÞÖÕâÕ ×ÐÓàã×Øâì "
+"áÞåàÐÝÕÝØï, ÕáÛØ ÝÕ ßàÕÞÑàÐ×ãÕâÕ Øå.\n"
"\n"
"½ÐÖÜØâÕ ¾º, çâÞÑë ßÕàÕÒÕáâØ Øå Ò ÝÞÒëÙ äÞàÜÐâ áÕÙçÐá, Ò ßàÞâØÒÝÞÜ áÛãçÐÕ íâÞ "
"áÞÞÑéÕÝØÕ ßÞïÒØâáï áÝÞÒÐ ßàØ áÛÕÔãîéÕÜ ×ÐßãáÚÕ ØÓàë.\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 "½Õ ãÔÐÛÞáì áÞåàÐÝØâì ØÓàã Ò äÐÙÛ."
@@ -2326,17 +2558,17 @@ 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 "½Õ ãÔÐÛÞáì áÞåàÐÝØâì ØÓàã"
#: engines/hopkins/detection.cpp:76 engines/hopkins/detection.cpp:86
msgid "Gore Mode"
-msgstr ""
+msgstr "ÀÕÖØÜ á ÚàÞÒìî"
#: engines/hopkins/detection.cpp:77 engines/hopkins/detection.cpp:87
msgid "Enable Gore Mode when available"
-msgstr ""
+msgstr "²ÚÛîçÐÕâ àÕÖØÜ á Ø×ÞÑàÐÖÕÝØÕÜ ÚàÞÒØ, ÕáÛØ ÔÞáâãßÝÞ"
#. I18N: Studio audience adds an applause and cheering sounds whenever
#. Malcolm makes a joke.
@@ -2455,7 +2687,7 @@ msgstr ""
"ºÐÖÕâáï, Òë ßëâÐÕâÕáì ØáßÞÛì×ÞÒÐâì ãáâàÞÙáâÒÞ\n"
"General MIDI, ÝÞ íâÐ ØÓàÐ ßÞÔÔÕàÖØÒÐÕâ âÞÛìÚÞ\n"
"Roland MT32 MIDI. ¼ë ßÞßàÞÑãÕÜ ßÞÔÞÑàÐâì General\n"
-"MIDI ØÝáâàãÜÕÝâë, ßÞåÞÖØÕ ÝÐ Roland MT32, ÝÞ\n"
+"MIDI-ØÝáâàãÜÕÝâë, ßÞåÞÖØÕ ÝÐ Roland MT32, ÝÞ\n"
"ÜÞÖÕâ âÐÚ ßÞÛãçØâìáï, çâÞ ÝÕÚÞâÞàëÕ âàÕÚØ ÑãÔãâ\n"
"áëÓàÐÝë ÝÕÒÕàÝÞ."
@@ -2469,6 +2701,13 @@ msgid ""
"Do you wish to use this save game file with ScummVM?\n"
"\n"
msgstr ""
+"½ØÖÕáÛÕÔãîéØÙ äÐÙÛ áÞåàÐÝÕÝØï Ø× ÞàØÓØÝÐÛìÝÞÙ ØÓàë ÑëÛ ÝÐÙÔÕÝ Ò ÒÐèÕÙ "
+"ØÓàÞÒÞÙ ÔØàÕÚâÞàØØ:\n"
+"\n"
+"%s %s\n"
+"\n"
+"²ë åÞâØâÕ ØáßÞÛì×ÞÒÐâì íâÞ áÞåàÐÝÕÝØÕ Ò ScummVM?\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:590
#, c-format
@@ -2476,6 +2715,8 @@ msgid ""
"A save game file was found in the specified slot %d. Overwrite?\n"
"\n"
msgstr ""
+"² ãÚÐ×ÐÝÝÞÜ áÛÞâÕ %d ãÖÕ Õáâì áÞåàÐÝÕÝØÕ ØÓàë. ¿ÕàÕ×ÐßØáÐâì?\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:623
#, c-format
@@ -2487,50 +2728,62 @@ msgid ""
"'import_savefile'.\n"
"\n"
msgstr ""
+"%d ÞàØÓØÝÐÛìÝëå äÐÙÛÞÒ áÞåàÐÝÕÝØï ÑëÛØ ãáßÕèÝÞ ØÜßÞàâØàÞÒÐÝë Ò ScummVM.\n"
+"µáÛØ Òë ×ÐåÞâØâÕ ØÜßÞàâØàÞÒÐâì ÞàØÓØÝÐÛìÝëÕ áÞåàÐÝÕÝØï, ÒÐÜ ÝãÖÝÞ ÑãÔÕâ\n"
+"ÞâÚàëâì ÞâÛÐÔÞçÝãî ÚÞÝáÞÛì 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"
@@ -2539,15 +2792,23 @@ msgstr ""
"½Õ ÜÞÓã áÞåàÐÝØâì ØÓàã Ò ßÞ×ØæØî %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:194
+msgid "Load file"
+msgstr "·ÐÓàã×Øâì äÐÙÛ"
+
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "·ÐÓàãÖÐî ØÓàã..."
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:209
+msgid "Save file"
+msgstr "ÁÞåàÐÝØâì äÐÙÛ"
+
+#: 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"
@@ -2557,17 +2818,18 @@ msgid ""
"Press OK to convert them now, otherwise you will be asked next time.\n"
msgstr ""
"ScummVM ÞÑÝÐàãÖØÛ ã ÒÐá áâÐàëÕ áÞåàÐÝÕÝØï ØÓàë Nippon Safes, ÚÞâÞàëÕ "
-"ÝÕÞÑåÞÔØÜÞ ßÕàÕØÜÕÝÞÒÐâì. ÁâÐàëÕ ÝÐ×ÒÐÝØï ÑÞÛìèÕ ÝÕ ßÞÔÔÕàÖØÒÐîâáï, Ø "
-"ßÞíâÞÜã Òë ÝÕ áÜÞÖÕâÕ ×ÐÓàã×Øâì áÞåàÐÝÕÝØï, ÕáÛØ ÝÕ ßÕàÕØÜÕÝãÕâÕ Øå.\n"
+"ÝÕÞÑåÞÔØÜÞ ßÕàÕØÜÕÝÞÒÐâì.\n"
+"ÁâÐàëÕ ÝÐ×ÒÐÝØï ÑÞÛìèÕ ÝÕ ßÞÔÔÕàÖØÒÐîâáï, Ø ßÞíâÞÜã Òë ÝÕ áÜÞÖÕâÕ ×ÐÓàã×Øâì "
+"áÞåàÐÝÕÝØï, ÕáÛØ ÝÕ ßÕàÕØÜÕÝãÕâÕ Øå.\n"
"\n"
"½ÐÖÜØâÕ ¾º, çâÞÑë ßÕàÕØÜÕÝÞÒÐâì Øå áÕÙçÐá, Ò ßàÞâØÒÝÞÜ áÛãçÐÕ íâÞ ÖÕ "
"áÞÞÑéÕÝØÕ ßÞïÒØâáï ßàØ áÛÕÔãîéÕÜ ×ÐßãáÚÕ ØÓàë.\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"
@@ -2585,11 +2847,11 @@ msgstr "½ÕÒÕàÝÞÕ ØÜï äÐÙÛÐ áÞåàÐÝÕÝØï"
#: engines/pegasus/pegasus.cpp:2507
msgid "Up/Zoom In/Move Forward/Open Doors"
-msgstr "²ÒÕàå/ÃÜÕÝìèØâì ÜÐáèâÐÑ/²ßÕàñÔ/¾âàëâì ÔÒÕàØ"
+msgstr "²ÒÕàå/ÃÒÕÛ. ÜÐáèâÐÑ/²ßÕàñÔ/¾âÚàëâì ÔÒÕàØ"
#: engines/pegasus/pegasus.cpp:2508
msgid "Down/Zoom Out"
-msgstr "²ÝØ×/ÃÒÕÛ. ÜÐáèâÐÑ"
+msgstr "²ÝØ×/ÃÜÕÝìè. ÜÐáèâÐÑ"
#: engines/pegasus/pegasus.cpp:2511
msgid "Display/Hide Inventory Tray"
@@ -2621,30 +2883,48 @@ msgstr "°ÛìâÕàÝÐâØÒÝÞÕ ÒáâãßÛÕÝØÕ"
#: engines/queen/detection.cpp:57
msgid "Use an alternative game intro (CD version only)"
-msgstr "¸áßÞÛì×ÞÒÐâì ÐÛìâÕàÝÐâØÒÝÞÕ ÒáâãßÛÕÝØÕ (âÞÛìÚÞ ÔÛï CD ÒÕàáØØ ØÓàë)"
+msgstr "¸áßÞÛì×ÞÒÐâì ÐÛìâÕàÝÐâØÒÝÞÕ ÒáâãßÛÕÝØÕ (âÞÛìÚÞ ÔÛï CD-ÒÕàáØØ ØÓàë)"
-#: engines/sci/detection.cpp:374
+#: engines/sci/detection.cpp:384
msgid "Skip EGA dithering pass (full color backgrounds)"
-msgstr ""
+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:395
+msgid "Enable high resolution graphics/content"
+msgstr "²ÚÛîçØâì ÓàÐäØÚã Ø ÚÞÝâÕÝâ ÒëáÞÚÞÓÞ àÐàÕèÕÝØï"
+
+#: 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:385
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
msgstr ""
"¾âÔÐÒÐâì ßàÕÔßÞçâÕÝØÕ æØäàÞÒëÜ ×ÒãÚÞÒëÜ íääÕÚâÐÜ ÒÜÕáâÞ áØÝâÕ×ØàÞÒÐÝÝëå"
-#: engines/sci/detection.cpp:404
+#: engines/sci/detection.cpp:434
msgid "Use IMF/Yamaha FB-01 for MIDI output"
msgstr "¸áßÞÛì×ÞÒÐâì IMF/Yamaha FB-01 ÔÛï ÒëÒÞÔÐ MIDI"
-#: engines/sci/detection.cpp:405
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2652,152 +2932,158 @@ msgstr ""
"¸áßÞÛì×ÞÒÐâì ×ÒãÚÞÒãî ÚÐàâã IBM Music Feature ØÛØ ÜÞÔãÛì áØÝâÕ×Ð Yamaha "
"FB-01 FM ÔÛï MIDI"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
-msgstr "¸áßÞÛì×ÞÒÐâì CD ÐãÔØÞ"
+msgstr "¸áßÞÛì×ÞÒÐâì CD-ÐãÔØÞ"
-#: engines/sci/detection.cpp:416
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
msgstr ""
"¸áßÞÛì×ÞÒÐâì ×ÒãÚÞÒëÕ ÔÞàÞÖÚØ á CD ÒÜÕáâÞ Üã×ëÚØ Ø× äÐÙÛÞÒ ØÓàë (ÕáÛØ "
"ÔÞáâãßÝÞ)"
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "¸áßÞÛì×ÞÒÐâì ÚãàáÞàë Windows"
-#: engines/sci/detection.cpp:427
+#: 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:437
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "¸áßÞÛì×ÞÒÐâì áÕàÕÑàïÝëÕ ÚãàáÞàë"
-#: engines/sci/detection.cpp:438
+#: 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
-#, fuzzy
+#: engines/scumm/dialogs.cpp:179
msgid "Are you sure you want to restart? (Y/N)Y"
-msgstr "²ë ãÒÕàÕÝë, çâÞ åÞâØâÕ ÝÐçÐâì áÝÞÒÐ? (Y/N)"
+msgstr "²ë ãÒÕàÕÝë, çâÞ åÞâØâÕ ÝÐçÐâì áÝÞÒÐ? (Y/N)Y"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
-#: engines/scumm/dialogs.cpp:185
-#, fuzzy
+#: engines/scumm/dialogs.cpp:181
msgid "Are you sure you want to quit? (Y/N)Y"
-msgstr "²ë ãÒÕàÕÝë, çâÞ åÞâØâÕ ÒëÙâØ? (Y/N)"
+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:600
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "ÂÞÛìÚÞ Þ×ÒãçÚÐ"
-#: engines/scumm/dialogs.cpp:601
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "¾×ÒãçÚÐ Ø áãÑâØâàë"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "ÂÞÛìÚÞ áãÑâØâàë"
-#: engines/scumm/dialogs.cpp:610
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "¾×ÒãçÚÐ Ø âÕÚáâ"
-#: engines/scumm/dialogs.cpp:656
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "²ëÑÕàØâÕ ãàÞÒÕÝì áÛÞÖÝÞáâØ."
-#: engines/scumm/dialogs.cpp:658
+#: engines/scumm/dialogs.cpp:656
msgid "Refer to your Loom(TM) manual for help."
-msgstr "·Ð ßÞÜÞéìî ÞÑàÐâØâÕáì Ú ØÝáâãÚæØØ Loom(TM)"
+msgstr "·Ð ßÞÜÞéìî ÞÑàÐâØâÕáì Ú ØÝáâàãÚæØØ Loom(TM)."
-#: engines/scumm/dialogs.cpp:662
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "¿àÐÚâØÚÐÝâ"
-#: engines/scumm/dialogs.cpp:663
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "ÍÚáßÕàâ"
@@ -2861,7 +3147,7 @@ msgstr "³àÞÜÚÞáâì Üã×ëÚØ ãÒÕÛØçØâì / ãÜÕÝìèØâì"
#: engines/scumm/help.cpp:89
msgid "Text speed slower / faster"
-msgstr "ÁÚÞàÞáâì âÕÚáâÐ ÑëáâàÕÕ / ÜÕÔÛÕÝÝÕÕ"
+msgstr "ÁÚÞàÞáâì âÕÚáâÐ ÜÕÔÛÕÝÝÕÕ / ÑëáâàÕÕ"
#: engines/scumm/help.cpp:90
msgid "Simulate left mouse button"
@@ -2881,7 +3167,7 @@ msgstr "ÁßÕæØÐÛìÝëÕ ÚÛÐÒØÐâãàÝëÕ ÚÞÜÐÝÔë:"
#: engines/scumm/help.cpp:95
msgid "Show / Hide console"
-msgstr "¿ÞÚÐ×Ðâì / ÃÑàÐâì ÚÞÝáÞÛì"
+msgstr "¿ÞÚÐ×Ðâì / ãÑàÐâì ÚÞÝáÞÛì"
#: engines/scumm/help.cpp:96
msgid "Start the debugger"
@@ -2909,7 +3195,7 @@ msgstr "¿ÕàÕÚÛîçÕÝØÕ ÜÕÖÔã ÓàÐäØçÕáÚØÜØ äØÛìâàÐÜØ"
#: engines/scumm/help.cpp:102
msgid "Increase / Decrease scale factor"
-msgstr "ÃÒÕÛØçØâì/ãÜÕÝìèØâì ÜÐáèâÐÑ"
+msgstr "ÃÒÕÛØçØâì / ãÜÕÝìèØâì ÜÐáèâÐÑ"
#: engines/scumm/help.cpp:103
msgid "Toggle aspect-ratio correction"
@@ -3043,7 +3329,7 @@ msgstr "¿ãâÕèÕáâÒÞÒÐâì"
#: engines/scumm/help.cpp:176
msgid "To Henry / To Indy"
-msgstr "³ÕÝàØ/¸ÝÔØ"
+msgstr "³ÕÝàØ / ¸ÝÔØ"
#. I18N: These are different musical notes
#: engines/scumm/help.cpp:180
@@ -3222,25 +3508,24 @@ msgid "Third kid"
msgstr "ÂàÕâØÙ ÓÕàÞÙ"
#: engines/scumm/help.cpp:292
-#, fuzzy
msgid "Toggle Inventory/IQ Points display"
-msgstr "²ÚÛîçØâì ßÞÚÐ× ÔÐÝÝëå Ò æÕÝâàÕ íÚàÐÝÐ"
+msgstr "¿ÕàÕÚÛîçØâì ßÞÚÐ× ØÝÒÕÝâÐàï/ÞçÚÞÒ IQ"
#: engines/scumm/help.cpp:293
msgid "Toggle Keyboard/Mouse Fighting (*)"
-msgstr ""
+msgstr "¿ÕàÕÚÛîçØâì ãßàÐÒÛÕÝØÕ ÑÞïÜØ ÚÛÐÒØÐâãàÞÙ/Üëèìî (*)"
#: engines/scumm/help.cpp:295
msgid "* Keyboard Fighting is always on,"
-msgstr ""
+msgstr "* ÃßàÐÒÛÕÝØÕ ÚÛÐÒØÐâãàÞÙ ÒáÕÓÔÐ ÒÚÛîçÕÝÞ,"
#: engines/scumm/help.cpp:296
msgid " so despite the in-game message this"
-msgstr ""
+msgstr " âÐÚ çâÞ, ÝÕáÜÞâàï ÝÐ áÞÞÑéÕÝØÕ ØÓàë,"
#: engines/scumm/help.cpp:297
msgid " actually toggles Mouse Fighting Off/On"
-msgstr ""
+msgstr " ÝÐ áÐÜÞÜ ÔÕÛÕ íâÞ ÒÚÛ/ÒëÚÛ ãßàÐÒÛÕÝØÕ Üëèìî"
#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
@@ -3277,7 +3562,7 @@ msgstr "ÃÔÐà áÝØ×ã"
#: engines/scumm/help.cpp:315
msgid "Sucker punch"
-msgstr ""
+msgstr "ÃÔÐà á×ÐÔØ"
#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
@@ -3335,7 +3620,23 @@ msgstr "»ÕâÕâì ÒßàÐÒÞ"
msgid "Fly to lower right"
msgstr "»ÕâÕâì ÒßàÐÒÞ-ÒÝØ×"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/input.cpp:578
+msgid "Snap scroll on"
+msgstr "¿àÞÚàãâÚÐ áÚÐçÚÐÜØ ÒÚÛîçÕÝÐ"
+
+#: engines/scumm/input.cpp:580
+msgid "Snap scroll off"
+msgstr "¿àÞÚàãâÚÐ áÚÐçÚÐÜØ ÒëÚÛîçÕÝÐ"
+
+#: engines/scumm/input.cpp:593
+msgid "Music volume: "
+msgstr "³àÞÜÚ. Üã×ëÚØ: "
+
+#: engines/scumm/input.cpp:610
+msgid "Subtitle speed: "
+msgstr "ÁÚÞàÞáâì âØâàÞÒ: "
+
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3344,28 +3645,87 @@ msgstr ""
"ÀÕÖØÜ \"àÞÔÝÞÓÞ\" MIDI âàÕÑãÕâ ÞÑÝÞÒÛÕÝØÕ Roland Upgrade Þâ\n"
"LucasArts, ÝÞ ÝÕ åÒÐâÐÕâ %s. ¿ÕàÕÚÛîçÐîáì ÝÐ AdLib."
-#: engines/scumm/scumm.cpp:2644
-#, fuzzy
+#: 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 ""
-"ÁÕÙçÐá ÔÞÛÖÝÐ ×ÐßãáâØâìáï ØÓàÐ Maniac Mansion. ½Þ ScummVM ßÞÚÐ íâÞÓÞ ÝÕ "
-"ãÜÕÕâ. ÇâÞÑë áëÓàÐâì, ÝÐÖÜØâÕ '½ÞÒÐï ØÓàÐ' Ò áâÐàâÞÒÞÜ ÜÕÝî ScummVM, Ð ×ÐâÕÜ "
-"ÒëÑÕàØâÕ ÔØàÕÚâÞàØî Maniac ÒÝãâàØ ÔØàÕÚâÞàØØ á ØÓàÞÙ Tentacle."
+"ÁÕÙçÐá ÔÞÛÖÝÐ ×ÐßãáâØâìáï ØÓàÐ Maniac Mansion. ½Þ çâÞÑë íâÞ àÐÑÞâÐÛÞ, äÐÙÛë "
+"ØÓàë Maniac Mansion ÔÞÛÖÝë Ñëâì áÚÞßØàÞÒÐÝë Ò ÔØàÕÚâÞàØî 'Maniac' ÒÝãâàØ "
+"ÔØàÕÚâÞàØØ ØÓàë Tentacle Ø áÐÜÐ ØÓàÐ ÔÞÛÖÝÐ Ñëâì ÔÞÑÐÒÛÕÝÐ Ò ScummVM."
#: 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 ""
+"½Õ ãÔÐÛÞáì ÝÐÙâØ ØáßÞÛÝØÜëÙ äÐÙÛ 'Loom' Macintosh, çâÞÑë ßàÞçØâÐâì\n"
+"ÔÐÝÝëÕ ÞÑ ØÝáâàãÜÕÝâÐå. ¼ã×ëÚÐ ÑãÔÕâ ÒëÚÛîçÕÝÐ."
#: 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 ""
+"½Õ ãÔÐÛÞáì ÝÐÙâØ ØáßÞÛÝØÜëÙ äÐÙÛ 'Monkey Island' Macintosh, çâÞÑë ßàÞçØâÐâì\n"
+"ÔÐÝÝëÕ ÞÑ ØÝáâàãÜÕÝâÐå. ¼ã×ëÚÐ ÑãÔÕâ ÒëÚÛîçÕÝÐ."
+
+#: engines/sherlock/detection.cpp:71
+msgid "Use original savegame dialog"
+msgstr "¸áßÞÛì×ÞÒÐâì ÞàØÓØÝÐÛìÝëÕ íÚàÐÝë ×ÐßØáØ/çâÕÝØï ØÓàë"
+
+#: engines/sherlock/detection.cpp:72
+msgid ""
+"Files button in-game shows original savegame dialog rather than the ScummVM "
+"menu"
+msgstr ""
+"ºÝÞßÚÐ \"ÄÐÙÛë\" Ò ØÓàÕ ßÞÚÐ×ëÒÐÕâ ÞàØÓØÝÐÛìÝëÙ ÔØÐÛÞÓ áÞåàÐÝÕÝØï, Ð ÝÕ ÜÕÝî "
+"ScummVM"
+
+#: engines/sherlock/detection.cpp:81
+msgid "Pixellated scene transitions"
+msgstr "¿ÕàÕåÞÔë ÜÕÖÔã áæÕÝÐÜØ á ßØÚáÕÛØ×ÐæØÕÙ"
+
+#: engines/sherlock/detection.cpp:82
+msgid "When changing scenes, a randomized pixel transition is done"
+msgstr "¿àØ áÜÕÝÕ áæÕÝ ßàÞØáåÞÔØâ ßÕàÕåÞÔ á àÐÝÔÞÜØ×ØàÞÒÐÝÝëÜØ ßØÚáÕÛïÜØ"
+
+#: engines/sherlock/detection.cpp:91
+msgid "Don't show hotspots when moving mouse"
+msgstr "½Õ ßÞÚÐ×ëÒÐâì åÞâáßÞâë ßàØ ÝÐÒÕÔÕÝØØ Üëèìî"
+
+#: engines/sherlock/detection.cpp:92
+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"
+msgstr "¿ÞÚÐ×ëÒÐâì ßÞàâàÕâë ÓÕàÞÕÒ"
+
+#: engines/sherlock/detection.cpp:102
+msgid "Show portraits for the characters when conversing"
+msgstr "¿ÞÚÐ×ëÒÐâì ßÞàâàÕâë ÓÕàÞÕÒ ÒÞ ÒàÕÜï ÔØÐÛÞÓÞÒ"
+
+#: engines/sherlock/detection.cpp:111
+msgid "Slide dialogs into view"
+msgstr "²êÕ×ÖÐîéØÕ ÔØÐÛÞÓØ"
+
+#: engines/sherlock/detection.cpp:112
+msgid "Slide UI dialogs into view, rather than simply showing them immediately"
+msgstr "´ØÐÛÞÓØ ÑãÔãâ ÒêÕ×ÖÐâì, Ð ÝÕ ßÞÚÐ×ëÒÐâìáï ÜÓÝÞÒÕÝÝÞ"
+
+#: engines/sherlock/detection.cpp:121
+msgid "Transparent windows"
+msgstr "¿àÞ×àÐçÝëÕ ÞÚÝÐ"
+
+#: engines/sherlock/detection.cpp:122
+msgid "Show windows with a partially transparent background"
+msgstr "¿ÞÚÐ×ëÒÐâì ÞÚÝÐ á çÐáâØçÝÞ ßàÞ×àÐçÝëÜ äÞÝÞÜ"
#: engines/sky/compact.cpp:130
msgid ""
@@ -3385,11 +3745,11 @@ msgstr ""
#: engines/sky/detection.cpp:44
msgid "Floppy intro"
-msgstr "²áâãßÛÕÝØÕ á äÛÞßßØÚÞÒ"
+msgstr "²áâãßÛÕÝØÕ á ÔØáÚÕâ"
#: engines/sky/detection.cpp:45
msgid "Use the floppy version's intro (CD version only)"
-msgstr "¸áßÞÛì×ÞÒÐâì ÒáâãßÛÕÝØÕ á ÓØÑÚØå ÔØáÚÞÒ (âÞÛìÚÞ ÔÛï CD ÒÕàáØØ ØÓàë)"
+msgstr "¸áßÞÛì×ÞÒÐâì ÒáâãßÛÕÝØÕ á ÓØÑÚØå ÔØáÚÞÒ (âÞÛìÚÞ ÔÛï CD-ÒÕàáØØ ØÓàë)"
#: engines/sword1/animation.cpp:524
#, c-format
@@ -3422,7 +3782,8 @@ msgid ""
"Press OK to convert them now, otherwise you will be asked again the next "
"time you start the game.\n"
msgstr ""
-"ScummVM ÞÑÝÐàãÖØÛ ã ÒÐá áÞåàÐÝÕÝØï ØÓàë ÁÛÞÜÐÝÝëÙ ¼Õç Ò áâÐàÞÜ äÞàÜÐâÕ.\n"
+"ScummVM ÞÑÝÐàãÖØÛ ã ÒÐá áÞåàÐÝÕÝØï ØÓàë \"ÁÛÞÜÐÝÝëÙ ÜÕç 1\" Ò áâÐàÞÜ "
+"äÞàÜÐâÕ.\n"
"ÁâÐàëÙ äÞàÜÐâ ÑÞÛìèÕ ÝÕ ßÞÔÔÕàÖØÒÐÕâáï, Ø, çâÞÑë ×ÐÓàã×Øâì áÞåàÐÝÕÝØï, ÞÝØ "
"ÔÞÛÖÝë Ñëâì ßÕàÕÒÕÔÕÝë Ò ÝÞÒëÙ äÞàÜÐâ.\n"
"\n"
@@ -3448,13 +3809,13 @@ msgstr "ÁÔÕÛÐâì ÝÞÒÞÕ"
#: engines/sword1/logic.cpp:1633
msgid "This is the end of the Broken Sword 1 Demo"
-msgstr "ÍâÞ ×ÐÒÕàèÕÝØÕ ÔÕÜÞ ÁÛÞÜÐÝÝÞÓÞ ¼ÕçÐ 1"
+msgstr "ÍâÞ ×ÐÒÕàèÕÝØÕ ÔÕÜÞ \"ÁÛÞÜÐÝÝÞÓÞ ÜÕçÐ 1\""
#: engines/sword2/animation.cpp:425
msgid ""
"PSX cutscenes found but ScummVM has been built without RGB color support"
msgstr ""
-"½ÐÙÔÕÝë ×ÐáâÐÒÚØ Ò äÞàÜÐâÕ PSX, ÝÞ ScummVM ÑëÛ áÞÑàÐÝ ÑÕ× ßÞÔÔÕàÖÚØ RGB "
+"½ÐÙÔÕÝë ×ÐáâÐÒÚØ Ò äÞàÜÐâÕ PSX, ÝÞ ScummVM ÑëÛ áÞÑàÐÝ ÑÕ× ßÞÔÔÕàÖÚØ RGB-"
"æÒÕâÞÒ"
#: engines/sword2/sword2.cpp:79
@@ -3465,30 +3826,40 @@ 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"
msgstr ""
-"ÄÐÙÛ teenagent.dat áÖÐâ, ÝÞ zlib ÝÕ ÒÚÛîçÕÝÞ Ò íâã ßàÞÓàÐÜÜã. ¿ÞÖÐÛãÙáâÐ, "
+"ÄÐÙÛ teenagent.dat áÖÐâ, ÝÞ zlib ÝÕ ÒÚÛîçñÝ Ò íâã ßàÞÓàÐÜÜã. ¿ÞÖÐÛãÙáâÐ, "
"àÐáßÐÚãÙâÕ ÕÓÞ"
#: engines/wintermute/detection.cpp:58
msgid "Show FPS-counter"
-msgstr ""
+msgstr "¿ÞÚÐ×Ðâì áçñâçØÚ ÚÐÔàÞÒ Ò áÕÚãÝÔã"
#: engines/wintermute/detection.cpp:59
msgid "Show the current number of frames per second in the upper left corner"
-msgstr ""
+msgstr "¿ÞÚÐ×Ðâì Ò ÒÕàåÝÕÜ ÛÕÒÞÜ ãÓÛã âÕÚãéÕÕ ÚÞÛØçÕáâÒÞ ÚÐÔàÞÒ Ò áÕÚãÝÔã"
#: engines/zvision/detection_tables.h:52
-#, fuzzy
msgid "Use the original save/load screens instead of the ScummVM interface"
msgstr ""
"¸áßÞÛì×ÞÒÐâì ÞàØÓØÝÐÛìÝëÕ íÚàÐÝë ×ÐßØáØ Ø áÞåàÐÝÕÝØï ØÓàë ÒÜÕáâÞ áÔÕÛÐÝÝëå Ò "
@@ -3496,123 +3867,34 @@ msgstr ""
#: engines/zvision/detection_tables.h:61
msgid "Double FPS"
-msgstr ""
+msgstr "´ÒÞÙÝÞÙ FPS"
#: engines/zvision/detection_tables.h:62
msgid "Increase framerate from 30 to 60 FPS"
-msgstr ""
+msgstr "ÃÒÕÛØçØâì çÐáâÞâã ÚÐÔàÞÒ á 30 ÔÞ 60 ³æ"
#: engines/zvision/detection_tables.h:71
-#, fuzzy
msgid "Enable Venus"
-msgstr "²ÚÛîçØâì àÕÖØÜ ÓÕÛØï"
+msgstr "²ÚÛîçØâì Venus"
#: engines/zvision/detection_tables.h:72
-#, fuzzy
msgid "Enable the Venus help system"
-msgstr "²ÚÛîçØâì àÕÖØÜ ÓÕÛØï"
+msgstr "²ÚÛîçØâì áØáâÕÜã ßÞÜÞéØ Venus"
#: engines/zvision/detection_tables.h:81
msgid "Disable animation while turning"
-msgstr ""
+msgstr "²ëÚÛîçØâì ÐÝØÜÐæØî ÒÞ ÒàÕÜï ßÞÒÞàÞâÞÒ"
#: engines/zvision/detection_tables.h:82
msgid "Disable animation while turning in panorama mode"
-msgstr ""
+msgstr "²ëÚÛîçØâì ÐÝØÜÐæØî ÒÞ ÒàÕÜï ßÞÒÞàÞâÞÒ Ò àÕÖØÜÕ ßÐÝÞàÐÜë"
#: engines/zvision/detection_tables.h:91
msgid "Use high resolution MPEG video"
-msgstr ""
+msgstr "¸áßÞÛì×ÞÒÐâì ÒØÔÕÞ MPEG ÒëáÞÚÞÓÞ àÐ×àÕèÕÝØï"
#: engines/zvision/detection_tables.h:92
-#, fuzzy
msgid "Use MPEG video from the DVD version, instead of lower resolution AVI"
msgstr ""
-"¸áßÞÛì×ÞÒÐâì ÐÛìâÕàÝÐâØÒÝëÙ ÝÐÑÞà áÕàÕÑàïÝëå ÚãàáÞàÞÒ ÒÜÕáâÞ ÞÑëçÝëå ×ÞÛÞâëå"
-
-#~ 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"
-
-#~ msgid "Hercules Green"
-#~ msgstr "Hercules ·ÕÛñÝëÙ"
-
-#~ msgid "Hercules Amber"
-#~ msgstr "Hercules ÏÝâÐàÝëÙ"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Green"
-#~ msgstr "Hercules ·ÕÛñÝëÙ"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Amber"
-#~ msgstr "Hercules ÏÝâÐàÝëÙ"
-
-#~ msgid "Save game failed!"
-#~ msgstr "½Õ ãÔÐÛÞáì áÞåàÐÝØâì ØÓàã!"
-
-#~ 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 "FM Towns Emulator"
-#~ msgstr "ÍÜãÛïâÞà FM Towns"
-
-#~ msgid "Invalid Path"
-#~ msgstr "½ÕÒÕàÝëÙ ßãâì"
+"¸áßÞÛì×ÞÒÐâì MPEG-ÒØÔÕÞ Ø× DVD-ÒÕàáØØ ÒÜÕáâÞ ÒØÔÕÞ ÝØ×ÚÞÓÞ àÐ×àÕèÕÝØï Ò "
+"äÞàÜÐâÕ AVI"
diff --git a/po/scummvm.pot b/po/scummvm.pot
index 7036c41f91..3a52afdde7 100644
--- a/po/scummvm.pot
+++ b/po/scummvm.pot
@@ -6,9 +6,9 @@
#, fuzzy
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: 2015-09-06 15:14+0200\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"
@@ -52,22 +52,23 @@ msgid "Go up"
msgstr ""
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:74 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: 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/fluidsynth-dialog.cpp:152 engines/engine.cpp:483
-#: backends/platform/wii/options.cpp:48
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
-#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:191 engines/sword1/control.cpp:865
+#: 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 ""
#: gui/browser.cpp:76 gui/browser_osx.mm:103 gui/chooser.cpp:47
-#: gui/themebrowser.cpp:56
+#: gui/filebrowser-dialog.cpp:65 gui/themebrowser.cpp:56
msgid "Choose"
msgstr ""
@@ -83,50 +84,134 @@ msgstr ""
msgid "Notes:"
msgstr ""
-#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:75
+#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74
msgid "Ok"
msgstr ""
-#: gui/gui-manager.cpp:117 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"
+#: gui/filebrowser-dialog.cpp:49
+msgid "Choose file for loading"
msgstr ""
-#: gui/gui-manager.cpp:120
-msgid "Mouse click"
+#: gui/filebrowser-dialog.cpp:49
+msgid "Enter filename for saving"
msgstr ""
-#: gui/gui-manager.cpp:124 base/main.cpp:319
-msgid "Display keyboard"
+#: gui/filebrowser-dialog.cpp:132
+msgid "Do you really want to overwrite the file?"
msgstr ""
-#: gui/gui-manager.cpp:128 base/main.cpp:323
-msgid "Remap keys"
+#: 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 ""
-#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:87
-msgid "Toggle fullscreen"
+#: 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 ""
-#: gui/KeysDialog.h:36 gui/KeysDialog.cpp:145
-msgid "Choose an action to map"
+#: gui/fluidsynth-dialog.cpp:68
+msgid "Reverb"
msgstr ""
-#: gui/KeysDialog.cpp:41
-msgid "Map"
+#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
+msgid "Active"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:72
+msgid "Room:"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:79
+msgid "Damp:"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:86
+msgid "Width:"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
+msgid "Level:"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:100
+msgid "Chorus"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:104
+msgid "N:"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:118
+msgid "Speed:"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:125
+msgid "Depth:"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:132
+msgid "Type:"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:135
+msgid "Sine"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:136
+msgid "Triangle"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
+msgid "Misc"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:140
+msgid "Interpolation:"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:143
+msgid "None (fastest)"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:144
+msgid "Linear"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:145
+msgid "Fourth-order"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:146
+msgid "Seventh-order"
+msgstr ""
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset"
msgstr ""
-#: gui/KeysDialog.cpp:42 gui/launcher.cpp:352 gui/launcher.cpp:1048
-#: gui/launcher.cpp:1052 gui/massadd.cpp:92 gui/options.cpp:1238
-#: gui/saveload-dialog.cpp:932 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:402 engines/engine.cpp:413
-#: backends/platform/wii/options.cpp:47
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset all FluidSynth settings to their default values."
+msgstr ""
+
+#: 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
@@ -138,6 +223,38 @@ msgstr ""
msgid "OK"
msgstr ""
+#: gui/fluidsynth-dialog.cpp:217
+msgid ""
+"Do you really want to reset all FluidSynth settings to their default values?"
+msgstr ""
+
+#: 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 ""
+
+#: gui/gui-manager.cpp:122
+msgid "Mouse click"
+msgstr ""
+
+#: gui/gui-manager.cpp:126 base/main.cpp:328
+msgid "Display keyboard"
+msgstr ""
+
+#: gui/gui-manager.cpp:130 base/main.cpp:332
+msgid "Remap keys"
+msgstr ""
+
+#: gui/gui-manager.cpp:133 base/main.cpp:335 engines/scumm/help.cpp:87
+msgid "Toggle fullscreen"
+msgstr ""
+
+#: gui/KeysDialog.cpp:41
+msgid "Map"
+msgstr ""
+
#: gui/KeysDialog.cpp:49
msgid "Select an action and click 'Map'"
msgstr ""
@@ -160,6 +277,10 @@ msgstr ""
msgid "Press the key to associate"
msgstr ""
+#: gui/KeysDialog.cpp:145 gui/KeysDialog.h:36
+msgid "Choose an action to map"
+msgstr ""
+
#: gui/launcher.cpp:193
msgid "Game"
msgstr ""
@@ -198,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 ""
@@ -221,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 ""
@@ -238,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 ""
@@ -251,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 ""
@@ -269,274 +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:95
+#: 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:69
+#: 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:1222
+#: 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/myst.cpp:245 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/myst.cpp:245
-#: engines/mohawk/riven.cpp:718 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:792
+#: 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:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 ""
-
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 ""
-
-#: gui/launcher.cpp:841
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr ""
-#: gui/launcher.cpp:853
+#: gui/launcher.cpp:857
msgid "ScummVM could not find any game in the specified directory!"
msgstr ""
-#: gui/launcher.cpp:867
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr ""
-#: gui/launcher.cpp:941
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr ""
-#: gui/launcher.cpp:999
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr ""
-#: gui/launcher.cpp:1048
+#: gui/launcher.cpp:1052
msgid "This game does not support loading games from the launcher."
msgstr ""
-#: gui/launcher.cpp:1052
+#: gui/launcher.cpp:1056
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr ""
-#: gui/launcher.cpp:1159
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr ""
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr ""
@@ -579,444 +681,466 @@ 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:2298
+#: 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:1168 gui/fluidsynth-dialog.cpp:138
-msgid "Misc"
-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."
msgstr ""
#. I18N: You must leave "#" as is, only word 'next' is translatable
-#: gui/predictivedialog.cpp:87
+#: gui/predictivedialog.cpp:86
msgid "# next"
msgstr ""
-#: gui/predictivedialog.cpp:88
+#: gui/predictivedialog.cpp:87
msgid "add"
msgstr ""
-#: gui/predictivedialog.cpp:92
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
msgstr ""
-#: gui/predictivedialog.cpp:96
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
msgstr ""
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:98
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr ""
-#: gui/recorderdialog.cpp:64
+#. I18N: 'Num' means Numbers
+#: gui/predictivedialog.cpp:578
+msgid "* Num"
+msgstr ""
+
+#. I18N: 'Abc' means Latin alphabet input
+#: gui/predictivedialog.cpp:581
+msgid "* Abc"
+msgstr ""
+
+#: 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:173
+msgid "Unknown Author"
+msgstr ""
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr ""
@@ -1077,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 ""
@@ -1086,149 +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:661
+#: 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
-msgid "Clear value"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:68
-msgid "Reverb"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
-msgid "Active"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:72
-msgid "Room:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:79
-msgid "Damp:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:86
-msgid "Width:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
-msgid "Level:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:100
-msgid "Chorus"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:104
-msgid "N:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:118
-msgid "Speed:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:125
-msgid "Depth:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:132
-msgid "Type:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:135
-msgid "Sine"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:136
-msgid "Triangle"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:140
-msgid "Interpolation:"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:143
-msgid "None (fastest)"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:144
-msgid "Linear"
-msgstr ""
-
-#: gui/fluidsynth-dialog.cpp:145
-msgid "Fourth-order"
+#: 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/fluidsynth-dialog.cpp:146
-msgid "Seventh-order"
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
msgstr ""
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset"
+#: gui/updates-dialog.cpp:92
+msgid "Check for updates automatically"
msgstr ""
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset all FluidSynth settings to their default values."
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
msgstr ""
-#: gui/fluidsynth-dialog.cpp:217
-msgid ""
-"Do you really want to reset all FluidSynth settings to their default values?"
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
+msgid "Clear value"
msgstr ""
-#: base/main.cpp:228
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr ""
-#: base/main.cpp:306
+#: base/main.cpp:315
msgid "Menu"
msgstr ""
-#: base/main.cpp:309 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:312 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:315
+#: base/main.cpp:324
msgid "Skip line"
msgstr ""
-#: base/main.cpp:507
+#: base/main.cpp:524
msgid "Error running game:"
msgstr ""
-#: base/main.cpp:554
+#: base/main.cpp:571
msgid "Could not find any engine capable of running the selected game"
msgstr ""
@@ -1296,16 +1355,59 @@ msgstr ""
msgid "Unknown error"
msgstr ""
-#: engines/advancedDetector.cpp:317
+#. I18N: Hercules is graphics card name
+#: common/rendermode.cpp:35
+msgid "Hercules Green"
+msgstr ""
+
+#: common/rendermode.cpp:36
+msgid "Hercules Amber"
+msgstr ""
+
+#: common/rendermode.cpp:42
+msgid "PC-9821 (256 Colors)"
+msgstr ""
+
+#: common/rendermode.cpp:43
+msgid "PC-9801 (16 Colors)"
+msgstr ""
+
+#: common/rendermode.cpp:73
+msgctxt "lowres"
+msgid "Hercules Green"
+msgstr ""
+
+#: common/rendermode.cpp:74
+msgctxt "lowres"
+msgid "Hercules Amber"
+msgstr ""
+
+#: 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 ""
@@ -1313,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 ""
@@ -1342,11 +1444,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr ""
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:803
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:873
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
-#: engines/toltecs/menu.cpp:281 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 ""
@@ -1355,11 +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:803 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/neverhood/menumodule.cpp:873 engines/pegasus/pegasus.cpp:377
-#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
-#: engines/toltecs/menu.cpp:281 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 ""
@@ -1377,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 ""
@@ -1391,23 +1502,23 @@ msgstr ""
msgid "~K~eys"
msgstr ""
-#: engines/engine.cpp:276
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr ""
-#: engines/engine.cpp:284
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr ""
-#: engines/engine.cpp:293
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr ""
-#: engines/engine.cpp:298
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr ""
-#: engines/engine.cpp:398
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1416,7 +1527,7 @@ msgid ""
"See the README file for details."
msgstr ""
-#: engines/engine.cpp:409
+#: 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"
@@ -1425,24 +1536,28 @@ msgid ""
"See the README file for details."
msgstr ""
-#: engines/engine.cpp:467
+#: 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:480
+#: 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:483
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr ""
+#: audio/adlib.cpp:2290
+msgid "AdLib Emulator"
+msgstr ""
+
#: audio/fmopl.cpp:62
msgid "MAME OPL emulator"
msgstr ""
@@ -1488,31 +1603,35 @@ msgid ""
"information."
msgstr ""
-#: audio/null.h:44
-msgid "No music"
-msgstr ""
-
#: audio/mods/paula.cpp:196
msgid "Amiga Audio Emulator"
msgstr ""
-#: audio/adlib.cpp:2291
-msgid "AdLib Emulator"
+#: audio/null.h:44
+msgid "No music"
msgstr ""
#: audio/softsynth/appleiigs.cpp:33
msgid "Apple II GS Emulator (NOT IMPLEMENTED)"
msgstr ""
-#: audio/softsynth/sid.cpp:1430
-msgid "C64 Audio Emulator"
+#: audio/softsynth/cms.cpp:350
+msgid "Creative Music System Emulator"
msgstr ""
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33
+msgid "FM-Towns Audio"
+msgstr ""
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58
+msgid "PC-98 Audio"
+msgstr ""
+
+#: 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 ""
@@ -1524,6 +1643,146 @@ msgstr ""
msgid "IBM PCjr Emulator"
msgstr ""
+#: audio/softsynth/sid.cpp:1430
+msgid "C64 Audio Emulator"
+msgstr ""
+
+#: backends/events/default/default-events.cpp:196
+msgid "Do you really want to return to the Launcher?"
+msgstr ""
+
+#: backends/events/default/default-events.cpp:196
+msgid "Launcher"
+msgstr ""
+
+#: backends/events/default/default-events.cpp:218
+msgid "Do you really want to quit?"
+msgstr ""
+
+#: 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 ""
+
+#: 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 ""
+
+#: 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 ""
+
+#: 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 ""
+
+#: backends/events/gph/gph-events.cpp:409
+msgid "Maximum Volume"
+msgstr ""
+
+#: backends/events/gph/gph-events.cpp:411
+msgid "Increasing Volume"
+msgstr ""
+
+#: backends/events/gph/gph-events.cpp:417
+msgid "Minimal Volume"
+msgstr ""
+
+#: backends/events/gph/gph-events.cpp:419
+msgid "Decreasing Volume"
+msgstr ""
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Enabled"
+msgstr ""
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Disabled"
+msgstr ""
+
+#: backends/events/openpandora/op-events.cpp:174
+msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
+msgstr ""
+
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
+msgid "Do you want to quit ?"
+msgstr ""
+
+#. I18N: Trackpad mode toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:308
+msgid "Trackpad mode is now"
+msgstr ""
+
+#. 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 ""
+
+#: backends/events/webossdl/webossdl-events.cpp:311
+#: backends/events/webossdl/webossdl-events.cpp:338
+msgid "OFF"
+msgstr ""
+
+#: backends/events/webossdl/webossdl-events.cpp:315
+msgid "Swipe two fingers to the right to toggle."
+msgstr ""
+
+#. I18N: Auto-drag toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:335
+msgid "Auto-drag mode is now"
+msgstr ""
+
+#: backends/events/webossdl/webossdl-events.cpp:342
+msgid "Swipe three fingers to the right to toggle."
+msgstr ""
+
+#: backends/graphics/opengl/opengl-graphics.cpp:126
+msgid "OpenGL"
+msgstr ""
+
+#: backends/graphics/opengl/opengl-graphics.cpp:127
+msgid "OpenGL (No filtering)"
+msgstr ""
+
+#: 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 ""
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:66
+msgctxt "lowres"
+msgid "Normal (no scaling)"
+msgstr ""
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
+msgid "Enabled aspect ratio correction"
+msgstr ""
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
+msgid "Disabled aspect ratio correction"
+msgstr ""
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
+msgid "Active graphics filter:"
+msgstr ""
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+msgid "Windowed mode"
+msgstr ""
+
#: backends/keymapper/remap-dialog.cpp:48
msgid "Keymap:"
msgstr ""
@@ -1553,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 ""
@@ -1629,18 +1888,26 @@ msgstr ""
msgid "Disable power off"
msgstr ""
+#: 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 ""
+#: 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 ""
+#: 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 ""
+#: 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 ""
@@ -1651,9 +1918,9 @@ msgstr ""
#: 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
-#: backends/platform/tizen/form.cpp:275
msgid "Left Click"
msgstr ""
@@ -1663,65 +1930,32 @@ msgstr ""
#: backends/platform/maemo/maemo.cpp:220
#: backends/platform/symbian/src/SymbianActions.cpp:43
-#: backends/platform/wince/CEActionsSmartphone.cpp:44
#: backends/platform/tizen/form.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:44
msgid "Right Click"
msgstr ""
-#: backends/platform/sdl/macosx/appmenu_osx.mm:77
+#: backends/platform/sdl/macosx/appmenu_osx.mm:88
msgid "Hide ScummVM"
msgstr ""
-#: backends/platform/sdl/macosx/appmenu_osx.mm:82
+#: backends/platform/sdl/macosx/appmenu_osx.mm:93
msgid "Hide Others"
msgstr ""
-#: backends/platform/sdl/macosx/appmenu_osx.mm:87
+#: backends/platform/sdl/macosx/appmenu_osx.mm:98
msgid "Show All"
msgstr ""
-#: backends/platform/sdl/macosx/appmenu_osx.mm:109
#: backends/platform/sdl/macosx/appmenu_osx.mm:120
+#: backends/platform/sdl/macosx/appmenu_osx.mm:131
msgid "Window"
msgstr ""
-#: backends/platform/sdl/macosx/appmenu_osx.mm:114
+#: backends/platform/sdl/macosx/appmenu_osx.mm:125
msgid "Minimize"
msgstr ""
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:46
-msgid "Normal (no scaling)"
-msgstr ""
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:65
-msgctxt "lowres"
-msgid "Normal (no scaling)"
-msgstr ""
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
-msgid "Enabled aspect ratio correction"
-msgstr ""
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
-msgid "Disabled aspect ratio correction"
-msgstr ""
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
-msgid "Active graphics filter:"
-msgstr ""
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
-msgid "Windowed mode"
-msgstr ""
-
-#: backends/graphics/opengl/opengl-graphics.cpp:118
-msgid "OpenGL"
-msgstr ""
-
-#: backends/graphics/opengl/opengl-graphics.cpp:119
-msgid "OpenGL (No filtering)"
-msgstr ""
-
#: backends/platform/symbian/src/SymbianActions.cpp:38
#: backends/platform/wince/CEActionsSmartphone.cpp:39
msgid "Up"
@@ -1765,14 +1999,6 @@ msgstr ""
msgid "Fast mode"
msgstr ""
-#: backends/platform/symbian/src/SymbianActions.cpp:52
-#: backends/platform/wince/CEActionsPocket.cpp:44
-#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: backends/events/default/default-events.cpp:218 engines/scumm/dialogs.cpp:192
-#: engines/scumm/help.cpp:83 engines/scumm/help.cpp:85
-msgid "Quit"
-msgstr ""
-
#: backends/platform/symbian/src/SymbianActions.cpp:53
msgid "Debugger"
msgstr ""
@@ -1789,8 +2015,48 @@ msgstr ""
msgid "Key mapper"
msgstr ""
-#: backends/events/symbiansdl/symbiansdl-events.cpp:186
-msgid "Do you want to quit ?"
+#: backends/platform/tizen/form.cpp:263
+msgid "Right Click Once"
+msgstr ""
+
+#: backends/platform/tizen/form.cpp:271
+msgid "Move Only"
+msgstr ""
+
+#: backends/platform/tizen/form.cpp:294
+msgid "Escape Key"
+msgstr ""
+
+#: backends/platform/tizen/form.cpp:299
+msgid "Game Menu"
+msgstr ""
+
+#: backends/platform/tizen/form.cpp:304
+msgid "Show Keypad"
+msgstr ""
+
+#: backends/platform/tizen/form.cpp:309
+msgid "Control Mouse"
+msgstr ""
+
+#: backends/platform/tizen/fs.cpp:259
+msgid "[ Data ]"
+msgstr ""
+
+#: backends/platform/tizen/fs.cpp:263
+msgid "[ Resources ]"
+msgstr ""
+
+#: backends/platform/tizen/fs.cpp:267
+msgid "[ SDCard ]"
+msgstr ""
+
+#: backends/platform/tizen/fs.cpp:271
+msgid "[ Media ]"
+msgstr ""
+
+#: backends/platform/tizen/fs.cpp:275
+msgid "[ Shared ]"
msgstr ""
#: backends/platform/wii/options.cpp:51
@@ -2034,102 +2300,37 @@ msgid ""
"Don't forget to map a key to 'Hide Toolbar' action to see the whole inventory"
msgstr ""
-#: backends/events/default/default-events.cpp:196
-msgid "Do you really want to return to the Launcher?"
-msgstr ""
-
-#: backends/events/default/default-events.cpp:196
-msgid "Launcher"
-msgstr ""
-
-#: backends/events/default/default-events.cpp:218
-msgid "Do you really want to quit?"
-msgstr ""
-
-#: 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 ""
-
-#: 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 ""
-
-#: 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 ""
-
-#: backends/events/gph/gph-events.cpp:409
-msgid "Maximum Volume"
-msgstr ""
-
-#: backends/events/gph/gph-events.cpp:411
-msgid "Increasing Volume"
-msgstr ""
-
-#: backends/events/gph/gph-events.cpp:417
-msgid "Minimal Volume"
-msgstr ""
-
-#: backends/events/gph/gph-events.cpp:419
-msgid "Decreasing Volume"
-msgstr ""
-
-#: backends/events/openpandora/op-events.cpp:174
-msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
-msgstr ""
-
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr ""
-#: backends/platform/tizen/form.cpp:263
-msgid "Right Click Once"
-msgstr ""
-
-#: backends/platform/tizen/form.cpp:271
-msgid "Move Only"
-msgstr ""
-
-#: backends/platform/tizen/form.cpp:294
-msgid "Escape Key"
-msgstr ""
-
-#: backends/platform/tizen/form.cpp:299
-msgid "Game Menu"
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+msgid "Color mode"
msgstr ""
-#: backends/platform/tizen/form.cpp:304
-msgid "Show Keypad"
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
msgstr ""
-#: backends/platform/tizen/form.cpp:309
-msgid "Control Mouse"
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Enabled"
-msgstr ""
-
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Disabled"
+#: engines/adl/detection.cpp:64
+msgid "Show scanlines"
msgstr ""
-#: engines/agi/detection.cpp:147 engines/drascula/detection.cpp:302
-#: engines/dreamweb/detection.cpp:47 engines/neverhood/detection.cpp:160
-#: engines/sci/detection.cpp:394 engines/toltecs/detection.cpp:200
-#: engines/zvision/detection_tables.h:51
+#: 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 ""
-#: engines/agi/detection.cpp:148 engines/drascula/detection.cpp:303
-#: engines/dreamweb/detection.cpp:48 engines/neverhood/detection.cpp:161
-#: engines/sci/detection.cpp:395 engines/toltecs/detection.cpp:201
+#: 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 ""
@@ -2152,19 +2353,45 @@ msgid ""
"Enables mouse support. Allows to use mouse for movement and in game menus."
msgstr ""
-#: engines/agi/saveload.cpp:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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"
@@ -2172,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"
@@ -2180,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"
@@ -2188,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 ""
@@ -2212,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 ""
@@ -2242,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 ""
@@ -2398,64 +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:204
+#: engines/parallaction/saveload.cpp:194
+msgid "Load file"
+msgstr ""
+
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr ""
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:209
+msgid "Save file"
+msgstr ""
+
+#: 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"
@@ -2465,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"
@@ -2521,171 +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:395
+msgid "Enable high resolution graphics/content"
+msgstr ""
+
+#: 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:385
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
msgstr ""
-#: engines/sci/detection.cpp:404
+#: engines/sci/detection.cpp:434
msgid "Use IMF/Yamaha FB-01 for MIDI output"
msgstr ""
-#: engines/sci/detection.cpp:405
+#: 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:415
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr ""
-#: engines/sci/detection.cpp:416
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
msgstr ""
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr ""
-#: engines/sci/detection.cpp:427
+#: engines/sci/detection.cpp:457
msgid ""
"Use the Windows cursors (smaller and monochrome) instead of the DOS ones"
msgstr ""
-#: engines/sci/detection.cpp:437
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr ""
-#: engines/sci/detection.cpp:438
+#: 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:600
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr ""
-#: engines/scumm/dialogs.cpp:601
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr ""
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr ""
-#: engines/scumm/dialogs.cpp:610
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr ""
-#: engines/scumm/dialogs.cpp:656
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr ""
-#: engines/scumm/dialogs.cpp:658
+#: engines/scumm/dialogs.cpp:656
msgid "Refer to your Loom(TM) manual for help."
msgstr ""
-#: engines/scumm/dialogs.cpp:662
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr ""
-#: engines/scumm/dialogs.cpp:663
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr ""
@@ -3222,14 +3489,30 @@ msgstr ""
msgid "Fly to lower right"
msgstr ""
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/input.cpp:578
+msgid "Snap scroll on"
+msgstr ""
+
+#: engines/scumm/input.cpp:580
+msgid "Snap scroll off"
+msgstr ""
+
+#: engines/scumm/input.cpp:593
+msgid "Music volume: "
+msgstr ""
+
+#: engines/scumm/input.cpp:610
+msgid "Subtitle speed: "
+msgstr ""
+
+#: 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 "
@@ -3248,6 +3531,58 @@ msgid ""
"instruments from. Music will be disabled."
msgstr ""
+#: engines/sherlock/detection.cpp:71
+msgid "Use original savegame dialog"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:72
+msgid ""
+"Files button in-game shows original savegame dialog rather than the ScummVM "
+"menu"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:81
+msgid "Pixellated scene transitions"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:82
+msgid "When changing scenes, a randomized pixel transition is done"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:91
+msgid "Don't show hotspots when moving mouse"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:92
+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"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:102
+msgid "Show portraits for the characters when conversing"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:111
+msgid "Slide dialogs into view"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:112
+msgid "Slide UI dialogs into view, rather than simply showing them immediately"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:121
+msgid "Transparent windows"
+msgstr ""
+
+#: engines/sherlock/detection.cpp:122
+msgid "Show windows with a partially transparent background"
+msgstr ""
+
#: engines/sky/compact.cpp:130
msgid ""
"Unable to find \"sky.cpt\" file!\n"
@@ -3330,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/se_SE.po b/po/sv_SE.po
index b74f82805c..8137176bc3 100644
--- a/po/se_SE.po
+++ b/po/sv_SE.po
@@ -1,5 +1,5 @@
# Swedish translation for ScummVM.
-# Copyright (C) 2011-2015 The ScummVM Team
+# Copyright (C) 2011-2016 The ScummVM Team
# This file is distributed under the same license as the ScummVM package.
# Hampus Flink <hampus.flink@gmail.com>, 2011.
#
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.5.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2015-09-06 15:14+0200\n"
-"PO-Revision-Date: 2014-07-02 16:30+0100\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"
"Language: Svenska\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Poedit-SourceCharset: iso-8859-1\n"
-"X-Generator: Poedit 1.6.5\n"
+"X-Generator: Poedit 1.8.7\n"
#: gui/about.cpp:94
#, c-format
@@ -30,7 +30,7 @@ msgstr "Funktioner kompilerade i:"
#: gui/about.cpp:110
msgid "Available engines:"
-msgstr "Tillgängliga motorer"
+msgstr "Tillgängliga motorer:"
#: gui/browser.cpp:68 gui/browser_osx.mm:104
msgid "Show hidden files"
@@ -54,28 +54,29 @@ msgid "Go up"
msgstr "Uppåt"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:74 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: 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/fluidsynth-dialog.cpp:152 engines/engine.cpp:483
-#: backends/platform/wii/options.cpp:48
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
-#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:191 engines/sword1/control.cpp:865
+#: 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 "Avbryt"
#: gui/browser.cpp:76 gui/browser_osx.mm:103 gui/chooser.cpp:47
-#: gui/themebrowser.cpp:56
+#: gui/filebrowser-dialog.cpp:65 gui/themebrowser.cpp:56
msgid "Choose"
msgstr "Välj"
#: gui/editrecorddialog.cpp:58
msgid "Author:"
-msgstr ""
+msgstr "Skapare:"
#: gui/editrecorddialog.cpp:59 gui/launcher.cpp:204
msgid "Name:"
@@ -83,63 +84,182 @@ msgstr "Namn:"
#: gui/editrecorddialog.cpp:60
msgid "Notes:"
-msgstr ""
+msgstr "Anteckningar:"
-#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:75
+#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74
msgid "Ok"
+msgstr "OK"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Choose file for loading"
+msgstr "Välj en fil att ladda"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Enter filename for saving"
+msgstr "Ange ett filnamn för att spara"
+
+#: gui/filebrowser-dialog.cpp:132
+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: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 "Ja"
+
+#: 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 "Nej"
+
+#: gui/fluidsynth-dialog.cpp:68
+msgid "Reverb"
+msgstr "Reverb"
+
+#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
+msgid "Active"
+msgstr "Aktiv"
+
+#: gui/fluidsynth-dialog.cpp:72
+msgid "Room:"
+msgstr "Rum:"
+
+#: gui/fluidsynth-dialog.cpp:79
+msgid "Damp:"
+msgstr "Dämpa:"
+
+#: gui/fluidsynth-dialog.cpp:86
+msgid "Width:"
+msgstr "Bredd:"
+
+#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
+msgid "Level:"
+msgstr "Nivå:"
+
+#: gui/fluidsynth-dialog.cpp:100
+msgid "Chorus"
+msgstr "Chorus"
+
+#: gui/fluidsynth-dialog.cpp:104
+msgid "N:"
+msgstr "N:"
+
+#: gui/fluidsynth-dialog.cpp:118
+msgid "Speed:"
+msgstr "Hastighet:"
+
+#: gui/fluidsynth-dialog.cpp:125
+msgid "Depth:"
+msgstr "Djup:"
+
+#: gui/fluidsynth-dialog.cpp:132
+msgid "Type:"
+msgstr "Typ:"
+
+#: gui/fluidsynth-dialog.cpp:135
+msgid "Sine"
+msgstr "Sinus"
+
+#: gui/fluidsynth-dialog.cpp:136
+msgid "Triangle"
+msgstr "Triangel"
+
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
+msgid "Misc"
+msgstr "Diverse"
+
+#: gui/fluidsynth-dialog.cpp:140
+msgid "Interpolation:"
+msgstr "Interpolering:"
+
+#: gui/fluidsynth-dialog.cpp:143
+msgid "None (fastest)"
+msgstr "Ingen (snabbast)"
+
+#: gui/fluidsynth-dialog.cpp:144
+msgid "Linear"
+msgstr "Linjär"
+
+#: gui/fluidsynth-dialog.cpp:145
+msgid "Fourth-order"
+msgstr "Fjärde ordningen"
+
+#: gui/fluidsynth-dialog.cpp:146
+msgid "Seventh-order"
+msgstr "Sjunde ordningen"
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset"
+msgstr "Återställ"
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset all FluidSynth settings to their default values."
msgstr ""
+"Återställ alla FluidSynth-inställningar till deras ursprungliga värden."
-#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
+#: 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 "OK"
+
+#: gui/fluidsynth-dialog.cpp:217
+msgid ""
+"Do you really want to reset all FluidSynth settings to their default values?"
+msgstr ""
+"Vill du verkligen återställa alla FluidSynth-inställningar till deras "
+"ursprungliga värden?"
+
+#: 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 "Stäng"
-#: gui/gui-manager.cpp:120
+#: gui/gui-manager.cpp:122
msgid "Mouse click"
msgstr "Musklick"
-#: gui/gui-manager.cpp:124 base/main.cpp:319
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Visa tangentbord"
-#: gui/gui-manager.cpp:128 base/main.cpp:323
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Ställ in tangenter"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 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"
-#: gui/KeysDialog.h:36 gui/KeysDialog.cpp:145
-msgid "Choose an action to map"
-msgstr "Välj en handling att ställa in"
-
#: gui/KeysDialog.cpp:41
msgid "Map"
msgstr "Ställ in"
-#: gui/KeysDialog.cpp:42 gui/launcher.cpp:352 gui/launcher.cpp:1048
-#: gui/launcher.cpp:1052 gui/massadd.cpp:92 gui/options.cpp:1238
-#: gui/saveload-dialog.cpp:932 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:402 engines/engine.cpp:413
-#: 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/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 "OK"
-
#: gui/KeysDialog.cpp:49
msgid "Select an action and click 'Map'"
msgstr "Välj en handling och klicka på \"Ställ in\""
@@ -162,6 +282,10 @@ msgstr "Var god välj en handling"
msgid "Press the key to associate"
msgstr "Tryck på en tangent för att ställa in"
+#: gui/KeysDialog.cpp:145 gui/KeysDialog.h:36
+msgid "Choose an action to map"
+msgstr "Välj en handling att ställa in"
+
#: gui/launcher.cpp:193
msgid "Game"
msgstr "Spel"
@@ -204,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>"
@@ -227,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"
@@ -244,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"
@@ -257,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"
@@ -275,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:95
+#: 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:69
+#: 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:1222
+#: 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/myst.cpp:245 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/myst.cpp:245
-#: engines/mohawk/riven.cpp:718 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:792
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -492,62 +617,42 @@ msgstr ""
"Vill du verkligen använda mass-speldetektorn? Processen kan potentiellt "
"lägga till ett enormt antal spel."
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Ja"
-
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "Nej"
-
-#: gui/launcher.cpp:841
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM kunde inte öppna den valda katalogen!"
-#: gui/launcher.cpp:853
+#: 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:867
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Välj spel:"
-#: gui/launcher.cpp:941
+#: 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:999
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "Vill du ladda sparat spel?"
-#: gui/launcher.cpp:1048
+#: 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:1052
+#: 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:1159
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Masstillägg..."
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1165
msgid "Record..."
-msgstr ""
+msgstr "Spela in..."
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
@@ -574,148 +679,146 @@ msgstr "Upptäckte %d nya spel, ignorerade %d tidigare tillagda spel ..."
#: gui/onscreendialog.cpp:101 gui/onscreendialog.cpp:103
msgid "Stop"
-msgstr ""
+msgstr "Stopp"
#: gui/onscreendialog.cpp:106
msgid "Edit record description"
-msgstr ""
+msgstr "Redigera beskrivning av inspelning"
#: gui/onscreendialog.cpp:108
-#, fuzzy
msgid "Switch to Game"
-msgstr "Byt"
+msgstr "Växla till spelet"
#: gui/onscreendialog.cpp:110
-#, fuzzy
msgid "Fast replay"
-msgstr "Snabbläge"
+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:2298
+#: 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"
@@ -723,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"
@@ -789,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"
@@ -806,175 +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:1168 gui/fluidsynth-dialog.cpp:138
-msgid "Misc"
-msgstr "Diverse"
-
-#: 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."
@@ -983,64 +1094,75 @@ msgstr ""
"måste först byta till ett annat språk."
#. I18N: You must leave "#" as is, only word 'next' is translatable
-#: gui/predictivedialog.cpp:87
+#: gui/predictivedialog.cpp:86
msgid "# next"
-msgstr ""
+msgstr "# nästa"
-#: gui/predictivedialog.cpp:88
+#: gui/predictivedialog.cpp:87
msgid "add"
-msgstr ""
+msgstr "Lägg till"
-#: gui/predictivedialog.cpp:92
-#, fuzzy
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
-msgstr "Radera"
+msgstr "Radera tecken"
-#: gui/predictivedialog.cpp:96
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
-msgstr ""
+msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:98
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
-msgstr ""
+msgstr "* Pre."
+
+#. I18N: 'Num' means Numbers
+#: gui/predictivedialog.cpp:578
+msgid "* Num"
+msgstr "* 123"
-#: gui/recorderdialog.cpp:64
+#. I18N: 'Abc' means Latin alphabet input
+#: gui/predictivedialog.cpp:581
+msgid "* Abc"
+msgstr "* ABC"
+
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
-msgstr ""
+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 ""
+msgstr "Spela in"
-#: gui/recorderdialog.cpp:72
-#, fuzzy
+#: gui/recorderdialog.cpp:71
msgid "Playback"
-msgstr "Spela"
+msgstr "Spela upp"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
-msgstr ""
+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 ""
+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 ""
+msgstr "Anteckningar: "
-#: gui/recorderdialog.cpp:155
-#, fuzzy
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
-msgstr "Vill du verkligen radera den här spardatan?"
+msgstr "Vill du verkligen radera den här inspelningen?"
+
+#: gui/recorderdialog.cpp:173
+msgid "Unknown Author"
+msgstr "Okänd skapare"
#: gui/saveload-dialog.cpp:167
msgid "List view"
@@ -1102,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:"
@@ -1111,152 +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:661
+#: 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
-msgid "Clear value"
-msgstr "Töm sökfältet"
-
-#: gui/fluidsynth-dialog.cpp:68
-msgid "Reverb"
-msgstr "Reverb"
-
-#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
-msgid "Active"
-msgstr "Aktiv"
-
-#: gui/fluidsynth-dialog.cpp:72
-msgid "Room:"
-msgstr "Rum:"
-
-#: gui/fluidsynth-dialog.cpp:79
-msgid "Damp:"
-msgstr "Dämpa:"
-
-#: gui/fluidsynth-dialog.cpp:86
-msgid "Width:"
-msgstr "Bredd:"
-
-#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
-msgid "Level:"
-msgstr "Nivå:"
-
-#: gui/fluidsynth-dialog.cpp:100
-msgid "Chorus"
-msgstr "Chorus"
-
-#: gui/fluidsynth-dialog.cpp:104
-msgid "N:"
-msgstr "N:"
-
-#: gui/fluidsynth-dialog.cpp:118
-msgid "Speed:"
-msgstr "Hastighet:"
-
-#: gui/fluidsynth-dialog.cpp:125
-msgid "Depth:"
-msgstr "Djup:"
-
-#: gui/fluidsynth-dialog.cpp:132
-msgid "Type:"
-msgstr "Typ:"
-
-#: gui/fluidsynth-dialog.cpp:135
-msgid "Sine"
-msgstr "Sinus"
-
-#: gui/fluidsynth-dialog.cpp:136
-msgid "Triangle"
-msgstr "Triangel"
-
-#: gui/fluidsynth-dialog.cpp:140
-msgid "Interpolation:"
-msgstr "Interpolering:"
-
-#: gui/fluidsynth-dialog.cpp:143
-msgid "None (fastest)"
-msgstr "Ingen (snabbast)"
-
-#: gui/fluidsynth-dialog.cpp:144
-msgid "Linear"
-msgstr "Linjär"
-
-#: gui/fluidsynth-dialog.cpp:145
-msgid "Fourth-order"
-msgstr "Fjärde ordningen"
+#: 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/fluidsynth-dialog.cpp:146
-msgid "Seventh-order"
-msgstr "Sjunde ordningen"
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr ""
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset"
-msgstr "Återställ"
+#: gui/updates-dialog.cpp:92
+#, fuzzy
+msgid "Check for updates automatically"
+msgstr "Sök efter uppdateringar..."
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset all FluidSynth settings to their default values."
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
msgstr ""
-"Återställ alla FluidSynth-inställningar till deras ursprungliga värden."
-#: gui/fluidsynth-dialog.cpp:217
-msgid ""
-"Do you really want to reset all FluidSynth settings to their default values?"
-msgstr ""
-"Vill du verkligen återställa alla FluidSynth-inställningar till deras "
-"ursprungliga värden?"
+#: 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:228
+#: 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:306
+#: base/main.cpp:315
msgid "Menu"
msgstr "Meny"
-#: base/main.cpp:309 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:312 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:315
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Skippa rad"
-#: base/main.cpp:507
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Fel under körning av spel:"
-#: base/main.cpp:554
+#: 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"
@@ -1324,17 +1379,61 @@ msgstr "Avbrutit av användaren"
msgid "Unknown error"
msgstr "Okänt fel"
-#: engines/advancedDetector.cpp:317
+#. I18N: Hercules is graphics card name
+#: common/rendermode.cpp:35
+msgid "Hercules Green"
+msgstr "Herkules grön"
+
+#: common/rendermode.cpp:36
+msgid "Hercules Amber"
+msgstr "Herkules bärnsten"
+
+#: common/rendermode.cpp:42
+msgid "PC-9821 (256 Colors)"
+msgstr "PC-9821 (256 färger)"
+
+#: common/rendermode.cpp:43
+msgid "PC-9801 (16 Colors)"
+msgstr "PC-9801 (16 färger)"
+
+#: common/rendermode.cpp:73
+msgctxt "lowres"
+msgid "Hercules Green"
+msgstr "Herkules grön"
+
+#: common/rendermode.cpp:74
+msgctxt "lowres"
+msgid "Hercules Amber"
+msgstr "Herkules bärnsten"
+
+#: 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.:"
@@ -1342,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"
@@ -1371,11 +1470,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "Åte~r~vänd till launcher"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:803
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:873
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
-#: engines/toltecs/menu.cpp:281 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:"
@@ -1384,11 +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:803 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/neverhood/menumodule.cpp:873 engines/pegasus/pegasus.cpp:377
-#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
-#: engines/toltecs/menu.cpp:281 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"
@@ -1411,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"
@@ -1425,23 +1533,23 @@ msgstr "A~v~bryt"
msgid "~K~eys"
msgstr "~T~angenter"
-#: engines/engine.cpp:276
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Kunde inte initialisera färgformat."
-#: engines/engine.cpp:284
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Kunde inte byta till videoläget: '"
-#: engines/engine.cpp:293
+#: 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:298
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Kunde inte applicera fullskärmsinställning."
-#: engines/engine.cpp:398
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1455,7 +1563,7 @@ msgstr ""
"datafilerna till din hårddisk istället.\n"
"Se README-filen för detaljer."
-#: engines/engine.cpp:409
+#: 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"
@@ -1469,7 +1577,7 @@ msgstr ""
"för att kunna lyssna på spelets musik.\n"
"Se README-filen för detaljer."
-#: engines/engine.cpp:467
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1478,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:480
+#: 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 "
@@ -1488,10 +1596,14 @@ 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:483
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Starta ändå"
+#: audio/adlib.cpp:2290
+msgid "AdLib Emulator"
+msgstr "AdLib-emulator"
+
#: audio/fmopl.cpp:62
msgid "MAME OPL emulator"
msgstr "MAME OPL-emulator"
@@ -1502,7 +1614,7 @@ msgstr "DOSBox OPL-emulator"
#: audio/fmopl.cpp:67
msgid "ALSA Direct FM"
-msgstr ""
+msgstr "ALSA Direct FM"
#: audio/mididrv.cpp:209
#, c-format
@@ -1545,31 +1657,35 @@ msgstr ""
"Den föredragna ljudenheten '%s' kan inte användas. Se loggfilen för mer "
"information."
-#: audio/null.h:44
-msgid "No music"
-msgstr "Ingen musik"
-
#: audio/mods/paula.cpp:196
msgid "Amiga Audio Emulator"
msgstr "Amiga ljudemulator"
-#: audio/adlib.cpp:2291
-msgid "AdLib Emulator"
-msgstr "AdLib-emulator"
+#: audio/null.h:44
+msgid "No music"
+msgstr "Ingen musik"
#: audio/softsynth/appleiigs.cpp:33
msgid "Apple II GS Emulator (NOT IMPLEMENTED)"
msgstr "Apple II GS-emulator (INTE IMPLEMENTERAD)"
-#: audio/softsynth/sid.cpp:1430
-msgid "C64 Audio Emulator"
-msgstr "C64 ljudemulator"
+#: audio/softsynth/cms.cpp:350
+msgid "Creative Music System Emulator"
+msgstr "Creative Music System-emulator"
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33
+msgid "FM-Towns Audio"
+msgstr "FM Towns-ljud"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58
+msgid "PC-98 Audio"
+msgstr "PC-98 ljud"
+
+#: 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"
@@ -1581,6 +1697,146 @@ msgstr "PC Speaker-emulator"
msgid "IBM PCjr Emulator"
msgstr "IBM PCjr-emulator"
+#: audio/softsynth/sid.cpp:1430
+msgid "C64 Audio Emulator"
+msgstr "C64 ljudemulator"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Do you really want to return to the Launcher?"
+msgstr "Vill du verkligen återgå till launchern?"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Launcher"
+msgstr "Launcher"
+
+#: backends/events/default/default-events.cpp:218
+msgid "Do you really want to quit?"
+msgstr "Vill du verkligen avsluta?"
+
+#: 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 "Avsluta"
+
+#: 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 "Touchscreen \"Tap-läge\" - Vänsterklick"
+
+#: 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 "Touchscren \"Tap-läge\" - Högerklick"
+
+#: 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 "Touchscreen \"Tap-läge\" - Hover (utan klick)"
+
+#: backends/events/gph/gph-events.cpp:409
+msgid "Maximum Volume"
+msgstr "Max. volym"
+
+#: backends/events/gph/gph-events.cpp:411
+msgid "Increasing Volume"
+msgstr "Höja volymen"
+
+#: backends/events/gph/gph-events.cpp:417
+msgid "Minimal Volume"
+msgstr "Min. volym"
+
+#: backends/events/gph/gph-events.cpp:419
+msgid "Decreasing Volume"
+msgstr "Sänka volymen"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Enabled"
+msgstr "Klickning aktiverad"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Disabled"
+msgstr "Klickning deaktiverad"
+
+#: backends/events/openpandora/op-events.cpp:174
+msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
+msgstr "Touchscreen 'Tap-läge' - Hover (DPad klick)"
+
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
+msgid "Do you want to quit ?"
+msgstr "Vill du avsluta?"
+
+#. I18N: Trackpad mode toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:308
+msgid "Trackpad mode is now"
+msgstr "Trackpad-läge "
+
+#. 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 "PÅ"
+
+#: backends/events/webossdl/webossdl-events.cpp:311
+#: backends/events/webossdl/webossdl-events.cpp:338
+msgid "OFF"
+msgstr "AV"
+
+#: backends/events/webossdl/webossdl-events.cpp:315
+msgid "Swipe two fingers to the right to toggle."
+msgstr "Svep åt höger med två fingrar för att byta läge."
+
+#. I18N: Auto-drag toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:335
+msgid "Auto-drag mode is now"
+msgstr "Automatiskt dragläge "
+
+#: backends/events/webossdl/webossdl-events.cpp:342
+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:126
+msgid "OpenGL"
+msgstr "OpenGL"
+
+#: backends/graphics/opengl/opengl-graphics.cpp:127
+msgid "OpenGL (No filtering)"
+msgstr "OpenGL (ingen filtrering)"
+
+#: 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 "Normalt (ingen skalning)"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:66
+msgctxt "lowres"
+msgid "Normal (no scaling)"
+msgstr "Normalt (ingen skalning)"
+
+#: 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:2219
+msgid "Disabled aspect ratio correction"
+msgstr "Korrektion av bildförhållande av"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
+msgid "Active graphics filter:"
+msgstr "Aktivt grafikfilter:"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+msgid "Windowed mode"
+msgstr "Fönsterläge"
+
#: backends/keymapper/remap-dialog.cpp:48
msgid "Keymap:"
msgstr "Tangenter:"
@@ -1610,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"
@@ -1686,18 +1942,26 @@ msgstr "Hög ljudkvalitet (långsammare) (omstart)"
msgid "Disable power off"
msgstr "Inaktivera strömsparning"
+#: 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 "Dra-och-släpp-läge med mus aktiverat."
+#: 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 "Dra-och-släpp-läge med mus deaktiverat."
+#: 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 "Touchpad-läge aktiverat."
+#: 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 "Touchpad-läge inaktiverat."
@@ -1708,9 +1972,9 @@ msgstr "Klickläge"
#: 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
-#: backends/platform/tizen/form.cpp:275
msgid "Left Click"
msgstr "Vänsterklick"
@@ -1720,65 +1984,32 @@ msgstr "Mittenklick"
#: backends/platform/maemo/maemo.cpp:220
#: backends/platform/symbian/src/SymbianActions.cpp:43
-#: backends/platform/wince/CEActionsSmartphone.cpp:44
#: backends/platform/tizen/form.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:44
msgid "Right Click"
msgstr "Högerklick"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:77
+#: backends/platform/sdl/macosx/appmenu_osx.mm:88
msgid "Hide ScummVM"
msgstr "Göm ScummVM"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:82
+#: backends/platform/sdl/macosx/appmenu_osx.mm:93
msgid "Hide Others"
msgstr "Göm övriga"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:87
+#: backends/platform/sdl/macosx/appmenu_osx.mm:98
msgid "Show All"
msgstr "Visa alla"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:109
#: backends/platform/sdl/macosx/appmenu_osx.mm:120
+#: backends/platform/sdl/macosx/appmenu_osx.mm:131
msgid "Window"
msgstr "Fönster"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:114
+#: backends/platform/sdl/macosx/appmenu_osx.mm:125
msgid "Minimize"
msgstr "Minimera"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:46
-msgid "Normal (no scaling)"
-msgstr "Normalt (ingen skalning)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:65
-msgctxt "lowres"
-msgid "Normal (no scaling)"
-msgstr "Normalt (ingen skalning)"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
-msgid "Enabled aspect ratio correction"
-msgstr "Korrektion av bildförhållande på"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
-msgid "Disabled aspect ratio correction"
-msgstr "Korrektion av bildförhållande av"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
-msgid "Active graphics filter:"
-msgstr "Aktivt grafikfilter:"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
-msgid "Windowed mode"
-msgstr "Fönsterläge"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:118
-msgid "OpenGL"
-msgstr "OpenGL"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:119
-msgid "OpenGL (No filtering)"
-msgstr "OpenGL (ingen filtrering)"
-
#: backends/platform/symbian/src/SymbianActions.cpp:38
#: backends/platform/wince/CEActionsSmartphone.cpp:39
msgid "Up"
@@ -1822,14 +2053,6 @@ msgstr "Skippa text"
msgid "Fast mode"
msgstr "Snabbläge"
-#: backends/platform/symbian/src/SymbianActions.cpp:52
-#: backends/platform/wince/CEActionsPocket.cpp:44
-#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: backends/events/default/default-events.cpp:218 engines/scumm/dialogs.cpp:192
-#: engines/scumm/help.cpp:83 engines/scumm/help.cpp:85
-msgid "Quit"
-msgstr "Avsluta"
-
#: backends/platform/symbian/src/SymbianActions.cpp:53
msgid "Debugger"
msgstr "Debug-konsol"
@@ -1846,9 +2069,49 @@ msgstr "Virtuellt tangentbord"
msgid "Key mapper"
msgstr "Tangentinst."
-#: backends/events/symbiansdl/symbiansdl-events.cpp:186
-msgid "Do you want to quit ?"
-msgstr "Vill du avsluta?"
+#: backends/platform/tizen/form.cpp:263
+msgid "Right Click Once"
+msgstr "Ett högerklick"
+
+#: backends/platform/tizen/form.cpp:271
+msgid "Move Only"
+msgstr "Endast rörelse"
+
+#: backends/platform/tizen/form.cpp:294
+msgid "Escape Key"
+msgstr "Escape-tangenten"
+
+#: backends/platform/tizen/form.cpp:299
+msgid "Game Menu"
+msgstr "Spelmeny"
+
+#: backends/platform/tizen/form.cpp:304
+msgid "Show Keypad"
+msgstr "Visa tangentbord"
+
+#: backends/platform/tizen/form.cpp:309
+msgid "Control Mouse"
+msgstr "Kontrollera musen"
+
+#: backends/platform/tizen/fs.cpp:259
+msgid "[ Data ]"
+msgstr "[ Data ]"
+
+#: backends/platform/tizen/fs.cpp:263
+msgid "[ Resources ]"
+msgstr "[ Resurser ]"
+
+#: backends/platform/tizen/fs.cpp:267
+msgid "[ SDCard ]"
+msgstr "[ SD-kort ]"
+
+#: backends/platform/tizen/fs.cpp:271
+msgid "[ Media ]"
+msgstr "[ Media ]"
+
+#: backends/platform/tizen/fs.cpp:275
+msgid "[ Shared ]"
+msgstr "[ Delad ]"
#: backends/platform/wii/options.cpp:51
msgid "Video"
@@ -2096,139 +2359,105 @@ msgstr ""
"Glöm inte att välja en tangent för \"Göm verktygsrad\" för att se hela "
"inventariet"
-#: backends/events/default/default-events.cpp:196
-msgid "Do you really want to return to the Launcher?"
-msgstr "Vill du verkligen återgå till launchern?"
-
-#: backends/events/default/default-events.cpp:196
-msgid "Launcher"
-msgstr "Launcher"
-
-#: backends/events/default/default-events.cpp:218
-msgid "Do you really want to quit?"
-msgstr "Vill du verkligen avsluta?"
-
-#: 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 "Touchscreen \"Tap-läge\" - Vänsterklick"
-
-#: 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 "Touchscren \"Tap-läge\" - Högerklick"
-
-#: 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 "Touchscreen \"Tap-läge\" - Hover (utan klick)"
-
-#: backends/events/gph/gph-events.cpp:409
-msgid "Maximum Volume"
-msgstr "Max. volym"
-
-#: backends/events/gph/gph-events.cpp:411
-msgid "Increasing Volume"
-msgstr "Höja volymen"
-
-#: backends/events/gph/gph-events.cpp:417
-msgid "Minimal Volume"
-msgstr "Min. volym"
-
-#: backends/events/gph/gph-events.cpp:419
-msgid "Decreasing Volume"
-msgstr "Sänka volymen"
-
-#: backends/events/openpandora/op-events.cpp:174
-msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
-msgstr "Touchscreen 'Tap-läge' - Hover (DPad klick)"
-
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Sök efter uppdateringar..."
-#: backends/platform/tizen/form.cpp:263
-msgid "Right Click Once"
-msgstr "Ett högerklick"
-
-#: backends/platform/tizen/form.cpp:271
-msgid "Move Only"
-msgstr "Endast rörelse"
-
-#: backends/platform/tizen/form.cpp:294
-msgid "Escape Key"
-msgstr "Escape-tangenten"
-
-#: backends/platform/tizen/form.cpp:299
-msgid "Game Menu"
-msgstr "Spelmeny"
-
-#: backends/platform/tizen/form.cpp:304
-msgid "Show Keypad"
-msgstr "Visa tangentbord"
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "Färgblint läge"
-#: backends/platform/tizen/form.cpp:309
-msgid "Control Mouse"
-msgstr "Kontrollera musen"
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Enabled"
-msgstr "Klickning aktiverad"
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Disabled"
-msgstr "Klickning deaktiverad"
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "Visa etiketter"
-#: engines/agi/detection.cpp:147 engines/drascula/detection.cpp:302
-#: engines/dreamweb/detection.cpp:47 engines/neverhood/detection.cpp:160
-#: engines/sci/detection.cpp:394 engines/toltecs/detection.cpp:200
-#: engines/zvision/detection_tables.h:51
+#: 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 "Använd originalskärmar för spara/ladda"
-#: engines/agi/detection.cpp:148 engines/drascula/detection.cpp:303
-#: engines/dreamweb/detection.cpp:48 engines/neverhood/detection.cpp:161
-#: engines/sci/detection.cpp:395 engines/toltecs/detection.cpp:201
+#: 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 "Använder originalskärmarna för spara/ladda istället för ScummVM:s"
#: engines/agi/detection.cpp:157
-#, fuzzy
msgid "Use an alternative palette"
-msgstr "Använd alternativt spelintro (endast CD-version)"
+msgstr "Använd alternativ färgkarta"
#: engines/agi/detection.cpp:158
msgid ""
"Use an alternative palette, common for all Amiga games. This was the old "
"behavior"
msgstr ""
+"Använd en alternativ färgkarta typisk för alla Amiga-spel. Det här är det "
+"mala beteendet"
#: engines/agi/detection.cpp:167
-#, fuzzy
msgid "Mouse support"
-msgstr "Skipp-stöd"
+msgstr "Musstöd"
#: engines/agi/detection.cpp:168
msgid ""
"Enables mouse support. Allows to use mouse for movement and in game menus."
msgstr ""
+"Aktiverar musstöd. Möjliggör användning av musen för rörelser och i "
+"spelmenyer."
+
+#: engines/agi/detection.cpp:177
+#, fuzzy
+msgid "Use Hercules hires font"
+msgstr "Herkules grön"
-#: engines/agi/saveload.cpp:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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"
@@ -2239,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"
@@ -2250,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"
@@ -2261,19 +2490,18 @@ 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!"
#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
-#, fuzzy
msgid "Color Blind Mode"
-msgstr "Klickläge"
+msgstr "Färgblint läge"
#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
-msgstr ""
+msgstr "Aktivera färgblint läge som standard"
#: engines/drascula/saveload.cpp:47
msgid ""
@@ -2293,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."
@@ -2323,17 +2551,17 @@ 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."
#: engines/hopkins/detection.cpp:76 engines/hopkins/detection.cpp:86
msgid "Gore Mode"
-msgstr ""
+msgstr "Våldsamt läge"
#: engines/hopkins/detection.cpp:77 engines/hopkins/detection.cpp:87
msgid "Enable Gore Mode when available"
-msgstr ""
+msgstr "Aktivera våldsamt läge om tillgängligt"
#. I18N: Studio audience adds an applause and cheering sounds whenever
#. Malcolm makes a joke.
@@ -2465,6 +2693,13 @@ msgid ""
"Do you wish to use this save game file with ScummVM?\n"
"\n"
msgstr ""
+"Följande originalspardata hittades i sökvägen för ditt spel:\n"
+"\n"
+"%s %s\n"
+"\n"
+"Vill du använda den här spardatan med ScummVM?\n"
+"\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:590
#, c-format
@@ -2472,6 +2707,8 @@ msgid ""
"A save game file was found in the specified slot %d. Overwrite?\n"
"\n"
msgstr ""
+"En sparfil hittades på den angivna platsen %d. Vill du skriva över den?\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:623
#, c-format
@@ -2483,50 +2720,65 @@ msgid ""
"'import_savefile'.\n"
"\n"
msgstr ""
+"%d originalspardata har importerats till ScummVM.\n"
+"Om du vill importera originalspardata manuellt måste du öppna "
+"debuggkonsolen\n"
+"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"
@@ -2535,15 +2787,25 @@ msgstr ""
"Kan inte spara data i position %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:194
+#, fuzzy
+msgid "Load file"
+msgstr "Ladda spel:"
+
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Laddar speldata..."
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:209
+#, fuzzy
+msgid "Save file"
+msgstr "Spara spelet:"
+
+#: 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"
@@ -2560,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"
@@ -2620,27 +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 ""
+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:394
+msgid "Enable high resolution graphics"
+msgstr "Aktivera högupplöst grafik"
+
+#: engines/sci/detection.cpp:395
+msgid "Enable high resolution graphics/content"
+msgstr "Aktivera högupplöst grafik/innehåll"
+
+#: 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:384
+#: engines/sci/detection.cpp:414
msgid "Prefer digital sound effects"
msgstr "Föredra digitala ljudeffekter"
-#: engines/sci/detection.cpp:385
+#: 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:404
+#: 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:405
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2648,149 +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:415
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "Använd CD-ljud"
-#: engines/sci/detection.cpp:416
+#: 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:426
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Använd Windows muspekare"
-#: engines/sci/detection.cpp:427
+#: 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:437
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Använd silverpekare"
-#: engines/sci/detection.cpp:438
+#: 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
-#, fuzzy
+#: 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
-#, fuzzy
+#: 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:600
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Endast tal"
-#: engines/scumm/dialogs.cpp:601
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Tal och undertexter"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Endast undertexter"
-#: engines/scumm/dialogs.cpp:610
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Tal & text"
-#: engines/scumm/dialogs.cpp:656
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Välj en skicklighetsnivå."
-#: engines/scumm/dialogs.cpp:658
+#: 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:662
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Övning"
-#: engines/scumm/dialogs.cpp:663
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Expert"
@@ -3215,25 +3501,24 @@ msgid "Third kid"
msgstr "Tredje ungen"
#: engines/scumm/help.cpp:292
-#, fuzzy
msgid "Toggle Inventory/IQ Points display"
-msgstr "Aktivera centrerad dataskärm"
+msgstr "Visa inventarie/IQ-poäng"
#: engines/scumm/help.cpp:293
msgid "Toggle Keyboard/Mouse Fighting (*)"
-msgstr ""
+msgstr "Aktivera slagsmål med tangentbord/mus (*)"
#: engines/scumm/help.cpp:295
msgid "* Keyboard Fighting is always on,"
-msgstr ""
+msgstr "(*) Slagsmål med tangentbord är alltid på,"
#: engines/scumm/help.cpp:296
msgid " so despite the in-game message this"
-msgstr ""
+msgstr "så trots meddelandet i spelet"
#: engines/scumm/help.cpp:297
msgid " actually toggles Mouse Fighting Off/On"
-msgstr ""
+msgstr "aktiverar det här endast slagsmål med mus."
#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
@@ -3270,7 +3555,7 @@ msgstr "Slå lågt"
#: engines/scumm/help.cpp:315
msgid "Sucker punch"
-msgstr ""
+msgstr "Smocka"
#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
@@ -3328,7 +3613,23 @@ msgstr "Flyg åt höger"
msgid "Fly to lower right"
msgstr "Flyg åt nedre höger"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/input.cpp:578
+msgid "Snap scroll on"
+msgstr "Snäpprullning på"
+
+#: engines/scumm/input.cpp:580
+msgid "Snap scroll off"
+msgstr "Snäpprullning av"
+
+#: engines/scumm/input.cpp:593
+msgid "Music volume: "
+msgstr "Musikvolym: "
+
+#: engines/scumm/input.cpp:610
+msgid "Subtitle speed: "
+msgstr "Texthastighet: "
+
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3337,28 +3638,89 @@ 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
-#, fuzzy
+#: 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 ""
-"Vanligtvis hade Maniac Mansion startat nu, men ScummVM kan inte göra detta "
-"än. För att spela spelet, gå till \"Lägg till spel\" i ScummVM:s huvudmeny "
-"och välj \"Maniac\"-katalogen inuti \"Tentacle\" katalogen."
+"Vanligtvis hade Maniac Mansion startat nu, men för att det ska fungera måste "
+"Maniac Mansion-filerna placeras i 'Maniac'-katalogen i 'Tentacle'-katalogen. "
+"Spelet måste även läggas till i ScummVM."
#: 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 ""
+"Kunde inte hitta Macintosh-programmet för 'Loom'\n"
+"för att läsa instrumenten. Musiken kommer att avaktiveras."
#: 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 ""
+"Kunde inte hitta Macintosh-programmet för 'Monkey Island'\n"
+"för att läsa instrumenten. Musiken kommer att avaktiveras."
+
+#: engines/sherlock/detection.cpp:71
+msgid "Use original savegame dialog"
+msgstr "Använd originalskärmar för spara/ladda"
+
+#: engines/sherlock/detection.cpp:72
+msgid ""
+"Files button in-game shows original savegame dialog rather than the ScummVM "
+"menu"
+msgstr ""
+"Filknappen i spelet visar originalskärmen för spara/ladda istället för "
+"ScummVM-menyn"
+
+#: engines/sherlock/detection.cpp:81
+msgid "Pixellated scene transitions"
+msgstr "Pixliga scenövergångar"
+
+#: engines/sherlock/detection.cpp:82
+msgid "When changing scenes, a randomized pixel transition is done"
+msgstr "En slumpmässig pixelövergång visas vid scenbyten"
+
+#: engines/sherlock/detection.cpp:91
+msgid "Don't show hotspots when moving mouse"
+msgstr "Visa inte aktiveringspunkter vid musrörelse"
+
+#: engines/sherlock/detection.cpp:92
+msgid ""
+"Only show hotspot names after you actually click on a hotspot or action "
+"button"
+msgstr ""
+"Visar endast namn för aktiveringspunkter när du klickar på en "
+"aktiveringspunkt eller handlingsknapp"
+
+#: engines/sherlock/detection.cpp:101
+msgid "Show character portraits"
+msgstr "Visa karaktärsporträtt"
+
+#: engines/sherlock/detection.cpp:102
+msgid "Show portraits for the characters when conversing"
+msgstr "Visa porträtt för karaktärerna under dialoger"
+
+#: engines/sherlock/detection.cpp:111
+msgid "Slide dialogs into view"
+msgstr "Låt dialogrutor glida in"
+
+#: engines/sherlock/detection.cpp:112
+msgid "Slide UI dialogs into view, rather than simply showing them immediately"
+msgstr ""
+"Låter gränssnittets dialogrutor glida in i bilden istället för att bara visa "
+"dem direkt"
+
+#: engines/sherlock/detection.cpp:121
+msgid "Transparent windows"
+msgstr "Genomskinliga fönster"
+
+#: engines/sherlock/detection.cpp:122
+msgid "Show windows with a partially transparent background"
+msgstr "Visar fönster med en delvis genomskinlig bakgrund"
#: engines/sky/compact.cpp:130
msgid ""
@@ -3440,7 +3802,7 @@ msgstr "Behåll den nya"
#: engines/sword1/logic.cpp:1633
msgid "This is the end of the Broken Sword 1 Demo"
-msgstr "Här slutar Broken Sword 1 demon"
+msgstr "Här slutar Broken Sword 1-demon"
#: engines/sword2/animation.cpp:425
msgid ""
@@ -3455,67 +3817,73 @@ 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"
msgstr ""
"Teenagent.dat-filen är komprimerad och zlib har inte inkluderats i det här "
-"programmet. Var god dekomprimera den"
+"programmet. Var god dekomprimera den"
#: engines/wintermute/detection.cpp:58
msgid "Show FPS-counter"
-msgstr ""
+msgstr "Visa FPS-räknare"
#: engines/wintermute/detection.cpp:59
msgid "Show the current number of frames per second in the upper left corner"
msgstr ""
+"Visar det aktuella antalet bildrutor per sekund i det övre vänstra hörnet"
#: engines/zvision/detection_tables.h:52
-#, fuzzy
msgid "Use the original save/load screens instead of the ScummVM interface"
-msgstr "Använder originalskärmarna för spara/ladda istället för ScummVM:s"
+msgstr "Använd originalskärmarna för spara/ladda istället för ScummVM:s"
#: engines/zvision/detection_tables.h:61
msgid "Double FPS"
-msgstr ""
+msgstr "Dubbel FPS"
#: engines/zvision/detection_tables.h:62
msgid "Increase framerate from 30 to 60 FPS"
-msgstr ""
+msgstr "Öka antalet bildrutor per sekund från 30 till 60"
#: engines/zvision/detection_tables.h:71
-#, fuzzy
msgid "Enable Venus"
-msgstr "Aktivera heliumläge"
+msgstr "Aktivera Venus"
#: engines/zvision/detection_tables.h:72
-#, fuzzy
msgid "Enable the Venus help system"
-msgstr "Aktivera heliumläge"
+msgstr "Aktivera Venus-hjälpsystemet"
#: engines/zvision/detection_tables.h:81
msgid "Disable animation while turning"
-msgstr ""
+msgstr "Avaktivera animering när skärmen vänds"
#: engines/zvision/detection_tables.h:82
msgid "Disable animation while turning in panorama mode"
-msgstr ""
+msgstr "Avaktivera animering medan skärmen vänds i panorama-läge"
#: engines/zvision/detection_tables.h:91
msgid "Use high resolution MPEG video"
-msgstr ""
+msgstr "Använd högupplöst MPEG-video"
#: engines/zvision/detection_tables.h:92
-#, fuzzy
msgid "Use MPEG video from the DVD version, instead of lower resolution AVI"
msgstr ""
-"Använd de alternativa silverpekarna istället för de normala guldpekarna"
+"Använd högupplöst MPEG-video från DVD-versionen istället för lågupplöst AVI"
#~ msgid "EGA undithering"
#~ msgstr "EGA anti-gitter"
@@ -3562,27 +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"
-
-#~ msgid "Hercules Green"
-#~ msgstr "Herkules grön"
-
-#~ msgid "Hercules Amber"
-#~ msgstr "Herkules bärnsten"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Green"
-#~ msgstr "Herkules grön"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Amber"
-#~ msgstr "Herkules bärnsten"
-
-#, fuzzy
-#~ msgid "Save game failed!"
-#~ msgstr "Spara spelet:"
-
#~ msgctxt "lowres"
#~ msgid "Add Game..."
#~ msgstr "Lägg till spel..."
@@ -3597,8 +3944,5 @@ msgstr ""
#~ msgid "Command line argument not processed"
#~ msgstr "Argument i kommandoraden ej verkställt"
-#~ msgid "FM Towns Emulator"
-#~ msgstr "FM Towns-emulator"
-
#~ msgid "Invalid Path"
#~ msgstr "Ogiltig sökväg"
diff --git a/po/uk_UA.po b/po/uk_UA.po
index c9f722c700..232138e930 100644
--- a/po/uk_UA.po
+++ b/po/uk_UA.po
@@ -1,23 +1,23 @@
# Ukrainian translation for ScummVM.
-# Copyright (C) 2010-2015 The ScummVM Team
+# Copyright (C) 2010-2016 The ScummVM Team
# This file is distributed under the same license as the ScummVM package.
# Lubomyr Lisen, 2010.
-# Eugene Sandulenko <sev@scummvm.org>, 2010-2014
+# Eugene Sandulenko <sev@scummvm.org>, 2010-2016
#
msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.3.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2015-09-06 15:14+0200\n"
-"PO-Revision-Date: 2014-07-01 02:34+0300\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"
"Language: Ukrainian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=iso-8859-5\n"
"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n"
-"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
+"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
+"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
#: gui/about.cpp:94
#, c-format
@@ -54,28 +54,29 @@ msgid "Go up"
msgstr "²ÓÞàã"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:74 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: 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/fluidsynth-dialog.cpp:152 engines/engine.cpp:483
-#: backends/platform/wii/options.cpp:48
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
-#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:191 engines/sword1/control.cpp:865
+#: 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 "²öÔÜöÝÐ"
#: gui/browser.cpp:76 gui/browser_osx.mm:103 gui/chooser.cpp:47
-#: gui/themebrowser.cpp:56
+#: gui/filebrowser-dialog.cpp:65 gui/themebrowser.cpp:56
msgid "Choose"
msgstr "²ØÑàÐâØ"
#: gui/editrecorddialog.cpp:58
msgid "Author:"
-msgstr ""
+msgstr "°ÒâÞà:"
#: gui/editrecorddialog.cpp:59 gui/launcher.cpp:204
msgid "Name:"
@@ -83,63 +84,181 @@ msgstr "½Ð×ÒÐ:"
#: gui/editrecorddialog.cpp:60
msgid "Notes:"
-msgstr ""
+msgstr "¿àØÜöâÚØ:"
-#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:75
+#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74
msgid "Ok"
+msgstr "³ÐàÐ×Ô"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Choose file for loading"
+msgstr "¾ÑÕàöâì äÐÙÛ ÔÛï ×ÐÒÐÝâÐÖÕÝÝï"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Enter filename for saving"
+msgstr "½ÐÔÐÙâÕ öÜ'ï äÐÙÛã ÔÛï ×ÐßØáã"
+
+#: gui/filebrowser-dialog.cpp:132
+msgid "Do you really want to overwrite the file?"
+msgstr "²Ø ÔöÙáÝÞ åÞçÕâÕ ×ÐÜöÝØâØ æÕÙ äÐÙÛ?"
+
+#: 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 "ÂÐÚ"
+
+#: 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 "½ö"
+
+#: gui/fluidsynth-dialog.cpp:68
+msgid "Reverb"
+msgstr "ÀÕÒÕàÑÕàÐæöï"
+
+#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
+msgid "Active"
+msgstr "°ÚâØÒÝÕ"
+
+#: gui/fluidsynth-dialog.cpp:72
+msgid "Room:"
+msgstr "ºöÜÝÐâÐ:"
+
+#: gui/fluidsynth-dialog.cpp:79
+msgid "Damp:"
+msgstr "²ÞÛÞÓöáâì:"
+
+#: gui/fluidsynth-dialog.cpp:86
+msgid "Width:"
+msgstr "ÈØàØÝÐ:"
+
+#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
+msgid "Level:"
+msgstr "ÀöÒÕÝì:"
+
+#: gui/fluidsynth-dialog.cpp:100
+msgid "Chorus"
+msgstr "ÅÞà"
+
+#: gui/fluidsynth-dialog.cpp:104
+msgid "N:"
+msgstr "N:"
+
+#: gui/fluidsynth-dialog.cpp:118
+msgid "Speed:"
+msgstr "ÈÒØÔÚöáâì:"
+
+#: gui/fluidsynth-dialog.cpp:125
+msgid "Depth:"
+msgstr "³ÛØÑØÝÐ:"
+
+#: gui/fluidsynth-dialog.cpp:132
+msgid "Type:"
+msgstr "ÂØß:"
+
+#: gui/fluidsynth-dialog.cpp:135
+msgid "Sine"
+msgstr "ÁØÝãáÞ÷ÔÐ"
+
+#: gui/fluidsynth-dialog.cpp:136
+msgid "Triangle"
+msgstr "ÂàØÚãâÝØÚ"
+
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
+msgid "Misc"
+msgstr "Àö×ÝÕ"
+
+#: gui/fluidsynth-dialog.cpp:140
+msgid "Interpolation:"
+msgstr "¦ÝâÕàßÞÛïæöï:"
+
+#: gui/fluidsynth-dialog.cpp:143
+msgid "None (fastest)"
+msgstr "½ÕÜÐ (ÝÐÙèÒØÔèÕ)"
+
+#: gui/fluidsynth-dialog.cpp:144
+msgid "Linear"
+msgstr "»öÝöÙÝÐ"
+
+#: gui/fluidsynth-dialog.cpp:145
+msgid "Fourth-order"
+msgstr "ÇÕâÒÕàâÞÓÞ ßÞàïÔÚã"
+
+#: gui/fluidsynth-dialog.cpp:146
+msgid "Seventh-order"
+msgstr "ÁìÞÜÞÓÞ ßÞàïÔÚã"
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset"
+msgstr "ÁÚØÝãâØ"
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset all FluidSynth settings to their default values."
+msgstr "ÁÚØÝãâØ Òáö ÝÐÛÐèâãÒÐÝÝï FluidSynth ÔÞ ÷å ×ÝÐçÕÝì ×Ð ×ÐÜÞÒçÕÝÝïÜ"
+
+#: 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 "OK"
+
+#: gui/fluidsynth-dialog.cpp:217
+msgid ""
+"Do you really want to reset all FluidSynth settings to their default values?"
msgstr ""
+"²Ø ÔöÙáÝÞ åÞçÕâÕ áÚØÝãâØ Òáö ÝÐÛÐèâãÒÐÝÝï FluidSynth ÔÞ ÷å ×ÝÐçÕÝì ×Ð "
+"×ÐÜÞÒçÕÝÝïÜ?"
-#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
+#: 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 "·ÐÚàØâØ"
-#: gui/gui-manager.cpp:120
+#: gui/gui-manager.cpp:122
msgid "Mouse click"
msgstr "ºÛöÚ ÜØèÚÞî"
-#: gui/gui-manager.cpp:124 base/main.cpp:319
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "¿ÞÚÐ×ÐâØ ÚÛÐÒöÐâãàã"
-#: gui/gui-manager.cpp:128 base/main.cpp:323
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "¿ÕàÕßàØ×ÝÐçØâØ ÚÛÐÒöèö"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:87
+#: gui/gui-manager.cpp:133 base/main.cpp:335 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "¿ÕàÕÜÚÝãâØ ßÞÒÝÞÕÚàÐÝÝØÙ àÕÖØÜ"
-#: gui/KeysDialog.h:36 gui/KeysDialog.cpp:145
-msgid "Choose an action to map"
-msgstr "²ØÑÕàöâì Ôöî ÔÛï ßàØ×ÝÐçÕÝÝï"
-
#: gui/KeysDialog.cpp:41
msgid "Map"
msgstr "¿àØ×ÝÐçØâØ"
-#: gui/KeysDialog.cpp:42 gui/launcher.cpp:352 gui/launcher.cpp:1048
-#: gui/launcher.cpp:1052 gui/massadd.cpp:92 gui/options.cpp:1238
-#: gui/saveload-dialog.cpp:932 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:402 engines/engine.cpp:413
-#: 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/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 "OK"
-
#: gui/KeysDialog.cpp:49
msgid "Select an action and click 'Map'"
msgstr "²ØÑÕàöâì Ôöî ö ÚÛöÚÝöâì '¿àØ×ÝÐçØâØ'"
@@ -162,6 +281,10 @@ msgstr "±ãÔì ÛÐáÚÐ, ÒØÑÕàöâì Ôöî"
msgid "Press the key to associate"
msgstr "½ÐâØáÝöâì ÚÛÐÒöèã ÔÛï ßàØ×ÝÐçÕÝÝï"
+#: gui/KeysDialog.cpp:145 gui/KeysDialog.h:36
+msgid "Choose an action to map"
+msgstr "²ØÑÕàöâì Ôöî ÔÛï ßàØ×ÝÐçÕÝÝï"
+
#: gui/launcher.cpp:193
msgid "Game"
msgstr "³àÐ"
@@ -204,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 "<×Ð ãÜÞÒçÐÝÝïÜ>"
@@ -227,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 "³àä"
@@ -244,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 "°ãÔöÞ"
@@ -257,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 "³ãçÝ."
@@ -275,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:95
+#: 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:69
+#: 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:1222
+#: 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/myst.cpp:245 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/myst.cpp:245
-#: engines/mohawk/riven.cpp:718 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:792
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -492,62 +616,41 @@ msgstr ""
"ÇØ ÒØ ÔöÙáÝÞ åÞçÕâÕ ×ÐßãáâØâØ ßÞèãÚ ãáöå öÓÞà? ÆÕ ßÞâÕÝæöÙÝÞ ÜÞÖÕ ÔÞÔÐâØ "
"ÒÕÛØÚã ÚöÛìÚöáâì öÓÞà."
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "ÂÐÚ"
-
-#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
-#: gui/fluidsynth-dialog.cpp:217
-#: 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 "½ö"
-
-#: gui/launcher.cpp:841
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM ÝÕ ÜÞÖÕ ÒöÔÚàØâØ ÒÚÐ×ÐÝã ßÐßÚã!"
-#: gui/launcher.cpp:853
+#: gui/launcher.cpp:857
msgid "ScummVM could not find any game in the specified directory!"
msgstr "ScummVM ÝÕ ÜÞÖÕ ×ÝÐÙâØ Óàã ã ÒÚÐ×ÐÝöÙ ßÐßæö!"
-#: gui/launcher.cpp:867
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "²ØÑÕàöâì Óàã:"
-#: gui/launcher.cpp:941
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "²Ø ÔöÙáÝÞ åÞçÕâÕ ÒØÔÐÛØâØ ãáâÐÝÞÒÚØ ÔÛï æöô÷ ÓàØ?"
-#: gui/launcher.cpp:999
-#, fuzzy
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
-msgstr "²Ø åÞçÕâÕ ×ÐÒÐÝâÐÖØâØ Óàã?"
+msgstr "²Ø åÞçÕâÕ ×ÐÒÐÝâÐÖØâØ ×ÑÕàÕÖÕÝã Óàã?"
-#: gui/launcher.cpp:1048
+#: gui/launcher.cpp:1052
msgid "This game does not support loading games from the launcher."
msgstr "Æï ÓàÐ ÝÕ ßöÔâàØÜãô ×ÐÒÐÝâÐÖÕÝÝï ×ÑÕàÕÖÕÝì çÕàÕ× ÓÞÛÞÒÝÕ ÜÕÝî."
-#: gui/launcher.cpp:1052
+#: gui/launcher.cpp:1056
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr "ScummVM ÝÕ ×ÜöÓ ×ÝÐÙâØ ÔÒØÖÞÚ ÔÛï ×ÐßãáÚã ÒØÑàÐÝÞ÷ ÓàØ!"
-#: gui/launcher.cpp:1159
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "´ÞÔ. ÑÐÓÐâÞ..."
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1165
msgid "Record..."
-msgstr ""
+msgstr "·ÐßØá..."
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
@@ -574,148 +677,146 @@ msgstr "·ÝÐÙÔÕÝÞ %d ÝÞÒØå öÓÞà, ßàÞßãéÕÝÞ %d ßÞßÕàÕÔÝìÞ ÔÞÔÐÝØå öÓÞà ..."
#: gui/onscreendialog.cpp:101 gui/onscreendialog.cpp:103
msgid "Stop"
-msgstr ""
+msgstr "ÁâÞß"
#: gui/onscreendialog.cpp:106
msgid "Edit record description"
-msgstr ""
+msgstr "ÀÕÔÐÓÒÐâØ ÞßØá ×ÐßØáã"
#: gui/onscreendialog.cpp:108
-#, fuzzy
msgid "Switch to Game"
-msgstr "¿ÕàÕÜÚÝãâØ"
+msgstr "¿ÕàÕÚÛîçØâØáï ÝÐ Óàã"
#: gui/onscreendialog.cpp:110
-#, fuzzy
msgid "Fast replay"
-msgstr "ÈÒØÔÚØÙ àÕÖØÜ"
+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:2298
+#: 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"
@@ -723,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"
@@ -791,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"
@@ -808,175 +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:1168 gui/fluidsynth-dialog.cpp:138
-msgid "Misc"
-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."
@@ -985,64 +1094,75 @@ msgstr ""
"âÕÜã, ßÞâàöÑÝÞ Ò ßÕàèã çÕàÓã ×ÜöÝØâØ ÜÞÒã."
#. I18N: You must leave "#" as is, only word 'next' is translatable
-#: gui/predictivedialog.cpp:87
+#: gui/predictivedialog.cpp:86
msgid "# next"
-msgstr ""
+msgstr "# ÝÐáâ"
-#: gui/predictivedialog.cpp:88
+#: gui/predictivedialog.cpp:87
msgid "add"
-msgstr ""
+msgstr "ÔÞÔ"
-#: gui/predictivedialog.cpp:92
-#, fuzzy
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
-msgstr "²ØÔÐÛØâØ"
+msgstr "²ØÔÐÛØâØ áÜÜÒÞÛ"
-#: gui/predictivedialog.cpp:96
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
-msgstr ""
+msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:98
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
-msgstr ""
+msgstr "* ¿àÕ"
+
+#. I18N: 'Num' means Numbers
+#: gui/predictivedialog.cpp:578
+msgid "* Num"
+msgstr "* Æäà"
-#: gui/recorderdialog.cpp:64
+#. I18N: 'Abc' means Latin alphabet input
+#: gui/predictivedialog.cpp:581
+msgid "* Abc"
+msgstr "* Abc"
+
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
-msgstr ""
+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 ""
+msgstr "·ÐßØáÐâØ"
-#: gui/recorderdialog.cpp:72
-#, fuzzy
+#: gui/recorderdialog.cpp:71
msgid "Playback"
-msgstr "³àÐâØ"
+msgstr "²öÔâÒÞàØâØ"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
-msgstr ""
+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 ""
+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 ""
+msgstr "¿àØÜöâÚØ: "
-#: gui/recorderdialog.cpp:155
-#, fuzzy
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
-msgstr "²Ø ÔöÙáÝÞ åÞçÕâÕ ÒØÔÐÛØâØ æÕ ×ÑÕàÕÖÕÝÝï?"
+msgstr "²Ø ÔöÙáÝÞ åÞçÕâÕ ÒØÔÐÛØâØ æÕÙ ×ÐßØá?"
+
+#: gui/recorderdialog.cpp:173
+msgid "Unknown Author"
+msgstr "½ÕÒöÔÞÜØÙ ÐÒâÞà"
#: gui/saveload-dialog.cpp:167
msgid "List view"
@@ -1104,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:"
@@ -1113,151 +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:661
+#: 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
-msgid "Clear value"
-msgstr "¾çØáâØâØ ×ÝÐçÕÝÝï"
-
-#: gui/fluidsynth-dialog.cpp:68
-msgid "Reverb"
-msgstr "ÀÕÒÕàÑÕàÐæöï"
-
-#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
-msgid "Active"
-msgstr "°ÚâØÒÝÕ"
-
-#: gui/fluidsynth-dialog.cpp:72
-msgid "Room:"
-msgstr "ºöÜÝÐâÐ:"
-
-#: gui/fluidsynth-dialog.cpp:79
-msgid "Damp:"
-msgstr "²ÞÛÞÓöáâì:"
-
-#: gui/fluidsynth-dialog.cpp:86
-msgid "Width:"
-msgstr "ÈØàØÝÐ:"
-
-#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
-msgid "Level:"
-msgstr "ÀöÒÕÝì:"
-
-#: gui/fluidsynth-dialog.cpp:100
-msgid "Chorus"
-msgstr "ÅÞà"
-
-#: gui/fluidsynth-dialog.cpp:104
-msgid "N:"
-msgstr "N:"
-
-#: gui/fluidsynth-dialog.cpp:118
-msgid "Speed:"
-msgstr "ÈÒØÔÚöáâì:"
-
-#: gui/fluidsynth-dialog.cpp:125
-msgid "Depth:"
-msgstr "³ÛØÑØÝÐ:"
-
-#: gui/fluidsynth-dialog.cpp:132
-msgid "Type:"
-msgstr "ÂØß:"
-
-#: gui/fluidsynth-dialog.cpp:135
-msgid "Sine"
-msgstr "ÁØÝãáÞ÷ÔÐ"
-
-#: gui/fluidsynth-dialog.cpp:136
-msgid "Triangle"
-msgstr "ÂàØÚãâÝØÚ"
-
-#: gui/fluidsynth-dialog.cpp:140
-msgid "Interpolation:"
-msgstr "¦ÝâÕàßÞÛïæöï:"
-
-#: gui/fluidsynth-dialog.cpp:143
-msgid "None (fastest)"
-msgstr "½ÕÜÐ (ÝÐÙèÒØÔèÕ)"
-
-#: gui/fluidsynth-dialog.cpp:144
-msgid "Linear"
-msgstr "»öÝöÙÝÐ"
-
-#: gui/fluidsynth-dialog.cpp:145
-msgid "Fourth-order"
-msgstr "ÇÕâÒÕàâÞÓÞ ßÞàïÔÚã"
+#: 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/fluidsynth-dialog.cpp:146
-msgid "Seventh-order"
-msgstr "ÁìÞÜÞÓÞ ßÞàïÔÚã"
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr "(²Ø ×ÐÒÖÔØ ÜÞÖÕâÕ ÒÚÛîçØâØ ÷÷ ã ½ÐÛÐèâãÒÐÝÝïå ÝÐ ×ÐÚÛÐÔæö ¦ÝèÕ)"
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset"
-msgstr "ÁÚØÝãâØ"
+#: gui/updates-dialog.cpp:92
+msgid "Check for updates automatically"
+msgstr "°ÒâÞÜÐâëçÝÞ ßÕàÕÒöàïâØ ÞÝÞÒÛÕÝÝï"
-#: gui/fluidsynth-dialog.cpp:150
-msgid "Reset all FluidSynth settings to their default values."
-msgstr "ÁÚØÝãâØ Òáö ÝÐÛÐèâãÒÐÝÝï FluidSynth ÔÞ ÷å ×ÝÐçÕÝì ×Ð ×ÐÜÞÒçÕÝÝïÜ"
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr "¿àÞÔÞÒÖØâØ"
-#: gui/fluidsynth-dialog.cpp:217
-msgid ""
-"Do you really want to reset all FluidSynth settings to their default values?"
-msgstr ""
-"²Ø ÔöÙáÝÞ åÞçÕâÕ áÚØÝãâØ Òáö ÝÐÛÐèâãÒÐÝÝï FluidSynth ÔÞ ÷å ×ÝÐçÕÝì ×Ð "
-"×ÐÜÞÒçÕÝÝïÜ?"
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
+msgid "Clear value"
+msgstr "¾çØáâØâØ ×ÝÐçÕÝÝï"
-#: base/main.cpp:228
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "´ÒØÖÞÚ ÝÕ ßöÔâàØÜãô àöÒÕÝì ÒöÔÛÐÔÚØ '%s'"
-#: base/main.cpp:306
+#: base/main.cpp:315
msgid "Menu"
msgstr "¼ÕÝî"
-#: base/main.cpp:309 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:312 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:315
+#: base/main.cpp:324
msgid "Skip line"
msgstr "¿àÞßãáâØâØ àïÔÞÚ"
-#: base/main.cpp:507
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "¿ÞÜØÛÚÐ ×ÐßãáÚã ÓàØ:"
-#: base/main.cpp:554
+#: base/main.cpp:571
msgid "Could not find any engine capable of running the selected game"
msgstr "½Õ ÜÞÖã ×ÝÐÙâØ ÔÒØÖÞÚ ÔÛï ×ÐßãáÚã ÒØÑàÐÝÞ÷ ÓàØ"
@@ -1325,16 +1382,59 @@ msgstr "²öÔÜöÝÕÝÞ ÚÞàØáâãÒÐçÕÜ"
msgid "Unknown error"
msgstr "½ÕÒöÔÞÜÐ ßÞÜØÛÚÐ"
-#: engines/advancedDetector.cpp:317
+#. I18N: Hercules is graphics card name
+#: common/rendermode.cpp:35
+msgid "Hercules Green"
+msgstr "Hercules ×ÕÛÕÝØÙ"
+
+#: common/rendermode.cpp:36
+msgid "Hercules Amber"
+msgstr "Hercules ÑãàèâØÝÝØÙ"
+
+#: common/rendermode.cpp:42
+msgid "PC-9821 (256 Colors)"
+msgstr "PC-9821 (256 ÚÞÛìÞàöÒ)"
+
+#: common/rendermode.cpp:43
+msgid "PC-9801 (16 Colors)"
+msgstr "PC-9801 (16 ÚÞÛìÞàöÒ)"
+
+#: common/rendermode.cpp:73
+msgctxt "lowres"
+msgid "Hercules Green"
+msgstr "Hercules ×ÕÛÕÝØÙ"
+
+#: common/rendermode.cpp:74
+msgctxt "lowres"
+msgid "Hercules Amber"
+msgstr "Hercules ÑãàèâØÝÝØÙ"
+
+#: 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 "ÝÐ×ÒÞî ÓàØ, ïÚã ÒØ ÝÐÜÐÓÐôâÕáì ÔÞÔÐâØ, Ð âÐÚÞÖ ÷÷ ÒÕàáöî/ÜÞÒã/âÐ öÝèÕ:"
@@ -1342,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 "~·~ÐßØáÐâØ"
@@ -1371,11 +1471,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "~¿~ÞÒÕà.Ò ÓÞÛÞÒÝÕ ÜÕÝî"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:803
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:873
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
-#: engines/toltecs/menu.cpp:281 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 "·ÑÕàÕÓâØ Óàã: "
@@ -1384,11 +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:803 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/neverhood/menumodule.cpp:873 engines/pegasus/pegasus.cpp:377
-#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
-#: engines/toltecs/menu.cpp:281 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 "·ÐßØáÐâØ"
@@ -1411,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 "²ö~Ô~ÜöÝÐ"
@@ -1425,23 +1534,23 @@ msgstr "²ö~Ô~ÜöÝÐ"
msgid "~K~eys"
msgstr "~º~ÛÐÒöèö"
-#: engines/engine.cpp:276
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "½Õ ÜÞÖã ÝÐÛÐèâãÒÐâØ äÞàÜÐâ ÚÞÛìÞàã."
-#: engines/engine.cpp:284
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "½Õ ÒÔÐÛÞáï ßÕàÕÚÛîçØâØ ÒöÔÕÞàÕÖØÜ: '"
-#: engines/engine.cpp:293
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "½Õ ÒÔÐÛÞáï ×ÐáâÞáãÒÐâØ ÚÞàÕÚæöî áßöÒÒöÔÝÞèÕÝÝï áâÞàöÝ."
-#: engines/engine.cpp:298
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "½Õ ÒÔÐÛÞáï ×ÐáâÞáãÒÐâØ ßÞÒÝÞÕÚàÐÝÝØÙ àÕÖØÜ."
-#: engines/engine.cpp:398
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1455,7 +1564,7 @@ msgstr ""
"ÓàØ ÝÐ ÖÞàáâÚØÙ ÔØáÚ.\n"
"´ØÒöâìáï äÐÙÛ README ÔÛï ßÞÔÐÛìèØå öÝáâàãÚæöÙ."
-#: engines/engine.cpp:409
+#: 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"
@@ -1469,7 +1578,7 @@ msgstr ""
"âÞÓÞ, éÞÑ ÜÞÖÝÐ ÑãÛÞ áÛãåÐâØ Üã×ØÚã ã Óàö.\n"
"´ØÒöâìáï äÐÙÛ README ÔÛï ßÞÔÐÛìèØå öÝáâàãÚæöÙ."
-#: engines/engine.cpp:467
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1478,7 +1587,7 @@ msgstr ""
"·ÐÒÐÝâÐÖÕÝÝï áâÐÝã ÓàØ ÝÕ ÒÔÐÛÞáï (%s)! . ±ãÔì-ÛÐáÚÐ, ÔØÒöâìáï äÐÙÛ README "
"ÔÛï ÞáÝÞÒÝÞ÷ öÝÞàÜÐæö÷, Ð âÐÚÞÖ öÝáâàãÚæöÙ, ïÚ ÞâàØÜÐâØ ßÞÔÐÛìèã ÔÞßÞÜÞÓã."
-#: engines/engine.cpp:480
+#: 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 "
@@ -1488,10 +1597,14 @@ msgstr ""
"ScummVM. ÁÚÞàèÕ ×Ð ÒáÕ ÒÞÝÐ ÝÕ ÑãÔÕ ßàÐæîÒÐâØ áâÐÑöÛìÝÞ, ö ×ÑÕàÕÖÕÝÝï öÓÞà, "
"ïÚö ÒØ ×àÞÑØâÕ, ÜÞÖãâì ÝÕ ßàÐæîÒÐâØ ã ßÞÔÐÛìèØå ÒÕàáöïå ScummVM."
-#: engines/engine.cpp:483
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "²áÕ ÞÔÝÞ ×ÐßãáâØâØ"
+#: audio/adlib.cpp:2290
+msgid "AdLib Emulator"
+msgstr "µÜãÛïâÞà AdLib"
+
#: audio/fmopl.cpp:62
msgid "MAME OPL emulator"
msgstr "µÜãÛïâÞà MAME OPL"
@@ -1502,7 +1615,7 @@ msgstr "µÜãÛïâÞà DOSBox OPL"
#: audio/fmopl.cpp:67
msgid "ALSA Direct FM"
-msgstr ""
+msgstr "±ÕáßÞáÕàÕÔÝöÙ ALSA FM"
#: audio/mididrv.cpp:209
#, c-format
@@ -1545,31 +1658,35 @@ msgstr ""
"ÃßÞÔÞÑÐÝØÙ ×ÒãÚÞÒØÙ ßàØáâàöÙ '%s' ÝÕ ÜÞÖÕ ÑãâØ ÒØÚÞàØáâÐÝØÙ. ´ØÒöâìáï äÐÙÛ "
"ÛÞÓã ÔÛï ÔÞÔÐâÚÞÒÞ÷ öÝäÞàÜÐæö÷."
-#: audio/null.h:44
-msgid "No music"
-msgstr "±Õ× Üã×ØÚØ"
-
#: audio/mods/paula.cpp:196
msgid "Amiga Audio Emulator"
msgstr "°ÜöÓÐ °ãÔöÞ µÜãÛïâÞà"
-#: audio/adlib.cpp:2291
-msgid "AdLib Emulator"
-msgstr "µÜãÛïâÞà AdLib"
+#: audio/null.h:44
+msgid "No music"
+msgstr "±Õ× Üã×ØÚØ"
#: audio/softsynth/appleiigs.cpp:33
msgid "Apple II GS Emulator (NOT IMPLEMENTED)"
msgstr "Apple II GS µÜãÛïâÞà (½µ Àµ°»¦·¾²°½¾)"
-#: audio/softsynth/sid.cpp:1430
-msgid "C64 Audio Emulator"
-msgstr "C64 °ãÔöÞ µÜãÛïâÞà"
+#: audio/softsynth/cms.cpp:350
+msgid "Creative Music System Emulator"
+msgstr "µÜãÛïâÞà Creative Music System"
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33
+msgid "FM-Towns Audio"
+msgstr "°ãÔöÞ FM-Towns"
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58
+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"
@@ -1581,6 +1698,146 @@ msgstr "µÜãÛïâÞà PC áßöÚÕàÐ"
msgid "IBM PCjr Emulator"
msgstr "µÜãÛïâÞà IBM PCjr"
+#: audio/softsynth/sid.cpp:1430
+msgid "C64 Audio Emulator"
+msgstr "C64 °ãÔöÞ µÜãÛïâÞà"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Do you really want to return to the Launcher?"
+msgstr "²Ø ÔöÙáÝÞ åÞçÕâÕ ßÞÒÕàÝãâØáï ÔÞ ÓÞÛÞÒÝÞÓÞ ÜÕÝî?"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Launcher"
+msgstr "³ÞÛÞÒÝÕ ÜÕÝî"
+
+#: backends/events/default/default-events.cpp:218
+msgid "Do you really want to quit?"
+msgstr "²Ø ÔöÙáÝÞ åÞçÕâÕ ÒØÙâØ?"
+
+#: 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 "²ØåöÔ"
+
+#: 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 "ÀÕÖØÜ ÔÞâØÚã ã âÐçáÚàöÝö - »öÒØÙ ÚÛöÚ"
+
+#: 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 "ÀÕÖØÜ ÔÞâØÚã ã âÐçáÚàöÝö - ¿àÐÒØÙ ÚÛöÚ"
+
+#: 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 "ÀÕÖØÜ ÔÞâØÚã ã âÐçáÚàöÝö - ¿àÞÛöâ (ÑÕ× ÚÛöÚã)"
+
+#: backends/events/gph/gph-events.cpp:409
+msgid "Maximum Volume"
+msgstr "¼ÐÚáØÜÐÛìÝÐ ³ãçÝöáâì"
+
+#: backends/events/gph/gph-events.cpp:411
+msgid "Increasing Volume"
+msgstr "¿öÔÒØéÕÝÝï ÓãçÝÞáâö"
+
+#: backends/events/gph/gph-events.cpp:417
+msgid "Minimal Volume"
+msgstr "¼öÝöÜÐÛìÝÐ ³ãçÝöáâì"
+
+#: backends/events/gph/gph-events.cpp:419
+msgid "Decreasing Volume"
+msgstr "¿ÞÝØÖÕÝÝï ÓãçÝÞáâö"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Enabled"
+msgstr "ºÛöÚØ ãÒöÜÚÝÕÝÞ"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Disabled"
+msgstr "ºÛöÚØ ÒØÜÚÝÕÝÞ"
+
+#: backends/events/openpandora/op-events.cpp:174
+msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
+msgstr "ÀÕÖØÜ ÔÞâØÚã ã âÐçáÚàöÝö - ¿àÞÛöâ (ÚÛöÚ DPad)"
+
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
+msgid "Do you want to quit ?"
+msgstr "²Ø ÔöÙáÝÞ åÞçÕâÕ ÒØÙâØ?"
+
+#. I18N: Trackpad mode toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:308
+msgid "Trackpad mode is now"
+msgstr "ÀÕÖØÜ âàÕÚßÐÔã ÒÚÛîçÕÝÞ."
+
+#. 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 "²º»"
+
+#: backends/events/webossdl/webossdl-events.cpp:311
+#: backends/events/webossdl/webossdl-events.cpp:338
+msgid "OFF"
+msgstr "²¸¼º"
+
+#: backends/events/webossdl/webossdl-events.cpp:315
+msgid "Swipe two fingers to the right to toggle."
+msgstr "¿àÞÒÕÔöâì ÔÒÞÜÐ ßÐÛìæïÜã ÝÐßàÐÒÞ ÔÛï ßÕàÕÚÛîçÕÝÝï."
+
+#. I18N: Auto-drag toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:335
+msgid "Auto-drag mode is now"
+msgstr "ÀÕÖØÜ áÐÜÞâïÓÝÕÝÝï ÒÚÛîçÕÝÞ"
+
+#: backends/events/webossdl/webossdl-events.cpp:342
+msgid "Swipe three fingers to the right to toggle."
+msgstr "¿àÞÒÕÔöâì âàìÞÜÐ ßÐÛìæïÜö ÝÐßàÐÒÞ ÔÛï ßÕàÕÚÛîçÕÝÝï."
+
+#: 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 "±Õ× ×ÑöÛìèÕÝÝï"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:66
+msgctxt "lowres"
+msgid "Normal (no scaling)"
+msgstr "±Õ× ×ÑöÛìèÕÝÝï"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
+msgid "Enabled aspect ratio correction"
+msgstr "ºÞàÕÚæöî áßöÒÒöÔÝÞèÕÝÝï áâÞàöÝ ãÒöÜÚÝÕÝÞ"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
+msgid "Disabled aspect ratio correction"
+msgstr "ºÞàÕÚæöî áßöÒÒöÔÝÞèÕÝÝï áâÞàöÝ ÒØÜÚÝÕÝÞ"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
+msgid "Active graphics filter:"
+msgstr "¿ÞâÞçÝØÙ ÓàÐäöçÝØÙ äöÛìâà:"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+msgid "Windowed mode"
+msgstr "²öÚÞÝÝØÙ àÕÖØÜ"
+
#: backends/keymapper/remap-dialog.cpp:48
msgid "Keymap:"
msgstr "¼ÐßÐ ÚÛÐÒöè:"
@@ -1610,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 "~·~ÐÚàØâØ"
@@ -1686,18 +1943,26 @@ msgstr "²ØáÞÚÐ ïÚöáâì ×ÒãÚã (ßÞÒöÛìÝöèÕ) (àÕÑãâ)"
msgid "Disable power off"
msgstr "·ÐÑÞàÞÝØâØ ÒØÜÚÝÕÝÝï"
+#: 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 "ÀÕÖØÜ ÜØèö ÚÛöÚÝãâØ-âÐ-âïÓÝãâØ ãÒöÜÚÝÕÝÞ."
+#: 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 "ÀÕÖØÜ ÜØèö ÚÛöÚÝãâØ-âÐ-âïÓÝãâØ ÒØÜÚÝÕÝÞ."
+#: 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 "ÀÕÖØÜ âÐçßÐÔã ãÒöÜÚÝÕÝÞ."
+#: 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 "ÀÕÖØÜ âÐçßÐÔã ÒØÜÚÝÕÝÞ."
@@ -1708,9 +1973,9 @@ msgstr "ÀÕÖØÜ ÚÛöÚöÒ"
#: 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
-#: backends/platform/tizen/form.cpp:275
msgid "Left Click"
msgstr "»öÒØÙ ÚÛöÚ"
@@ -1720,65 +1985,32 @@ msgstr "ÁÕàÕÔÝöÙ ÚÛöÚ"
#: backends/platform/maemo/maemo.cpp:220
#: backends/platform/symbian/src/SymbianActions.cpp:43
-#: backends/platform/wince/CEActionsSmartphone.cpp:44
#: backends/platform/tizen/form.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:44
msgid "Right Click"
msgstr "¿àÐÒØÙ ÚÛöÚ"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:77
+#: backends/platform/sdl/macosx/appmenu_osx.mm:88
msgid "Hide ScummVM"
msgstr "ÁåÞÒÐâØ ScummVM"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:82
+#: backends/platform/sdl/macosx/appmenu_osx.mm:93
msgid "Hide Others"
msgstr "ÁåÞÒÐâØ ¦Ýèö"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:87
+#: backends/platform/sdl/macosx/appmenu_osx.mm:98
msgid "Show All"
msgstr "¿ÞÚÐ×ÐâØ ²áÕ"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:109
#: backends/platform/sdl/macosx/appmenu_osx.mm:120
+#: backends/platform/sdl/macosx/appmenu_osx.mm:131
msgid "Window"
msgstr "²öÚÝÞ"
-#: backends/platform/sdl/macosx/appmenu_osx.mm:114
+#: backends/platform/sdl/macosx/appmenu_osx.mm:125
msgid "Minimize"
msgstr "¼öÝöÜö×ãÒÐâØ"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:46
-msgid "Normal (no scaling)"
-msgstr "±Õ× ×ÑöÛìèÕÝÝï"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:65
-msgctxt "lowres"
-msgid "Normal (no scaling)"
-msgstr "±Õ× ×ÑöÛìèÕÝÝï"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
-msgid "Enabled aspect ratio correction"
-msgstr "ºÞàÕÚæöî áßöÒÒöÔÝÞèÕÝÝï áâÞàöÝ ãÒöÜÚÝÕÝÞ"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
-msgid "Disabled aspect ratio correction"
-msgstr "ºÞàÕÚæöî áßöÒÒöÔÝÞèÕÝÝï áâÞàöÝ ÒØÜÚÝÕÝÞ"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
-msgid "Active graphics filter:"
-msgstr "¿ÞâÞçÝØÙ ÓàÐäöçÝØÙ äöÛìâà:"
-
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
-msgid "Windowed mode"
-msgstr "²öÚÞÝÝØÙ àÕÖØÜ"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:118
-msgid "OpenGL"
-msgstr "OpenGL"
-
-#: backends/graphics/opengl/opengl-graphics.cpp:119
-msgid "OpenGL (No filtering)"
-msgstr "OpenGL (ÑÕ× äöÛìâàöÒ)"
-
#: backends/platform/symbian/src/SymbianActions.cpp:38
#: backends/platform/wince/CEActionsSmartphone.cpp:39
msgid "Up"
@@ -1822,14 +2054,6 @@ msgstr "¿àÞßãáâØâØ âÕÚáâ"
msgid "Fast mode"
msgstr "ÈÒØÔÚØÙ àÕÖØÜ"
-#: backends/platform/symbian/src/SymbianActions.cpp:52
-#: backends/platform/wince/CEActionsPocket.cpp:44
-#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: backends/events/default/default-events.cpp:218 engines/scumm/dialogs.cpp:192
-#: engines/scumm/help.cpp:83 engines/scumm/help.cpp:85
-msgid "Quit"
-msgstr "²ØåöÔ"
-
#: backends/platform/symbian/src/SymbianActions.cpp:53
msgid "Debugger"
msgstr "²öÔÛÐÔçØÚ"
@@ -1846,9 +2070,49 @@ msgstr "²öàâãÐÛìÝÐ ÚÛÐÒöÐâãàÐ"
msgid "Key mapper"
msgstr "¿àØ×ÝÐçÕÝÝï ÚÛÐÒöè"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:186
-msgid "Do you want to quit ?"
-msgstr "²Ø ÔöÙáÝÞ åÞçÕâÕ ÒØÙâØ?"
+#: backends/platform/tizen/form.cpp:263
+msgid "Right Click Once"
+msgstr "¾ÔØÝ ßàÐÒØÙ ÚÛöÚ"
+
+#: backends/platform/tizen/form.cpp:271
+msgid "Move Only"
+msgstr "ÂöÛìÚØ ßÕàÕÜöáâØâØ"
+
+#: backends/platform/tizen/form.cpp:294
+msgid "Escape Key"
+msgstr "ºÛÐÒöèÐ ESC"
+
+#: backends/platform/tizen/form.cpp:299
+msgid "Game Menu"
+msgstr "¼ÕÝî ÓàØ"
+
+#: backends/platform/tizen/form.cpp:304
+msgid "Show Keypad"
+msgstr "¿ÞÚÐ×ÐâØ ÚÛÐÒöÐâãàã"
+
+#: backends/platform/tizen/form.cpp:309
+msgid "Control Mouse"
+msgstr "ÃßàÐÒÛöÝÝï ÜØèÕî"
+
+#: backends/platform/tizen/fs.cpp:259
+msgid "[ Data ]"
+msgstr "[ ´ÐÝö ]"
+
+#: backends/platform/tizen/fs.cpp:263
+msgid "[ Resources ]"
+msgstr "[ ÀÕáãàáØ ]"
+
+#: backends/platform/tizen/fs.cpp:267
+msgid "[ SDCard ]"
+msgstr "[ ºÐàâÚÐ SD ]"
+
+#: backends/platform/tizen/fs.cpp:271
+msgid "[ Media ]"
+msgstr "[ ¼ÕÔöÐ ]"
+
+#: backends/platform/tizen/fs.cpp:275
+msgid "[ Shared ]"
+msgstr "[ ¼ÕàÕÖÕÒÐ ßÐßÚÐ ]"
#: backends/platform/wii/options.cpp:51
msgid "Video"
@@ -2095,140 +2359,109 @@ msgstr ""
"½Õ ×ÐÑãÔìâÕ ßÕàÕßàØ×ÝÐçØâØ ÚÝÞßÚã ÔÛï Ôö÷ 'ÁåÞÒÐâØ ¿ÐÝÕÛì öÝáâà.' éÞÑ "
"ßÞÑÐçØâØ ÒÕáì öÝÒÕÝâÐà"
-#: backends/events/default/default-events.cpp:196
-msgid "Do you really want to return to the Launcher?"
-msgstr "²Ø ÔöÙáÝÞ åÞçÕâÕ ßÞÒÕàÝãâØáï ÔÞ ÓÞÛÞÒÝÞÓÞ ÜÕÝî?"
-
-#: backends/events/default/default-events.cpp:196
-msgid "Launcher"
-msgstr "³ÞÛÞÒÝÕ ÜÕÝî"
-
-#: backends/events/default/default-events.cpp:218
-msgid "Do you really want to quit?"
-msgstr "²Ø ÔöÙáÝÞ åÞçÕâÕ ÒØÙâØ?"
-
-#: 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 "ÀÕÖØÜ ÔÞâØÚã ã âÐçáÚàöÝö - »öÒØÙ ÚÛöÚ"
-
-#: 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 "ÀÕÖØÜ ÔÞâØÚã ã âÐçáÚàöÝö - ¿àÐÒØÙ ÚÛöÚ"
-
-#: 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 "ÀÕÖØÜ ÔÞâØÚã ã âÐçáÚàöÝö - ¿àÞÛöâ (ÑÕ× ÚÛöÚã)"
-
-#: backends/events/gph/gph-events.cpp:409
-msgid "Maximum Volume"
-msgstr "¼ÐÚáØÜÐÛìÝÐ ³ãçÝöáâì"
-
-#: backends/events/gph/gph-events.cpp:411
-msgid "Increasing Volume"
-msgstr "¿öÔÒØéÕÝÝï ÓãçÝÞáâö"
-
-#: backends/events/gph/gph-events.cpp:417
-msgid "Minimal Volume"
-msgstr "¼öÝöÜÐÛìÝÐ ³ãçÝöáâì"
-
-#: backends/events/gph/gph-events.cpp:419
-msgid "Decreasing Volume"
-msgstr "¿ÞÝØÖÕÝÝï ÓãçÝÞáâö"
-
-#: backends/events/openpandora/op-events.cpp:174
-msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
-msgstr "ÀÕÖØÜ ÔÞâØÚã ã âÐçáÚàöÝö - ¿àÞÛöâ (ÚÛöÚ DPad)"
-
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
-msgstr "¿ÕàÕÒöàïî ÞÝÞÒÛÕÝÝï..."
-
-#: backends/platform/tizen/form.cpp:263
-msgid "Right Click Once"
-msgstr "¾ÔØÝ ßàÐÒØÙ ÚÛöÚ"
-
-#: backends/platform/tizen/form.cpp:271
-msgid "Move Only"
-msgstr "ÂöÛìÚØ ßÕàÕÜöáâØâØ"
-
-#: backends/platform/tizen/form.cpp:294
-msgid "Escape Key"
-msgstr "ºÛÐÒöèÐ ESC"
-
-#: backends/platform/tizen/form.cpp:299
-msgid "Game Menu"
-msgstr "¼ÕÝî ÓàØ"
+msgstr "¿ÕàÕÒöàØâØ ÞÝÞÒÛÕÝÝï..."
-#: backends/platform/tizen/form.cpp:304
-msgid "Show Keypad"
-msgstr "¿ÞÚÐ×ÐâØ ÚÛÐÒöÐâãàã"
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "ÀÕÖØÜ ÑÕ× ÚÞÛìÞàã"
-#: backends/platform/tizen/form.cpp:309
-msgid "Control Mouse"
-msgstr "ÃßàÐÒÛöÝÝï ÜØèÕî"
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Enabled"
-msgstr "ºÛöÚØ ãÒöÜÚÝÕÝÞ"
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
-#: backends/events/maemosdl/maemosdl-events.cpp:180
-msgid "Clicking Disabled"
-msgstr "ºÛöÚØ ÒØÜÚÝÕÝÞ"
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "¿ÞÚÐ×ãÒÐâØ ÛöÝö÷ ÞÑ'ôÚâöÒ"
-#: engines/agi/detection.cpp:147 engines/drascula/detection.cpp:302
-#: engines/dreamweb/detection.cpp:47 engines/neverhood/detection.cpp:160
-#: engines/sci/detection.cpp:394 engines/toltecs/detection.cpp:200
-#: engines/zvision/detection_tables.h:51
+#: 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 "²ØÚÞàØáâÞÒãÒÐâØ ÞàØÓ. ×ÑÕàÕÖÕÝÝï/×ÐÒÐÝâÐÖÕÝÝï ÕÚàÐÝØ"
-#: engines/agi/detection.cpp:148 engines/drascula/detection.cpp:303
-#: engines/dreamweb/detection.cpp:48 engines/neverhood/detection.cpp:161
-#: engines/sci/detection.cpp:395 engines/toltecs/detection.cpp:201
+#: 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 ""
"²ØÚÞàØáâÞÒãÒÐâØ ÞàØÓöÝÐÛìÝö ×ÑÕàÕÖÕÝÝï/×ÐÒÐÝâÐÖÕÝÝï ÕÚàÐÝØ, ×ÐÜöáâì ScummVM"
#: engines/agi/detection.cpp:157
-#, fuzzy
msgid "Use an alternative palette"
-msgstr "²ØÚÞàØáâÞÒãÒÐâØ ÐÛìâÕàÝÐâØÒÝØÙ Òáâãß ÓàØ (âöÛìÚØ CD ÒÕàáöï)"
+msgstr "²ØÚÞàØáâÞÒãÒÐâØ ÐÛìâÕàÝÐâØÒÝã ßÐÛöâàã"
#: engines/agi/detection.cpp:158
msgid ""
"Use an alternative palette, common for all Amiga games. This was the old "
"behavior"
msgstr ""
+"²ØÚÞàØáâÞÒãÒÐâØ ÐÛìâÕàÝÐâØÒÝã ßÐÛöâàã, ×ÒØçÐÙÝã ÔÛï öÓÞà × Amiga. ÆÕ ÑãÛÐ "
+"áâÐàÐ ßÞÒÕÔöÝÚÐ."
#: engines/agi/detection.cpp:167
-#, fuzzy
msgid "Mouse support"
-msgstr "¿öÔâàØÜãÒÐâØ ¿àÞßãáâØâØ"
+msgstr "¿öÔâàØÜÚÐ ÜØèö"
#: engines/agi/detection.cpp:168
msgid ""
"Enables mouse support. Allows to use mouse for movement and in game menus."
msgstr ""
+"²ÚÛîçÐô ßöÔâàØÜÚã ÜØèö. ´Þ×ÒÞÛïô ÒØÚÞàØáâÞÒãÒÐâØ ÜØèã ÔÛï ßÕàÕáãÒÐÝÝï âÐ "
+"ãßàÐÒÛöÝÝï ÜÕÝî."
+
+#: 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/saveload.cpp:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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:816 engines/drascula/saveload.cpp:349
-#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886
-#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
+#: 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"
@@ -2239,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"
@@ -2250,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"
@@ -2261,19 +2494,18 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/animation.cpp:557
+#: engines/agos/animation.cpp:558
#, c-format
msgid "Cutscene file '%s' not found!"
msgstr "ÄÐÙÛ àÞÛØÚã '%s' ÝÕ ×ÝÐÙÔÕÝÞ!"
#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
-#, fuzzy
msgid "Color Blind Mode"
-msgstr "ÀÕÖØÜ ÚÛöÚöÒ"
+msgstr "ÀÕÖØÜ ÑÕ× ÚÞÛìÞàã"
#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
-msgstr ""
+msgstr "²ÚÛîçÐô àÕÖØÜ ÔÛï ÛîÔÕÙ × ßÞÓöàèÕÝÝØÜ áßàØïââïÜ ÚÞÛìÞàã"
#: engines/drascula/saveload.cpp:47
msgid ""
@@ -2292,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 "½Õ ÒÔÐÛÞáï ×ÑÕàÕÓâØ áâÐÝ ÓàØ ã äÐÙÛ."
@@ -2322,17 +2554,17 @@ 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 "½Õ ÒÔÐÛÞáï ×ÐßØáÐâØ Óàã"
#: engines/hopkins/detection.cpp:76 engines/hopkins/detection.cpp:86
msgid "Gore Mode"
-msgstr ""
+msgstr "ÀÕÖØÜ × ÚàÞÒ'î"
#: engines/hopkins/detection.cpp:77 engines/hopkins/detection.cpp:87
msgid "Enable Gore Mode when available"
-msgstr ""
+msgstr "ÃÒöÜÚÝãâØ àÕÖØÜ × ÚàÞÒ'î, ïÚéÞ ô ÔÞáâãßÝØÙ"
#. I18N: Studio audience adds an applause and cheering sounds whenever
#. Malcolm makes a joke.
@@ -2464,6 +2696,12 @@ msgid ""
"Do you wish to use this save game file with ScummVM?\n"
"\n"
msgstr ""
+"½ÐáâãßÝØÙ ÞàØÓöÝÐÛìÝØÙ äÐÙÛ áâÐÝã ÓàØ ÑãÛÞ ×ÝÐÙÔÕÝÞ ã ÒÐèöÙ ßÐßæö × ÓàÞî:\n"
+"\n"
+"%s %s\n"
+"\n"
+"ÇØ ÒØ ÑÐÖÐôâÕ ÒØÚÞàØáâÞÒãÒÐâØ æÕÙ áâÐÝ ÓàØ ×ö ScummVM?\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:590
#, c-format
@@ -2471,6 +2709,8 @@ msgid ""
"A save game file was found in the specified slot %d. Overwrite?\n"
"\n"
msgstr ""
+"ÄÐÙÛ áâÐÝã ÓàØ ÑãÛÞ ×ÝÐÙÔÕÝÞ ã ÒÚÐ×ÐÝöÙ ßÞ×Øæö÷ %d. ¿ÕàÕâÕàâØ?\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:623
#, c-format
@@ -2482,50 +2722,63 @@ msgid ""
"'import_savefile'.\n"
"\n"
msgstr ""
+"%d ÞàØÓöÝÐÛìÝØå äÐÙÛöÒ ×ö áâÐÝÞÜ ÓàØ ÑãÛÞ ãáßöèÝÞ öÜßÞàâÞÒÐÝÞ ã\n"
+"ScummVM. ÏÚéÞ ÒØ ×ÐåÞçÕâÕ ßö×ÝöèÕ öÜßÞàâãÒÐâØ ÞàØÓöÝÐÛìÝö äÐÙÛØ ×ö áâÐÝÞÜ "
+"ÓàØ, ÒÐÜ ßÞâàöÑÝÞ\n"
+"ÒöÔÚàØâØ ÚÞÝáÞÛì ÒöÔÛÐÔçØÚÐ ö ÒÒÕáâØ ÚÞÜÐÝÔã '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"
@@ -2534,15 +2787,23 @@ msgstr ""
"½Õ ÜÞÖã ×ÑÕàÕÓâØ Óàã ã áÛÞâ %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:194
+msgid "Load file"
+msgstr "·ÐÒÐÝâÐÖØâØ äÐÙÛ"
+
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "·ÐÒÐÝâÐÖãî Óàã..."
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:209
+msgid "Save file"
+msgstr "·ÑÕàÕÓâØ äÐÙÛ"
+
+#: 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"
@@ -2558,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"
@@ -2618,27 +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 ""
+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:395
+msgid "Enable high resolution graphics/content"
+msgstr "ÃÒöÜÚÝãâØ ÓàÐäöÚã âÐ ÚÞÝâÕÝâ ã ÒØáÞÚÞÜã àÞ×ÓÐÛãÖÕÝÝö"
+
+#: 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:385
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
msgstr "²öÔÔÐÒÐâØ ßÕàÕÒÐÓã æØäàÞÒØÜ ×ÒãÚÞÒØÜ ÕäÕÚâÐÜ, Ð ÝÕ áØÝâÕ×ÞÒÐÝØÜ"
-#: engines/sci/detection.cpp:404
+#: engines/sci/detection.cpp:434
msgid "Use IMF/Yamaha FB-01 for MIDI output"
msgstr "²ØÚÞàØáâÞÒãÒÐâØ IMF/Yahama FB-01 ÔÛï MIDI ÒØåÞÔã"
-#: engines/sci/detection.cpp:405
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2646,149 +2925,155 @@ msgstr ""
"²ØÚÞàØáâÞÒãÒÐâØ ÔÛïÒ ÒØÒÞÔã MIDI àÕÖØÜ ÚÐàâØ IBM Feature ÐÑÞ FM áöÝâÕ× "
"Yamaha FB-01"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "²ØÚÞàØáâÞÒãÒÐâØ CD ÐãÔöÞ"
-#: engines/sci/detection.cpp:416
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
msgstr "²ØÚÞàØáâÞÒãÒÐâØ CD ÐãÔöÞ ×ÐÜöáâì ã-Óàö ÐãÔöÞ, ïÚéÞ âÐÚö ô"
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "²ØÚÞàØáâÞÒãÒÐâØ Windows ÚãàáÞàØ"
-#: engines/sci/detection.cpp:427
+#: 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:437
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "²ØÚÞàØáâÞÒãÒÐâØ áàöÑÝö ÚãàáÞàØ"
-#: engines/sci/detection.cpp:438
+#: 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
-#, fuzzy
+#: engines/scumm/dialogs.cpp:179
msgid "Are you sure you want to restart? (Y/N)Y"
-msgstr "²Ø ãßÕÒÝÕÝö, éÞ åÞçÕâÕ àÞ×ßÞçÐâØ áßÞçÐâÚã? (Y/N)"
+msgstr "²Ø ãßÕÒÝÕÝö, éÞ åÞçÕâÕ àÞ×ßÞçÐâØ áßÞçÐâÚã? (Y/N)Y"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
-#: engines/scumm/dialogs.cpp:185
-#, fuzzy
+#: engines/scumm/dialogs.cpp:181
msgid "Are you sure you want to quit? (Y/N)Y"
-msgstr "²Ø ãßÕÒÝÕÝö, éÞ åÞçÕâÕ ÒØÙâØ? (Y/N)"
+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:600
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "ÂöÛìÚØ Þ×ÒãçÚÐ"
-#: engines/scumm/dialogs.cpp:601
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "¾×ÒãçÚÐ âÐ áãÑâØâàØ"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "ÂöÛìÚØ áãÑâØâàØ"
-#: engines/scumm/dialogs.cpp:610
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "¾×ÒãçÚÐ âÐ âÕÚáâ"
-#: engines/scumm/dialogs.cpp:656
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "¾ÑÕàöâì àÕÖØÜ áÚÛÐÔÝÞáâö."
-#: engines/scumm/dialogs.cpp:658
+#: engines/scumm/dialogs.cpp:656
msgid "Refer to your Loom(TM) manual for help."
msgstr "·Ð ÔÞßÞÜÞÓÞî ×ÒÕàâÐÙâÕáï ÔÞ öÝáâàãÚæö÷ Loom(TM)."
-#: engines/scumm/dialogs.cpp:662
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "¿àÐÚâØÚÐ"
-#: engines/scumm/dialogs.cpp:663
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "µÚáßÕàâ"
@@ -3213,25 +3498,24 @@ msgid "Third kid"
msgstr "ÂàÕâï ÔØâØÝÐ"
#: engines/scumm/help.cpp:292
-#, fuzzy
msgid "Toggle Inventory/IQ Points display"
-msgstr "¿ÕàÕÜÚÝãâØ ßÞÚÐ×ãÒÐÝÝï Ò æÕÝâàö ÕÚàÐÝã"
+msgstr "¿ÕàÕÜÚÝãâØ ßÞÚÐ×ãÒÐÝÝï öÝÒÕÝâÐàî ÐÑÞ ×ÝÐçÕÝÝï IQ"
#: engines/scumm/help.cpp:293
msgid "Toggle Keyboard/Mouse Fighting (*)"
-msgstr ""
+msgstr "¿ÕàÕÜÚÝãâØ ÚÕàãÒÐÝÝï ÑöÙÚÞî ºÛÐÒöÐâãàÐ/¼ØèÐ (*)"
#: engines/scumm/help.cpp:295
msgid "* Keyboard Fighting is always on,"
-msgstr ""
+msgstr "* ÃßàÐÒÛöÝÝï ÚÛÐÒöÐâãàÞî ×ÐÒÖÔØ ÒÛîçÕÝÕ, âÞÜã, "
#: engines/scumm/help.cpp:296
msgid " so despite the in-game message this"
-msgstr ""
+msgstr " ÝÕ×ÒÐÖÐîçØ ÝÐ ßÞÒöÔÞÜÛÕÝÝï ÓàØ, æÕ ÝÐÛÐèâãÒÐÝÝï"
#: engines/scumm/help.cpp:297
msgid " actually toggles Mouse Fighting Off/On"
-msgstr ""
+msgstr " ÝÐáßàÐÒÔö ÒÚÛîçÐô âÐ ÒØÚÛîçÐô ãßàÐÒÛöÝÝï ÜØèÕî."
#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
@@ -3268,7 +3552,7 @@ msgstr "±ØâØ ×ÝØ×ã"
#: engines/scumm/help.cpp:315
msgid "Sucker punch"
-msgstr ""
+msgstr "±ØâØ ××ÐÔã"
#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
@@ -3326,7 +3610,23 @@ msgstr "»ÕâöâØ ÝÐßàÐÒÞ"
msgid "Fly to lower right"
msgstr "»ÕâöâØ ÔÞÝØ×ã ÝÐßàÐÒÞ"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/input.cpp:578
+msgid "Snap scroll on"
+msgstr "¿àÞÚàãâÚÐ áâàØÑÚÐÜØ"
+
+#: engines/scumm/input.cpp:580
+msgid "Snap scroll off"
+msgstr "²ÜØÚÐô ßàÞÚàãâÚã áâàØÑÚÐÜØ"
+
+#: engines/scumm/input.cpp:593
+msgid "Music volume: "
+msgstr "³ãçÝöáâì Üã×ØÚØ: "
+
+#: engines/scumm/input.cpp:610
+msgid "Subtitle speed: "
+msgstr "ÈÒØÔ. áãÑâØâàöÒ: "
+
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3335,28 +3635,87 @@ msgstr ""
"ÀÕÖØÜ \"àöÔÝÞÓÞ\" MIDI ßÞâàÕÑãô ßÞÝÞÒÛÕÝÝï Roland Upgrade ÒöÔ\n"
"LucasArts, ßàÞâÕ %s ÒöÔáãâÝöÙ. ¿ÕàÕÜØÚÐîáì ÝÐ AdLib."
-#: engines/scumm/scumm.cpp:2644
-#, fuzzy
+#: 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 ""
-"·Ð×ÒØçÐÙ, ×ÐàÐ× ÑØ ×ÐßãáâØÒáï Maniac Mansion. ¿àÞâÕ ScummVM éÕ æìÞÓÞ ÝÕ "
-"ÒÜöô. ÉÞÑ ÓàÐâØ ã ÝìÞÓÞ, ÞÑÕàöâì '´ÞÔÐâØ Óàã' ã ßÞçÐâÚÞÒÞÜã ÜÕÝî ScummVM, ö "
-"ÒØÑÕàöâì ßÐßÚã Maniac ÒáÕàÕÔÕÝö ßÒßÚØ × ÓàÞî Tentacle."
+"·Ð×ÒØçÐÙ, ×ÐàÐ× ÑØ ×ÐßãáâØÒáï Maniac Mansion. °ÛÕ, éÞÑ æÕ ÜÞÓÛÞ ßàÐæîÒÐâØ, "
+"ÒÐÜ ßÞâàöÑÝÞ ßÕàÕßØáÐâØ äÐÙÛØ ÓàØ Maniac Manssion ã ßÐßÚã Maniac ÒáÕàÕÔØÝö "
+"ßÒßÚØ × ÓàÞî Tentacle, Ð âÐÚÞÖ ÔÞÔÐâØ áÐÜã Óàã ã ScummVM."
#: 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 ""
+"½Õ ÒÐÔÛÞáï ×ÝÐÙâØ äÐÙÛ ßàÞÓàÐÜØ 'Loom' Macintosh ÐÑØ ßàÞçØâÐâØ\n"
+"× ÝìÞÓÞ öÝáâàãÜÕÝâØ. ¼ã×ØÚã ÑãÛÞ ÒØÜÚÝÕÝÞ."
#: 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 ""
+"½Õ ÒÐÔÛÞáï ×ÝÐÙâØ äÐÙÛ ßàÞÓàÐÜØ 'Monkey Island' Macintosh ÐÑØ ßàÞçØâÐâØ\n"
+"× ÝìÞÓÞ öÝáâàãÜÕÝâØ. ¼ã×ØÚã ÑãÛÞ ÒØÜÚÝÕÝÞ."
+
+#: engines/sherlock/detection.cpp:71
+msgid "Use original savegame dialog"
+msgstr "²ØÚÞàØáâÞÒãÒÐâØ ÞàØÓöÝÐÛìÝØÙ ÕÚàÐÝ ×ÑÕàÕÖÕÝÝï"
+
+#: engines/sherlock/detection.cpp:72
+msgid ""
+"Files button in-game shows original savegame dialog rather than the ScummVM "
+"menu"
+msgstr ""
+"ºÝÞßÚÐ \"ÄÐÙÛØ\" ã Óàö ßÞÚÐ×ãÒÐâØÜÕ ÞàØÓöÝÐÛìÝØÙ ÕÚàÐÝ ×ÑÕàÕÖÕÝÝï ×ÐÜöáâì "
+"ÜÕÝî ScummVM"
+
+#: engines/sherlock/detection.cpp:81
+msgid "Pixellated scene transitions"
+msgstr "¿öÕáÕÛìÞÒÐÝö ßÕàÕåÞÔØ ÜöÖ áæÕÝÐÜØ"
+
+#: engines/sherlock/detection.cpp:82
+msgid "When changing scenes, a randomized pixel transition is done"
+msgstr "¿àØ ×ÜöÝö áæÕÝ ÑãÔÕ ÒöÔÑãÒÐâØáï ßÕàÕåöÔ ã ÒØÓÛïÔö ÒØßÐÔÚÞÒØå ßöÚáÕÛöÒ"
+
+#: engines/sherlock/detection.cpp:91
+msgid "Don't show hotspots when moving mouse"
+msgstr "½Õ ßÞÚÐ×ãÒÐâØ æöÚÐÒö âÞçÚØ ßàØ ÝÐÒÕÔÕÝÝö ÜØèÕî"
+
+#: engines/sherlock/detection.cpp:92
+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"
+msgstr "¿ÞÚÐ×ãÒÐâØ ßÞàâàÕâØ ÓÕàÞ÷Ò"
+
+#: engines/sherlock/detection.cpp:102
+msgid "Show portraits for the characters when conversing"
+msgstr "¿ÞÚÐ×ãÒÐâØ ßÞàâàÕâØ ÓÕàÞ÷Ò ßöÔ çÐá áßöÛÚãÒÐÝÝï"
+
+#: engines/sherlock/detection.cpp:111
+msgid "Slide dialogs into view"
+msgstr "·ÐÒÞÔØâØ ÔöÐÛÞÓØ ÔÞ ÞÑ×Þàã"
+
+#: engines/sherlock/detection.cpp:112
+msgid "Slide UI dialogs into view, rather than simply showing them immediately"
+msgstr "·ÐÒÞÔØâØ ÔöÐÛÞÓØ ÔÞ ÞÑ×Þàã ×ÐÜöáâì ÜØââôÒÞÓÞ ßÞÚÐ×ã"
+
+#: engines/sherlock/detection.cpp:121
+msgid "Transparent windows"
+msgstr "¿àÞ×Þàö ÒöÚÝÐ"
+
+#: engines/sherlock/detection.cpp:122
+msgid "Show windows with a partially transparent background"
+msgstr "¿ÞÚÐ×ãÒÐâØ ÒöÚÝÐ × çÐáâÚÞÒÞ ßàÞ×ÞàØÜ âÛÞÜ"
#: engines/sky/compact.cpp:130
msgid ""
@@ -3454,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"
@@ -3470,136 +3840,47 @@ msgstr ""
#: engines/wintermute/detection.cpp:58
msgid "Show FPS-counter"
-msgstr ""
+msgstr "¿ÞÚÐ×ÐâØ ÛöçØÛìÝØÚ ÚÐÔàöØ"
#: engines/wintermute/detection.cpp:59
msgid "Show the current number of frames per second in the upper left corner"
-msgstr ""
+msgstr "¿ÞÚÐ×ãô ã ÒÕàÝìÞÜã ÛöÒÞÜã Úãâö ßÞâÞçÝã ÚöÛìÚöáâì ÚÐÔàöÒ ÝÐ áÕÚãÝÔã"
#: engines/zvision/detection_tables.h:52
-#, fuzzy
msgid "Use the original save/load screens instead of the ScummVM interface"
msgstr ""
-"²ØÚÞàØáâÞÒãÒÐâØ ÞàØÓöÝÐÛìÝö ×ÑÕàÕÖÕÝÝï/×ÐÒÐÝâÐÖÕÝÝï ÕÚàÐÝØ, ×ÐÜöáâì ScummVM"
+"²ØÚÞàØáâÞÒãÒÐâØ ÞàØÓöÝÐÛìÝö ÕÚàÐÝØ ×ÑÕàÕÖÕÝÝï/×ÐÒÐÝâÐÖÕÝÝï ×ÐÜöáâì ScummVM"
#: engines/zvision/detection_tables.h:61
msgid "Double FPS"
-msgstr ""
+msgstr "¿ÞÔÒöÙÝÐ FPS"
#: engines/zvision/detection_tables.h:62
msgid "Increase framerate from 30 to 60 FPS"
-msgstr ""
+msgstr "¿öÔÒØéØâØ ÚöÛìÚöáâì ÚÐÔàöÒ ÝÐ áÕÚãÝÔã × 30 ÔÞ 60"
#: engines/zvision/detection_tables.h:71
-#, fuzzy
msgid "Enable Venus"
-msgstr "ÃÒöÜÚÝãâØ àÕÖØÜ ³ÕÛöãÜ"
+msgstr "ÃÒöÜÚÝãâØ Venus"
#: engines/zvision/detection_tables.h:72
-#, fuzzy
msgid "Enable the Venus help system"
-msgstr "ÃÒöÜÚÝãâØ àÕÖØÜ ³ÕÛöãÜ"
+msgstr "ÃÒöÜÚÝãâØ ÔÞßÞÜöÖÝã áØáâÕÜã Venus"
#: engines/zvision/detection_tables.h:81
msgid "Disable animation while turning"
-msgstr ""
+msgstr "²ØÚÛîçØâØ ÐÝöÜÐæöî ßöÔ çÐá ßÞÒÞàÞâöÒ"
#: engines/zvision/detection_tables.h:82
msgid "Disable animation while turning in panorama mode"
-msgstr ""
+msgstr "²ØÚÛîçÐô ÐÝöÜÐæöî ßöÔ çÐ ßÞÒÞàÞâöÒ ã àÕÖØÜö ßÐÝÞàÐÜØ"
#: engines/zvision/detection_tables.h:91
msgid "Use high resolution MPEG video"
-msgstr ""
+msgstr "²ØÚÞàØáâÞÒãÒÐâØ ÒöÔÕÞ MPEG × ßöÔÒØéÕÝÞî àÞ×ÔöÛìÝöáâî"
#: engines/zvision/detection_tables.h:92
-#, fuzzy
msgid "Use MPEG video from the DVD version, instead of lower resolution AVI"
msgstr ""
-"²ØÚÞàØáâÞÒãÒÐâØ ÐÛìâÕàÝÐâØÒÝØÙ ÝÐÑöà áàöÑÝØå ÚãàáÞàöÒ, ×ÐÜöáâì ×ÒØçÐÙÝØå "
-"×ÞÛÞâØå"
-
-#~ 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"
-
-#~ msgid "Hercules Green"
-#~ msgstr "Hercules ·ÕÛÕÝØÙ"
-
-#~ msgid "Hercules Amber"
-#~ msgstr "Hercules ±ãàèâØÝÝØÙ"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Green"
-#~ msgstr "Hercules ·ÕÛÕÝØÙ"
-
-#~ msgctxt "lowres"
-#~ msgid "Hercules Amber"
-#~ msgstr "Hercules ±ãàèâØÝÝØÙ"
-
-#~ msgid "Save game failed!"
-#~ msgstr "½Õ ÒÔÐÛÞáï ×ÑÕàÕÓâØ Óàã!"
-
-#~ 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 "FM Towns Emulator"
-#~ msgstr "µÜãÛïâÞà FM Towns"
-
-#~ msgid "Invalid Path"
-#~ msgstr "½ÕßàÐÒØÛìÝØÙ èÛïå"
+"²ØÚÞàØáâÞÒãÒÐâØ ÒöÔÕÞ MPEG × DVD-ÒÕàáö÷, ×ÐÜöáâì äÐÙÛöÒ AVI × ÝöÖçÞî "
+"àÞ×ÔöÛìÝÞî ×ÔÐâÝöáâî"
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 398a0c4b5a..dce5a5d153 100644
--- a/ports.mk
+++ b/ports.mk
@@ -53,16 +53,52 @@ 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
- cp $(srcdir)/dists/macosx/Info.plist $(bundle_name)/Contents/
+ sed -e 's/$$(PRODUCT_BUNDLE_IDENTIFIER)/org.scummvm.scummvm/' $(srcdir)/dists/macosx/Info.plist >$(bundle_name)/Contents/Info.plist
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)
@@ -91,17 +131,141 @@ endif
cp $(srcdir)/dists/iphone/icon.png $(bundle_name)/
cp $(srcdir)/dists/iphone/icon-72.png $(bundle_name)/
cp $(srcdir)/dists/iphone/Default.png $(bundle_name)/
- # Binary patch workaround for Iphone 5/IPad 4 "Illegal instruction: 4" toolchain issue (http://code.google.com/p/iphone-gcc-full/issues/detail?id=6)
- cp scummvm scummvm-iph5
- sed -i'' 's/\x00\x30\x93\xe4/\x00\x30\x93\xe5/g;s/\x00\x30\xd3\xe4/\x00\x30\xd3\xe5/g;' scummvm-iph5
- ldid -S scummvm-iph5
- chmod 755 scummvm-iph5
- cp scummvm-iph5 $(bundle_name)/ScummVM-iph5
+
+ios7bundle: iphone
+ mkdir -p $(bundle_name)
+ awk 'BEGIN {s=0}\
+ /<key>CFBundleIcons<\/key>/ {\
+ print $$0;\
+ print "\t<dict>";\
+ print "\t\t<key>CFBundlePrimaryIcon</key>";\
+ print "\t\t<dict>";\
+ print "\t\t\t<key>CFBundleIconFiles</key>";\
+ print "\t\t\t<array>";\
+ print "\t\t\t\t<string>AppIcon29x29</string>";\
+ print "\t\t\t\t<string>AppIcon40x40</string>";\
+ print "\t\t\t\t<string>AppIcon60x60</string>";\
+ print "\t\t\t</array>";\
+ print "\t\t</dict>";\
+ print "\t</dict>";\
+ s=2}\
+ /<key>CFBundleIcons~ipad<\/key>/ {\
+ print $$0;\
+ print "\t<dict>";\
+ print "\t\t<key>CFBundlePrimaryIcon</key>";\
+ print "\t\t<dict>";\
+ print "\t\t\t<key>CFBundleIconFiles</key>";\
+ print "\t\t\t<array>";\
+ print "\t\t\t\t<string>AppIcon29x29</string>";\
+ print "\t\t\t\t<string>AppIcon40x40</string>";\
+ print "\t\t\t\t<string>AppIcon60x60</string>";\
+ print "\t\t\t\t<string>AppIcon76x76</string>";\
+ print "\t\t\t\t<string>AppIcon83.5x83.5</string>";\
+ print "\t\t\t</array>";\
+ print "\t\t</dict>";\
+ print "\t</dict>";\
+ s=2}\
+ /<key>UILaunchImages<\/key>/ {\
+ print $$0;\
+ print "\t<array>";\
+ print "\t\t<dict>";\
+ print "\t\t\t<key>UILaunchImageMinimumOSVersion</key>";\
+ print "\t\t\t<string>8.0</string>";\
+ print "\t\t\t<key>UILaunchImageName</key>";\
+ print "\t\t\t<string>LaunchImage-800-Portrait-736h</string>";\
+ print "\t\t\t<key>UILaunchImageOrientation</key>";\
+ print "\t\t\t<string>Portrait</string>";\
+ print "\t\t\t<key>UILaunchImageSize</key>";\
+ print "\t\t\t<string>{414, 736}</string>";\
+ print "\t\t\t<key>UILaunchImageMinimumOSVersion</key>";\
+ print "\t\t\t<string>8.0</string>";\
+ print "\t\t\t<key>UILaunchImageName</key>";\
+ print "\t\t\t<string>LaunchImage-800-Landscape-736h</string>";\
+ print "\t\t\t<key>UILaunchImageOrientation</key>";\
+ print "\t\t\t<string>Landscape</string>";\
+ print "\t\t\t<key>UILaunchImageSize</key>";\
+ print "\t\t\t<string>{414, 736}</string>";\
+ print "\t\t\t<key>UILaunchImageMinimumOSVersion</key>";\
+ print "\t\t\t<string>8.0</string>";\
+ print "\t\t\t<key>UILaunchImageName</key>";\
+ print "\t\t\t<string>LaunchImage-800-667h</string>";\
+ print "\t\t\t<key>UILaunchImageOrientation</key>";\
+ print "\t\t\t<string>Portrait</string>";\
+ print "\t\t\t<key>UILaunchImageSize</key>";\
+ print "\t\t\t<string>{375, 667}</string>";\
+ print "\t\t\t<key>UILaunchImageMinimumOSVersion</key>";\
+ print "\t\t\t<string>7.0</string>";\
+ print "\t\t\t<key>UILaunchImageName</key>";\
+ print "\t\t\t<string>LaunchImage-700-568h</string>";\
+ print "\t\t\t<key>UILaunchImageOrientation</key>";\
+ print "\t\t\t<string>Portrait</string>";\
+ print "\t\t\t<key>UILaunchImageSize</key>";\
+ print "\t\t\t<string>{320, 568}</string>";\
+ print "\t\t</dict>";\
+ print "\t\t<dict>";\
+ print "\t\t\t<key>UILaunchImageMinimumOSVersion</key>";\
+ print "\t\t\t<string>7.0</string>";\
+ print "\t\t\t<key>UILaunchImageName</key>";\
+ print "\t\t\t<string>LaunchImage-700-Portrait</string>";\
+ print "\t\t\t<key>UILaunchImageOrientation</key>";\
+ print "\t\t\t<string>Portrait</string>";\
+ print "\t\t\t<key>UILaunchImageSize</key>";\
+ print "\t\t\t<string>{768, 1024}</string>";\
+ print "\t\t</dict>";\
+ print "\t\t<dict>";\
+ print "\t\t\t<key>UILaunchImageMinimumOSVersion</key>";\
+ print "\t\t\t<string>7.0</string>";\
+ print "\t\t\t<key>UILaunchImageName</key>";\
+ print "\t\t\t<string>LaunchImage-700-Landscape</string>";\
+ print "\t\t\t<key>UILaunchImageOrientation</key>";\
+ print "\t\t\t<string>Landscape</string>";\
+ print "\t\t\t<key>UILaunchImageSize</key>";\
+ print "\t\t\t<string>{768, 1024}</string>";\
+ print "\t\t</dict>";\
+ print "\t</array>";\
+ s=2}\
+ s==0 {print $$0}\
+ s > 0 { s-- }' $(srcdir)/dists/ios7/Info.plist >$(bundle_name)/Info.plist
+ sed -i'' -e 's/$$(PRODUCT_BUNDLE_IDENTIFIER)/org.scummvm.scummvm/' $(bundle_name)/Info.plist
+ cp $(DIST_FILES_DOCS) $(bundle_name)/
+ cp $(DIST_FILES_THEMES) $(bundle_name)/
+ifdef DIST_FILES_ENGINEDATA
+ cp $(DIST_FILES_ENGINEDATA) $(bundle_name)/
+endif
+ $(STRIP) scummvm
+ ldid -S scummvm
+ chmod 755 scummvm
+ cp scummvm $(bundle_name)/ScummVM
+ cp $(srcdir)/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29@2x.png $(bundle_name)/AppIcon29x29@2x.png
+ cp $(srcdir)/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29@2x.png $(bundle_name)/AppIcon29x29@2x~ipad.png
+ cp $(srcdir)/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29@3x.png $(bundle_name)/AppIcon29x29@3x.png
+ cp $(srcdir)/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29.png $(bundle_name)/AppIcon29x29~ipad.png
+ cp $(srcdir)/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40@2x.png $(bundle_name)/AppIcon40x40@2x.png
+ cp $(srcdir)/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40@2x.png $(bundle_name)/AppIcon40x40@2x~ipad.png
+ cp $(srcdir)/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40@3x.png $(bundle_name)/AppIcon40x40@3x.png
+ cp $(srcdir)/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40.png $(bundle_name)/AppIcon40x40~ipad.png
+ cp $(srcdir)/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-60@2x.png $(bundle_name)/AppIcon60x60@2x.png
+ cp $(srcdir)/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-60@3x.png $(bundle_name)/AppIcon60x60@3x.png
+ cp $(srcdir)/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-76@2x.png $(bundle_name)/AppIcon76x76@2x~ipad.png
+ cp $(srcdir)/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-76.png $(bundle_name)/AppIcon76x76~ipad.png
+ cp $(srcdir)/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-83.5@2x.png $(bundle_name)/AppIcon83.5x83.5@2x~ipad.png
+ cp $(srcdir)/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-640x1136-1.png $(bundle_name)/LaunchImage-700-568h@2x.png
+ cp $(srcdir)/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-2048x1536.png $(bundle_name)/LaunchImage-700-Landscape@2x~ipad.png
+ cp $(srcdir)/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-1024x768.png $(bundle_name)/LaunchImage-700-Landscape~ipad.png
+ cp $(srcdir)/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-1536x2048.png $(bundle_name)/LaunchImage-700-Portrait@2x~ipad.png
+ cp $(srcdir)/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-768x1024.png $(bundle_name)/LaunchImage-700-Portrait~ipad.png
+ cp $(srcdir)/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-1242x2208.png $(bundle_name)/LaunchImage-800-Portrait-736h@3x.png
+ cp $(srcdir)/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-2208x1242.png $(bundle_name)/LaunchImage-800-Landscape-736h@3x.png
+ cp $(srcdir)/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-750x1334.png $(bundle_name)/LaunchImage-800-667h@2x.png
# Location of static libs for the iPhone
ifneq ($(BACKEND), iphone)
+ifneq ($(BACKEND), ios7)
# Static libaries, used for the scummvm-static and iphone targets
-OSX_STATIC_LIBS := `$(STATICLIBPATH)/bin/sdl-config --static-libs`
+OSX_STATIC_LIBS := `$(SDLCONFIG) --static-libs`
+# With sdl2-config we don't always get the OpenGL framework
+OSX_STATIC_LIBS += -framework OpenGL
+endif
endif
ifdef USE_FREETYPE2
@@ -125,8 +289,16 @@ endif
ifdef USE_FLUIDSYNTH
OSX_STATIC_LIBS += \
- -framework CoreAudio \
- $(STATICLIBPATH)/lib/libfluidsynth.a
+ -liconv -framework CoreMIDI -framework CoreAudio\
+ $(STATICLIBPATH)/lib/libfluidsynth.a \
+ $(STATICLIBPATH)/lib/libglib-2.0.a \
+ $(STATICLIBPATH)/lib/libintl.a
+
+ifneq ($(BACKEND), iphone)
+ifneq ($(BACKEND), ios7)
+OSX_STATIC_LIBS += -lreadline
+endif
+endif
endif
ifdef USE_MAD
@@ -158,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.
@@ -170,7 +345,7 @@ scummvm-static: $(OBJS)
$(OSX_STATIC_LIBS) \
$(OSX_ZLIB)
-# Special target to create a static linked binary for the iPhone
+# Special target to create a static linked binary for the iPhone (legacy, and iOS 7+)
iphone: $(OBJS)
$(CXX) $(LDFLAGS) -o scummvm $(OBJS) \
$(OSX_STATIC_LIBS) \
@@ -211,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/*
@@ -220,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
#
@@ -309,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
@@ -331,5 +509,13 @@ endif
@echo Now run
@echo "\tgit commit -m 'DISTS: Generated Code::Blocks and MSVC project files'"
+# Target to create Raspberry Pi zip containig binary and specific README
+raspberrypi_dist:
+ mkdir -p $(srcdir)/scummvm-rpi
+ cp $(srcdir)/backends/platform/sdl/raspberrypi/README.RASPBERRYPI $(srcdir)/scummvm-rpi/README
+ cp $(srcdir)/scummvm $(srcdir)/scummvm-rpi
+ zip -r scummvm-rpi.zip scummvm-rpi
+ rm -f -R scummvm-rpi
+
# Mark special targets as phony
.PHONY: deb bundle osxsnap win32dist install uninstall
diff --git a/test/common/algorithm.h b/test/common/algorithm.h
index 6eecae3635..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) {}
@@ -47,10 +75,28 @@ public:
void test_pod_sort() {
{
+ int dummy;
+ Common::sort(&dummy, &dummy);
+ TS_ASSERT_EQUALS(checkSort(&dummy, &dummy, Common::Less<int>()), true);
+ }
+ {
+ int array[] = { 12 };
+ Common::sort(array, ARRAYEND(array));
+ TS_ASSERT_EQUALS(checkSort(array, ARRAYEND(array), Common::Less<int>()), true);
+
+ // already sorted
+ Common::sort(array, ARRAYEND(array));
+ TS_ASSERT_EQUALS(checkSort(array, ARRAYEND(array), Common::Less<int>()), true);
+ }
+ {
int array[] = { 63, 11, 31, 72, 1, 48, 32, 69, 38, 31 };
Common::sort(array, ARRAYEND(array));
TS_ASSERT_EQUALS(checkSort(array, ARRAYEND(array), Common::Less<int>()), true);
+ int sortedArray[] = { 1, 11, 31, 31, 32, 38, 48, 63, 69, 72 };
+ for (size_t i = 0; i < 10; ++i)
+ TS_ASSERT_EQUALS(array[i], sortedArray[i]);
+
// already sorted
Common::sort(array, ARRAYEND(array));
TS_ASSERT_EQUALS(checkSort(array, ARRAYEND(array), Common::Less<int>()), true);
@@ -79,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 f0027ec201..2dc67837db 100644
--- a/test/common/array.h
+++ b/test/common/array.h
@@ -44,6 +44,48 @@ class ArrayTestSuite : public CxxTest::TestSuite
TS_ASSERT_EQUALS(iter, array.end());
}
+ void test_erase_iterator() {
+ Common::Array<int> array;
+ Common::Array<int>::iterator iter;
+
+ // Fill the array with some random data
+ array.push_back(17);
+ array.push_back(33);
+ array.push_back(-11);
+
+ iter = array.begin();
+ ++iter;
+
+ iter = array.erase(iter);
+ TS_ASSERT_DIFFERS(iter, array.end());
+ TS_ASSERT_EQUALS(*iter, -11);
+ TS_ASSERT_EQUALS(array.size(), (unsigned int)2);
+ TS_ASSERT_EQUALS(array[0], 17);
+ TS_ASSERT_EQUALS(array[1], -11);
+ }
+
+ void test_insert_iterator() {
+ Common::Array<int> array;
+ Common::Array<int>::iterator iter;
+
+ // Fill the array with some random data
+ array.push_back(17);
+ array.push_back(33);
+ array.push_back(-11);
+
+ iter = array.begin();
+ ++iter;
+
+ array.insert(iter, 99);
+
+ TS_ASSERT_EQUALS(*iter, 99);
+ TS_ASSERT_EQUALS(array.size(), (unsigned int)4);
+ TS_ASSERT_EQUALS(array[0], 17);
+ TS_ASSERT_EQUALS(array[1], 99);
+ TS_ASSERT_EQUALS(array[2], 33);
+ TS_ASSERT_EQUALS(array[3], -11);
+ }
+
void test_direct_access() {
Common::Array<int> array;
@@ -312,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/rational.h b/test/common/rational.h
index 46dfc278c7..23d0c10acd 100644
--- a/test/common/rational.h
+++ b/test/common/rational.h
@@ -130,4 +130,15 @@ public:
TS_ASSERT_EQUALS(r1 / 2, Common::Rational(1, 4));
TS_ASSERT_EQUALS(2 / r1, Common::Rational(4, 1));
}
+
+ void test_isOne() {
+ Common::Rational r0(5, 5);
+ Common::Rational r1(1, 2);
+ Common::Rational r2(2, 1);
+ Common::Rational r3(1, 1);
+ TS_ASSERT(r0.isOne());
+ TS_ASSERT(!r1.isOne());
+ TS_ASSERT(!r2.isOne());
+ TS_ASSERT(r3.isOne());
+ }
};
diff --git a/test/common/str.h b/test/common/str.h
index adc6a099e4..461b26088a 100644
--- a/test/common/str.h
+++ b/test/common/str.h
@@ -332,6 +332,9 @@ class StringTestSuite : public CxxTest::TestSuite
TS_ASSERT(!Common::matchString("monkey.s99", "monkey.s*1"));
TS_ASSERT(Common::matchString("monkey.s101", "monkey.s*1"));
+ TS_ASSERT(Common::matchString("monkey.s01", "monkey.s##"));
+ TS_ASSERT(!Common::matchString("monkey.s01", "monkey.###"));
+
TS_ASSERT(!Common::String("").matchString("*_"));
TS_ASSERT(Common::String("a").matchString("a***"));
}
@@ -416,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/avi_decoder.cpp b/video/avi_decoder.cpp
index 52a55f600c..e07805f489 100644
--- a/video/avi_decoder.cpp
+++ b/video/avi_decoder.cpp
@@ -115,7 +115,7 @@ bool AVIDecoder::parseNextChunk() {
if (_fileStream->eos())
return false;
- debug(3, "Decoding tag %s", tag2str(tag));
+ debug(6, "Decoding tag %s", tag2str(tag));
switch (tag) {
case ID_LIST:
@@ -169,7 +169,7 @@ void AVIDecoder::handleList(uint32 listSize) {
listSize -= 4; // Subtract away listType's 4 bytes
uint32 curPos = _fileStream->pos();
- debug(0, "Found LIST of type %s", tag2str(listType));
+ debug(7, "Found LIST of type %s", tag2str(listType));
switch (listType) {
case ID_MOVI: // Movie List
@@ -384,7 +384,7 @@ void AVIDecoder::handleNextPacket(TrackStatus &status) {
if (status.track->getTrackType() == Track::kTrackTypeVideo) {
// Horrible AVI video has a premature end
// Force the frame to be the last frame
- debug(0, "Forcing end of AVI video");
+ debug(7, "Forcing end of AVI video");
((AVIVideoTrack *)status.track)->forceTrackEnd();
}
@@ -404,7 +404,7 @@ void AVIDecoder::handleNextPacket(TrackStatus &status) {
if (status.track->getTrackType() == Track::kTrackTypeVideo) {
// Horrible AVI video has a premature end
// Force the frame to be the last frame
- debug(0, "Forcing end of AVI video");
+ debug(7, "Forcing end of AVI video");
((AVIVideoTrack *)status.track)->forceTrackEnd();
}
@@ -647,7 +647,7 @@ byte AVIDecoder::getStreamIndex(uint32 tag) const {
void AVIDecoder::readOldIndex(uint32 size) {
uint32 entryCount = size / 16;
- debug(0, "Old Index: %d entries", entryCount);
+ debug(7, "Old Index: %d entries", entryCount);
if (entryCount == 0)
return;
@@ -663,12 +663,12 @@ void AVIDecoder::readOldIndex(uint32 size) {
// If it's absolute, the offset will equal the start of the movie list
bool isAbsolute = firstEntry.offset == _movieListStart;
- debug(1, "Old index is %s", isAbsolute ? "absolute" : "relative");
+ debug(6, "Old index is %s", isAbsolute ? "absolute" : "relative");
if (!isAbsolute)
firstEntry.offset += _movieListStart - 4;
- debug(0, "Index 0: Tag '%s', Offset = %d, Size = %d (Flags = %d)", tag2str(firstEntry.id), firstEntry.offset, firstEntry.size, firstEntry.flags);
+ debug(7, "Index 0: Tag '%s', Offset = %d, Size = %d (Flags = %d)", tag2str(firstEntry.id), firstEntry.offset, firstEntry.size, firstEntry.flags);
_indexEntries.push_back(firstEntry);
for (uint32 i = 1; i < entryCount; i++) {
@@ -683,7 +683,7 @@ void AVIDecoder::readOldIndex(uint32 size) {
indexEntry.offset += _movieListStart - 4;
_indexEntries.push_back(indexEntry);
- debug(0, "Index %d: Tag '%s', Offset = %d, Size = %d (Flags = %d)", i, tag2str(indexEntry.id), indexEntry.offset, indexEntry.size, indexEntry.flags);
+ debug(7, "Index %d: Tag '%s', Offset = %d, Size = %d (Flags = %d)", i, tag2str(indexEntry.id), indexEntry.offset, indexEntry.size, indexEntry.flags);
}
}
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"
diff --git a/video/qt_decoder.cpp b/video/qt_decoder.cpp
index 324bf65294..49034aad17 100644
--- a/video/qt_decoder.cpp
+++ b/video/qt_decoder.cpp
@@ -447,7 +447,9 @@ const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::decodeNextFrame()
}
// Update the edit list, if applicable
- if (endOfCurEdit()) {
+ // FIXME: Add support for playing backwards videos with more than one edit
+ // For now, stay on the first edit for reversed playback
+ if (endOfCurEdit() && !_reversed) {
_curEdit++;
if (atLastEdit())